From fd867a92c736cebb7e1dadfcfa9c5b909999bfed Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 21 Jan 2020 20:31:00 +0300 Subject: [PATCH 01/30] Escape asterisks in peer names in live location panel subtitle --- Telegram-iOS/en.lproj/Localizable.strings | 2 + ...ionBroadcastNavigationAccessoryPanel.swift | 4 +- .../Sources/PresentationStrings.swift | 6683 +++++++++-------- .../Resources/PresentationStrings.mapping | Bin 144171 -> 144219 bytes 4 files changed, 3347 insertions(+), 3342 deletions(-) diff --git a/Telegram-iOS/en.lproj/Localizable.strings b/Telegram-iOS/en.lproj/Localizable.strings index 0fdd4b8f34..c2aade54e4 100644 --- a/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram-iOS/en.lproj/Localizable.strings @@ -5282,3 +5282,5 @@ Any member of this group will be able to see messages in the channel."; "Forward.ErrorPublicQuizDisabledInChannels" = "Sorry, public polls can’t be forwarded to channels."; "Map.PlacesInThisArea" = "Places In This Area"; + +"Conversation.LiveLocationYouAndOther" = "**You** and %@"; diff --git a/submodules/TelegramBaseController/Sources/LocationBroadcastNavigationAccessoryPanel.swift b/submodules/TelegramBaseController/Sources/LocationBroadcastNavigationAccessoryPanel.swift index d75b0ee04f..59430f3883 100644 --- a/submodules/TelegramBaseController/Sources/LocationBroadcastNavigationAccessoryPanel.swift +++ b/submodules/TelegramBaseController/Sources/LocationBroadcastNavigationAccessoryPanel.swift @@ -135,13 +135,13 @@ final class LocationBroadcastNavigationAccessoryPanel: ASDisplayNode { } else { let otherString: String if filteredPeers.count == 1 { - otherString = peers[0].compactDisplayTitle + otherString = peers[0].compactDisplayTitle.replacingOccurrences(of: "*", with: "") } else { otherString = self.strings.Conversation_LiveLocationMembersCount(Int32(peers.count)) } let rawText: String if filteredPeers.count != peers.count { - rawText = self.strings.Conversation_LiveLocationYouAnd(otherString).0.replacingOccurrences(of: "*", with: "**") + rawText = self.strings.Conversation_LiveLocationYouAndOther(otherString).0 } else { rawText = otherString } diff --git a/submodules/TelegramPresentationData/Sources/PresentationStrings.swift b/submodules/TelegramPresentationData/Sources/PresentationStrings.swift index 08c5862b4c..f55acaf222 100644 --- a/submodules/TelegramPresentationData/Sources/PresentationStrings.swift +++ b/submodules/TelegramPresentationData/Sources/PresentationStrings.swift @@ -1131,4170 +1131,4173 @@ public final class PresentationStrings: Equatable { public var TwoStepAuth_EnterPasswordPassword: String { return self._s[869]! } public var NotificationsSound_Calypso: String { return self._s[870]! } public var Map_Map: String { return self._s[871]! } - public var CheckoutInfo_ReceiverInfoTitle: String { return self._s[873]! } - public var ChatSettings_TextSizeUnits: String { return self._s[874]! } + public func Conversation_LiveLocationYouAndOther(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[872]!, self._r[872]!, [_0]) + } + public var CheckoutInfo_ReceiverInfoTitle: String { return self._s[874]! } + public var ChatSettings_TextSizeUnits: String { return self._s[875]! } public func VoiceOver_Chat_FileFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[875]!, self._r[875]!, [_0]) + return formatWithArgumentRanges(self._s[876]!, self._r[876]!, [_0]) } - public var Common_of: String { return self._s[876]! } - public var Conversation_ForwardContacts: String { return self._s[879]! } - public var IntentsSettings_SuggestByAll: String { return self._s[881]! } + public var Common_of: String { return self._s[877]! } + public var Conversation_ForwardContacts: String { return self._s[880]! } + public var IntentsSettings_SuggestByAll: String { return self._s[882]! } public func Call_AnsweringWithAccount(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[882]!, self._r[882]!, [_0]) + return formatWithArgumentRanges(self._s[883]!, self._r[883]!, [_0]) } - public var Passport_Language_hy: String { return self._s[883]! } - public var Notifications_MessageNotificationsHelp: String { return self._s[884]! } - public var AutoDownloadSettings_Reset: String { return self._s[885]! } - public var Wallet_TransactionInfo_AddressCopied: String { return self._s[886]! } - public var Paint_ClearConfirm: String { return self._s[887]! } - public var Camera_VideoMode: String { return self._s[888]! } + public var Passport_Language_hy: String { return self._s[884]! } + public var Notifications_MessageNotificationsHelp: String { return self._s[885]! } + public var AutoDownloadSettings_Reset: String { return self._s[886]! } + public var Wallet_TransactionInfo_AddressCopied: String { return self._s[887]! } + public var Paint_ClearConfirm: String { return self._s[888]! } + public var Camera_VideoMode: String { return self._s[889]! } public func Conversation_RestrictedStickersTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[889]!, self._r[889]!, [_0]) + return formatWithArgumentRanges(self._s[890]!, self._r[890]!, [_0]) } - public var Privacy_Calls_AlwaysAllow_Placeholder: String { return self._s[890]! } - public var Conversation_ViewBackground: String { return self._s[891]! } + public var Privacy_Calls_AlwaysAllow_Placeholder: String { return self._s[891]! } + public var Conversation_ViewBackground: String { return self._s[892]! } public func Wallet_Info_TransactionDateHeaderYear(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[892]!, self._r[892]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[893]!, self._r[893]!, [_1, _2, _3]) } - public var Passport_Language_el: String { return self._s[893]! } - public var PhotoEditor_Original: String { return self._s[894]! } - public var Settings_FAQ_Button: String { return self._s[896]! } - public var Channel_Setup_PublicNoLink: String { return self._s[898]! } - public var Conversation_UnsupportedMedia: String { return self._s[899]! } - public var Conversation_SlideToCancel: String { return self._s[900]! } - public var Appearance_ThemePreview_ChatList_4_Name: String { return self._s[901]! } - public var Passport_Identity_OneOfTypeInternalPassport: String { return self._s[902]! } - public var CheckoutInfo_ShippingInfoPostcode: String { return self._s[903]! } - public var Conversation_ReportSpamChannelConfirmation: String { return self._s[904]! } - public var AutoNightTheme_NotAvailable: String { return self._s[905]! } - public var Conversation_Owner: String { return self._s[906]! } - public var Common_Create: String { return self._s[907]! } - public var Settings_ApplyProxyAlertEnable: String { return self._s[908]! } - public var ContactList_Context_Call: String { return self._s[909]! } - public var Localization_ChooseLanguage: String { return self._s[911]! } - public var ChatList_Context_AddToContacts: String { return self._s[913]! } - public var OldChannels_NoticeTitle: String { return self._s[914]! } - public var Settings_Proxy: String { return self._s[916]! } - public var Privacy_TopPeersHelp: String { return self._s[917]! } - public var CheckoutInfo_ShippingInfoCountryPlaceholder: String { return self._s[918]! } - public var Chat_UnsendMyMessages: String { return self._s[919]! } + public var Passport_Language_el: String { return self._s[894]! } + public var PhotoEditor_Original: String { return self._s[895]! } + public var Settings_FAQ_Button: String { return self._s[897]! } + public var Channel_Setup_PublicNoLink: String { return self._s[899]! } + public var Conversation_UnsupportedMedia: String { return self._s[900]! } + public var Conversation_SlideToCancel: String { return self._s[901]! } + public var Appearance_ThemePreview_ChatList_4_Name: String { return self._s[902]! } + public var Passport_Identity_OneOfTypeInternalPassport: String { return self._s[903]! } + public var CheckoutInfo_ShippingInfoPostcode: String { return self._s[904]! } + public var Conversation_ReportSpamChannelConfirmation: String { return self._s[905]! } + public var AutoNightTheme_NotAvailable: String { return self._s[906]! } + public var Conversation_Owner: String { return self._s[907]! } + public var Common_Create: String { return self._s[908]! } + public var Settings_ApplyProxyAlertEnable: String { return self._s[909]! } + public var ContactList_Context_Call: String { return self._s[910]! } + public var Localization_ChooseLanguage: String { return self._s[912]! } + public var ChatList_Context_AddToContacts: String { return self._s[914]! } + public var OldChannels_NoticeTitle: String { return self._s[915]! } + public var Settings_Proxy: String { return self._s[917]! } + public var Privacy_TopPeersHelp: String { return self._s[918]! } + public var CheckoutInfo_ShippingInfoCountryPlaceholder: String { return self._s[919]! } + public var Chat_UnsendMyMessages: String { return self._s[920]! } public func VoiceOver_Chat_Duration(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[920]!, self._r[920]!, [_0]) + return formatWithArgumentRanges(self._s[921]!, self._r[921]!, [_0]) } - public var TwoStepAuth_ConfirmationAbort: String { return self._s[921]! } + public var TwoStepAuth_ConfirmationAbort: String { return self._s[922]! } public func Contacts_AccessDeniedHelpPortrait(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[923]!, self._r[923]!, [_0]) + return formatWithArgumentRanges(self._s[924]!, self._r[924]!, [_0]) } - public var Contacts_SortedByPresence: String { return self._s[924]! } - public var Passport_Identity_SurnamePlaceholder: String { return self._s[925]! } - public var Cache_Title: String { return self._s[926]! } + public var Contacts_SortedByPresence: String { return self._s[925]! } + public var Passport_Identity_SurnamePlaceholder: String { return self._s[926]! } + public var Cache_Title: String { return self._s[927]! } public func Login_PhoneBannedEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[927]!, self._r[927]!, [_0]) + return formatWithArgumentRanges(self._s[928]!, self._r[928]!, [_0]) } - public var TwoStepAuth_EmailCodeExpired: String { return self._s[928]! } - public var Channel_Moderator_Title: String { return self._s[929]! } - public var InstantPage_AutoNightTheme: String { return self._s[931]! } + public var TwoStepAuth_EmailCodeExpired: String { return self._s[929]! } + public var Channel_Moderator_Title: String { return self._s[930]! } + public var InstantPage_AutoNightTheme: String { return self._s[932]! } public func PUSH_MESSAGE_POLL(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[934]!, self._r[934]!, [_1]) + return formatWithArgumentRanges(self._s[935]!, self._r[935]!, [_1]) } - public var Passport_Scans_Upload: String { return self._s[935]! } - public var Undo_Undo: String { return self._s[937]! } - public var Contacts_AccessDeniedHelpON: String { return self._s[938]! } - public var TwoStepAuth_RemovePassword: String { return self._s[939]! } - public var Common_Delete: String { return self._s[940]! } - public var Contacts_AddPeopleNearby: String { return self._s[942]! } - public var Conversation_ContextMenuDelete: String { return self._s[943]! } - public var SocksProxySetup_Credentials: String { return self._s[944]! } - public var Appearance_EditTheme: String { return self._s[946]! } - public var ClearCache_StorageOtherApps: String { return self._s[947]! } - public var PasscodeSettings_AutoLock_Disabled: String { return self._s[948]! } - public var Wallet_Send_NetworkErrorText: String { return self._s[949]! } - public var AuthSessions_DevicesTitle: String { return self._s[951]! } - public var Passport_Address_OneOfTypeRentalAgreement: String { return self._s[953]! } - public var Conversation_ShareBotContactConfirmationTitle: String { return self._s[954]! } - public var Passport_Language_id: String { return self._s[956]! } - public var WallpaperSearch_ColorTeal: String { return self._s[957]! } - public var ChannelIntro_Title: String { return self._s[958]! } + public var Passport_Scans_Upload: String { return self._s[936]! } + public var Undo_Undo: String { return self._s[938]! } + public var Contacts_AccessDeniedHelpON: String { return self._s[939]! } + public var TwoStepAuth_RemovePassword: String { return self._s[940]! } + public var Common_Delete: String { return self._s[941]! } + public var Contacts_AddPeopleNearby: String { return self._s[943]! } + public var Conversation_ContextMenuDelete: String { return self._s[944]! } + public var SocksProxySetup_Credentials: String { return self._s[945]! } + public var Appearance_EditTheme: String { return self._s[947]! } + public var ClearCache_StorageOtherApps: String { return self._s[948]! } + public var PasscodeSettings_AutoLock_Disabled: String { return self._s[949]! } + public var Wallet_Send_NetworkErrorText: String { return self._s[950]! } + public var AuthSessions_DevicesTitle: String { return self._s[952]! } + public var Passport_Address_OneOfTypeRentalAgreement: String { return self._s[954]! } + public var Conversation_ShareBotContactConfirmationTitle: String { return self._s[955]! } + public var Passport_Language_id: String { return self._s[957]! } + public var WallpaperSearch_ColorTeal: String { return self._s[958]! } + public var ChannelIntro_Title: String { return self._s[959]! } public func Channel_AdminLog_MessageToggleSignaturesOff(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[959]!, self._r[959]!, [_0]) + return formatWithArgumentRanges(self._s[960]!, self._r[960]!, [_0]) } - public var VoiceOver_Chat_OpenLinkHint: String { return self._s[961]! } - public var VoiceOver_Chat_Reply: String { return self._s[962]! } - public var ScheduledMessages_BotActionUnavailable: String { return self._s[963]! } - public var Channel_Info_Description: String { return self._s[964]! } - public var Stickers_FavoriteStickers: String { return self._s[965]! } - public var Channel_BanUser_PermissionAddMembers: String { return self._s[966]! } - public var Notifications_DisplayNamesOnLockScreen: String { return self._s[967]! } - public var ChatSearch_ResultsTooltip: String { return self._s[968]! } - public var Wallet_VoiceOver_Editing_ClearText: String { return self._s[969]! } - public var Calls_NoMissedCallsPlacehoder: String { return self._s[970]! } - public var Group_PublicLink_Placeholder: String { return self._s[971]! } - public var Notifications_ExceptionsDefaultSound: String { return self._s[972]! } + public var VoiceOver_Chat_OpenLinkHint: String { return self._s[962]! } + public var VoiceOver_Chat_Reply: String { return self._s[963]! } + public var ScheduledMessages_BotActionUnavailable: String { return self._s[964]! } + public var Channel_Info_Description: String { return self._s[965]! } + public var Stickers_FavoriteStickers: String { return self._s[966]! } + public var Channel_BanUser_PermissionAddMembers: String { return self._s[967]! } + public var Notifications_DisplayNamesOnLockScreen: String { return self._s[968]! } + public var ChatSearch_ResultsTooltip: String { return self._s[969]! } + public var Wallet_VoiceOver_Editing_ClearText: String { return self._s[970]! } + public var Calls_NoMissedCallsPlacehoder: String { return self._s[971]! } + public var Group_PublicLink_Placeholder: String { return self._s[972]! } + public var Notifications_ExceptionsDefaultSound: String { return self._s[973]! } public func PUSH_CHANNEL_MESSAGE_POLL(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[973]!, self._r[973]!, [_1]) + return formatWithArgumentRanges(self._s[974]!, self._r[974]!, [_1]) } - public var TextFormat_Underline: String { return self._s[974]! } + public var TextFormat_Underline: String { return self._s[975]! } public func DialogList_SearchSubtitleFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[976]!, self._r[976]!, [_1, _2]) + return formatWithArgumentRanges(self._s[977]!, self._r[977]!, [_1, _2]) } public func Channel_AdminLog_MessageRemovedGroupStickerPack(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[977]!, self._r[977]!, [_0]) + return formatWithArgumentRanges(self._s[978]!, self._r[978]!, [_0]) } - public var Appearance_ThemePreview_ChatList_3_Name: String { return self._s[978]! } + public var Appearance_ThemePreview_ChatList_3_Name: String { return self._s[979]! } public func Channel_OwnershipTransfer_TransferCompleted(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[979]!, self._r[979]!, [_1, _2]) + return formatWithArgumentRanges(self._s[980]!, self._r[980]!, [_1, _2]) } - public var Wallet_Intro_ImportExisting: String { return self._s[980]! } - public var GroupPermission_Delete: String { return self._s[981]! } - public var Passport_Language_uk: String { return self._s[982]! } - public var StickerPack_HideStickers: String { return self._s[984]! } - public var ChangePhoneNumberNumber_NumberPlaceholder: String { return self._s[985]! } + public var Wallet_Intro_ImportExisting: String { return self._s[981]! } + public var GroupPermission_Delete: String { return self._s[982]! } + public var Passport_Language_uk: String { return self._s[983]! } + public var StickerPack_HideStickers: String { return self._s[985]! } + public var ChangePhoneNumberNumber_NumberPlaceholder: String { return self._s[986]! } public func PUSH_CHAT_MESSAGE_PHOTO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[986]!, self._r[986]!, [_1, _2]) + return formatWithArgumentRanges(self._s[987]!, self._r[987]!, [_1, _2]) } - public var Activity_UploadingVideoMessage: String { return self._s[987]! } + public var Activity_UploadingVideoMessage: String { return self._s[988]! } public func GroupPermission_ApplyAlertText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[988]!, self._r[988]!, [_0]) + return formatWithArgumentRanges(self._s[989]!, self._r[989]!, [_0]) } - public var Channel_TitleInfo: String { return self._s[989]! } - public var StickerPacksSettings_ArchivedPacks_Info: String { return self._s[990]! } - public var Settings_CallSettings: String { return self._s[991]! } - public var Camera_SquareMode: String { return self._s[992]! } - public var Conversation_SendMessage_ScheduleMessage: String { return self._s[993]! } - public var GroupInfo_SharedMediaNone: String { return self._s[994]! } + public var Channel_TitleInfo: String { return self._s[990]! } + public var StickerPacksSettings_ArchivedPacks_Info: String { return self._s[991]! } + public var Settings_CallSettings: String { return self._s[992]! } + public var Camera_SquareMode: String { return self._s[993]! } + public var Conversation_SendMessage_ScheduleMessage: String { return self._s[994]! } + public var GroupInfo_SharedMediaNone: String { return self._s[995]! } public func PUSH_MESSAGE_VIDEO_SECRET(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[995]!, self._r[995]!, [_1]) + return formatWithArgumentRanges(self._s[996]!, self._r[996]!, [_1]) } - public var Bot_GenericBotStatus: String { return self._s[996]! } - public var Application_Update: String { return self._s[998]! } - public var Month_ShortJanuary: String { return self._s[999]! } - public var Contacts_PermissionsKeepDisabled: String { return self._s[1000]! } - public var Channel_AdminLog_BanReadMessages: String { return self._s[1001]! } - public var Settings_AppLanguage_Unofficial: String { return self._s[1002]! } - public var Passport_Address_Street2Placeholder: String { return self._s[1003]! } + public var Bot_GenericBotStatus: String { return self._s[997]! } + public var Application_Update: String { return self._s[999]! } + public var Month_ShortJanuary: String { return self._s[1000]! } + public var Contacts_PermissionsKeepDisabled: String { return self._s[1001]! } + public var Channel_AdminLog_BanReadMessages: String { return self._s[1002]! } + public var Settings_AppLanguage_Unofficial: String { return self._s[1003]! } + public var Passport_Address_Street2Placeholder: String { return self._s[1004]! } public func Map_LiveLocationShortHour(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1004]!, self._r[1004]!, [_0]) + return formatWithArgumentRanges(self._s[1005]!, self._r[1005]!, [_0]) } - public var NetworkUsageSettings_Cellular: String { return self._s[1005]! } - public var Appearance_PreviewOutgoingText: String { return self._s[1006]! } + public var NetworkUsageSettings_Cellular: String { return self._s[1006]! } + public var Appearance_PreviewOutgoingText: String { return self._s[1007]! } public func StickerPackActionInfo_RemovedText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1007]!, self._r[1007]!, [_0]) + return formatWithArgumentRanges(self._s[1008]!, self._r[1008]!, [_0]) } - public var Notifications_PermissionsAllowInSettings: String { return self._s[1008]! } - public var AutoDownloadSettings_OnForAll: String { return self._s[1010]! } - public var Map_Directions: String { return self._s[1011]! } - public var Passport_FieldIdentityTranslationHelp: String { return self._s[1013]! } - public var Appearance_ThemeDay: String { return self._s[1014]! } - public var LogoutOptions_LogOut: String { return self._s[1015]! } - public var Group_PublicLink_Title: String { return self._s[1017]! } - public var Channel_AddBotErrorNoRights: String { return self._s[1018]! } - public var ChatList_Search_ShowLess: String { return self._s[1019]! } - public var Passport_Identity_AddPassport: String { return self._s[1020]! } - public var LocalGroup_ButtonTitle: String { return self._s[1021]! } - public var Call_Message: String { return self._s[1022]! } - public var PhotoEditor_ExposureTool: String { return self._s[1023]! } - public var Wallet_Receive_CommentInfo: String { return self._s[1025]! } - public var Passport_FieldOneOf_Delimeter: String { return self._s[1026]! } - public var Channel_AdminLog_CanBanUsers: String { return self._s[1028]! } - public var Appearance_ThemePreview_ChatList_2_Name: String { return self._s[1029]! } - public var Appearance_Preview: String { return self._s[1030]! } - public var Compose_ChannelMembers: String { return self._s[1031]! } - public var Conversation_DeleteManyMessages: String { return self._s[1032]! } - public var ReportPeer_ReasonOther_Title: String { return self._s[1033]! } - public var Checkout_ErrorProviderAccountTimeout: String { return self._s[1034]! } - public var TwoStepAuth_ResetAccountConfirmation: String { return self._s[1035]! } - public var Channel_Stickers_CreateYourOwn: String { return self._s[1038]! } - public var Conversation_UpdateTelegram: String { return self._s[1039]! } - public var EditTheme_Create_TopInfo: String { return self._s[1040]! } + public var Notifications_PermissionsAllowInSettings: String { return self._s[1009]! } + public var AutoDownloadSettings_OnForAll: String { return self._s[1011]! } + public var Map_Directions: String { return self._s[1012]! } + public var Passport_FieldIdentityTranslationHelp: String { return self._s[1014]! } + public var Appearance_ThemeDay: String { return self._s[1015]! } + public var LogoutOptions_LogOut: String { return self._s[1016]! } + public var Group_PublicLink_Title: String { return self._s[1018]! } + public var Channel_AddBotErrorNoRights: String { return self._s[1019]! } + public var ChatList_Search_ShowLess: String { return self._s[1020]! } + public var Passport_Identity_AddPassport: String { return self._s[1021]! } + public var LocalGroup_ButtonTitle: String { return self._s[1022]! } + public var Call_Message: String { return self._s[1023]! } + public var PhotoEditor_ExposureTool: String { return self._s[1024]! } + public var Wallet_Receive_CommentInfo: String { return self._s[1026]! } + public var Passport_FieldOneOf_Delimeter: String { return self._s[1027]! } + public var Channel_AdminLog_CanBanUsers: String { return self._s[1029]! } + public var Appearance_ThemePreview_ChatList_2_Name: String { return self._s[1030]! } + public var Appearance_Preview: String { return self._s[1031]! } + public var Compose_ChannelMembers: String { return self._s[1032]! } + public var Conversation_DeleteManyMessages: String { return self._s[1033]! } + public var ReportPeer_ReasonOther_Title: String { return self._s[1034]! } + public var Checkout_ErrorProviderAccountTimeout: String { return self._s[1035]! } + public var TwoStepAuth_ResetAccountConfirmation: String { return self._s[1036]! } + public var Channel_Stickers_CreateYourOwn: String { return self._s[1039]! } + public var Conversation_UpdateTelegram: String { return self._s[1040]! } + public var EditTheme_Create_TopInfo: String { return self._s[1041]! } public func Notification_PinnedPhotoMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1041]!, self._r[1041]!, [_0]) + return formatWithArgumentRanges(self._s[1042]!, self._r[1042]!, [_0]) } - public var Wallet_WordCheck_Continue: String { return self._s[1042]! } - public var TwoFactorSetup_Hint_Action: String { return self._s[1043]! } - public var IntentsSettings_ResetAll: String { return self._s[1044]! } + public var Wallet_WordCheck_Continue: String { return self._s[1043]! } + public var TwoFactorSetup_Hint_Action: String { return self._s[1044]! } + public var IntentsSettings_ResetAll: String { return self._s[1045]! } public func PUSH_PINNED_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1045]!, self._r[1045]!, [_1]) + return formatWithArgumentRanges(self._s[1046]!, self._r[1046]!, [_1]) } - public var GroupInfo_Administrators_Title: String { return self._s[1046]! } - public var Privacy_Forwards_PreviewMessageText: String { return self._s[1047]! } + public var GroupInfo_Administrators_Title: String { return self._s[1047]! } + public var Privacy_Forwards_PreviewMessageText: String { return self._s[1048]! } public func PrivacySettings_LastSeenNobodyPlus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1048]!, self._r[1048]!, [_0]) + return formatWithArgumentRanges(self._s[1049]!, self._r[1049]!, [_0]) } - public var Tour_Title3: String { return self._s[1049]! } - public var Channel_EditAdmin_PermissionInviteSubscribers: String { return self._s[1050]! } - public var Clipboard_SendPhoto: String { return self._s[1054]! } - public var MediaPicker_Videos: String { return self._s[1055]! } - public var Passport_Email_Title: String { return self._s[1056]! } + public var Tour_Title3: String { return self._s[1050]! } + public var Channel_EditAdmin_PermissionInviteSubscribers: String { return self._s[1051]! } + public var Clipboard_SendPhoto: String { return self._s[1055]! } + public var MediaPicker_Videos: String { return self._s[1056]! } + public var Passport_Email_Title: String { return self._s[1057]! } public func PrivacySettings_LastSeenEverybodyMinus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1057]!, self._r[1057]!, [_0]) + return formatWithArgumentRanges(self._s[1058]!, self._r[1058]!, [_0]) } - public var StickerPacksSettings_Title: String { return self._s[1058]! } - public var Conversation_MessageDialogDelete: String { return self._s[1059]! } - public var Privacy_Calls_CustomHelp: String { return self._s[1061]! } - public var Message_Wallpaper: String { return self._s[1062]! } - public var MemberSearch_BotSection: String { return self._s[1063]! } - public var GroupInfo_SetSound: String { return self._s[1064]! } - public var Core_ServiceUserStatus: String { return self._s[1065]! } - public var LiveLocationUpdated_JustNow: String { return self._s[1066]! } - public var Call_StatusFailed: String { return self._s[1067]! } - public var TwoFactorSetup_Email_Placeholder: String { return self._s[1068]! } - public var TwoStepAuth_SetupPasswordDescription: String { return self._s[1069]! } - public var TwoStepAuth_SetPassword: String { return self._s[1070]! } - public var Permissions_PeopleNearbyText_v0: String { return self._s[1071]! } + public var StickerPacksSettings_Title: String { return self._s[1059]! } + public var Conversation_MessageDialogDelete: String { return self._s[1060]! } + public var Privacy_Calls_CustomHelp: String { return self._s[1062]! } + public var Message_Wallpaper: String { return self._s[1063]! } + public var MemberSearch_BotSection: String { return self._s[1064]! } + public var GroupInfo_SetSound: String { return self._s[1065]! } + public var Core_ServiceUserStatus: String { return self._s[1066]! } + public var LiveLocationUpdated_JustNow: String { return self._s[1067]! } + public var Call_StatusFailed: String { return self._s[1068]! } + public var TwoFactorSetup_Email_Placeholder: String { return self._s[1069]! } + public var TwoStepAuth_SetupPasswordDescription: String { return self._s[1070]! } + public var TwoStepAuth_SetPassword: String { return self._s[1071]! } + public var Permissions_PeopleNearbyText_v0: String { return self._s[1072]! } public func SocksProxySetup_ProxyStatusPing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1073]!, self._r[1073]!, [_0]) + return formatWithArgumentRanges(self._s[1074]!, self._r[1074]!, [_0]) } - public var Calls_SubmitRating: String { return self._s[1074]! } - public var Map_NoPlacesNearby: String { return self._s[1075]! } - public var Profile_Username: String { return self._s[1076]! } - public var Bot_DescriptionTitle: String { return self._s[1077]! } - public var MaskStickerSettings_Title: String { return self._s[1078]! } - public var SharedMedia_CategoryOther: String { return self._s[1079]! } - public var GroupInfo_SetGroupPhoto: String { return self._s[1080]! } - public var Common_NotNow: String { return self._s[1081]! } - public var CallFeedback_IncludeLogsInfo: String { return self._s[1082]! } - public var Conversation_ShareMyPhoneNumber: String { return self._s[1083]! } - public var Map_Location: String { return self._s[1084]! } - public var Invitation_JoinGroup: String { return self._s[1085]! } - public var AutoDownloadSettings_Title: String { return self._s[1087]! } - public var Conversation_DiscardVoiceMessageDescription: String { return self._s[1088]! } - public var Channel_ErrorAddBlocked: String { return self._s[1089]! } - public var Conversation_UnblockUser: String { return self._s[1090]! } - public var EditTheme_Edit_TopInfo: String { return self._s[1091]! } - public var Watch_Bot_Restart: String { return self._s[1092]! } - public var TwoStepAuth_Title: String { return self._s[1093]! } - public var Channel_AdminLog_BanSendMessages: String { return self._s[1094]! } - public var Checkout_ShippingMethod: String { return self._s[1095]! } - public var Passport_Identity_OneOfTypeIdentityCard: String { return self._s[1096]! } + public var Calls_SubmitRating: String { return self._s[1075]! } + public var Map_NoPlacesNearby: String { return self._s[1076]! } + public var Profile_Username: String { return self._s[1077]! } + public var Bot_DescriptionTitle: String { return self._s[1078]! } + public var MaskStickerSettings_Title: String { return self._s[1079]! } + public var SharedMedia_CategoryOther: String { return self._s[1080]! } + public var GroupInfo_SetGroupPhoto: String { return self._s[1081]! } + public var Common_NotNow: String { return self._s[1082]! } + public var CallFeedback_IncludeLogsInfo: String { return self._s[1083]! } + public var Conversation_ShareMyPhoneNumber: String { return self._s[1084]! } + public var Map_Location: String { return self._s[1085]! } + public var Invitation_JoinGroup: String { return self._s[1086]! } + public var AutoDownloadSettings_Title: String { return self._s[1088]! } + public var Conversation_DiscardVoiceMessageDescription: String { return self._s[1089]! } + public var Channel_ErrorAddBlocked: String { return self._s[1090]! } + public var Conversation_UnblockUser: String { return self._s[1091]! } + public var EditTheme_Edit_TopInfo: String { return self._s[1092]! } + public var Watch_Bot_Restart: String { return self._s[1093]! } + public var TwoStepAuth_Title: String { return self._s[1094]! } + public var Channel_AdminLog_BanSendMessages: String { return self._s[1095]! } + public var Checkout_ShippingMethod: String { return self._s[1096]! } + public var Passport_Identity_OneOfTypeIdentityCard: String { return self._s[1097]! } public func PUSH_CHAT_MESSAGE_STICKER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1097]!, self._r[1097]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1098]!, self._r[1098]!, [_1, _2, _3]) } - public var EditTheme_ChangeColors: String { return self._s[1099]! } + public var EditTheme_ChangeColors: String { return self._s[1100]! } public func Chat_UnsendMyMessagesAlertTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1100]!, self._r[1100]!, [_0]) - } - public func Channel_Username_LinkHint(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1101]!, self._r[1101]!, [_0]) } - public var Appearance_ThemePreview_ChatList_1_Name: String { return self._s[1102]! } - public var SettingsSearch_Synonyms_Data_AutoplayGifs: String { return self._s[1103]! } - public var AuthSessions_TerminateOtherSessions: String { return self._s[1104]! } - public var Contacts_FailedToSendInvitesMessage: String { return self._s[1105]! } - public var PrivacySettings_TwoStepAuth: String { return self._s[1106]! } - public var Notification_Exceptions_PreviewAlwaysOn: String { return self._s[1107]! } - public var SettingsSearch_Synonyms_Privacy_Passcode: String { return self._s[1108]! } - public var Conversation_EditingMessagePanelMedia: String { return self._s[1109]! } - public var Checkout_PaymentMethod_Title: String { return self._s[1110]! } - public var SocksProxySetup_Connection: String { return self._s[1111]! } - public var Group_MessagePhotoRemoved: String { return self._s[1112]! } - public var Channel_Stickers_NotFound: String { return self._s[1115]! } - public var Group_About_Help: String { return self._s[1116]! } - public var Notification_PassportValueProofOfIdentity: String { return self._s[1117]! } - public var PeopleNearby_Title: String { return self._s[1119]! } - public func ApplyLanguage_ChangeLanguageOfficialText(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1120]!, self._r[1120]!, [_1]) + public func Channel_Username_LinkHint(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1102]!, self._r[1102]!, [_0]) } - public var Map_Home: String { return self._s[1121]! } - public var CheckoutInfo_ShippingInfoStatePlaceholder: String { return self._s[1123]! } - public var Notifications_GroupNotificationsExceptionsHelp: String { return self._s[1124]! } - public var SocksProxySetup_Password: String { return self._s[1125]! } - public var Notifications_PermissionsEnable: String { return self._s[1126]! } - public var TwoStepAuth_ChangeEmail: String { return self._s[1128]! } + public var Appearance_ThemePreview_ChatList_1_Name: String { return self._s[1103]! } + public var SettingsSearch_Synonyms_Data_AutoplayGifs: String { return self._s[1104]! } + public var AuthSessions_TerminateOtherSessions: String { return self._s[1105]! } + public var Contacts_FailedToSendInvitesMessage: String { return self._s[1106]! } + public var PrivacySettings_TwoStepAuth: String { return self._s[1107]! } + public var Notification_Exceptions_PreviewAlwaysOn: String { return self._s[1108]! } + public var SettingsSearch_Synonyms_Privacy_Passcode: String { return self._s[1109]! } + public var Conversation_EditingMessagePanelMedia: String { return self._s[1110]! } + public var Checkout_PaymentMethod_Title: String { return self._s[1111]! } + public var SocksProxySetup_Connection: String { return self._s[1112]! } + public var Group_MessagePhotoRemoved: String { return self._s[1113]! } + public var Channel_Stickers_NotFound: String { return self._s[1116]! } + public var Group_About_Help: String { return self._s[1117]! } + public var Notification_PassportValueProofOfIdentity: String { return self._s[1118]! } + public var PeopleNearby_Title: String { return self._s[1120]! } + public func ApplyLanguage_ChangeLanguageOfficialText(_ _1: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1121]!, self._r[1121]!, [_1]) + } + public var Map_Home: String { return self._s[1122]! } + public var CheckoutInfo_ShippingInfoStatePlaceholder: String { return self._s[1124]! } + public var Notifications_GroupNotificationsExceptionsHelp: String { return self._s[1125]! } + public var SocksProxySetup_Password: String { return self._s[1126]! } + public var Notifications_PermissionsEnable: String { return self._s[1127]! } + public var TwoStepAuth_ChangeEmail: String { return self._s[1129]! } public func Channel_AdminLog_MessageInvitedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1129]!, self._r[1129]!, [_1]) + return formatWithArgumentRanges(self._s[1130]!, self._r[1130]!, [_1]) } public func Time_MonthOfYear_m10(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1131]!, self._r[1131]!, [_0]) + return formatWithArgumentRanges(self._s[1132]!, self._r[1132]!, [_0]) } - public var Passport_Identity_TypeDriversLicense: String { return self._s[1132]! } - public var ArchivedPacksAlert_Title: String { return self._s[1133]! } - public var Wallet_Receive_InvoiceUrlCopied: String { return self._s[1134]! } - public var Map_PlacesNearby: String { return self._s[1135]! } + public var Passport_Identity_TypeDriversLicense: String { return self._s[1133]! } + public var ArchivedPacksAlert_Title: String { return self._s[1134]! } + public var Wallet_Receive_InvoiceUrlCopied: String { return self._s[1135]! } + public var Map_PlacesNearby: String { return self._s[1136]! } public func Time_PreciseDate_m7(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1136]!, self._r[1136]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1137]!, self._r[1137]!, [_1, _2, _3]) } - public var PrivacyLastSeenSettings_GroupsAndChannelsHelp: String { return self._s[1137]! } - public var Privacy_Calls_NeverAllow_Placeholder: String { return self._s[1139]! } - public var Conversation_StatusTyping: String { return self._s[1140]! } - public var Broadcast_AdminLog_EmptyText: String { return self._s[1141]! } - public var Notification_PassportValueProofOfAddress: String { return self._s[1142]! } - public var UserInfo_CreateNewContact: String { return self._s[1143]! } - public var Passport_Identity_FrontSide: String { return self._s[1144]! } - public var Login_PhoneNumberAlreadyAuthorizedSwitch: String { return self._s[1145]! } - public var Calls_CallTabTitle: String { return self._s[1146]! } - public var Channel_AdminLog_ChannelEmptyText: String { return self._s[1147]! } + public var PrivacyLastSeenSettings_GroupsAndChannelsHelp: String { return self._s[1138]! } + public var Privacy_Calls_NeverAllow_Placeholder: String { return self._s[1140]! } + public var Conversation_StatusTyping: String { return self._s[1141]! } + public var Broadcast_AdminLog_EmptyText: String { return self._s[1142]! } + public var Notification_PassportValueProofOfAddress: String { return self._s[1143]! } + public var UserInfo_CreateNewContact: String { return self._s[1144]! } + public var Passport_Identity_FrontSide: String { return self._s[1145]! } + public var Login_PhoneNumberAlreadyAuthorizedSwitch: String { return self._s[1146]! } + public var Calls_CallTabTitle: String { return self._s[1147]! } + public var Channel_AdminLog_ChannelEmptyText: String { return self._s[1148]! } public func Login_BannedPhoneBody(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1149]!, self._r[1149]!, [_0]) + return formatWithArgumentRanges(self._s[1150]!, self._r[1150]!, [_0]) } - public var Watch_UserInfo_MuteTitle: String { return self._s[1150]! } - public var Group_EditAdmin_RankAdminPlaceholder: String { return self._s[1151]! } - public var SharedMedia_EmptyMusicText: String { return self._s[1152]! } - public var Wallet_Completed_Text: String { return self._s[1153]! } - public var PasscodeSettings_AutoLock_IfAwayFor_1minute: String { return self._s[1154]! } - public var Paint_Stickers: String { return self._s[1155]! } - public var Privacy_GroupsAndChannels: String { return self._s[1156]! } - public var ChatList_Context_Delete: String { return self._s[1158]! } - public var UserInfo_AddContact: String { return self._s[1159]! } + public var Watch_UserInfo_MuteTitle: String { return self._s[1151]! } + public var Group_EditAdmin_RankAdminPlaceholder: String { return self._s[1152]! } + public var SharedMedia_EmptyMusicText: String { return self._s[1153]! } + public var Wallet_Completed_Text: String { return self._s[1154]! } + public var PasscodeSettings_AutoLock_IfAwayFor_1minute: String { return self._s[1155]! } + public var Paint_Stickers: String { return self._s[1156]! } + public var Privacy_GroupsAndChannels: String { return self._s[1157]! } + public var ChatList_Context_Delete: String { return self._s[1159]! } + public var UserInfo_AddContact: String { return self._s[1160]! } public func Conversation_MessageViaUser(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1160]!, self._r[1160]!, [_0]) + return formatWithArgumentRanges(self._s[1161]!, self._r[1161]!, [_0]) } - public var PhoneNumberHelp_ChangeNumber: String { return self._s[1162]! } + public var PhoneNumberHelp_ChangeNumber: String { return self._s[1163]! } public func ChatList_ClearChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1164]!, self._r[1164]!, [_0]) + return formatWithArgumentRanges(self._s[1165]!, self._r[1165]!, [_0]) } - public var DialogList_NoMessagesTitle: String { return self._s[1165]! } - public var EditProfile_NameAndPhotoHelp: String { return self._s[1166]! } - public var BlockedUsers_BlockUser: String { return self._s[1167]! } - public var Notifications_PermissionsOpenSettings: String { return self._s[1168]! } - public var MediaPicker_UngroupDescription: String { return self._s[1170]! } - public var Watch_NoConnection: String { return self._s[1171]! } - public var Month_GenSeptember: String { return self._s[1172]! } - public var Conversation_ViewGroup: String { return self._s[1174]! } - public var Channel_AdminLogFilter_EventsLeavingSubscribers: String { return self._s[1177]! } - public var Privacy_Forwards_AlwaysLink: String { return self._s[1178]! } - public var Channel_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[1179]! } - public var Passport_FieldOneOf_FinalDelimeter: String { return self._s[1180]! } - public var Wallet_WordCheck_IncorrectHeader: String { return self._s[1181]! } - public var MediaPicker_CameraRoll: String { return self._s[1183]! } - public var Month_GenAugust: String { return self._s[1184]! } - public var Wallet_Configuration_SourceHeader: String { return self._s[1185]! } - public var AccessDenied_VideoMessageMicrophone: String { return self._s[1186]! } - public var SharedMedia_EmptyText: String { return self._s[1187]! } - public var Map_ShareLiveLocation: String { return self._s[1188]! } - public var Calls_All: String { return self._s[1189]! } - public var Map_SendThisPlace: String { return self._s[1191]! } - public var Appearance_ThemeNight: String { return self._s[1193]! } - public var Conversation_HoldForAudio: String { return self._s[1194]! } - public var SettingsSearch_Synonyms_Support: String { return self._s[1197]! } - public var GroupInfo_GroupHistoryHidden: String { return self._s[1198]! } - public var SocksProxySetup_Secret: String { return self._s[1199]! } + public var DialogList_NoMessagesTitle: String { return self._s[1166]! } + public var EditProfile_NameAndPhotoHelp: String { return self._s[1167]! } + public var BlockedUsers_BlockUser: String { return self._s[1168]! } + public var Notifications_PermissionsOpenSettings: String { return self._s[1169]! } + public var MediaPicker_UngroupDescription: String { return self._s[1171]! } + public var Watch_NoConnection: String { return self._s[1172]! } + public var Month_GenSeptember: String { return self._s[1173]! } + public var Conversation_ViewGroup: String { return self._s[1175]! } + public var Channel_AdminLogFilter_EventsLeavingSubscribers: String { return self._s[1178]! } + public var Privacy_Forwards_AlwaysLink: String { return self._s[1179]! } + public var Channel_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[1180]! } + public var Passport_FieldOneOf_FinalDelimeter: String { return self._s[1181]! } + public var Wallet_WordCheck_IncorrectHeader: String { return self._s[1182]! } + public var MediaPicker_CameraRoll: String { return self._s[1184]! } + public var Month_GenAugust: String { return self._s[1185]! } + public var Wallet_Configuration_SourceHeader: String { return self._s[1186]! } + public var AccessDenied_VideoMessageMicrophone: String { return self._s[1187]! } + public var SharedMedia_EmptyText: String { return self._s[1188]! } + public var Map_ShareLiveLocation: String { return self._s[1189]! } + public var Calls_All: String { return self._s[1190]! } + public var Map_SendThisPlace: String { return self._s[1192]! } + public var Appearance_ThemeNight: String { return self._s[1194]! } + public var Conversation_HoldForAudio: String { return self._s[1195]! } + public var SettingsSearch_Synonyms_Support: String { return self._s[1198]! } + public var GroupInfo_GroupHistoryHidden: String { return self._s[1199]! } + public var SocksProxySetup_Secret: String { return self._s[1200]! } public func Activity_RemindAboutChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1200]!, self._r[1200]!, [_0]) + return formatWithArgumentRanges(self._s[1201]!, self._r[1201]!, [_0]) } - public var Channel_BanList_RestrictedTitle: String { return self._s[1202]! } - public var Conversation_Location: String { return self._s[1203]! } + public var Channel_BanList_RestrictedTitle: String { return self._s[1203]! } + public var Conversation_Location: String { return self._s[1204]! } public func AutoDownloadSettings_UpToFor(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1204]!, self._r[1204]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1205]!, self._r[1205]!, [_1, _2]) } - public var ChatSettings_AutoDownloadPhotos: String { return self._s[1206]! } - public var SettingsSearch_Synonyms_Privacy_Title: String { return self._s[1207]! } - public var Notifications_PermissionsText: String { return self._s[1208]! } - public var SettingsSearch_Synonyms_Data_SaveIncomingPhotos: String { return self._s[1209]! } - public var Call_Flip: String { return self._s[1210]! } - public var Channel_AdminLog_CanDeleteMessagesOfOthers: String { return self._s[1212]! } - public var SocksProxySetup_ProxyStatusConnecting: String { return self._s[1213]! } - public var Wallet_TransactionInfo_StorageFeeInfoUrl: String { return self._s[1214]! } - public var PrivacyPhoneNumberSettings_DiscoveryHeader: String { return self._s[1215]! } - public var Channel_EditAdmin_PermissionPinMessages: String { return self._s[1217]! } - public var TwoStepAuth_ReEnterPasswordDescription: String { return self._s[1219]! } - public var Channel_TooMuchBots: String { return self._s[1221]! } - public var Passport_DeletePassportConfirmation: String { return self._s[1222]! } - public var Login_InvalidCodeError: String { return self._s[1223]! } - public var StickerPacksSettings_FeaturedPacks: String { return self._s[1224]! } + public var ChatSettings_AutoDownloadPhotos: String { return self._s[1207]! } + public var SettingsSearch_Synonyms_Privacy_Title: String { return self._s[1208]! } + public var Notifications_PermissionsText: String { return self._s[1209]! } + public var SettingsSearch_Synonyms_Data_SaveIncomingPhotos: String { return self._s[1210]! } + public var Call_Flip: String { return self._s[1211]! } + public var Channel_AdminLog_CanDeleteMessagesOfOthers: String { return self._s[1213]! } + public var SocksProxySetup_ProxyStatusConnecting: String { return self._s[1214]! } + public var Wallet_TransactionInfo_StorageFeeInfoUrl: String { return self._s[1215]! } + public var PrivacyPhoneNumberSettings_DiscoveryHeader: String { return self._s[1216]! } + public var Channel_EditAdmin_PermissionPinMessages: String { return self._s[1218]! } + public var TwoStepAuth_ReEnterPasswordDescription: String { return self._s[1220]! } + public var Channel_TooMuchBots: String { return self._s[1222]! } + public var Passport_DeletePassportConfirmation: String { return self._s[1223]! } + public var Login_InvalidCodeError: String { return self._s[1224]! } + public var StickerPacksSettings_FeaturedPacks: String { return self._s[1225]! } public func ChatList_DeleteSecretChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1225]!, self._r[1225]!, [_0]) - } - public func GroupInfo_InvitationLinkAcceptChannel(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1226]!, self._r[1226]!, [_0]) } - public var VoiceOver_Navigation_ProxySettings: String { return self._s[1227]! } - public var Call_CallInProgressTitle: String { return self._s[1228]! } - public var Month_ShortSeptember: String { return self._s[1229]! } - public var Watch_ChannelInfo_Title: String { return self._s[1230]! } - public var ChatList_DeleteSavedMessagesConfirmation: String { return self._s[1233]! } - public var DialogList_PasscodeLockHelp: String { return self._s[1234]! } - public var Chat_MultipleTextMessagesDisabled: String { return self._s[1235]! } - public var Wallet_Receive_Title: String { return self._s[1236]! } - public var Notifications_Badge_IncludePublicGroups: String { return self._s[1237]! } - public var Channel_AdminLogFilter_EventsTitle: String { return self._s[1238]! } - public var PhotoEditor_CropReset: String { return self._s[1239]! } - public var Group_Username_CreatePrivateLinkHelp: String { return self._s[1241]! } - public var Channel_Management_LabelEditor: String { return self._s[1242]! } - public var Passport_Identity_LatinNameHelp: String { return self._s[1244]! } - public var PhotoEditor_HighlightsTool: String { return self._s[1245]! } - public var Wallet_Info_WalletCreated: String { return self._s[1246]! } - public var UserInfo_Title: String { return self._s[1247]! } - public var ChatList_HideAction: String { return self._s[1248]! } - public var AccessDenied_Title: String { return self._s[1249]! } - public var DialogList_SearchLabel: String { return self._s[1250]! } - public var Group_Setup_HistoryHidden: String { return self._s[1251]! } - public var TwoStepAuth_PasswordChangeSuccess: String { return self._s[1252]! } - public var State_Updating: String { return self._s[1254]! } - public var Contacts_TabTitle: String { return self._s[1255]! } - public var Notifications_Badge_CountUnreadMessages: String { return self._s[1257]! } - public var GroupInfo_GroupHistory: String { return self._s[1258]! } - public var Conversation_UnsupportedMediaPlaceholder: String { return self._s[1259]! } - public var Wallpaper_SetColor: String { return self._s[1260]! } - public var CheckoutInfo_ShippingInfoCountry: String { return self._s[1261]! } - public var SettingsSearch_Synonyms_SavedMessages: String { return self._s[1262]! } - public var Chat_AttachmentLimitReached: String { return self._s[1263]! } - public var Passport_Identity_OneOfTypeDriversLicense: String { return self._s[1264]! } - public var Contacts_NotRegisteredSection: String { return self._s[1265]! } + public func GroupInfo_InvitationLinkAcceptChannel(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1227]!, self._r[1227]!, [_0]) + } + public var VoiceOver_Navigation_ProxySettings: String { return self._s[1228]! } + public var Call_CallInProgressTitle: String { return self._s[1229]! } + public var Month_ShortSeptember: String { return self._s[1230]! } + public var Watch_ChannelInfo_Title: String { return self._s[1231]! } + public var ChatList_DeleteSavedMessagesConfirmation: String { return self._s[1234]! } + public var DialogList_PasscodeLockHelp: String { return self._s[1235]! } + public var Chat_MultipleTextMessagesDisabled: String { return self._s[1236]! } + public var Wallet_Receive_Title: String { return self._s[1237]! } + public var Notifications_Badge_IncludePublicGroups: String { return self._s[1238]! } + public var Channel_AdminLogFilter_EventsTitle: String { return self._s[1239]! } + public var PhotoEditor_CropReset: String { return self._s[1240]! } + public var Group_Username_CreatePrivateLinkHelp: String { return self._s[1242]! } + public var Channel_Management_LabelEditor: String { return self._s[1243]! } + public var Passport_Identity_LatinNameHelp: String { return self._s[1245]! } + public var PhotoEditor_HighlightsTool: String { return self._s[1246]! } + public var Wallet_Info_WalletCreated: String { return self._s[1247]! } + public var UserInfo_Title: String { return self._s[1248]! } + public var ChatList_HideAction: String { return self._s[1249]! } + public var AccessDenied_Title: String { return self._s[1250]! } + public var DialogList_SearchLabel: String { return self._s[1251]! } + public var Group_Setup_HistoryHidden: String { return self._s[1252]! } + public var TwoStepAuth_PasswordChangeSuccess: String { return self._s[1253]! } + public var State_Updating: String { return self._s[1255]! } + public var Contacts_TabTitle: String { return self._s[1256]! } + public var Notifications_Badge_CountUnreadMessages: String { return self._s[1258]! } + public var GroupInfo_GroupHistory: String { return self._s[1259]! } + public var Conversation_UnsupportedMediaPlaceholder: String { return self._s[1260]! } + public var Wallpaper_SetColor: String { return self._s[1261]! } + public var CheckoutInfo_ShippingInfoCountry: String { return self._s[1262]! } + public var SettingsSearch_Synonyms_SavedMessages: String { return self._s[1263]! } + public var Chat_AttachmentLimitReached: String { return self._s[1264]! } + public var Passport_Identity_OneOfTypeDriversLicense: String { return self._s[1265]! } + public var Contacts_NotRegisteredSection: String { return self._s[1266]! } public func Time_PreciseDate_m4(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1266]!, self._r[1266]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1267]!, self._r[1267]!, [_1, _2, _3]) } - public var Paint_Clear: String { return self._s[1267]! } - public var StickerPacksSettings_ArchivedMasks: String { return self._s[1268]! } - public var SocksProxySetup_Connecting: String { return self._s[1269]! } - public var ExplicitContent_AlertChannel: String { return self._s[1270]! } - public var CreatePoll_AllOptionsAdded: String { return self._s[1271]! } - public var Conversation_Contact: String { return self._s[1272]! } - public var Login_CodeExpired: String { return self._s[1273]! } - public var Passport_DiscardMessageAction: String { return self._s[1274]! } - public var ChatList_Context_Unpin: String { return self._s[1275]! } - public var Channel_AdminLog_MessagePreviousDescription: String { return self._s[1276]! } + public var Paint_Clear: String { return self._s[1268]! } + public var StickerPacksSettings_ArchivedMasks: String { return self._s[1269]! } + public var SocksProxySetup_Connecting: String { return self._s[1270]! } + public var ExplicitContent_AlertChannel: String { return self._s[1271]! } + public var CreatePoll_AllOptionsAdded: String { return self._s[1272]! } + public var Conversation_Contact: String { return self._s[1273]! } + public var Login_CodeExpired: String { return self._s[1274]! } + public var Passport_DiscardMessageAction: String { return self._s[1275]! } + public var ChatList_Context_Unpin: String { return self._s[1276]! } + public var Channel_AdminLog_MessagePreviousDescription: String { return self._s[1277]! } public func VoiceOver_Chat_MusicFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1277]!, self._r[1277]!, [_0]) + return formatWithArgumentRanges(self._s[1278]!, self._r[1278]!, [_0]) } - public var Channel_AdminLog_EmptyMessageText: String { return self._s[1278]! } - public var SettingsSearch_Synonyms_Data_NetworkUsage: String { return self._s[1279]! } + public var Channel_AdminLog_EmptyMessageText: String { return self._s[1279]! } + public var SettingsSearch_Synonyms_Data_NetworkUsage: String { return self._s[1280]! } public func Group_EditAdmin_RankInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1280]!, self._r[1280]!, [_0]) + return formatWithArgumentRanges(self._s[1281]!, self._r[1281]!, [_0]) } - public var Month_ShortApril: String { return self._s[1281]! } - public var AuthSessions_CurrentSession: String { return self._s[1282]! } - public var Chat_AttachmentMultipleFilesDisabled: String { return self._s[1285]! } - public var Wallet_Navigation_Cancel: String { return self._s[1287]! } - public var WallpaperPreview_CropTopText: String { return self._s[1288]! } - public var PrivacySettings_DeleteAccountIfAwayFor: String { return self._s[1289]! } - public var CheckoutInfo_ShippingInfoTitle: String { return self._s[1290]! } + public var Month_ShortApril: String { return self._s[1282]! } + public var AuthSessions_CurrentSession: String { return self._s[1283]! } + public var Chat_AttachmentMultipleFilesDisabled: String { return self._s[1286]! } + public var Wallet_Navigation_Cancel: String { return self._s[1288]! } + public var WallpaperPreview_CropTopText: String { return self._s[1289]! } + public var PrivacySettings_DeleteAccountIfAwayFor: String { return self._s[1290]! } + public var CheckoutInfo_ShippingInfoTitle: String { return self._s[1291]! } public func Conversation_ScheduleMessage_SendOn(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1291]!, self._r[1291]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1292]!, self._r[1292]!, [_0, _1]) } - public var Appearance_ThemePreview_Chat_2_Text: String { return self._s[1292]! } - public var Channel_Setup_TypePrivate: String { return self._s[1294]! } - public var Forward_ChannelReadOnly: String { return self._s[1297]! } - public var PhotoEditor_CurvesBlue: String { return self._s[1298]! } - public var AddContact_SharedContactException: String { return self._s[1299]! } - public var UserInfo_BotPrivacy: String { return self._s[1301]! } - public var Wallet_CreateInvoice_Title: String { return self._s[1302]! } - public var Notification_PassportValueEmail: String { return self._s[1303]! } - public var EmptyGroupInfo_Subtitle: String { return self._s[1304]! } - public var GroupPermission_NewTitle: String { return self._s[1305]! } - public var CallFeedback_ReasonDropped: String { return self._s[1306]! } - public var GroupInfo_Permissions_AddException: String { return self._s[1307]! } - public var Channel_SignMessages_Help: String { return self._s[1309]! } - public var Undo_ChatDeleted: String { return self._s[1311]! } - public var Conversation_ChatBackground: String { return self._s[1312]! } + public var Appearance_ThemePreview_Chat_2_Text: String { return self._s[1293]! } + public var Channel_Setup_TypePrivate: String { return self._s[1295]! } + public var Forward_ChannelReadOnly: String { return self._s[1298]! } + public var PhotoEditor_CurvesBlue: String { return self._s[1299]! } + public var AddContact_SharedContactException: String { return self._s[1300]! } + public var UserInfo_BotPrivacy: String { return self._s[1302]! } + public var Wallet_CreateInvoice_Title: String { return self._s[1303]! } + public var Notification_PassportValueEmail: String { return self._s[1304]! } + public var EmptyGroupInfo_Subtitle: String { return self._s[1305]! } + public var GroupPermission_NewTitle: String { return self._s[1306]! } + public var CallFeedback_ReasonDropped: String { return self._s[1307]! } + public var GroupInfo_Permissions_AddException: String { return self._s[1308]! } + public var Channel_SignMessages_Help: String { return self._s[1310]! } + public var Undo_ChatDeleted: String { return self._s[1312]! } + public var Conversation_ChatBackground: String { return self._s[1313]! } public func Wallet_WordCheck_Text(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1313]!, self._r[1313]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1314]!, self._r[1314]!, [_1, _2, _3]) } - public var ChannelMembers_WhoCanAddMembers_Admins: String { return self._s[1314]! } - public var FastTwoStepSetup_EmailPlaceholder: String { return self._s[1315]! } - public var Passport_Language_pt: String { return self._s[1316]! } - public var VoiceOver_Chat_YourVoiceMessage: String { return self._s[1317]! } - public var NotificationsSound_Popcorn: String { return self._s[1320]! } - public var AutoNightTheme_Disabled: String { return self._s[1321]! } - public var BlockedUsers_LeavePrefix: String { return self._s[1322]! } - public var WallpaperPreview_CustomColorTopText: String { return self._s[1323]! } - public var Contacts_PermissionsSuppressWarningText: String { return self._s[1324]! } - public var WallpaperSearch_ColorBlue: String { return self._s[1325]! } + public var ChannelMembers_WhoCanAddMembers_Admins: String { return self._s[1315]! } + public var FastTwoStepSetup_EmailPlaceholder: String { return self._s[1316]! } + public var Passport_Language_pt: String { return self._s[1317]! } + public var VoiceOver_Chat_YourVoiceMessage: String { return self._s[1318]! } + public var NotificationsSound_Popcorn: String { return self._s[1321]! } + public var AutoNightTheme_Disabled: String { return self._s[1322]! } + public var BlockedUsers_LeavePrefix: String { return self._s[1323]! } + public var WallpaperPreview_CustomColorTopText: String { return self._s[1324]! } + public var Contacts_PermissionsSuppressWarningText: String { return self._s[1325]! } + public var WallpaperSearch_ColorBlue: String { return self._s[1326]! } public func CancelResetAccount_TextSMS(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1326]!, self._r[1326]!, [_0]) + return formatWithArgumentRanges(self._s[1327]!, self._r[1327]!, [_0]) } - public var CheckoutInfo_ErrorNameInvalid: String { return self._s[1327]! } - public var SocksProxySetup_UseForCalls: String { return self._s[1328]! } - public var Passport_DeleteDocumentConfirmation: String { return self._s[1330]! } + public var CheckoutInfo_ErrorNameInvalid: String { return self._s[1328]! } + public var SocksProxySetup_UseForCalls: String { return self._s[1329]! } + public var Passport_DeleteDocumentConfirmation: String { return self._s[1331]! } public func Conversation_Megabytes(_ _0: Float) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1331]!, self._r[1331]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[1332]!, self._r[1332]!, ["\(_0)"]) } - public var SocksProxySetup_Hostname: String { return self._s[1334]! } - public var ChatSettings_AutoDownloadSettings_OffForAll: String { return self._s[1335]! } - public var Compose_NewEncryptedChat: String { return self._s[1336]! } - public var Login_CodeFloodError: String { return self._s[1337]! } - public var Calls_TabTitle: String { return self._s[1338]! } - public var Privacy_ProfilePhoto: String { return self._s[1339]! } - public var Passport_Language_he: String { return self._s[1340]! } + public var SocksProxySetup_Hostname: String { return self._s[1335]! } + public var ChatSettings_AutoDownloadSettings_OffForAll: String { return self._s[1336]! } + public var Compose_NewEncryptedChat: String { return self._s[1337]! } + public var Login_CodeFloodError: String { return self._s[1338]! } + public var Calls_TabTitle: String { return self._s[1339]! } + public var Privacy_ProfilePhoto: String { return self._s[1340]! } + public var Passport_Language_he: String { return self._s[1341]! } public func Conversation_SetReminder_RemindToday(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1341]!, self._r[1341]!, [_0]) + return formatWithArgumentRanges(self._s[1342]!, self._r[1342]!, [_0]) } - public var GroupPermission_Title: String { return self._s[1342]! } + public var GroupPermission_Title: String { return self._s[1343]! } public func Channel_AdminLog_MessageGroupPreHistoryHidden(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1343]!, self._r[1343]!, [_0]) + return formatWithArgumentRanges(self._s[1344]!, self._r[1344]!, [_0]) } - public var Wallet_TransactionInfo_SenderHeader: String { return self._s[1344]! } - public var GroupPermission_NoChangeInfo: String { return self._s[1345]! } - public var ChatList_DeleteForCurrentUser: String { return self._s[1346]! } - public var Tour_Text1: String { return self._s[1347]! } - public var Channel_EditAdmin_TransferOwnership: String { return self._s[1348]! } - public var Month_ShortFebruary: String { return self._s[1349]! } - public var TwoStepAuth_EmailSkip: String { return self._s[1350]! } + public var Wallet_TransactionInfo_SenderHeader: String { return self._s[1345]! } + public var GroupPermission_NoChangeInfo: String { return self._s[1346]! } + public var ChatList_DeleteForCurrentUser: String { return self._s[1347]! } + public var Tour_Text1: String { return self._s[1348]! } + public var Channel_EditAdmin_TransferOwnership: String { return self._s[1349]! } + public var Month_ShortFebruary: String { return self._s[1350]! } + public var TwoStepAuth_EmailSkip: String { return self._s[1351]! } public func Wallet_Time_PreciseDate_m4(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1351]!, self._r[1351]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1352]!, self._r[1352]!, [_1, _2, _3]) } - public var NotificationsSound_Glass: String { return self._s[1352]! } - public var Appearance_ThemeNightBlue: String { return self._s[1353]! } - public var CheckoutInfo_Pay: String { return self._s[1354]! } - public var Invite_LargeRecipientsCountWarning: String { return self._s[1356]! } - public var Call_CallAgain: String { return self._s[1358]! } - public var AttachmentMenu_SendAsFile: String { return self._s[1359]! } - public var AccessDenied_MicrophoneRestricted: String { return self._s[1360]! } - public var Passport_InvalidPasswordError: String { return self._s[1361]! } - public var Watch_Message_Game: String { return self._s[1362]! } - public var Stickers_Install: String { return self._s[1363]! } - public var VoiceOver_Chat_Message: String { return self._s[1364]! } - public var PrivacyLastSeenSettings_NeverShareWith: String { return self._s[1365]! } - public var Passport_Identity_ResidenceCountry: String { return self._s[1367]! } - public var Notifications_GroupNotificationsHelp: String { return self._s[1368]! } - public var AuthSessions_OtherSessions: String { return self._s[1369]! } - public var Channel_Username_Help: String { return self._s[1370]! } - public var Camera_Title: String { return self._s[1371]! } - public var IntentsSettings_Title: String { return self._s[1372]! } - public var GroupInfo_SetGroupPhotoDelete: String { return self._s[1374]! } - public var Privacy_ProfilePhoto_NeverShareWith_Title: String { return self._s[1375]! } - public var Channel_AdminLog_SendPolls: String { return self._s[1376]! } - public var Channel_AdminLog_TitleAllEvents: String { return self._s[1377]! } - public var Channel_EditAdmin_PermissionInviteMembers: String { return self._s[1378]! } - public var Contacts_MemberSearchSectionTitleGroup: String { return self._s[1379]! } - public var ScheduledMessages_DeleteMany: String { return self._s[1380]! } - public var Conversation_RestrictedStickers: String { return self._s[1381]! } - public var Notifications_ExceptionsResetToDefaults: String { return self._s[1383]! } - public var UserInfo_TelegramCall: String { return self._s[1385]! } - public var TwoStepAuth_SetupResendEmailCode: String { return self._s[1386]! } - public var CreatePoll_OptionsHeader: String { return self._s[1387]! } - public var SettingsSearch_Synonyms_Data_CallsUseLessData: String { return self._s[1388]! } - public var ArchivedChats_IntroTitle1: String { return self._s[1389]! } - public var Privacy_GroupsAndChannels_AlwaysAllow_Title: String { return self._s[1390]! } - public var Theme_Colors_Proceed: String { return self._s[1391]! } - public var Passport_Identity_EditPersonalDetails: String { return self._s[1392]! } + public var NotificationsSound_Glass: String { return self._s[1353]! } + public var Appearance_ThemeNightBlue: String { return self._s[1354]! } + public var CheckoutInfo_Pay: String { return self._s[1355]! } + public var Invite_LargeRecipientsCountWarning: String { return self._s[1357]! } + public var Call_CallAgain: String { return self._s[1359]! } + public var AttachmentMenu_SendAsFile: String { return self._s[1360]! } + public var AccessDenied_MicrophoneRestricted: String { return self._s[1361]! } + public var Passport_InvalidPasswordError: String { return self._s[1362]! } + public var Watch_Message_Game: String { return self._s[1363]! } + public var Stickers_Install: String { return self._s[1364]! } + public var VoiceOver_Chat_Message: String { return self._s[1365]! } + public var PrivacyLastSeenSettings_NeverShareWith: String { return self._s[1366]! } + public var Passport_Identity_ResidenceCountry: String { return self._s[1368]! } + public var Notifications_GroupNotificationsHelp: String { return self._s[1369]! } + public var AuthSessions_OtherSessions: String { return self._s[1370]! } + public var Channel_Username_Help: String { return self._s[1371]! } + public var Camera_Title: String { return self._s[1372]! } + public var IntentsSettings_Title: String { return self._s[1373]! } + public var GroupInfo_SetGroupPhotoDelete: String { return self._s[1375]! } + public var Privacy_ProfilePhoto_NeverShareWith_Title: String { return self._s[1376]! } + public var Channel_AdminLog_SendPolls: String { return self._s[1377]! } + public var Channel_AdminLog_TitleAllEvents: String { return self._s[1378]! } + public var Channel_EditAdmin_PermissionInviteMembers: String { return self._s[1379]! } + public var Contacts_MemberSearchSectionTitleGroup: String { return self._s[1380]! } + public var ScheduledMessages_DeleteMany: String { return self._s[1381]! } + public var Conversation_RestrictedStickers: String { return self._s[1382]! } + public var Notifications_ExceptionsResetToDefaults: String { return self._s[1384]! } + public var UserInfo_TelegramCall: String { return self._s[1386]! } + public var TwoStepAuth_SetupResendEmailCode: String { return self._s[1387]! } + public var CreatePoll_OptionsHeader: String { return self._s[1388]! } + public var SettingsSearch_Synonyms_Data_CallsUseLessData: String { return self._s[1389]! } + public var ArchivedChats_IntroTitle1: String { return self._s[1390]! } + public var Privacy_GroupsAndChannels_AlwaysAllow_Title: String { return self._s[1391]! } + public var Theme_Colors_Proceed: String { return self._s[1392]! } + public var Passport_Identity_EditPersonalDetails: String { return self._s[1393]! } public func Time_PreciseDate_m1(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1393]!, self._r[1393]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1394]!, self._r[1394]!, [_1, _2, _3]) } - public var Wallet_Month_GenAugust: String { return self._s[1394]! } - public var Settings_SaveEditedPhotos: String { return self._s[1395]! } - public var TwoStepAuth_ConfirmationTitle: String { return self._s[1396]! } - public var Privacy_GroupsAndChannels_NeverAllow_Title: String { return self._s[1397]! } - public var Conversation_MessageDialogRetry: String { return self._s[1398]! } - public var ChatList_Context_MarkAsUnread: String { return self._s[1399]! } - public var MessagePoll_SubmitVote: String { return self._s[1400]! } - public var Conversation_DiscardVoiceMessageAction: String { return self._s[1401]! } - public var Permissions_PeopleNearbyTitle_v0: String { return self._s[1402]! } - public var Group_Setup_TypeHeader: String { return self._s[1403]! } - public var Paint_RecentStickers: String { return self._s[1404]! } - public var PhotoEditor_GrainTool: String { return self._s[1405]! } - public var CheckoutInfo_ShippingInfoState: String { return self._s[1406]! } - public var EmptyGroupInfo_Line4: String { return self._s[1407]! } - public var Watch_AuthRequired: String { return self._s[1409]! } + public var Wallet_Month_GenAugust: String { return self._s[1395]! } + public var Settings_SaveEditedPhotos: String { return self._s[1396]! } + public var TwoStepAuth_ConfirmationTitle: String { return self._s[1397]! } + public var Privacy_GroupsAndChannels_NeverAllow_Title: String { return self._s[1398]! } + public var Conversation_MessageDialogRetry: String { return self._s[1399]! } + public var ChatList_Context_MarkAsUnread: String { return self._s[1400]! } + public var MessagePoll_SubmitVote: String { return self._s[1401]! } + public var Conversation_DiscardVoiceMessageAction: String { return self._s[1402]! } + public var Permissions_PeopleNearbyTitle_v0: String { return self._s[1403]! } + public var Group_Setup_TypeHeader: String { return self._s[1404]! } + public var Paint_RecentStickers: String { return self._s[1405]! } + public var PhotoEditor_GrainTool: String { return self._s[1406]! } + public var CheckoutInfo_ShippingInfoState: String { return self._s[1407]! } + public var EmptyGroupInfo_Line4: String { return self._s[1408]! } + public var Watch_AuthRequired: String { return self._s[1410]! } public func Passport_Email_UseTelegramEmail(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1410]!, self._r[1410]!, [_0]) + return formatWithArgumentRanges(self._s[1411]!, self._r[1411]!, [_0]) } - public var Conversation_EncryptedDescriptionTitle: String { return self._s[1411]! } - public var ChannelIntro_Text: String { return self._s[1412]! } - public var DialogList_DeleteBotConfirmation: String { return self._s[1413]! } - public var GroupPermission_NoSendMedia: String { return self._s[1414]! } - public var Calls_AddTab: String { return self._s[1415]! } - public var Message_ReplyActionButtonShowReceipt: String { return self._s[1416]! } - public var Channel_AdminLog_EmptyFilterText: String { return self._s[1417]! } - public var Conversation_WalletRequiredSetup: String { return self._s[1418]! } - public var Notification_MessageLifetime1d: String { return self._s[1419]! } - public var Notifications_ChannelNotificationsExceptionsHelp: String { return self._s[1420]! } - public var Channel_BanUser_PermissionsHeader: String { return self._s[1421]! } - public var Passport_Identity_GenderFemale: String { return self._s[1422]! } - public var BlockedUsers_BlockTitle: String { return self._s[1423]! } + public var Conversation_EncryptedDescriptionTitle: String { return self._s[1412]! } + public var ChannelIntro_Text: String { return self._s[1413]! } + public var DialogList_DeleteBotConfirmation: String { return self._s[1414]! } + public var GroupPermission_NoSendMedia: String { return self._s[1415]! } + public var Calls_AddTab: String { return self._s[1416]! } + public var Message_ReplyActionButtonShowReceipt: String { return self._s[1417]! } + public var Channel_AdminLog_EmptyFilterText: String { return self._s[1418]! } + public var Conversation_WalletRequiredSetup: String { return self._s[1419]! } + public var Notification_MessageLifetime1d: String { return self._s[1420]! } + public var Notifications_ChannelNotificationsExceptionsHelp: String { return self._s[1421]! } + public var Channel_BanUser_PermissionsHeader: String { return self._s[1422]! } + public var Passport_Identity_GenderFemale: String { return self._s[1423]! } + public var BlockedUsers_BlockTitle: String { return self._s[1424]! } public func PUSH_CHANNEL_MESSAGE_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1424]!, self._r[1424]!, [_1]) + return formatWithArgumentRanges(self._s[1425]!, self._r[1425]!, [_1]) } - public var Weekday_Yesterday: String { return self._s[1425]! } - public var WallpaperSearch_ColorBlack: String { return self._s[1426]! } - public var Settings_Context_Logout: String { return self._s[1427]! } - public var Wallet_Info_UnknownTransaction: String { return self._s[1428]! } - public var ChatList_ArchiveAction: String { return self._s[1429]! } - public var AutoNightTheme_Scheduled: String { return self._s[1430]! } - public var TwoFactorSetup_Email_SkipAction: String { return self._s[1431]! } - public var Settings_Devices: String { return self._s[1432]! } - public var ContactInfo_Note: String { return self._s[1433]! } + public var Weekday_Yesterday: String { return self._s[1426]! } + public var WallpaperSearch_ColorBlack: String { return self._s[1427]! } + public var Settings_Context_Logout: String { return self._s[1428]! } + public var Wallet_Info_UnknownTransaction: String { return self._s[1429]! } + public var ChatList_ArchiveAction: String { return self._s[1430]! } + public var AutoNightTheme_Scheduled: String { return self._s[1431]! } + public var TwoFactorSetup_Email_SkipAction: String { return self._s[1432]! } + public var Settings_Devices: String { return self._s[1433]! } + public var ContactInfo_Note: String { return self._s[1434]! } public func Login_PhoneGenericEmailBody(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String, _ _6: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1434]!, self._r[1434]!, [_1, _2, _3, _4, _5, _6]) + return formatWithArgumentRanges(self._s[1435]!, self._r[1435]!, [_1, _2, _3, _4, _5, _6]) } - public var EditTheme_ThemeTemplateAlertTitle: String { return self._s[1435]! } - public var Wallet_Receive_CreateInvoice: String { return self._s[1436]! } - public var PrivacyPolicy_DeclineDeleteNow: String { return self._s[1437]! } - public var Theme_Colors_ColorWallpaperWarningProceed: String { return self._s[1438]! } + public var EditTheme_ThemeTemplateAlertTitle: String { return self._s[1436]! } + public var Wallet_Receive_CreateInvoice: String { return self._s[1437]! } + public var PrivacyPolicy_DeclineDeleteNow: String { return self._s[1438]! } + public var Theme_Colors_ColorWallpaperWarningProceed: String { return self._s[1439]! } public func PUSH_CHAT_JOINED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1439]!, self._r[1439]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1440]!, self._r[1440]!, [_1, _2]) } - public var CreatePoll_Create: String { return self._s[1440]! } - public var Channel_Members_AddBannedErrorAdmin: String { return self._s[1441]! } + public var CreatePoll_Create: String { return self._s[1441]! } + public var Channel_Members_AddBannedErrorAdmin: String { return self._s[1442]! } public func Notification_CallFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1442]!, self._r[1442]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1443]!, self._r[1443]!, [_1, _2]) } - public var ScheduledMessages_ClearAllConfirmation: String { return self._s[1443]! } - public var Checkout_ErrorProviderAccountInvalid: String { return self._s[1444]! } - public var Notifications_InAppNotificationsSounds: String { return self._s[1446]! } + public var ScheduledMessages_ClearAllConfirmation: String { return self._s[1444]! } + public var Checkout_ErrorProviderAccountInvalid: String { return self._s[1445]! } + public var Notifications_InAppNotificationsSounds: String { return self._s[1447]! } public func PUSH_PINNED_GAME_SCORE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1447]!, self._r[1447]!, [_1]) + return formatWithArgumentRanges(self._s[1448]!, self._r[1448]!, [_1]) } - public var Preview_OpenInInstagram: String { return self._s[1448]! } - public var Notification_MessageLifetimeRemovedOutgoing: String { return self._s[1449]! } + public var Preview_OpenInInstagram: String { return self._s[1449]! } + public var Notification_MessageLifetimeRemovedOutgoing: String { return self._s[1450]! } public func PUSH_CHAT_ADD_MEMBER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1450]!, self._r[1450]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1451]!, self._r[1451]!, [_1, _2, _3]) } public func Passport_PrivacyPolicy(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1451]!, self._r[1451]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1452]!, self._r[1452]!, [_1, _2]) } - public var Channel_AdminLog_InfoPanelAlertTitle: String { return self._s[1452]! } - public var ArchivedChats_IntroText3: String { return self._s[1453]! } - public var ChatList_UndoArchiveHiddenText: String { return self._s[1454]! } - public var NetworkUsageSettings_TotalSection: String { return self._s[1455]! } - public var Wallet_Month_GenSeptember: String { return self._s[1456]! } - public var Channel_Setup_TypePrivateHelp: String { return self._s[1457]! } + public var Channel_AdminLog_InfoPanelAlertTitle: String { return self._s[1453]! } + public var ArchivedChats_IntroText3: String { return self._s[1454]! } + public var ChatList_UndoArchiveHiddenText: String { return self._s[1455]! } + public var NetworkUsageSettings_TotalSection: String { return self._s[1456]! } + public var Wallet_Month_GenSeptember: String { return self._s[1457]! } + public var Channel_Setup_TypePrivateHelp: String { return self._s[1458]! } public func PUSH_CHAT_MESSAGE_POLL(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1458]!, self._r[1458]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1459]!, self._r[1459]!, [_1, _2, _3]) } - public var Privacy_GroupsAndChannels_NeverAllow_Placeholder: String { return self._s[1460]! } - public var FastTwoStepSetup_HintSection: String { return self._s[1461]! } - public var Wallpaper_PhotoLibrary: String { return self._s[1462]! } - public var TwoStepAuth_SetupResendEmailCodeAlert: String { return self._s[1463]! } - public var Gif_NoGifsFound: String { return self._s[1464]! } - public var Watch_LastSeen_WithinAMonth: String { return self._s[1465]! } - public var VoiceOver_MessageContextDelete: String { return self._s[1466]! } - public var EditTheme_Preview: String { return self._s[1467]! } + public var Privacy_GroupsAndChannels_NeverAllow_Placeholder: String { return self._s[1461]! } + public var FastTwoStepSetup_HintSection: String { return self._s[1462]! } + public var Wallpaper_PhotoLibrary: String { return self._s[1463]! } + public var TwoStepAuth_SetupResendEmailCodeAlert: String { return self._s[1464]! } + public var Gif_NoGifsFound: String { return self._s[1465]! } + public var Watch_LastSeen_WithinAMonth: String { return self._s[1466]! } + public var VoiceOver_MessageContextDelete: String { return self._s[1467]! } + public var EditTheme_Preview: String { return self._s[1468]! } public func ClearCache_StorageTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1468]!, self._r[1468]!, [_0]) + return formatWithArgumentRanges(self._s[1469]!, self._r[1469]!, [_0]) } - public var GroupInfo_ActionPromote: String { return self._s[1469]! } - public var PasscodeSettings_SimplePasscode: String { return self._s[1470]! } - public var GroupInfo_Permissions_Title: String { return self._s[1471]! } - public var Permissions_ContactsText_v0: String { return self._s[1472]! } - public var PrivacyPhoneNumberSettings_CustomDisabledHelp: String { return self._s[1473]! } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedPublicGroups: String { return self._s[1474]! } - public var PrivacySettings_DataSettingsHelp: String { return self._s[1477]! } - public var Passport_FieldEmailHelp: String { return self._s[1478]! } + public var GroupInfo_ActionPromote: String { return self._s[1470]! } + public var PasscodeSettings_SimplePasscode: String { return self._s[1471]! } + public var GroupInfo_Permissions_Title: String { return self._s[1472]! } + public var Permissions_ContactsText_v0: String { return self._s[1473]! } + public var PrivacyPhoneNumberSettings_CustomDisabledHelp: String { return self._s[1474]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedPublicGroups: String { return self._s[1475]! } + public var PrivacySettings_DataSettingsHelp: String { return self._s[1478]! } + public var Passport_FieldEmailHelp: String { return self._s[1479]! } public func Activity_RemindAboutUser(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1479]!, self._r[1479]!, [_0]) + return formatWithArgumentRanges(self._s[1480]!, self._r[1480]!, [_0]) } - public var Passport_Identity_GenderPlaceholder: String { return self._s[1480]! } - public var Weekday_ShortSaturday: String { return self._s[1481]! } - public var ContactInfo_PhoneLabelMain: String { return self._s[1482]! } - public var Watch_Conversation_UserInfo: String { return self._s[1483]! } - public var CheckoutInfo_ShippingInfoCityPlaceholder: String { return self._s[1484]! } - public var GroupPermission_PermissionDisabledByDefault: String { return self._s[1485]! } - public var PrivacyLastSeenSettings_Title: String { return self._s[1486]! } - public var Conversation_ShareBotLocationConfirmation: String { return self._s[1487]! } - public var PhotoEditor_VignetteTool: String { return self._s[1488]! } - public var Passport_Address_Street1Placeholder: String { return self._s[1489]! } - public var Passport_Language_et: String { return self._s[1490]! } - public var AppUpgrade_Running: String { return self._s[1491]! } - public var Channel_DiscussionGroup_Info: String { return self._s[1493]! } - public var EditTheme_Create_Preview_IncomingReplyName: String { return self._s[1494]! } - public var Passport_Language_bg: String { return self._s[1495]! } - public var Stickers_NoStickersFound: String { return self._s[1497]! } + public var Passport_Identity_GenderPlaceholder: String { return self._s[1481]! } + public var Weekday_ShortSaturday: String { return self._s[1482]! } + public var ContactInfo_PhoneLabelMain: String { return self._s[1483]! } + public var Watch_Conversation_UserInfo: String { return self._s[1484]! } + public var CheckoutInfo_ShippingInfoCityPlaceholder: String { return self._s[1485]! } + public var GroupPermission_PermissionDisabledByDefault: String { return self._s[1486]! } + public var PrivacyLastSeenSettings_Title: String { return self._s[1487]! } + public var Conversation_ShareBotLocationConfirmation: String { return self._s[1488]! } + public var PhotoEditor_VignetteTool: String { return self._s[1489]! } + public var Passport_Address_Street1Placeholder: String { return self._s[1490]! } + public var Passport_Language_et: String { return self._s[1491]! } + public var AppUpgrade_Running: String { return self._s[1492]! } + public var Channel_DiscussionGroup_Info: String { return self._s[1494]! } + public var EditTheme_Create_Preview_IncomingReplyName: String { return self._s[1495]! } + public var Passport_Language_bg: String { return self._s[1496]! } + public var Stickers_NoStickersFound: String { return self._s[1498]! } public func PUSH_CHANNEL_MESSAGE_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1499]!, self._r[1499]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1500]!, self._r[1500]!, [_1, _2]) } public func VoiceOver_Chat_ContactFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1500]!, self._r[1500]!, [_0]) + return formatWithArgumentRanges(self._s[1501]!, self._r[1501]!, [_0]) } - public var Wallet_Month_GenJuly: String { return self._s[1501]! } - public var Wallet_Receive_AddressHeader: String { return self._s[1502]! } - public var Wallet_Send_AmountText: String { return self._s[1503]! } - public var Settings_About: String { return self._s[1504]! } + public var Wallet_Month_GenJuly: String { return self._s[1502]! } + public var Wallet_Receive_AddressHeader: String { return self._s[1503]! } + public var Wallet_Send_AmountText: String { return self._s[1504]! } + public var Settings_About: String { return self._s[1505]! } public func Channel_AdminLog_MessageRestricted(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1505]!, self._r[1505]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[1506]!, self._r[1506]!, [_0, _1, _2]) } - public var ChatList_Context_MarkAsRead: String { return self._s[1507]! } - public var KeyCommand_NewMessage: String { return self._s[1508]! } - public var Group_ErrorAddBlocked: String { return self._s[1509]! } + public var ChatList_Context_MarkAsRead: String { return self._s[1508]! } + public var KeyCommand_NewMessage: String { return self._s[1509]! } + public var Group_ErrorAddBlocked: String { return self._s[1510]! } public func Message_PaymentSent(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1510]!, self._r[1510]!, [_0]) + return formatWithArgumentRanges(self._s[1511]!, self._r[1511]!, [_0]) } - public var Map_LocationTitle: String { return self._s[1511]! } - public var ReportGroupLocation_Title: String { return self._s[1512]! } - public var CallSettings_UseLessDataLongDescription: String { return self._s[1513]! } - public var Cache_ClearProgress: String { return self._s[1514]! } + public var Map_LocationTitle: String { return self._s[1512]! } + public var ReportGroupLocation_Title: String { return self._s[1513]! } + public var CallSettings_UseLessDataLongDescription: String { return self._s[1514]! } + public var Cache_ClearProgress: String { return self._s[1515]! } public func Channel_Management_ErrorNotMember(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1515]!, self._r[1515]!, [_0]) + return formatWithArgumentRanges(self._s[1516]!, self._r[1516]!, [_0]) } - public var GroupRemoved_AddToGroup: String { return self._s[1516]! } - public var Passport_UpdateRequiredError: String { return self._s[1517]! } - public var Wallet_SecureStorageNotAvailable_Text: String { return self._s[1518]! } + public var GroupRemoved_AddToGroup: String { return self._s[1517]! } + public var Passport_UpdateRequiredError: String { return self._s[1518]! } + public var Wallet_SecureStorageNotAvailable_Text: String { return self._s[1519]! } public func PUSH_MESSAGE_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1519]!, self._r[1519]!, [_1]) + return formatWithArgumentRanges(self._s[1520]!, self._r[1520]!, [_1]) } - public var Notifications_PermissionsSuppressWarningText: String { return self._s[1521]! } - public var Passport_Identity_MainPageHelp: String { return self._s[1522]! } - public var Conversation_StatusKickedFromGroup: String { return self._s[1523]! } - public var Passport_Language_ka: String { return self._s[1524]! } + public var Notifications_PermissionsSuppressWarningText: String { return self._s[1522]! } + public var Passport_Identity_MainPageHelp: String { return self._s[1523]! } + public var Conversation_StatusKickedFromGroup: String { return self._s[1524]! } + public var Passport_Language_ka: String { return self._s[1525]! } public func Wallet_Time_PreciseDate_m12(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1525]!, self._r[1525]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1526]!, self._r[1526]!, [_1, _2, _3]) } - public var Call_Decline: String { return self._s[1526]! } - public var SocksProxySetup_ProxyEnabled: String { return self._s[1527]! } - public var TwoFactorSetup_Email_SkipConfirmationText: String { return self._s[1530]! } + public var Call_Decline: String { return self._s[1527]! } + public var SocksProxySetup_ProxyEnabled: String { return self._s[1528]! } + public var TwoFactorSetup_Email_SkipConfirmationText: String { return self._s[1531]! } public func AuthCode_Alert(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1531]!, self._r[1531]!, [_0]) + return formatWithArgumentRanges(self._s[1532]!, self._r[1532]!, [_0]) } - public var CallFeedback_Send: String { return self._s[1532]! } - public var EditTheme_EditTitle: String { return self._s[1533]! } + public var CallFeedback_Send: String { return self._s[1533]! } + public var EditTheme_EditTitle: String { return self._s[1534]! } public func Channel_AdminLog_MessagePromotedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1534]!, self._r[1534]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1535]!, self._r[1535]!, [_1, _2]) } - public var Passport_Phone_UseTelegramNumberHelp: String { return self._s[1535]! } + public var Passport_Phone_UseTelegramNumberHelp: String { return self._s[1536]! } public func Wallet_Updated_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1537]!, self._r[1537]!, [_0]) + return formatWithArgumentRanges(self._s[1538]!, self._r[1538]!, [_0]) } - public var SettingsSearch_Synonyms_Data_Title: String { return self._s[1538]! } - public var Passport_DeletePassport: String { return self._s[1539]! } - public var Appearance_AppIconFilled: String { return self._s[1540]! } - public var Privacy_Calls_P2PAlways: String { return self._s[1541]! } - public var Month_ShortDecember: String { return self._s[1542]! } - public var Channel_AdminLog_CanEditMessages: String { return self._s[1544]! } + public var SettingsSearch_Synonyms_Data_Title: String { return self._s[1539]! } + public var Passport_DeletePassport: String { return self._s[1540]! } + public var Appearance_AppIconFilled: String { return self._s[1541]! } + public var Privacy_Calls_P2PAlways: String { return self._s[1542]! } + public var Month_ShortDecember: String { return self._s[1543]! } + public var Channel_AdminLog_CanEditMessages: String { return self._s[1545]! } public func Contacts_AccessDeniedHelpLandscape(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1545]!, self._r[1545]!, [_0]) + return formatWithArgumentRanges(self._s[1546]!, self._r[1546]!, [_0]) } - public var Channel_Stickers_Searching: String { return self._s[1546]! } - public var Conversation_EncryptedDescription1: String { return self._s[1547]! } - public var Conversation_EncryptedDescription2: String { return self._s[1548]! } - public var PasscodeSettings_PasscodeOptions: String { return self._s[1549]! } - public var Conversation_EncryptedDescription3: String { return self._s[1551]! } - public var PhotoEditor_SharpenTool: String { return self._s[1552]! } - public var Wallet_Configuration_Title: String { return self._s[1553]! } + public var Channel_Stickers_Searching: String { return self._s[1547]! } + public var Conversation_EncryptedDescription1: String { return self._s[1548]! } + public var Conversation_EncryptedDescription2: String { return self._s[1549]! } + public var PasscodeSettings_PasscodeOptions: String { return self._s[1550]! } + public var Conversation_EncryptedDescription3: String { return self._s[1552]! } + public var PhotoEditor_SharpenTool: String { return self._s[1553]! } + public var Wallet_Configuration_Title: String { return self._s[1554]! } public func Conversation_AddNameToContacts(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1554]!, self._r[1554]!, [_0]) + return formatWithArgumentRanges(self._s[1555]!, self._r[1555]!, [_0]) } - public var Conversation_EncryptedDescription4: String { return self._s[1556]! } - public var Channel_Members_AddMembers: String { return self._s[1557]! } - public var Wallpaper_Search: String { return self._s[1558]! } - public var Weekday_Friday: String { return self._s[1560]! } - public var Privacy_ContactsSync: String { return self._s[1561]! } - public var SettingsSearch_Synonyms_Privacy_Data_ContactsReset: String { return self._s[1562]! } - public var ApplyLanguage_ChangeLanguageAction: String { return self._s[1563]! } + public var Conversation_EncryptedDescription4: String { return self._s[1557]! } + public var Channel_Members_AddMembers: String { return self._s[1558]! } + public var Wallpaper_Search: String { return self._s[1559]! } + public var Weekday_Friday: String { return self._s[1561]! } + public var Privacy_ContactsSync: String { return self._s[1562]! } + public var SettingsSearch_Synonyms_Privacy_Data_ContactsReset: String { return self._s[1563]! } + public var ApplyLanguage_ChangeLanguageAction: String { return self._s[1564]! } public func Channel_Management_RestrictedBy(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1564]!, self._r[1564]!, [_0]) + return formatWithArgumentRanges(self._s[1565]!, self._r[1565]!, [_0]) } - public var Wallet_Configuration_BlockchainIdHeader: String { return self._s[1565]! } - public var GroupInfo_Permissions_Removed: String { return self._s[1566]! } - public var ScheduledMessages_ScheduledOnline: String { return self._s[1567]! } - public var Passport_Identity_GenderMale: String { return self._s[1568]! } + public var Wallet_Configuration_BlockchainIdHeader: String { return self._s[1566]! } + public var GroupInfo_Permissions_Removed: String { return self._s[1567]! } + public var ScheduledMessages_ScheduledOnline: String { return self._s[1568]! } + public var Passport_Identity_GenderMale: String { return self._s[1569]! } public func Call_StatusBar(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1569]!, self._r[1569]!, [_0]) + return formatWithArgumentRanges(self._s[1570]!, self._r[1570]!, [_0]) } - public var Notifications_PermissionsKeepDisabled: String { return self._s[1570]! } - public var Conversation_JumpToDate: String { return self._s[1571]! } - public var Contacts_GlobalSearch: String { return self._s[1572]! } - public var AutoDownloadSettings_ResetHelp: String { return self._s[1573]! } - public var SettingsSearch_Synonyms_FAQ: String { return self._s[1574]! } - public var Profile_MessageLifetime1d: String { return self._s[1575]! } + public var Notifications_PermissionsKeepDisabled: String { return self._s[1571]! } + public var Conversation_JumpToDate: String { return self._s[1572]! } + public var Contacts_GlobalSearch: String { return self._s[1573]! } + public var AutoDownloadSettings_ResetHelp: String { return self._s[1574]! } + public var SettingsSearch_Synonyms_FAQ: String { return self._s[1575]! } + public var Profile_MessageLifetime1d: String { return self._s[1576]! } public func MESSAGE_INVOICE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1576]!, self._r[1576]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1577]!, self._r[1577]!, [_1, _2]) } - public var StickerPack_BuiltinPackName: String { return self._s[1579]! } + public var StickerPack_BuiltinPackName: String { return self._s[1580]! } public func PUSH_CHAT_MESSAGE_AUDIO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1580]!, self._r[1580]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1581]!, self._r[1581]!, [_1, _2]) } - public var VoiceOver_Chat_RecordModeVoiceMessageInfo: String { return self._s[1581]! } - public var Passport_InfoTitle: String { return self._s[1583]! } - public var Notifications_PermissionsUnreachableText: String { return self._s[1584]! } + public var VoiceOver_Chat_RecordModeVoiceMessageInfo: String { return self._s[1582]! } + public var Passport_InfoTitle: String { return self._s[1584]! } + public var Notifications_PermissionsUnreachableText: String { return self._s[1585]! } public func NetworkUsageSettings_CellularUsageSince(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1588]!, self._r[1588]!, [_0]) + return formatWithArgumentRanges(self._s[1589]!, self._r[1589]!, [_0]) } public func PUSH_CHAT_MESSAGE_GEO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1589]!, self._r[1589]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1590]!, self._r[1590]!, [_1, _2]) } - public var Passport_Address_TypePassportRegistrationUploadScan: String { return self._s[1590]! } - public var Profile_BotInfo: String { return self._s[1591]! } - public var Watch_Compose_CreateMessage: String { return self._s[1592]! } - public var AutoDownloadSettings_VoiceMessagesInfo: String { return self._s[1593]! } - public var Month_ShortNovember: String { return self._s[1594]! } - public var Conversation_ScamWarning: String { return self._s[1595]! } - public var Wallpaper_SetCustomBackground: String { return self._s[1596]! } - public var Appearance_TextSize_Title: String { return self._s[1597]! } - public var Passport_Identity_TranslationsHelp: String { return self._s[1598]! } - public var NotificationsSound_Chime: String { return self._s[1599]! } - public var Passport_Language_ko: String { return self._s[1601]! } - public var InviteText_URL: String { return self._s[1602]! } - public var TextFormat_Monospace: String { return self._s[1603]! } + public var Passport_Address_TypePassportRegistrationUploadScan: String { return self._s[1591]! } + public var Profile_BotInfo: String { return self._s[1592]! } + public var Watch_Compose_CreateMessage: String { return self._s[1593]! } + public var AutoDownloadSettings_VoiceMessagesInfo: String { return self._s[1594]! } + public var Month_ShortNovember: String { return self._s[1595]! } + public var Conversation_ScamWarning: String { return self._s[1596]! } + public var Wallpaper_SetCustomBackground: String { return self._s[1597]! } + public var Appearance_TextSize_Title: String { return self._s[1598]! } + public var Passport_Identity_TranslationsHelp: String { return self._s[1599]! } + public var NotificationsSound_Chime: String { return self._s[1600]! } + public var Passport_Language_ko: String { return self._s[1602]! } + public var InviteText_URL: String { return self._s[1603]! } + public var TextFormat_Monospace: String { return self._s[1604]! } public func Time_PreciseDate_m11(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1604]!, self._r[1604]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1605]!, self._r[1605]!, [_1, _2, _3]) } - public var EditTheme_Edit_BottomInfo: String { return self._s[1605]! } + public var EditTheme_Edit_BottomInfo: String { return self._s[1606]! } public func Login_WillSendSms(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1606]!, self._r[1606]!, [_0]) + return formatWithArgumentRanges(self._s[1607]!, self._r[1607]!, [_0]) } public func Watch_Time_ShortWeekdayAt(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1607]!, self._r[1607]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1608]!, self._r[1608]!, [_1, _2]) } - public var Wallet_Words_Title: String { return self._s[1608]! } - public var Wallet_Month_ShortMay: String { return self._s[1609]! } - public var EditTheme_CreateTitle: String { return self._s[1611]! } - public var Passport_InfoLearnMore: String { return self._s[1612]! } - public var TwoStepAuth_EmailPlaceholder: String { return self._s[1613]! } - public var Passport_Identity_AddIdentityCard: String { return self._s[1614]! } - public var Your_card_has_expired: String { return self._s[1615]! } - public var StickerPacksSettings_StickerPacksSection: String { return self._s[1616]! } - public var GroupInfo_InviteLink_Help: String { return self._s[1617]! } - public var TwoFactorSetup_EmailVerification_ResendAction: String { return self._s[1621]! } - public var Conversation_Report: String { return self._s[1623]! } - public var Notifications_MessageNotificationsSound: String { return self._s[1624]! } - public var Notification_MessageLifetime1m: String { return self._s[1625]! } - public var Privacy_ContactsTitle: String { return self._s[1626]! } - public var Conversation_ShareMyContactInfo: String { return self._s[1627]! } - public var Wallet_WordCheck_Title: String { return self._s[1628]! } - public var ChannelMembers_WhoCanAddMembersAdminsHelp: String { return self._s[1629]! } - public var Channel_Members_Title: String { return self._s[1630]! } - public var Map_OpenInWaze: String { return self._s[1631]! } - public var Appearance_RemoveThemeColorConfirmation: String { return self._s[1632]! } - public var Login_PhoneBannedError: String { return self._s[1633]! } + public var Wallet_Words_Title: String { return self._s[1609]! } + public var Wallet_Month_ShortMay: String { return self._s[1610]! } + public var EditTheme_CreateTitle: String { return self._s[1612]! } + public var Passport_InfoLearnMore: String { return self._s[1613]! } + public var TwoStepAuth_EmailPlaceholder: String { return self._s[1614]! } + public var Passport_Identity_AddIdentityCard: String { return self._s[1615]! } + public var Your_card_has_expired: String { return self._s[1616]! } + public var StickerPacksSettings_StickerPacksSection: String { return self._s[1617]! } + public var GroupInfo_InviteLink_Help: String { return self._s[1618]! } + public var TwoFactorSetup_EmailVerification_ResendAction: String { return self._s[1622]! } + public var Conversation_Report: String { return self._s[1624]! } + public var Notifications_MessageNotificationsSound: String { return self._s[1625]! } + public var Notification_MessageLifetime1m: String { return self._s[1626]! } + public var Privacy_ContactsTitle: String { return self._s[1627]! } + public var Conversation_ShareMyContactInfo: String { return self._s[1628]! } + public var Wallet_WordCheck_Title: String { return self._s[1629]! } + public var ChannelMembers_WhoCanAddMembersAdminsHelp: String { return self._s[1630]! } + public var Channel_Members_Title: String { return self._s[1631]! } + public var Map_OpenInWaze: String { return self._s[1632]! } + public var Appearance_RemoveThemeColorConfirmation: String { return self._s[1633]! } + public var Login_PhoneBannedError: String { return self._s[1634]! } public func LiveLocationUpdated_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1634]!, self._r[1634]!, [_0]) + return formatWithArgumentRanges(self._s[1635]!, self._r[1635]!, [_0]) } - public var IntentsSettings_MainAccount: String { return self._s[1635]! } - public var Group_Management_AddModeratorHelp: String { return self._s[1636]! } - public var AutoDownloadSettings_WifiTitle: String { return self._s[1637]! } - public var Common_OK: String { return self._s[1638]! } - public var Passport_Address_TypeBankStatementUploadScan: String { return self._s[1639]! } - public var Wallet_Words_NotDoneResponse: String { return self._s[1640]! } - public var Cache_Music: String { return self._s[1641]! } - public var Wallet_Configuration_SourceURL: String { return self._s[1642]! } - public var SettingsSearch_Synonyms_EditProfile_PhoneNumber: String { return self._s[1643]! } - public var PasscodeSettings_UnlockWithTouchId: String { return self._s[1645]! } - public var TwoStepAuth_HintPlaceholder: String { return self._s[1646]! } + public var IntentsSettings_MainAccount: String { return self._s[1636]! } + public var Group_Management_AddModeratorHelp: String { return self._s[1637]! } + public var AutoDownloadSettings_WifiTitle: String { return self._s[1638]! } + public var Common_OK: String { return self._s[1639]! } + public var Passport_Address_TypeBankStatementUploadScan: String { return self._s[1640]! } + public var Wallet_Words_NotDoneResponse: String { return self._s[1641]! } + public var Cache_Music: String { return self._s[1642]! } + public var Wallet_Configuration_SourceURL: String { return self._s[1643]! } + public var SettingsSearch_Synonyms_EditProfile_PhoneNumber: String { return self._s[1644]! } + public var PasscodeSettings_UnlockWithTouchId: String { return self._s[1646]! } + public var TwoStepAuth_HintPlaceholder: String { return self._s[1647]! } public func PUSH_PINNED_INVOICE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1647]!, self._r[1647]!, [_1]) + return formatWithArgumentRanges(self._s[1648]!, self._r[1648]!, [_1]) } public func Passport_RequestHeader(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1648]!, self._r[1648]!, [_0]) + return formatWithArgumentRanges(self._s[1649]!, self._r[1649]!, [_0]) } - public var TwoFactorSetup_Done_Action: String { return self._s[1649]! } + public var TwoFactorSetup_Done_Action: String { return self._s[1650]! } public func VoiceOver_Chat_ContactOrganization(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1650]!, self._r[1650]!, [_0]) + return formatWithArgumentRanges(self._s[1651]!, self._r[1651]!, [_0]) } - public var Wallet_Send_ErrorNotEnoughFundsText: String { return self._s[1651]! } - public var Watch_MessageView_ViewOnPhone: String { return self._s[1653]! } - public var Privacy_Calls_CustomShareHelp: String { return self._s[1654]! } - public var Wallet_Receive_CreateInvoiceInfo: String { return self._s[1656]! } - public var ChangePhoneNumberNumber_Title: String { return self._s[1657]! } - public var State_ConnectingToProxyInfo: String { return self._s[1658]! } - public var Conversation_SwipeToReplyHintTitle: String { return self._s[1659]! } - public var Message_VideoMessage: String { return self._s[1661]! } - public var ChannelInfo_DeleteChannel: String { return self._s[1662]! } - public var ContactInfo_PhoneLabelOther: String { return self._s[1663]! } - public var Channel_EditAdmin_CannotEdit: String { return self._s[1664]! } - public var Passport_DeleteAddressConfirmation: String { return self._s[1665]! } + public var Wallet_Send_ErrorNotEnoughFundsText: String { return self._s[1652]! } + public var Watch_MessageView_ViewOnPhone: String { return self._s[1654]! } + public var Privacy_Calls_CustomShareHelp: String { return self._s[1655]! } + public var Wallet_Receive_CreateInvoiceInfo: String { return self._s[1657]! } + public var ChangePhoneNumberNumber_Title: String { return self._s[1658]! } + public var State_ConnectingToProxyInfo: String { return self._s[1659]! } + public var Conversation_SwipeToReplyHintTitle: String { return self._s[1660]! } + public var Message_VideoMessage: String { return self._s[1662]! } + public var ChannelInfo_DeleteChannel: String { return self._s[1663]! } + public var ContactInfo_PhoneLabelOther: String { return self._s[1664]! } + public var Channel_EditAdmin_CannotEdit: String { return self._s[1665]! } + public var Passport_DeleteAddressConfirmation: String { return self._s[1666]! } public func Wallet_Time_PreciseDate_m9(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1666]!, self._r[1666]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1667]!, self._r[1667]!, [_1, _2, _3]) } - public var WallpaperPreview_SwipeBottomText: String { return self._s[1667]! } - public var Activity_RecordingAudio: String { return self._s[1668]! } - public var SettingsSearch_Synonyms_Watch: String { return self._s[1669]! } - public var PasscodeSettings_TryAgainIn1Minute: String { return self._s[1670]! } - public var Wallet_Info_Address: String { return self._s[1671]! } + public var WallpaperPreview_SwipeBottomText: String { return self._s[1668]! } + public var Activity_RecordingAudio: String { return self._s[1669]! } + public var SettingsSearch_Synonyms_Watch: String { return self._s[1670]! } + public var PasscodeSettings_TryAgainIn1Minute: String { return self._s[1671]! } + public var Wallet_Info_Address: String { return self._s[1672]! } public func Notification_ChangedGroupName(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1673]!, self._r[1673]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1674]!, self._r[1674]!, [_0, _1]) } public func EmptyGroupInfo_Line1(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1677]!, self._r[1677]!, [_0]) + return formatWithArgumentRanges(self._s[1678]!, self._r[1678]!, [_0]) } - public var Conversation_ApplyLocalization: String { return self._s[1678]! } - public var TwoFactorSetup_Intro_Action: String { return self._s[1679]! } - public var UserInfo_AddPhone: String { return self._s[1680]! } - public var Map_ShareLiveLocationHelp: String { return self._s[1681]! } + public var Conversation_ApplyLocalization: String { return self._s[1679]! } + public var TwoFactorSetup_Intro_Action: String { return self._s[1680]! } + public var UserInfo_AddPhone: String { return self._s[1681]! } + public var Map_ShareLiveLocationHelp: String { return self._s[1682]! } public func Passport_Identity_NativeNameGenericHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1682]!, self._r[1682]!, [_0]) + return formatWithArgumentRanges(self._s[1683]!, self._r[1683]!, [_0]) } - public var Passport_Scans: String { return self._s[1684]! } - public var BlockedUsers_Unblock: String { return self._s[1685]! } + public var Passport_Scans: String { return self._s[1685]! } + public var BlockedUsers_Unblock: String { return self._s[1686]! } public func PUSH_ENCRYPTION_REQUEST(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1686]!, self._r[1686]!, [_1]) + return formatWithArgumentRanges(self._s[1687]!, self._r[1687]!, [_1]) } - public var Channel_Management_LabelCreator: String { return self._s[1687]! } - public var Conversation_ReportSpamAndLeave: String { return self._s[1688]! } - public var SettingsSearch_Synonyms_EditProfile_Bio: String { return self._s[1689]! } - public var ChatList_UndoArchiveMultipleTitle: String { return self._s[1690]! } - public var Passport_Identity_NativeNameGenericTitle: String { return self._s[1691]! } + public var Channel_Management_LabelCreator: String { return self._s[1688]! } + public var Conversation_ReportSpamAndLeave: String { return self._s[1689]! } + public var SettingsSearch_Synonyms_EditProfile_Bio: String { return self._s[1690]! } + public var ChatList_UndoArchiveMultipleTitle: String { return self._s[1691]! } + public var Passport_Identity_NativeNameGenericTitle: String { return self._s[1692]! } public func Login_EmailPhoneBody(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1692]!, self._r[1692]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[1693]!, self._r[1693]!, [_0, _1, _2]) } - public var Login_PhoneNumberHelp: String { return self._s[1693]! } - public var LastSeen_ALongTimeAgo: String { return self._s[1694]! } - public var Channel_AdminLog_CanPinMessages: String { return self._s[1695]! } - public var ChannelIntro_CreateChannel: String { return self._s[1696]! } - public var Conversation_UnreadMessages: String { return self._s[1697]! } - public var SettingsSearch_Synonyms_Stickers_ArchivedPacks: String { return self._s[1698]! } - public var Channel_AdminLog_EmptyText: String { return self._s[1699]! } - public var Theme_Context_Apply: String { return self._s[1700]! } - public var Notification_GroupActivated: String { return self._s[1701]! } - public var NotificationSettings_ContactJoinedInfo: String { return self._s[1702]! } - public var Wallet_Intro_CreateWallet: String { return self._s[1703]! } + public var Login_PhoneNumberHelp: String { return self._s[1694]! } + public var LastSeen_ALongTimeAgo: String { return self._s[1695]! } + public var Channel_AdminLog_CanPinMessages: String { return self._s[1696]! } + public var ChannelIntro_CreateChannel: String { return self._s[1697]! } + public var Conversation_UnreadMessages: String { return self._s[1698]! } + public var SettingsSearch_Synonyms_Stickers_ArchivedPacks: String { return self._s[1699]! } + public var Channel_AdminLog_EmptyText: String { return self._s[1700]! } + public var Theme_Context_Apply: String { return self._s[1701]! } + public var Notification_GroupActivated: String { return self._s[1702]! } + public var NotificationSettings_ContactJoinedInfo: String { return self._s[1703]! } + public var Wallet_Intro_CreateWallet: String { return self._s[1704]! } public func Notification_PinnedContactMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1704]!, self._r[1704]!, [_0]) + return formatWithArgumentRanges(self._s[1705]!, self._r[1705]!, [_0]) } public func DownloadingStatus(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1705]!, self._r[1705]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1706]!, self._r[1706]!, [_0, _1]) } - public var GroupInfo_ConvertToSupergroup: String { return self._s[1707]! } + public var GroupInfo_ConvertToSupergroup: String { return self._s[1708]! } public func PrivacyPolicy_AgeVerificationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1708]!, self._r[1708]!, [_0]) + return formatWithArgumentRanges(self._s[1709]!, self._r[1709]!, [_0]) } - public var Undo_DeletedChannel: String { return self._s[1709]! } - public var CallFeedback_AddComment: String { return self._s[1710]! } + public var Undo_DeletedChannel: String { return self._s[1710]! } + public var CallFeedback_AddComment: String { return self._s[1711]! } public func Conversation_OpenBotLinkAllowMessages(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1711]!, self._r[1711]!, [_0]) + return formatWithArgumentRanges(self._s[1712]!, self._r[1712]!, [_0]) } - public var Document_TargetConfirmationFormat: String { return self._s[1712]! } + public var Document_TargetConfirmationFormat: String { return self._s[1713]! } public func Call_StatusOngoing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1713]!, self._r[1713]!, [_0]) + return formatWithArgumentRanges(self._s[1714]!, self._r[1714]!, [_0]) } - public var LogoutOptions_SetPasscodeTitle: String { return self._s[1714]! } + public var LogoutOptions_SetPasscodeTitle: String { return self._s[1715]! } public func PUSH_CHAT_MESSAGE_GAME_SCORE(_ _1: String, _ _2: String, _ _3: String, _ _4: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1715]!, self._r[1715]!, [_1, _2, _3, _4]) + return formatWithArgumentRanges(self._s[1716]!, self._r[1716]!, [_1, _2, _3, _4]) } - public var Wallet_SecureStorageChanged_PasscodeText: String { return self._s[1716]! } - public var Theme_ErrorNotFound: String { return self._s[1717]! } - public var Contacts_SortByName: String { return self._s[1718]! } - public var SettingsSearch_Synonyms_Privacy_Forwards: String { return self._s[1719]! } + public var Wallet_SecureStorageChanged_PasscodeText: String { return self._s[1717]! } + public var Theme_ErrorNotFound: String { return self._s[1718]! } + public var Contacts_SortByName: String { return self._s[1719]! } + public var SettingsSearch_Synonyms_Privacy_Forwards: String { return self._s[1720]! } public func CHAT_MESSAGE_INVOICE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1721]!, self._r[1721]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1722]!, self._r[1722]!, [_1, _2, _3]) } - public var Notification_Exceptions_RemoveFromExceptions: String { return self._s[1722]! } - public var ScheduledMessages_EditTime: String { return self._s[1723]! } - public var Conversation_ClearSelfHistory: String { return self._s[1724]! } - public var Checkout_NewCard_PostcodePlaceholder: String { return self._s[1725]! } - public var PasscodeSettings_DoNotMatch: String { return self._s[1726]! } - public var Stickers_SuggestNone: String { return self._s[1727]! } - public var ChatSettings_Cache: String { return self._s[1728]! } - public var Settings_SaveIncomingPhotos: String { return self._s[1729]! } - public var Media_ShareThisPhoto: String { return self._s[1730]! } - public var Chat_SlowmodeTooltipPending: String { return self._s[1731]! } - public var InfoPlist_NSContactsUsageDescription: String { return self._s[1732]! } - public var Conversation_ContextMenuCopyLink: String { return self._s[1733]! } - public var PrivacyPolicy_AgeVerificationTitle: String { return self._s[1734]! } - public var SettingsSearch_Synonyms_Stickers_Masks: String { return self._s[1735]! } - public var TwoStepAuth_SetupPasswordEnterPasswordNew: String { return self._s[1736]! } - public var Appearance_ThemePreview_Chat_6_Text: String { return self._s[1737]! } + public var Notification_Exceptions_RemoveFromExceptions: String { return self._s[1723]! } + public var ScheduledMessages_EditTime: String { return self._s[1724]! } + public var Conversation_ClearSelfHistory: String { return self._s[1725]! } + public var Checkout_NewCard_PostcodePlaceholder: String { return self._s[1726]! } + public var PasscodeSettings_DoNotMatch: String { return self._s[1727]! } + public var Stickers_SuggestNone: String { return self._s[1728]! } + public var ChatSettings_Cache: String { return self._s[1729]! } + public var Settings_SaveIncomingPhotos: String { return self._s[1730]! } + public var Media_ShareThisPhoto: String { return self._s[1731]! } + public var Chat_SlowmodeTooltipPending: String { return self._s[1732]! } + public var InfoPlist_NSContactsUsageDescription: String { return self._s[1733]! } + public var Conversation_ContextMenuCopyLink: String { return self._s[1734]! } + public var PrivacyPolicy_AgeVerificationTitle: String { return self._s[1735]! } + public var SettingsSearch_Synonyms_Stickers_Masks: String { return self._s[1736]! } + public var TwoStepAuth_SetupPasswordEnterPasswordNew: String { return self._s[1737]! } + public var Appearance_ThemePreview_Chat_6_Text: String { return self._s[1738]! } public func Wallet_SecureStorageReset_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1738]!, self._r[1738]!, [_0]) + return formatWithArgumentRanges(self._s[1739]!, self._r[1739]!, [_0]) } - public var Permissions_CellularDataTitle_v0: String { return self._s[1739]! } - public var WallpaperSearch_ColorWhite: String { return self._s[1741]! } - public var Channel_AdminLog_DefaultRestrictionsUpdated: String { return self._s[1742]! } - public var Conversation_ErrorInaccessibleMessage: String { return self._s[1743]! } - public var Map_OpenIn: String { return self._s[1744]! } + public var Permissions_CellularDataTitle_v0: String { return self._s[1740]! } + public var WallpaperSearch_ColorWhite: String { return self._s[1742]! } + public var Channel_AdminLog_DefaultRestrictionsUpdated: String { return self._s[1743]! } + public var Conversation_ErrorInaccessibleMessage: String { return self._s[1744]! } + public var Map_OpenIn: String { return self._s[1745]! } public func PUSH_PHONE_CALL_MISSED(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1747]!, self._r[1747]!, [_1]) + return formatWithArgumentRanges(self._s[1748]!, self._r[1748]!, [_1]) } public func ChannelInfo_AddParticipantConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1748]!, self._r[1748]!, [_0]) + return formatWithArgumentRanges(self._s[1749]!, self._r[1749]!, [_0]) } - public var GroupInfo_Permissions_SlowmodeHeader: String { return self._s[1749]! } - public var MessagePoll_LabelClosed: String { return self._s[1750]! } - public var GroupPermission_PermissionGloballyDisabled: String { return self._s[1752]! } - public var Wallet_Send_SendAnyway: String { return self._s[1753]! } - public var Passport_Identity_MiddleNamePlaceholder: String { return self._s[1754]! } - public var UserInfo_FirstNamePlaceholder: String { return self._s[1755]! } - public var PrivacyLastSeenSettings_WhoCanSeeMyTimestamp: String { return self._s[1756]! } - public var Map_SetThisPlace: String { return self._s[1757]! } - public var Login_SelectCountry_Title: String { return self._s[1758]! } - public var Channel_EditAdmin_PermissionBanUsers: String { return self._s[1759]! } + public var GroupInfo_Permissions_SlowmodeHeader: String { return self._s[1750]! } + public var MessagePoll_LabelClosed: String { return self._s[1751]! } + public var GroupPermission_PermissionGloballyDisabled: String { return self._s[1753]! } + public var Wallet_Send_SendAnyway: String { return self._s[1754]! } + public var Passport_Identity_MiddleNamePlaceholder: String { return self._s[1755]! } + public var UserInfo_FirstNamePlaceholder: String { return self._s[1756]! } + public var PrivacyLastSeenSettings_WhoCanSeeMyTimestamp: String { return self._s[1757]! } + public var Map_SetThisPlace: String { return self._s[1758]! } + public var Login_SelectCountry_Title: String { return self._s[1759]! } + public var Channel_EditAdmin_PermissionBanUsers: String { return self._s[1760]! } public func Conversation_OpenBotLinkLogin(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1760]!, self._r[1760]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1761]!, self._r[1761]!, [_1, _2]) } - public var Channel_AdminLog_ChangeInfo: String { return self._s[1761]! } - public var Watch_Suggestion_BRB: String { return self._s[1762]! } - public var Passport_Identity_EditIdentityCard: String { return self._s[1763]! } - public var Contacts_PermissionsTitle: String { return self._s[1764]! } - public var Conversation_RestrictedInline: String { return self._s[1765]! } - public var Appearance_RemoveThemeColor: String { return self._s[1767]! } - public var StickerPack_ViewPack: String { return self._s[1768]! } - public var Wallet_UnknownError: String { return self._s[1769]! } + public var Channel_AdminLog_ChangeInfo: String { return self._s[1762]! } + public var Watch_Suggestion_BRB: String { return self._s[1763]! } + public var Passport_Identity_EditIdentityCard: String { return self._s[1764]! } + public var Contacts_PermissionsTitle: String { return self._s[1765]! } + public var Conversation_RestrictedInline: String { return self._s[1766]! } + public var Appearance_RemoveThemeColor: String { return self._s[1768]! } + public var StickerPack_ViewPack: String { return self._s[1769]! } + public var Wallet_UnknownError: String { return self._s[1770]! } public func Update_AppVersion(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1770]!, self._r[1770]!, [_0]) + return formatWithArgumentRanges(self._s[1771]!, self._r[1771]!, [_0]) } - public var Compose_NewChannel: String { return self._s[1772]! } - public var ChatSettings_AutoDownloadSettings_TypePhoto: String { return self._s[1775]! } - public var MessagePoll_LabelQuiz: String { return self._s[1777]! } - public var Conversation_ReportSpamGroupConfirmation: String { return self._s[1778]! } - public var Channel_Info_Stickers: String { return self._s[1779]! } - public var AutoNightTheme_PreferredTheme: String { return self._s[1780]! } - public var PrivacyPolicy_AgeVerificationAgree: String { return self._s[1781]! } - public var Passport_DeletePersonalDetails: String { return self._s[1782]! } - public var LogoutOptions_AddAccountTitle: String { return self._s[1783]! } - public var Channel_DiscussionGroupInfo: String { return self._s[1784]! } - public var Group_EditAdmin_RankOwnerPlaceholder: String { return self._s[1785]! } - public var Conversation_SearchNoResults: String { return self._s[1788]! } - public var Wallet_Configuration_ApplyErrorTextURLInvalid: String { return self._s[1789]! } - public var MessagePoll_LabelAnonymous: String { return self._s[1790]! } - public var Channel_Members_AddAdminErrorNotAMember: String { return self._s[1791]! } - public var Login_Code: String { return self._s[1792]! } - public var EditTheme_Create_BottomInfo: String { return self._s[1793]! } - public var Watch_Suggestion_WhatsUp: String { return self._s[1794]! } - public var Weekday_ShortThursday: String { return self._s[1795]! } - public var Resolve_ErrorNotFound: String { return self._s[1797]! } - public var LastSeen_Offline: String { return self._s[1798]! } - public var PeopleNearby_NoMembers: String { return self._s[1799]! } - public var GroupPermission_AddMembersNotAvailable: String { return self._s[1800]! } - public var Privacy_Calls_AlwaysAllow_Title: String { return self._s[1801]! } - public var GroupInfo_Title: String { return self._s[1803]! } - public var NotificationsSound_Note: String { return self._s[1804]! } - public var Conversation_EditingMessagePanelTitle: String { return self._s[1805]! } - public var Watch_Message_Poll: String { return self._s[1806]! } - public var Privacy_Calls: String { return self._s[1807]! } + public var Compose_NewChannel: String { return self._s[1773]! } + public var ChatSettings_AutoDownloadSettings_TypePhoto: String { return self._s[1776]! } + public var MessagePoll_LabelQuiz: String { return self._s[1778]! } + public var Conversation_ReportSpamGroupConfirmation: String { return self._s[1779]! } + public var Channel_Info_Stickers: String { return self._s[1780]! } + public var AutoNightTheme_PreferredTheme: String { return self._s[1781]! } + public var PrivacyPolicy_AgeVerificationAgree: String { return self._s[1782]! } + public var Passport_DeletePersonalDetails: String { return self._s[1783]! } + public var LogoutOptions_AddAccountTitle: String { return self._s[1784]! } + public var Channel_DiscussionGroupInfo: String { return self._s[1785]! } + public var Group_EditAdmin_RankOwnerPlaceholder: String { return self._s[1786]! } + public var Conversation_SearchNoResults: String { return self._s[1789]! } + public var Wallet_Configuration_ApplyErrorTextURLInvalid: String { return self._s[1790]! } + public var MessagePoll_LabelAnonymous: String { return self._s[1791]! } + public var Channel_Members_AddAdminErrorNotAMember: String { return self._s[1792]! } + public var Login_Code: String { return self._s[1793]! } + public var EditTheme_Create_BottomInfo: String { return self._s[1794]! } + public var Watch_Suggestion_WhatsUp: String { return self._s[1795]! } + public var Weekday_ShortThursday: String { return self._s[1796]! } + public var Resolve_ErrorNotFound: String { return self._s[1798]! } + public var LastSeen_Offline: String { return self._s[1799]! } + public var PeopleNearby_NoMembers: String { return self._s[1800]! } + public var GroupPermission_AddMembersNotAvailable: String { return self._s[1801]! } + public var Privacy_Calls_AlwaysAllow_Title: String { return self._s[1802]! } + public var GroupInfo_Title: String { return self._s[1804]! } + public var NotificationsSound_Note: String { return self._s[1805]! } + public var Conversation_EditingMessagePanelTitle: String { return self._s[1806]! } + public var Watch_Message_Poll: String { return self._s[1807]! } + public var Privacy_Calls: String { return self._s[1808]! } public func Channel_AdminLog_MessageRankUsername(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1808]!, self._r[1808]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1809]!, self._r[1809]!, [_1, _2, _3]) } - public var Month_ShortAugust: String { return self._s[1809]! } - public var TwoStepAuth_SetPasswordHelp: String { return self._s[1810]! } - public var Notifications_Reset: String { return self._s[1811]! } - public var Conversation_Pin: String { return self._s[1812]! } - public var Passport_Language_lv: String { return self._s[1813]! } - public var Permissions_PeopleNearbyAllowInSettings_v0: String { return self._s[1814]! } - public var BlockedUsers_Info: String { return self._s[1815]! } - public var SettingsSearch_Synonyms_Data_AutoplayVideos: String { return self._s[1817]! } - public var Watch_Conversation_Unblock: String { return self._s[1819]! } + public var Month_ShortAugust: String { return self._s[1810]! } + public var TwoStepAuth_SetPasswordHelp: String { return self._s[1811]! } + public var Notifications_Reset: String { return self._s[1812]! } + public var Conversation_Pin: String { return self._s[1813]! } + public var Passport_Language_lv: String { return self._s[1814]! } + public var Permissions_PeopleNearbyAllowInSettings_v0: String { return self._s[1815]! } + public var BlockedUsers_Info: String { return self._s[1816]! } + public var SettingsSearch_Synonyms_Data_AutoplayVideos: String { return self._s[1818]! } + public var Watch_Conversation_Unblock: String { return self._s[1820]! } public func Time_MonthOfYear_m9(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1820]!, self._r[1820]!, [_0]) + return formatWithArgumentRanges(self._s[1821]!, self._r[1821]!, [_0]) } - public var CloudStorage_Title: String { return self._s[1821]! } - public var GroupInfo_DeleteAndExitConfirmation: String { return self._s[1822]! } + public var CloudStorage_Title: String { return self._s[1822]! } + public var GroupInfo_DeleteAndExitConfirmation: String { return self._s[1823]! } public func NetworkUsageSettings_WifiUsageSince(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1823]!, self._r[1823]!, [_0]) + return formatWithArgumentRanges(self._s[1824]!, self._r[1824]!, [_0]) } - public var Channel_AdminLogFilter_AdminsTitle: String { return self._s[1824]! } - public var Watch_Suggestion_OnMyWay: String { return self._s[1825]! } - public var TwoStepAuth_RecoveryEmailTitle: String { return self._s[1826]! } - public var Passport_Address_EditBankStatement: String { return self._s[1827]! } + public var Channel_AdminLogFilter_AdminsTitle: String { return self._s[1825]! } + public var Watch_Suggestion_OnMyWay: String { return self._s[1826]! } + public var TwoStepAuth_RecoveryEmailTitle: String { return self._s[1827]! } + public var Passport_Address_EditBankStatement: String { return self._s[1828]! } public func Channel_AdminLog_MessageChangedUnlinkedGroup(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1828]!, self._r[1828]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1829]!, self._r[1829]!, [_1, _2]) } - public var ChatSettings_DownloadInBackgroundInfo: String { return self._s[1829]! } - public var ShareMenu_Comment: String { return self._s[1830]! } - public var Permissions_ContactsTitle_v0: String { return self._s[1831]! } - public var Notifications_PermissionsTitle: String { return self._s[1832]! } - public var GroupPermission_NoSendLinks: String { return self._s[1833]! } - public var Privacy_Forwards_NeverAllow_Title: String { return self._s[1834]! } - public var Wallet_SecureStorageChanged_ImportWallet: String { return self._s[1835]! } - public var Settings_Support: String { return self._s[1836]! } - public var Notifications_ChannelNotificationsSound: String { return self._s[1837]! } - public var SettingsSearch_Synonyms_Data_AutoDownloadReset: String { return self._s[1838]! } - public var Privacy_Forwards_Preview: String { return self._s[1839]! } - public var GroupPermission_ApplyAlertAction: String { return self._s[1840]! } - public var Watch_Stickers_StickerPacks: String { return self._s[1841]! } - public var Common_Select: String { return self._s[1843]! } - public var CheckoutInfo_ErrorEmailInvalid: String { return self._s[1844]! } - public var WallpaperSearch_ColorGray: String { return self._s[1847]! } - public var TwoFactorSetup_Password_PlaceholderPassword: String { return self._s[1848]! } - public var TwoFactorSetup_Hint_SkipAction: String { return self._s[1849]! } - public var ChatAdmins_AllMembersAreAdminsOffHelp: String { return self._s[1850]! } - public var PollResults_Title: String { return self._s[1851]! } - public var PasscodeSettings_AutoLock_IfAwayFor_5hours: String { return self._s[1852]! } - public var Appearance_PreviewReplyAuthor: String { return self._s[1853]! } - public var TwoStepAuth_RecoveryTitle: String { return self._s[1854]! } - public var Widget_AuthRequired: String { return self._s[1855]! } - public var Camera_FlashOn: String { return self._s[1856]! } - public var Conversation_ContextMenuLookUp: String { return self._s[1857]! } - public var Channel_Stickers_NotFoundHelp: String { return self._s[1858]! } - public var Watch_Suggestion_OK: String { return self._s[1859]! } + public var ChatSettings_DownloadInBackgroundInfo: String { return self._s[1830]! } + public var ShareMenu_Comment: String { return self._s[1831]! } + public var Permissions_ContactsTitle_v0: String { return self._s[1832]! } + public var Notifications_PermissionsTitle: String { return self._s[1833]! } + public var GroupPermission_NoSendLinks: String { return self._s[1834]! } + public var Privacy_Forwards_NeverAllow_Title: String { return self._s[1835]! } + public var Wallet_SecureStorageChanged_ImportWallet: String { return self._s[1836]! } + public var Settings_Support: String { return self._s[1837]! } + public var Notifications_ChannelNotificationsSound: String { return self._s[1838]! } + public var SettingsSearch_Synonyms_Data_AutoDownloadReset: String { return self._s[1839]! } + public var Privacy_Forwards_Preview: String { return self._s[1840]! } + public var GroupPermission_ApplyAlertAction: String { return self._s[1841]! } + public var Watch_Stickers_StickerPacks: String { return self._s[1842]! } + public var Common_Select: String { return self._s[1844]! } + public var CheckoutInfo_ErrorEmailInvalid: String { return self._s[1845]! } + public var WallpaperSearch_ColorGray: String { return self._s[1848]! } + public var TwoFactorSetup_Password_PlaceholderPassword: String { return self._s[1849]! } + public var TwoFactorSetup_Hint_SkipAction: String { return self._s[1850]! } + public var ChatAdmins_AllMembersAreAdminsOffHelp: String { return self._s[1851]! } + public var PollResults_Title: String { return self._s[1852]! } + public var PasscodeSettings_AutoLock_IfAwayFor_5hours: String { return self._s[1853]! } + public var Appearance_PreviewReplyAuthor: String { return self._s[1854]! } + public var TwoStepAuth_RecoveryTitle: String { return self._s[1855]! } + public var Widget_AuthRequired: String { return self._s[1856]! } + public var Camera_FlashOn: String { return self._s[1857]! } + public var Conversation_ContextMenuLookUp: String { return self._s[1858]! } + public var Channel_Stickers_NotFoundHelp: String { return self._s[1859]! } + public var Watch_Suggestion_OK: String { return self._s[1860]! } public func Username_LinkHint(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1861]!, self._r[1861]!, [_0]) + return formatWithArgumentRanges(self._s[1862]!, self._r[1862]!, [_0]) } public func Notification_PinnedLiveLocationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1863]!, self._r[1863]!, [_0]) + return formatWithArgumentRanges(self._s[1864]!, self._r[1864]!, [_0]) } - public var TextFormat_Strikethrough: String { return self._s[1864]! } - public var DialogList_AdLabel: String { return self._s[1865]! } - public var WatchRemote_NotificationText: String { return self._s[1866]! } - public var IntentsSettings_SuggestedChatsSavedMessages: String { return self._s[1867]! } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsAlert: String { return self._s[1868]! } - public var Conversation_ReportSpam: String { return self._s[1869]! } - public var SettingsSearch_Synonyms_Privacy_Data_TopPeers: String { return self._s[1870]! } - public var Settings_LogoutConfirmationTitle: String { return self._s[1872]! } - public var PhoneLabel_Title: String { return self._s[1873]! } - public var Passport_Address_EditRentalAgreement: String { return self._s[1874]! } - public var Settings_ChangePhoneNumber: String { return self._s[1875]! } - public var Notifications_ExceptionsTitle: String { return self._s[1876]! } - public var Notifications_AlertTones: String { return self._s[1877]! } - public var Call_ReportIncludeLogDescription: String { return self._s[1878]! } - public var SettingsSearch_Synonyms_Notifications_ResetAllNotifications: String { return self._s[1879]! } - public var AutoDownloadSettings_PrivateChats: String { return self._s[1880]! } - public var VoiceOver_Chat_Photo: String { return self._s[1882]! } - public var TwoStepAuth_AddHintTitle: String { return self._s[1883]! } - public var ReportPeer_ReasonOther: String { return self._s[1884]! } - public var ChatList_Context_JoinChannel: String { return self._s[1885]! } - public var KeyCommand_ScrollDown: String { return self._s[1887]! } - public var Conversation_ScheduleMessage_Title: String { return self._s[1888]! } + public var TextFormat_Strikethrough: String { return self._s[1865]! } + public var DialogList_AdLabel: String { return self._s[1866]! } + public var WatchRemote_NotificationText: String { return self._s[1867]! } + public var IntentsSettings_SuggestedChatsSavedMessages: String { return self._s[1868]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsAlert: String { return self._s[1869]! } + public var Conversation_ReportSpam: String { return self._s[1870]! } + public var SettingsSearch_Synonyms_Privacy_Data_TopPeers: String { return self._s[1871]! } + public var Settings_LogoutConfirmationTitle: String { return self._s[1873]! } + public var PhoneLabel_Title: String { return self._s[1874]! } + public var Passport_Address_EditRentalAgreement: String { return self._s[1875]! } + public var Settings_ChangePhoneNumber: String { return self._s[1876]! } + public var Notifications_ExceptionsTitle: String { return self._s[1877]! } + public var Notifications_AlertTones: String { return self._s[1878]! } + public var Call_ReportIncludeLogDescription: String { return self._s[1879]! } + public var SettingsSearch_Synonyms_Notifications_ResetAllNotifications: String { return self._s[1880]! } + public var AutoDownloadSettings_PrivateChats: String { return self._s[1881]! } + public var VoiceOver_Chat_Photo: String { return self._s[1883]! } + public var TwoStepAuth_AddHintTitle: String { return self._s[1884]! } + public var ReportPeer_ReasonOther: String { return self._s[1885]! } + public var ChatList_Context_JoinChannel: String { return self._s[1886]! } + public var KeyCommand_ScrollDown: String { return self._s[1888]! } + public var Conversation_ScheduleMessage_Title: String { return self._s[1889]! } public func Login_BannedPhoneSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1889]!, self._r[1889]!, [_0]) + return formatWithArgumentRanges(self._s[1890]!, self._r[1890]!, [_0]) } - public var NetworkUsageSettings_MediaVideoDataSection: String { return self._s[1890]! } - public var ChannelInfo_DeleteGroupConfirmation: String { return self._s[1891]! } - public var AuthSessions_LogOut: String { return self._s[1892]! } - public var Passport_Identity_TypeInternalPassport: String { return self._s[1893]! } - public var ChatSettings_AutoDownloadVoiceMessages: String { return self._s[1894]! } - public var Passport_Phone_Title: String { return self._s[1895]! } - public var ContactList_Context_StartSecretChat: String { return self._s[1896]! } - public var Settings_PhoneNumber: String { return self._s[1897]! } + public var NetworkUsageSettings_MediaVideoDataSection: String { return self._s[1891]! } + public var ChannelInfo_DeleteGroupConfirmation: String { return self._s[1892]! } + public var AuthSessions_LogOut: String { return self._s[1893]! } + public var Passport_Identity_TypeInternalPassport: String { return self._s[1894]! } + public var ChatSettings_AutoDownloadVoiceMessages: String { return self._s[1895]! } + public var Passport_Phone_Title: String { return self._s[1896]! } + public var ContactList_Context_StartSecretChat: String { return self._s[1897]! } + public var Settings_PhoneNumber: String { return self._s[1898]! } public func Conversation_ScheduleMessage_SendToday(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1898]!, self._r[1898]!, [_0]) + return formatWithArgumentRanges(self._s[1899]!, self._r[1899]!, [_0]) } - public var NotificationsSound_Alert: String { return self._s[1900]! } - public var Wallet_SecureStorageChanged_CreateWallet: String { return self._s[1901]! } - public var WebSearch_SearchNoResults: String { return self._s[1902]! } - public var Privacy_ProfilePhoto_AlwaysShareWith_Title: String { return self._s[1904]! } - public var Wallet_Configuration_SourceInfo: String { return self._s[1905]! } - public var LogoutOptions_AlternativeOptionsSection: String { return self._s[1906]! } - public var SettingsSearch_Synonyms_Passport: String { return self._s[1907]! } - public var PhotoEditor_CurvesTool: String { return self._s[1908]! } - public var Checkout_PaymentMethod: String { return self._s[1910]! } + public var NotificationsSound_Alert: String { return self._s[1901]! } + public var Wallet_SecureStorageChanged_CreateWallet: String { return self._s[1902]! } + public var WebSearch_SearchNoResults: String { return self._s[1903]! } + public var Privacy_ProfilePhoto_AlwaysShareWith_Title: String { return self._s[1905]! } + public var Wallet_Configuration_SourceInfo: String { return self._s[1906]! } + public var LogoutOptions_AlternativeOptionsSection: String { return self._s[1907]! } + public var SettingsSearch_Synonyms_Passport: String { return self._s[1908]! } + public var PhotoEditor_CurvesTool: String { return self._s[1909]! } + public var Checkout_PaymentMethod: String { return self._s[1911]! } public func PUSH_CHAT_ADD_YOU(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1911]!, self._r[1911]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1912]!, self._r[1912]!, [_1, _2]) } - public var Contacts_AccessDeniedError: String { return self._s[1912]! } - public var Camera_PhotoMode: String { return self._s[1915]! } - public var EditTheme_Expand_Preview_IncomingText: String { return self._s[1916]! } - public var Appearance_TextSize_Apply: String { return self._s[1917]! } - public var Passport_Address_AddUtilityBill: String { return self._s[1919]! } - public var CallSettings_OnMobile: String { return self._s[1920]! } - public var Tour_Text2: String { return self._s[1921]! } + public var Contacts_AccessDeniedError: String { return self._s[1913]! } + public var Camera_PhotoMode: String { return self._s[1916]! } + public var EditTheme_Expand_Preview_IncomingText: String { return self._s[1917]! } + public var Appearance_TextSize_Apply: String { return self._s[1918]! } + public var Passport_Address_AddUtilityBill: String { return self._s[1920]! } + public var CallSettings_OnMobile: String { return self._s[1921]! } + public var Tour_Text2: String { return self._s[1922]! } public func PUSH_CHAT_MESSAGE_ROUND(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1922]!, self._r[1922]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1923]!, self._r[1923]!, [_1, _2]) } - public var DialogList_EncryptionProcessing: String { return self._s[1924]! } - public var Permissions_Skip: String { return self._s[1925]! } - public var Wallet_Words_NotDoneOk: String { return self._s[1926]! } - public var SecretImage_Title: String { return self._s[1927]! } - public var Watch_MessageView_Title: String { return self._s[1928]! } - public var Channel_DiscussionGroupAdd: String { return self._s[1929]! } - public var AttachmentMenu_Poll: String { return self._s[1930]! } + public var DialogList_EncryptionProcessing: String { return self._s[1925]! } + public var Permissions_Skip: String { return self._s[1926]! } + public var Wallet_Words_NotDoneOk: String { return self._s[1927]! } + public var SecretImage_Title: String { return self._s[1928]! } + public var Watch_MessageView_Title: String { return self._s[1929]! } + public var Channel_DiscussionGroupAdd: String { return self._s[1930]! } + public var AttachmentMenu_Poll: String { return self._s[1931]! } public func Notification_GroupInviter(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1931]!, self._r[1931]!, [_0]) + return formatWithArgumentRanges(self._s[1932]!, self._r[1932]!, [_0]) } public func Channel_DiscussionGroup_PrivateChannelLink(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1932]!, self._r[1932]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1933]!, self._r[1933]!, [_1, _2]) } - public var Notification_CallCanceled: String { return self._s[1933]! } - public var WallpaperPreview_Title: String { return self._s[1934]! } - public var Privacy_PaymentsClear_PaymentInfo: String { return self._s[1935]! } - public var Settings_ProxyConnecting: String { return self._s[1936]! } - public var Settings_CheckPhoneNumberText: String { return self._s[1938]! } - public var VoiceOver_Chat_YourVideo: String { return self._s[1939]! } - public var Wallet_Intro_Title: String { return self._s[1940]! } - public var TwoFactorSetup_Password_Action: String { return self._s[1941]! } - public var Profile_MessageLifetime5s: String { return self._s[1942]! } - public var Username_InvalidCharacters: String { return self._s[1943]! } - public var VoiceOver_Media_PlaybackRateFast: String { return self._s[1944]! } - public var ScheduledMessages_ClearAll: String { return self._s[1945]! } - public var WallpaperPreview_CropBottomText: String { return self._s[1946]! } - public var AutoDownloadSettings_LimitBySize: String { return self._s[1947]! } - public var Settings_AddAccount: String { return self._s[1948]! } - public var Notification_CreatedChannel: String { return self._s[1951]! } + public var Notification_CallCanceled: String { return self._s[1934]! } + public var WallpaperPreview_Title: String { return self._s[1935]! } + public var Privacy_PaymentsClear_PaymentInfo: String { return self._s[1936]! } + public var Settings_ProxyConnecting: String { return self._s[1937]! } + public var Settings_CheckPhoneNumberText: String { return self._s[1939]! } + public var VoiceOver_Chat_YourVideo: String { return self._s[1940]! } + public var Wallet_Intro_Title: String { return self._s[1941]! } + public var TwoFactorSetup_Password_Action: String { return self._s[1942]! } + public var Profile_MessageLifetime5s: String { return self._s[1943]! } + public var Username_InvalidCharacters: String { return self._s[1944]! } + public var VoiceOver_Media_PlaybackRateFast: String { return self._s[1945]! } + public var ScheduledMessages_ClearAll: String { return self._s[1946]! } + public var WallpaperPreview_CropBottomText: String { return self._s[1947]! } + public var AutoDownloadSettings_LimitBySize: String { return self._s[1948]! } + public var Settings_AddAccount: String { return self._s[1949]! } + public var Notification_CreatedChannel: String { return self._s[1952]! } public func PUSH_CHAT_DELETE_MEMBER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1952]!, self._r[1952]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1953]!, self._r[1953]!, [_1, _2, _3]) } - public var Passcode_AppLockedAlert: String { return self._s[1954]! } - public var StickerPacksSettings_AnimatedStickersInfo: String { return self._s[1955]! } - public var VoiceOver_Media_PlaybackStop: String { return self._s[1956]! } - public var Contacts_TopSection: String { return self._s[1957]! } - public var ChatList_DeleteForEveryoneConfirmationAction: String { return self._s[1958]! } + public var Passcode_AppLockedAlert: String { return self._s[1955]! } + public var StickerPacksSettings_AnimatedStickersInfo: String { return self._s[1956]! } + public var VoiceOver_Media_PlaybackStop: String { return self._s[1957]! } + public var Contacts_TopSection: String { return self._s[1958]! } + public var ChatList_DeleteForEveryoneConfirmationAction: String { return self._s[1959]! } public func Conversation_SetReminder_RemindOn(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1959]!, self._r[1959]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1960]!, self._r[1960]!, [_0, _1]) } - public var Wallet_Info_Receive: String { return self._s[1960]! } - public var Wallet_Completed_ViewWallet: String { return self._s[1961]! } + public var Wallet_Info_Receive: String { return self._s[1961]! } + public var Wallet_Completed_ViewWallet: String { return self._s[1962]! } public func Time_MonthOfYear_m6(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1962]!, self._r[1962]!, [_0]) + return formatWithArgumentRanges(self._s[1963]!, self._r[1963]!, [_0]) } - public var ReportPeer_ReasonSpam: String { return self._s[1963]! } - public var UserInfo_TapToCall: String { return self._s[1964]! } - public var Conversation_ForwardAuthorHiddenTooltip: String { return self._s[1966]! } - public var AutoDownloadSettings_DataUsageCustom: String { return self._s[1967]! } - public var Common_Search: String { return self._s[1968]! } - public var ScheduledMessages_EmptyPlaceholder: String { return self._s[1969]! } + public var ReportPeer_ReasonSpam: String { return self._s[1964]! } + public var UserInfo_TapToCall: String { return self._s[1965]! } + public var Conversation_ForwardAuthorHiddenTooltip: String { return self._s[1967]! } + public var AutoDownloadSettings_DataUsageCustom: String { return self._s[1968]! } + public var Common_Search: String { return self._s[1969]! } + public var ScheduledMessages_EmptyPlaceholder: String { return self._s[1970]! } public func Channel_AdminLog_MessageChangedGroupGeoLocation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1970]!, self._r[1970]!, [_0]) + return formatWithArgumentRanges(self._s[1971]!, self._r[1971]!, [_0]) } - public var Wallet_Month_ShortJuly: String { return self._s[1971]! } - public var AuthSessions_IncompleteAttemptsInfo: String { return self._s[1973]! } - public var Message_InvoiceLabel: String { return self._s[1974]! } - public var Conversation_InputTextPlaceholder: String { return self._s[1975]! } - public var NetworkUsageSettings_MediaImageDataSection: String { return self._s[1976]! } + public var Wallet_Month_ShortJuly: String { return self._s[1972]! } + public var AuthSessions_IncompleteAttemptsInfo: String { return self._s[1974]! } + public var Message_InvoiceLabel: String { return self._s[1975]! } + public var Conversation_InputTextPlaceholder: String { return self._s[1976]! } + public var NetworkUsageSettings_MediaImageDataSection: String { return self._s[1977]! } public func Passport_Address_UploadOneOfScan(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1977]!, self._r[1977]!, [_0]) + return formatWithArgumentRanges(self._s[1978]!, self._r[1978]!, [_0]) } - public var IntentsSettings_Reset: String { return self._s[1978]! } - public var Conversation_Info: String { return self._s[1979]! } - public var Login_InfoDeletePhoto: String { return self._s[1980]! } - public var Passport_Language_vi: String { return self._s[1982]! } - public var UserInfo_ScamUserWarning: String { return self._s[1983]! } - public var Conversation_Search: String { return self._s[1984]! } - public var DialogList_DeleteBotConversationConfirmation: String { return self._s[1986]! } - public var ReportPeer_ReasonPornography: String { return self._s[1987]! } - public var AutoDownloadSettings_PhotosTitle: String { return self._s[1988]! } - public var Conversation_SendMessageErrorGroupRestricted: String { return self._s[1989]! } - public var Map_LiveLocationGroupDescription: String { return self._s[1990]! } - public var Channel_Setup_TypeHeader: String { return self._s[1991]! } - public var AuthSessions_LoggedIn: String { return self._s[1992]! } - public var Privacy_Forwards_AlwaysAllow_Title: String { return self._s[1993]! } - public var Login_SmsRequestState3: String { return self._s[1994]! } - public var Passport_Address_EditUtilityBill: String { return self._s[1995]! } - public var Appearance_ReduceMotionInfo: String { return self._s[1996]! } - public var Join_ChannelsTooMuch: String { return self._s[1997]! } - public var Channel_Edit_LinkItem: String { return self._s[1998]! } - public var Privacy_Calls_P2PNever: String { return self._s[1999]! } - public var Conversation_AddToReadingList: String { return self._s[2001]! } - public var Share_MultipleMessagesDisabled: String { return self._s[2002]! } - public var Message_Animation: String { return self._s[2003]! } - public var Conversation_DefaultRestrictedMedia: String { return self._s[2004]! } - public var Map_Unknown: String { return self._s[2005]! } - public var AutoDownloadSettings_LastDelimeter: String { return self._s[2006]! } + public var IntentsSettings_Reset: String { return self._s[1979]! } + public var Conversation_Info: String { return self._s[1980]! } + public var Login_InfoDeletePhoto: String { return self._s[1981]! } + public var Passport_Language_vi: String { return self._s[1983]! } + public var UserInfo_ScamUserWarning: String { return self._s[1984]! } + public var Conversation_Search: String { return self._s[1985]! } + public var DialogList_DeleteBotConversationConfirmation: String { return self._s[1987]! } + public var ReportPeer_ReasonPornography: String { return self._s[1988]! } + public var AutoDownloadSettings_PhotosTitle: String { return self._s[1989]! } + public var Conversation_SendMessageErrorGroupRestricted: String { return self._s[1990]! } + public var Map_LiveLocationGroupDescription: String { return self._s[1991]! } + public var Channel_Setup_TypeHeader: String { return self._s[1992]! } + public var AuthSessions_LoggedIn: String { return self._s[1993]! } + public var Privacy_Forwards_AlwaysAllow_Title: String { return self._s[1994]! } + public var Login_SmsRequestState3: String { return self._s[1995]! } + public var Passport_Address_EditUtilityBill: String { return self._s[1996]! } + public var Appearance_ReduceMotionInfo: String { return self._s[1997]! } + public var Join_ChannelsTooMuch: String { return self._s[1998]! } + public var Channel_Edit_LinkItem: String { return self._s[1999]! } + public var Privacy_Calls_P2PNever: String { return self._s[2000]! } + public var Conversation_AddToReadingList: String { return self._s[2002]! } + public var Share_MultipleMessagesDisabled: String { return self._s[2003]! } + public var Message_Animation: String { return self._s[2004]! } + public var Conversation_DefaultRestrictedMedia: String { return self._s[2005]! } + public var Map_Unknown: String { return self._s[2006]! } + public var AutoDownloadSettings_LastDelimeter: String { return self._s[2007]! } public func PUSH_PINNED_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2007]!, self._r[2007]!, [_1, _2]) - } - public func Passport_FieldOneOf_Or(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2008]!, self._r[2008]!, [_1, _2]) } - public var Call_StatusRequesting: String { return self._s[2009]! } - public var Conversation_SecretChatContextBotAlert: String { return self._s[2010]! } - public var SocksProxySetup_ProxyStatusChecking: String { return self._s[2011]! } + public func Passport_FieldOneOf_Or(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2009]!, self._r[2009]!, [_1, _2]) + } + public var Call_StatusRequesting: String { return self._s[2010]! } + public var Conversation_SecretChatContextBotAlert: String { return self._s[2011]! } + public var SocksProxySetup_ProxyStatusChecking: String { return self._s[2012]! } public func PUSH_CHAT_MESSAGE_DOC(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2012]!, self._r[2012]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2013]!, self._r[2013]!, [_1, _2]) } public func Notification_PinnedLocationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2013]!, self._r[2013]!, [_0]) + return formatWithArgumentRanges(self._s[2014]!, self._r[2014]!, [_0]) } - public var Update_Skip: String { return self._s[2014]! } - public var Group_Username_RemoveExistingUsernamesInfo: String { return self._s[2015]! } - public var Message_PinnedPollMessage: String { return self._s[2016]! } - public var BlockedUsers_Title: String { return self._s[2017]! } + public var Update_Skip: String { return self._s[2015]! } + public var Group_Username_RemoveExistingUsernamesInfo: String { return self._s[2016]! } + public var Message_PinnedPollMessage: String { return self._s[2017]! } + public var BlockedUsers_Title: String { return self._s[2018]! } public func PUSH_CHANNEL_MESSAGE_AUDIO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2018]!, self._r[2018]!, [_1]) + return formatWithArgumentRanges(self._s[2019]!, self._r[2019]!, [_1]) } - public var Username_CheckingUsername: String { return self._s[2019]! } - public var NotificationsSound_Bell: String { return self._s[2020]! } - public var Conversation_SendMessageErrorFlood: String { return self._s[2021]! } - public var Weekday_Monday: String { return self._s[2022]! } - public var SettingsSearch_Synonyms_Notifications_DisplayNamesOnLockScreen: String { return self._s[2023]! } - public var ChannelMembers_ChannelAdminsTitle: String { return self._s[2024]! } - public var ChatSettings_Groups: String { return self._s[2025]! } - public var WallpaperPreview_PatternPaternDiscard: String { return self._s[2026]! } + public var Username_CheckingUsername: String { return self._s[2020]! } + public var NotificationsSound_Bell: String { return self._s[2021]! } + public var Conversation_SendMessageErrorFlood: String { return self._s[2022]! } + public var Weekday_Monday: String { return self._s[2023]! } + public var SettingsSearch_Synonyms_Notifications_DisplayNamesOnLockScreen: String { return self._s[2024]! } + public var ChannelMembers_ChannelAdminsTitle: String { return self._s[2025]! } + public var ChatSettings_Groups: String { return self._s[2026]! } + public var WallpaperPreview_PatternPaternDiscard: String { return self._s[2027]! } public func Conversation_SetReminder_RemindTomorrow(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2027]!, self._r[2027]!, [_0]) + return formatWithArgumentRanges(self._s[2028]!, self._r[2028]!, [_0]) } - public var Your_card_was_declined: String { return self._s[2028]! } - public var TwoStepAuth_EnterPasswordHelp: String { return self._s[2030]! } - public var Wallet_Month_ShortApril: String { return self._s[2031]! } - public var ChatList_Unmute: String { return self._s[2032]! } - public var AuthSessions_AddDevice_ScanTitle: String { return self._s[2033]! } - public var PhotoEditor_CurvesAll: String { return self._s[2034]! } - public var Weekday_ShortTuesday: String { return self._s[2035]! } - public var DialogList_Read: String { return self._s[2036]! } - public var Appearance_AppIconClassic: String { return self._s[2037]! } - public var ChannelMembers_WhoCanAddMembers_AllMembers: String { return self._s[2038]! } - public var Passport_Identity_Gender: String { return self._s[2039]! } + public var Your_card_was_declined: String { return self._s[2029]! } + public var TwoStepAuth_EnterPasswordHelp: String { return self._s[2031]! } + public var Wallet_Month_ShortApril: String { return self._s[2032]! } + public var ChatList_Unmute: String { return self._s[2033]! } + public var AuthSessions_AddDevice_ScanTitle: String { return self._s[2034]! } + public var PhotoEditor_CurvesAll: String { return self._s[2035]! } + public var Weekday_ShortTuesday: String { return self._s[2036]! } + public var DialogList_Read: String { return self._s[2037]! } + public var Appearance_AppIconClassic: String { return self._s[2038]! } + public var ChannelMembers_WhoCanAddMembers_AllMembers: String { return self._s[2039]! } + public var Passport_Identity_Gender: String { return self._s[2040]! } public func Target_ShareGameConfirmationPrivate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2040]!, self._r[2040]!, [_0]) + return formatWithArgumentRanges(self._s[2041]!, self._r[2041]!, [_0]) } - public var Target_SelectGroup: String { return self._s[2041]! } - public var Map_HomeAndWorkInfo: String { return self._s[2043]! } + public var Target_SelectGroup: String { return self._s[2042]! } + public var Map_HomeAndWorkInfo: String { return self._s[2044]! } public func DialogList_EncryptedChatStartedIncoming(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2044]!, self._r[2044]!, [_0]) + return formatWithArgumentRanges(self._s[2045]!, self._r[2045]!, [_0]) } - public var Passport_Language_en: String { return self._s[2045]! } - public var AutoDownloadSettings_AutodownloadPhotos: String { return self._s[2046]! } - public var Channel_Username_CreatePublicLinkHelp: String { return self._s[2047]! } - public var Login_CancelPhoneVerificationContinue: String { return self._s[2048]! } - public var ScheduledMessages_SendNow: String { return self._s[2049]! } - public var Checkout_NewCard_PaymentCard: String { return self._s[2051]! } - public var Login_InfoHelp: String { return self._s[2052]! } - public var Contacts_PermissionsSuppressWarningTitle: String { return self._s[2053]! } - public var SettingsSearch_Synonyms_Stickers_FeaturedPacks: String { return self._s[2054]! } + public var Passport_Language_en: String { return self._s[2046]! } + public var AutoDownloadSettings_AutodownloadPhotos: String { return self._s[2047]! } + public var Channel_Username_CreatePublicLinkHelp: String { return self._s[2048]! } + public var Login_CancelPhoneVerificationContinue: String { return self._s[2049]! } + public var ScheduledMessages_SendNow: String { return self._s[2050]! } + public var Checkout_NewCard_PaymentCard: String { return self._s[2052]! } + public var Login_InfoHelp: String { return self._s[2053]! } + public var Contacts_PermissionsSuppressWarningTitle: String { return self._s[2054]! } + public var SettingsSearch_Synonyms_Stickers_FeaturedPacks: String { return self._s[2055]! } public func Channel_AdminLog_MessageChangedLinkedChannel(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2055]!, self._r[2055]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2056]!, self._r[2056]!, [_1, _2]) } - public var SocksProxySetup_AddProxy: String { return self._s[2058]! } - public var CreatePoll_Title: String { return self._s[2059]! } - public var MessagePoll_QuizNoUsers: String { return self._s[2060]! } - public var Conversation_ViewTheme: String { return self._s[2061]! } - public var SettingsSearch_Synonyms_Privacy_Data_SecretChatLinkPreview: String { return self._s[2062]! } - public var PasscodeSettings_SimplePasscodeHelp: String { return self._s[2063]! } - public var TwoFactorSetup_Intro_Text: String { return self._s[2064]! } - public var UserInfo_GroupsInCommon: String { return self._s[2065]! } - public var TelegramWallet_Intro_TermsUrl: String { return self._s[2066]! } - public var Call_AudioRouteHide: String { return self._s[2067]! } + public var SocksProxySetup_AddProxy: String { return self._s[2059]! } + public var CreatePoll_Title: String { return self._s[2060]! } + public var MessagePoll_QuizNoUsers: String { return self._s[2061]! } + public var Conversation_ViewTheme: String { return self._s[2062]! } + public var SettingsSearch_Synonyms_Privacy_Data_SecretChatLinkPreview: String { return self._s[2063]! } + public var PasscodeSettings_SimplePasscodeHelp: String { return self._s[2064]! } + public var TwoFactorSetup_Intro_Text: String { return self._s[2065]! } + public var UserInfo_GroupsInCommon: String { return self._s[2066]! } + public var TelegramWallet_Intro_TermsUrl: String { return self._s[2067]! } + public var Call_AudioRouteHide: String { return self._s[2068]! } public func Wallet_Info_TransactionDateHeader(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2069]!, self._r[2069]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2070]!, self._r[2070]!, [_1, _2]) } - public var ContactInfo_PhoneLabelMobile: String { return self._s[2070]! } - public var IntentsSettings_SuggestedChatsInfo: String { return self._s[2071]! } - public var CreatePoll_QuizOptionsHeader: String { return self._s[2072]! } + public var ContactInfo_PhoneLabelMobile: String { return self._s[2071]! } + public var IntentsSettings_SuggestedChatsInfo: String { return self._s[2072]! } + public var CreatePoll_QuizOptionsHeader: String { return self._s[2073]! } public func ChatList_LeaveGroupConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2073]!, self._r[2073]!, [_0]) + return formatWithArgumentRanges(self._s[2074]!, self._r[2074]!, [_0]) } - public var TextFormat_Bold: String { return self._s[2074]! } - public var FastTwoStepSetup_EmailSection: String { return self._s[2075]! } - public var StickerPackActionInfo_AddedTitle: String { return self._s[2076]! } - public var Notifications_Title: String { return self._s[2077]! } - public var Group_Username_InvalidTooShort: String { return self._s[2078]! } - public var Channel_ErrorAddTooMuch: String { return self._s[2079]! } + public var TextFormat_Bold: String { return self._s[2075]! } + public var FastTwoStepSetup_EmailSection: String { return self._s[2076]! } + public var StickerPackActionInfo_AddedTitle: String { return self._s[2077]! } + public var Notifications_Title: String { return self._s[2078]! } + public var Group_Username_InvalidTooShort: String { return self._s[2079]! } + public var Channel_ErrorAddTooMuch: String { return self._s[2080]! } public func DialogList_MultipleTypingSuffix(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2080]!, self._r[2080]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[2081]!, self._r[2081]!, ["\(_0)"]) } - public var VoiceOver_DiscardPreparedContent: String { return self._s[2082]! } - public var Stickers_SuggestAdded: String { return self._s[2083]! } - public var Login_CountryCode: String { return self._s[2084]! } - public var ChatSettings_AutoPlayVideos: String { return self._s[2085]! } - public var Map_GetDirections: String { return self._s[2086]! } - public var Wallet_Receive_ShareInvoiceUrl: String { return self._s[2087]! } - public var Login_PhoneFloodError: String { return self._s[2088]! } + public var VoiceOver_DiscardPreparedContent: String { return self._s[2083]! } + public var Stickers_SuggestAdded: String { return self._s[2084]! } + public var Login_CountryCode: String { return self._s[2085]! } + public var ChatSettings_AutoPlayVideos: String { return self._s[2086]! } + public var Map_GetDirections: String { return self._s[2087]! } + public var Wallet_Receive_ShareInvoiceUrl: String { return self._s[2088]! } + public var Login_PhoneFloodError: String { return self._s[2089]! } public func Time_MonthOfYear_m3(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2089]!, self._r[2089]!, [_0]) + return formatWithArgumentRanges(self._s[2090]!, self._r[2090]!, [_0]) } public func Wallet_Time_PreciseDate_m10(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2090]!, self._r[2090]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2091]!, self._r[2091]!, [_1, _2, _3]) } - public var IntentsSettings_SuggestedChatsPrivateChats: String { return self._s[2091]! } - public var Settings_SetUsername: String { return self._s[2093]! } - public var Group_Location_ChangeLocation: String { return self._s[2094]! } - public var Notification_GroupInviterSelf: String { return self._s[2095]! } - public var InstantPage_TapToOpenLink: String { return self._s[2096]! } + public var IntentsSettings_SuggestedChatsPrivateChats: String { return self._s[2092]! } + public var Settings_SetUsername: String { return self._s[2094]! } + public var Group_Location_ChangeLocation: String { return self._s[2095]! } + public var Notification_GroupInviterSelf: String { return self._s[2096]! } + public var InstantPage_TapToOpenLink: String { return self._s[2097]! } public func Notification_ChannelInviter(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2097]!, self._r[2097]!, [_0]) + return formatWithArgumentRanges(self._s[2098]!, self._r[2098]!, [_0]) } - public var Watch_Suggestion_TalkLater: String { return self._s[2098]! } - public var SecretChat_Title: String { return self._s[2099]! } - public var Group_UpgradeNoticeText1: String { return self._s[2100]! } - public var AuthSessions_Title: String { return self._s[2101]! } + public var Watch_Suggestion_TalkLater: String { return self._s[2099]! } + public var SecretChat_Title: String { return self._s[2100]! } + public var Group_UpgradeNoticeText1: String { return self._s[2101]! } + public var AuthSessions_Title: String { return self._s[2102]! } public func TextFormat_AddLinkText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2102]!, self._r[2102]!, [_0]) + return formatWithArgumentRanges(self._s[2103]!, self._r[2103]!, [_0]) } - public var PhotoEditor_CropAuto: String { return self._s[2103]! } - public var Channel_About_Title: String { return self._s[2104]! } - public var Theme_ThemeChanged: String { return self._s[2105]! } - public var FastTwoStepSetup_EmailHelp: String { return self._s[2106]! } + public var PhotoEditor_CropAuto: String { return self._s[2104]! } + public var Channel_About_Title: String { return self._s[2105]! } + public var Theme_ThemeChanged: String { return self._s[2106]! } + public var FastTwoStepSetup_EmailHelp: String { return self._s[2107]! } public func Conversation_Bytes(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2108]!, self._r[2108]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[2109]!, self._r[2109]!, ["\(_0)"]) } - public var VoiceOver_MessageContextReport: String { return self._s[2109]! } - public var Conversation_PinMessageAlert_OnlyPin: String { return self._s[2111]! } - public var Group_Setup_HistoryVisibleHelp: String { return self._s[2112]! } + public var VoiceOver_MessageContextReport: String { return self._s[2110]! } + public var Conversation_PinMessageAlert_OnlyPin: String { return self._s[2112]! } + public var Group_Setup_HistoryVisibleHelp: String { return self._s[2113]! } public func PUSH_MESSAGE_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2113]!, self._r[2113]!, [_1]) + return formatWithArgumentRanges(self._s[2114]!, self._r[2114]!, [_1]) } public func SharedMedia_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2115]!, self._r[2115]!, [_0]) - } - public func TwoStepAuth_RecoveryEmailUnavailable(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2116]!, self._r[2116]!, [_0]) } - public var Privacy_PaymentsClearInfoHelp: String { return self._s[2117]! } - public var Presence_online: String { return self._s[2120]! } - public var PasscodeSettings_Title: String { return self._s[2121]! } - public var Passport_Identity_ExpiryDatePlaceholder: String { return self._s[2122]! } - public var Web_OpenExternal: String { return self._s[2123]! } - public var AutoDownloadSettings_AutoDownload: String { return self._s[2125]! } - public var Channel_OwnershipTransfer_EnterPasswordText: String { return self._s[2126]! } - public var LocalGroup_Title: String { return self._s[2127]! } + public func TwoStepAuth_RecoveryEmailUnavailable(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2117]!, self._r[2117]!, [_0]) + } + public var Privacy_PaymentsClearInfoHelp: String { return self._s[2118]! } + public var Presence_online: String { return self._s[2121]! } + public var PasscodeSettings_Title: String { return self._s[2122]! } + public var Passport_Identity_ExpiryDatePlaceholder: String { return self._s[2123]! } + public var Web_OpenExternal: String { return self._s[2124]! } + public var AutoDownloadSettings_AutoDownload: String { return self._s[2126]! } + public var Channel_OwnershipTransfer_EnterPasswordText: String { return self._s[2127]! } + public var LocalGroup_Title: String { return self._s[2128]! } public func AutoNightTheme_AutomaticHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2128]!, self._r[2128]!, [_0]) + return formatWithArgumentRanges(self._s[2129]!, self._r[2129]!, [_0]) } - public var FastTwoStepSetup_PasswordConfirmationPlaceholder: String { return self._s[2129]! } - public var Conversation_StopQuizConfirmation: String { return self._s[2130]! } - public var Map_YouAreHere: String { return self._s[2131]! } + public var FastTwoStepSetup_PasswordConfirmationPlaceholder: String { return self._s[2130]! } + public var Conversation_StopQuizConfirmation: String { return self._s[2131]! } + public var Map_YouAreHere: String { return self._s[2132]! } public func AuthSessions_Message(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2132]!, self._r[2132]!, [_0]) - } - public func ChatList_DeleteChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2133]!, self._r[2133]!, [_0]) } - public var Theme_Context_ChangeColors: String { return self._s[2134]! } - public var PrivacyLastSeenSettings_AlwaysShareWith: String { return self._s[2135]! } - public var Target_InviteToGroupErrorAlreadyInvited: String { return self._s[2136]! } - public func AuthSessions_AppUnofficial(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2137]!, self._r[2137]!, [_0]) + public func ChatList_DeleteChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2134]!, self._r[2134]!, [_0]) } - public func DialogList_LiveLocationSharingTo(_ _0: String) -> (String, [(Int, NSRange)]) { + public var Theme_Context_ChangeColors: String { return self._s[2135]! } + public var PrivacyLastSeenSettings_AlwaysShareWith: String { return self._s[2136]! } + public var Target_InviteToGroupErrorAlreadyInvited: String { return self._s[2137]! } + public func AuthSessions_AppUnofficial(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2138]!, self._r[2138]!, [_0]) } - public var SocksProxySetup_Username: String { return self._s[2139]! } - public var Bot_Start: String { return self._s[2140]! } - public func Channel_AdminLog_EmptyFilterQueryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2141]!, self._r[2141]!, [_0]) + public func DialogList_LiveLocationSharingTo(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2139]!, self._r[2139]!, [_0]) } - public func Channel_AdminLog_MessagePinned(_ _0: String) -> (String, [(Int, NSRange)]) { + public var SocksProxySetup_Username: String { return self._s[2140]! } + public var Bot_Start: String { return self._s[2141]! } + public func Channel_AdminLog_EmptyFilterQueryText(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2142]!, self._r[2142]!, [_0]) } - public var Contacts_SortByPresence: String { return self._s[2143]! } - public var AccentColor_Title: String { return self._s[2145]! } - public var Conversation_DiscardVoiceMessageTitle: String { return self._s[2146]! } + public func Channel_AdminLog_MessagePinned(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2143]!, self._r[2143]!, [_0]) + } + public var Contacts_SortByPresence: String { return self._s[2144]! } + public var AccentColor_Title: String { return self._s[2146]! } + public var Conversation_DiscardVoiceMessageTitle: String { return self._s[2147]! } public func PUSH_CHAT_CREATED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2147]!, self._r[2147]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2148]!, self._r[2148]!, [_1, _2]) } public func PrivacySettings_LastSeenContactsMinus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2148]!, self._r[2148]!, [_0]) + return formatWithArgumentRanges(self._s[2149]!, self._r[2149]!, [_0]) } public func Channel_AdminLog_MessageChangedLinkedGroup(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2149]!, self._r[2149]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2150]!, self._r[2150]!, [_1, _2]) } - public var Passport_Email_EnterOtherEmail: String { return self._s[2150]! } - public var Login_InfoAvatarPhoto: String { return self._s[2151]! } - public var Privacy_PaymentsClear_ShippingInfo: String { return self._s[2152]! } - public var Tour_Title4: String { return self._s[2153]! } - public var Passport_Identity_Translation: String { return self._s[2154]! } - public var SettingsSearch_Synonyms_Notifications_ContactJoined: String { return self._s[2155]! } - public var Login_TermsOfServiceLabel: String { return self._s[2157]! } - public var Passport_Language_it: String { return self._s[2158]! } - public var KeyCommand_JumpToNextUnreadChat: String { return self._s[2159]! } - public var Passport_Identity_SelfieHelp: String { return self._s[2160]! } - public var Conversation_ClearAll: String { return self._s[2162]! } - public var Wallet_Send_UninitializedText: String { return self._s[2164]! } - public var Channel_OwnershipTransfer_Title: String { return self._s[2165]! } - public var TwoStepAuth_FloodError: String { return self._s[2166]! } + public var Passport_Email_EnterOtherEmail: String { return self._s[2151]! } + public var Login_InfoAvatarPhoto: String { return self._s[2152]! } + public var Privacy_PaymentsClear_ShippingInfo: String { return self._s[2153]! } + public var Tour_Title4: String { return self._s[2154]! } + public var Passport_Identity_Translation: String { return self._s[2155]! } + public var SettingsSearch_Synonyms_Notifications_ContactJoined: String { return self._s[2156]! } + public var Login_TermsOfServiceLabel: String { return self._s[2158]! } + public var Passport_Language_it: String { return self._s[2159]! } + public var KeyCommand_JumpToNextUnreadChat: String { return self._s[2160]! } + public var Passport_Identity_SelfieHelp: String { return self._s[2161]! } + public var Conversation_ClearAll: String { return self._s[2163]! } + public var Wallet_Send_UninitializedText: String { return self._s[2165]! } + public var Channel_OwnershipTransfer_Title: String { return self._s[2166]! } + public var TwoStepAuth_FloodError: String { return self._s[2167]! } public func PUSH_CHANNEL_MESSAGE_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2167]!, self._r[2167]!, [_1]) + return formatWithArgumentRanges(self._s[2168]!, self._r[2168]!, [_1]) } - public var Paint_Delete: String { return self._s[2168]! } + public var Paint_Delete: String { return self._s[2169]! } public func Wallet_Sent_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2169]!, self._r[2169]!, [_0]) + return formatWithArgumentRanges(self._s[2170]!, self._r[2170]!, [_0]) } - public var Privacy_AddNewPeer: String { return self._s[2170]! } + public var Privacy_AddNewPeer: String { return self._s[2171]! } public func Channel_AdminLog_MessageRank(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2171]!, self._r[2171]!, [_1]) + return formatWithArgumentRanges(self._s[2172]!, self._r[2172]!, [_1]) } - public var LogoutOptions_SetPasscodeText: String { return self._s[2172]! } + public var LogoutOptions_SetPasscodeText: String { return self._s[2173]! } public func Passport_AcceptHelp(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2173]!, self._r[2173]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2174]!, self._r[2174]!, [_1, _2]) } - public var Message_PinnedAudioMessage: String { return self._s[2174]! } + public var Message_PinnedAudioMessage: String { return self._s[2175]! } public func Watch_Time_ShortTodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2175]!, self._r[2175]!, [_0]) + return formatWithArgumentRanges(self._s[2176]!, self._r[2176]!, [_0]) } - public var Notification_Mute1hMin: String { return self._s[2176]! } - public var Notifications_GroupNotificationsSound: String { return self._s[2177]! } - public var Wallet_Month_GenNovember: String { return self._s[2178]! } - public var SocksProxySetup_ShareProxyList: String { return self._s[2179]! } - public var Conversation_MessageEditedLabel: String { return self._s[2180]! } + public var Notification_Mute1hMin: String { return self._s[2177]! } + public var Notifications_GroupNotificationsSound: String { return self._s[2178]! } + public var Wallet_Month_GenNovember: String { return self._s[2179]! } + public var SocksProxySetup_ShareProxyList: String { return self._s[2180]! } + public var Conversation_MessageEditedLabel: String { return self._s[2181]! } public func ClearCache_Success(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2181]!, self._r[2181]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2182]!, self._r[2182]!, [_0, _1]) } - public var Notification_Exceptions_AlwaysOff: String { return self._s[2182]! } - public var Notification_Exceptions_NewException_MessagePreviewHeader: String { return self._s[2183]! } + public var Notification_Exceptions_AlwaysOff: String { return self._s[2183]! } + public var Notification_Exceptions_NewException_MessagePreviewHeader: String { return self._s[2184]! } public func Channel_AdminLog_MessageAdmin(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2184]!, self._r[2184]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[2185]!, self._r[2185]!, [_0, _1, _2]) } - public var NetworkUsageSettings_ResetStats: String { return self._s[2185]! } + public var NetworkUsageSettings_ResetStats: String { return self._s[2186]! } public func PUSH_MESSAGE_GEOLIVE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2186]!, self._r[2186]!, [_1]) + return formatWithArgumentRanges(self._s[2187]!, self._r[2187]!, [_1]) } - public var AccessDenied_LocationTracking: String { return self._s[2187]! } - public var Month_GenOctober: String { return self._s[2188]! } - public var GroupInfo_InviteLink_RevokeAlert_Revoke: String { return self._s[2189]! } - public var EnterPasscode_EnterPasscode: String { return self._s[2190]! } - public var MediaPicker_TimerTooltip: String { return self._s[2192]! } - public var SharedMedia_TitleAll: String { return self._s[2193]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsExceptions: String { return self._s[2196]! } - public var Conversation_RestrictedMedia: String { return self._s[2197]! } - public var AccessDenied_PhotosRestricted: String { return self._s[2198]! } - public var Privacy_Forwards_WhoCanForward: String { return self._s[2200]! } - public var ChangePhoneNumberCode_Called: String { return self._s[2201]! } + public var AccessDenied_LocationTracking: String { return self._s[2188]! } + public var Month_GenOctober: String { return self._s[2189]! } + public var GroupInfo_InviteLink_RevokeAlert_Revoke: String { return self._s[2190]! } + public var EnterPasscode_EnterPasscode: String { return self._s[2191]! } + public var MediaPicker_TimerTooltip: String { return self._s[2193]! } + public var SharedMedia_TitleAll: String { return self._s[2194]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsExceptions: String { return self._s[2197]! } + public var Conversation_RestrictedMedia: String { return self._s[2198]! } + public var AccessDenied_PhotosRestricted: String { return self._s[2199]! } + public var Privacy_Forwards_WhoCanForward: String { return self._s[2201]! } + public var ChangePhoneNumberCode_Called: String { return self._s[2202]! } public func Notification_PinnedDocumentMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2202]!, self._r[2202]!, [_0]) + return formatWithArgumentRanges(self._s[2203]!, self._r[2203]!, [_0]) } - public var Conversation_SavedMessages: String { return self._s[2205]! } - public var Your_cards_expiration_month_is_invalid: String { return self._s[2207]! } - public var FastTwoStepSetup_PasswordPlaceholder: String { return self._s[2208]! } + public var Conversation_SavedMessages: String { return self._s[2206]! } + public var Your_cards_expiration_month_is_invalid: String { return self._s[2208]! } + public var FastTwoStepSetup_PasswordPlaceholder: String { return self._s[2209]! } public func Target_ShareGameConfirmationGroup(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2210]!, self._r[2210]!, [_0]) + return formatWithArgumentRanges(self._s[2211]!, self._r[2211]!, [_0]) } - public var VoiceOver_Chat_YourMessage: String { return self._s[2211]! } + public var VoiceOver_Chat_YourMessage: String { return self._s[2212]! } public func VoiceOver_Chat_Title(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2212]!, self._r[2212]!, [_0]) + return formatWithArgumentRanges(self._s[2213]!, self._r[2213]!, [_0]) } - public var ReportPeer_AlertSuccess: String { return self._s[2213]! } - public var PhotoEditor_CropAspectRatioOriginal: String { return self._s[2214]! } + public var ReportPeer_AlertSuccess: String { return self._s[2214]! } + public var PhotoEditor_CropAspectRatioOriginal: String { return self._s[2215]! } public func InstantPage_RelatedArticleAuthorAndDateTitle(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2215]!, self._r[2215]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2216]!, self._r[2216]!, [_1, _2]) } - public var Checkout_PasswordEntry_Title: String { return self._s[2216]! } - public var PhotoEditor_FadeTool: String { return self._s[2217]! } - public var Privacy_ContactsReset: String { return self._s[2218]! } + public var Checkout_PasswordEntry_Title: String { return self._s[2217]! } + public var PhotoEditor_FadeTool: String { return self._s[2218]! } + public var Privacy_ContactsReset: String { return self._s[2219]! } public func Channel_AdminLog_MessageRestrictedUntil(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2220]!, self._r[2220]!, [_0]) + return formatWithArgumentRanges(self._s[2221]!, self._r[2221]!, [_0]) } - public var Message_PinnedVideoMessage: String { return self._s[2221]! } - public var ChatList_Mute: String { return self._s[2222]! } + public var Message_PinnedVideoMessage: String { return self._s[2222]! } + public var ChatList_Mute: String { return self._s[2223]! } public func Wallet_Time_PreciseDate_m5(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2223]!, self._r[2223]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2224]!, self._r[2224]!, [_1, _2, _3]) } - public var Permissions_CellularDataText_v0: String { return self._s[2224]! } - public var ShareMenu_SelectChats: String { return self._s[2227]! } - public var ChatList_Context_Unarchive: String { return self._s[2228]! } - public var MusicPlayer_VoiceNote: String { return self._s[2229]! } - public var Conversation_RestrictedText: String { return self._s[2230]! } - public var SettingsSearch_Synonyms_Privacy_Data_DeleteDrafts: String { return self._s[2231]! } - public var Wallet_Month_GenApril: String { return self._s[2232]! } - public var Wallet_Month_ShortMarch: String { return self._s[2233]! } - public var TwoStepAuth_DisableSuccess: String { return self._s[2234]! } - public var Cache_Videos: String { return self._s[2235]! } - public var PrivacySettings_PhoneNumber: String { return self._s[2236]! } - public var Wallet_Month_GenFebruary: String { return self._s[2237]! } - public var FeatureDisabled_Oops: String { return self._s[2239]! } - public var Passport_Address_PostcodePlaceholder: String { return self._s[2240]! } + public var Permissions_CellularDataText_v0: String { return self._s[2225]! } + public var ShareMenu_SelectChats: String { return self._s[2228]! } + public var ChatList_Context_Unarchive: String { return self._s[2229]! } + public var MusicPlayer_VoiceNote: String { return self._s[2230]! } + public var Conversation_RestrictedText: String { return self._s[2231]! } + public var SettingsSearch_Synonyms_Privacy_Data_DeleteDrafts: String { return self._s[2232]! } + public var Wallet_Month_GenApril: String { return self._s[2233]! } + public var Wallet_Month_ShortMarch: String { return self._s[2234]! } + public var TwoStepAuth_DisableSuccess: String { return self._s[2235]! } + public var Cache_Videos: String { return self._s[2236]! } + public var PrivacySettings_PhoneNumber: String { return self._s[2237]! } + public var Wallet_Month_GenFebruary: String { return self._s[2238]! } + public var FeatureDisabled_Oops: String { return self._s[2240]! } + public var Passport_Address_PostcodePlaceholder: String { return self._s[2241]! } public func AddContact_StatusSuccess(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2241]!, self._r[2241]!, [_0]) + return formatWithArgumentRanges(self._s[2242]!, self._r[2242]!, [_0]) } - public var Stickers_GroupStickersHelp: String { return self._s[2242]! } - public var GroupPermission_NoSendPolls: String { return self._s[2243]! } - public var Wallet_Qr_ScanCode: String { return self._s[2244]! } - public var Message_VideoExpired: String { return self._s[2246]! } - public var GroupInfo_GroupHistoryVisible: String { return self._s[2247]! } - public var Notifications_Badge: String { return self._s[2248]! } - public var Wallet_Receive_AddressCopied: String { return self._s[2249]! } - public var CreatePoll_OptionPlaceholder: String { return self._s[2250]! } - public var Username_InvalidTooShort: String { return self._s[2251]! } - public var EnterPasscode_EnterNewPasscodeChange: String { return self._s[2252]! } - public var Channel_AdminLog_PinMessages: String { return self._s[2253]! } - public var ArchivedChats_IntroTitle3: String { return self._s[2254]! } + public var Stickers_GroupStickersHelp: String { return self._s[2243]! } + public var GroupPermission_NoSendPolls: String { return self._s[2244]! } + public var Wallet_Qr_ScanCode: String { return self._s[2245]! } + public var Message_VideoExpired: String { return self._s[2247]! } + public var GroupInfo_GroupHistoryVisible: String { return self._s[2248]! } + public var Notifications_Badge: String { return self._s[2249]! } + public var Wallet_Receive_AddressCopied: String { return self._s[2250]! } + public var CreatePoll_OptionPlaceholder: String { return self._s[2251]! } + public var Username_InvalidTooShort: String { return self._s[2252]! } + public var EnterPasscode_EnterNewPasscodeChange: String { return self._s[2253]! } + public var Channel_AdminLog_PinMessages: String { return self._s[2254]! } + public var ArchivedChats_IntroTitle3: String { return self._s[2255]! } public func Notification_MessageLifetimeRemoved(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2255]!, self._r[2255]!, [_1]) + return formatWithArgumentRanges(self._s[2256]!, self._r[2256]!, [_1]) } - public var Permissions_SiriAllowInSettings_v0: String { return self._s[2256]! } - public var Conversation_DefaultRestrictedText: String { return self._s[2257]! } - public var SharedMedia_CategoryDocs: String { return self._s[2260]! } + public var Permissions_SiriAllowInSettings_v0: String { return self._s[2257]! } + public var Conversation_DefaultRestrictedText: String { return self._s[2258]! } + public var SharedMedia_CategoryDocs: String { return self._s[2261]! } public func PUSH_MESSAGE_CONTACT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2261]!, self._r[2261]!, [_1]) + return formatWithArgumentRanges(self._s[2262]!, self._r[2262]!, [_1]) } - public var Wallet_Send_UninitializedTitle: String { return self._s[2262]! } - public var StickerPackActionInfo_ArchivedTitle: String { return self._s[2263]! } - public var Privacy_Forwards_NeverLink: String { return self._s[2265]! } + public var Wallet_Send_UninitializedTitle: String { return self._s[2263]! } + public var StickerPackActionInfo_ArchivedTitle: String { return self._s[2264]! } + public var Privacy_Forwards_NeverLink: String { return self._s[2266]! } public func Notification_MessageLifetimeChangedOutgoing(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2266]!, self._r[2266]!, [_1]) + return formatWithArgumentRanges(self._s[2267]!, self._r[2267]!, [_1]) } - public var CheckoutInfo_ErrorShippingNotAvailable: String { return self._s[2267]! } + public var CheckoutInfo_ErrorShippingNotAvailable: String { return self._s[2268]! } public func Time_MonthOfYear_m12(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2268]!, self._r[2268]!, [_0]) + return formatWithArgumentRanges(self._s[2269]!, self._r[2269]!, [_0]) } - public var ChatSettings_PrivateChats: String { return self._s[2269]! } - public var SettingsSearch_Synonyms_EditProfile_Logout: String { return self._s[2270]! } - public var Conversation_PrivateMessageLinkCopied: String { return self._s[2271]! } - public var Channel_UpdatePhotoItem: String { return self._s[2272]! } - public var GroupInfo_LeftStatus: String { return self._s[2273]! } - public var Watch_MessageView_Forward: String { return self._s[2275]! } - public var ReportPeer_ReasonChildAbuse: String { return self._s[2276]! } - public var Cache_ClearEmpty: String { return self._s[2278]! } - public var Localization_LanguageName: String { return self._s[2279]! } - public var Wallet_AccessDenied_Title: String { return self._s[2280]! } - public var WebSearch_GIFs: String { return self._s[2281]! } - public var Notifications_DisplayNamesOnLockScreenInfoWithLink: String { return self._s[2282]! } - public var Wallet_AccessDenied_Settings: String { return self._s[2283]! } - public var Username_InvalidStartsWithNumber: String { return self._s[2284]! } - public var Common_Back: String { return self._s[2285]! } - public var GroupInfo_Permissions_EditingDisabled: String { return self._s[2286]! } - public var Passport_Identity_DateOfBirthPlaceholder: String { return self._s[2287]! } - public var Wallet_Send_Send: String { return self._s[2288]! } + public var ChatSettings_PrivateChats: String { return self._s[2270]! } + public var SettingsSearch_Synonyms_EditProfile_Logout: String { return self._s[2271]! } + public var Conversation_PrivateMessageLinkCopied: String { return self._s[2272]! } + public var Channel_UpdatePhotoItem: String { return self._s[2273]! } + public var GroupInfo_LeftStatus: String { return self._s[2274]! } + public var Watch_MessageView_Forward: String { return self._s[2276]! } + public var ReportPeer_ReasonChildAbuse: String { return self._s[2277]! } + public var Cache_ClearEmpty: String { return self._s[2279]! } + public var Localization_LanguageName: String { return self._s[2280]! } + public var Wallet_AccessDenied_Title: String { return self._s[2281]! } + public var WebSearch_GIFs: String { return self._s[2282]! } + public var Notifications_DisplayNamesOnLockScreenInfoWithLink: String { return self._s[2283]! } + public var Wallet_AccessDenied_Settings: String { return self._s[2284]! } + public var Username_InvalidStartsWithNumber: String { return self._s[2285]! } + public var Common_Back: String { return self._s[2286]! } + public var GroupInfo_Permissions_EditingDisabled: String { return self._s[2287]! } + public var Passport_Identity_DateOfBirthPlaceholder: String { return self._s[2288]! } + public var Wallet_Send_Send: String { return self._s[2289]! } public func PUSH_CHANNEL_MESSAGE_STICKER(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2290]!, self._r[2290]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2291]!, self._r[2291]!, [_1, _2]) } - public var Wallet_Info_RefreshErrorTitle: String { return self._s[2291]! } - public var Wallet_Month_GenJune: String { return self._s[2292]! } - public var Passport_Email_Help: String { return self._s[2293]! } - public var Watch_Conversation_Reply: String { return self._s[2295]! } - public var Conversation_EditingMessageMediaChange: String { return self._s[2298]! } - public var Passport_Identity_IssueDatePlaceholder: String { return self._s[2299]! } - public var Channel_BanUser_Unban: String { return self._s[2301]! } - public var Channel_EditAdmin_PermissionPostMessages: String { return self._s[2302]! } - public var Group_Username_CreatePublicLinkHelp: String { return self._s[2303]! } - public var TwoStepAuth_ConfirmEmailCodePlaceholder: String { return self._s[2305]! } - public var Wallet_Send_AddressHeader: String { return self._s[2306]! } - public var Passport_Identity_Name: String { return self._s[2307]! } + public var Wallet_Info_RefreshErrorTitle: String { return self._s[2292]! } + public var Wallet_Month_GenJune: String { return self._s[2293]! } + public var Passport_Email_Help: String { return self._s[2294]! } + public var Watch_Conversation_Reply: String { return self._s[2296]! } + public var Conversation_EditingMessageMediaChange: String { return self._s[2299]! } + public var Passport_Identity_IssueDatePlaceholder: String { return self._s[2300]! } + public var Channel_BanUser_Unban: String { return self._s[2302]! } + public var Channel_EditAdmin_PermissionPostMessages: String { return self._s[2303]! } + public var Group_Username_CreatePublicLinkHelp: String { return self._s[2304]! } + public var TwoStepAuth_ConfirmEmailCodePlaceholder: String { return self._s[2306]! } + public var Wallet_Send_AddressHeader: String { return self._s[2307]! } + public var Passport_Identity_Name: String { return self._s[2308]! } public func Channel_DiscussionGroup_HeaderGroupSet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2308]!, self._r[2308]!, [_0]) + return formatWithArgumentRanges(self._s[2309]!, self._r[2309]!, [_0]) } - public var GroupRemoved_ViewUserInfo: String { return self._s[2309]! } - public var Conversation_BlockUser: String { return self._s[2310]! } - public var Month_GenJanuary: String { return self._s[2311]! } - public var ChatSettings_TextSize: String { return self._s[2312]! } - public var Notification_PassportValuePhone: String { return self._s[2313]! } - public var MediaPlayer_UnknownArtist: String { return self._s[2314]! } - public var Passport_Language_ne: String { return self._s[2315]! } - public var Notification_CallBack: String { return self._s[2316]! } - public var Wallet_SecureStorageReset_BiometryTouchId: String { return self._s[2317]! } - public var TwoStepAuth_EmailHelp: String { return self._s[2318]! } + public var GroupRemoved_ViewUserInfo: String { return self._s[2310]! } + public var Conversation_BlockUser: String { return self._s[2311]! } + public var Month_GenJanuary: String { return self._s[2312]! } + public var ChatSettings_TextSize: String { return self._s[2313]! } + public var Notification_PassportValuePhone: String { return self._s[2314]! } + public var MediaPlayer_UnknownArtist: String { return self._s[2315]! } + public var Passport_Language_ne: String { return self._s[2316]! } + public var Notification_CallBack: String { return self._s[2317]! } + public var Wallet_SecureStorageReset_BiometryTouchId: String { return self._s[2318]! } + public var TwoStepAuth_EmailHelp: String { return self._s[2319]! } public func Time_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2319]!, self._r[2319]!, [_0]) + return formatWithArgumentRanges(self._s[2320]!, self._r[2320]!, [_0]) } - public var Channel_Info_Management: String { return self._s[2320]! } - public var Passport_FieldIdentityUploadHelp: String { return self._s[2321]! } - public var Stickers_FrequentlyUsed: String { return self._s[2322]! } - public var Channel_BanUser_PermissionSendMessages: String { return self._s[2323]! } - public var Passport_Address_OneOfTypeUtilityBill: String { return self._s[2325]! } + public var Channel_Info_Management: String { return self._s[2321]! } + public var Passport_FieldIdentityUploadHelp: String { return self._s[2322]! } + public var Stickers_FrequentlyUsed: String { return self._s[2323]! } + public var Channel_BanUser_PermissionSendMessages: String { return self._s[2324]! } + public var Passport_Address_OneOfTypeUtilityBill: String { return self._s[2326]! } public func LOCAL_CHANNEL_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2326]!, self._r[2326]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[2327]!, self._r[2327]!, [_1, "\(_2)"]) } - public var TwoFactorSetup_Password_Title: String { return self._s[2327]! } - public var Passport_Address_EditResidentialAddress: String { return self._s[2328]! } - public var PrivacyPolicy_DeclineTitle: String { return self._s[2329]! } - public var CreatePoll_TextHeader: String { return self._s[2330]! } + public var TwoFactorSetup_Password_Title: String { return self._s[2328]! } + public var Passport_Address_EditResidentialAddress: String { return self._s[2329]! } + public var PrivacyPolicy_DeclineTitle: String { return self._s[2330]! } + public var CreatePoll_TextHeader: String { return self._s[2331]! } public func Checkout_SavePasswordTimeoutAndTouchId(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2331]!, self._r[2331]!, [_0]) + return formatWithArgumentRanges(self._s[2332]!, self._r[2332]!, [_0]) } - public var PhotoEditor_QualityMedium: String { return self._s[2332]! } - public var InfoPlist_NSMicrophoneUsageDescription: String { return self._s[2333]! } - public var Conversation_StatusKickedFromChannel: String { return self._s[2335]! } - public var CheckoutInfo_ReceiverInfoName: String { return self._s[2336]! } - public var Group_ErrorSendRestrictedStickers: String { return self._s[2337]! } + public var PhotoEditor_QualityMedium: String { return self._s[2333]! } + public var InfoPlist_NSMicrophoneUsageDescription: String { return self._s[2334]! } + public var Conversation_StatusKickedFromChannel: String { return self._s[2336]! } + public var CheckoutInfo_ReceiverInfoName: String { return self._s[2337]! } + public var Group_ErrorSendRestrictedStickers: String { return self._s[2338]! } public func Conversation_RestrictedInlineTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2338]!, self._r[2338]!, [_0]) + return formatWithArgumentRanges(self._s[2339]!, self._r[2339]!, [_0]) } public func Channel_AdminLog_MessageTransferedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2339]!, self._r[2339]!, [_1]) + return formatWithArgumentRanges(self._s[2340]!, self._r[2340]!, [_1]) } - public var LogoutOptions_LogOutWalletInfo: String { return self._s[2340]! } - public var TwoFactorSetup_Email_SkipConfirmationTitle: String { return self._s[2341]! } - public var Conversation_LinkDialogOpen: String { return self._s[2343]! } - public var TwoFactorSetup_Hint_Title: String { return self._s[2344]! } - public var VoiceOver_Chat_PollNoVotes: String { return self._s[2345]! } - public var Settings_Username: String { return self._s[2347]! } - public var Conversation_Block: String { return self._s[2349]! } - public var Wallpaper_Wallpaper: String { return self._s[2350]! } - public var SocksProxySetup_UseProxy: String { return self._s[2352]! } - public var Wallet_Send_Confirmation: String { return self._s[2353]! } - public var EditTheme_UploadEditedTheme: String { return self._s[2354]! } - public var UserInfo_ShareMyContactInfo: String { return self._s[2355]! } - public var MessageTimer_Forever: String { return self._s[2356]! } - public var Privacy_Calls_WhoCanCallMe: String { return self._s[2357]! } - public var PhotoEditor_DiscardChanges: String { return self._s[2358]! } - public var AuthSessions_TerminateOtherSessionsHelp: String { return self._s[2359]! } - public var Passport_Language_da: String { return self._s[2360]! } - public var SocksProxySetup_PortPlaceholder: String { return self._s[2361]! } + public var LogoutOptions_LogOutWalletInfo: String { return self._s[2341]! } + public var TwoFactorSetup_Email_SkipConfirmationTitle: String { return self._s[2342]! } + public var Conversation_LinkDialogOpen: String { return self._s[2344]! } + public var TwoFactorSetup_Hint_Title: String { return self._s[2345]! } + public var VoiceOver_Chat_PollNoVotes: String { return self._s[2346]! } + public var Settings_Username: String { return self._s[2348]! } + public var Conversation_Block: String { return self._s[2350]! } + public var Wallpaper_Wallpaper: String { return self._s[2351]! } + public var SocksProxySetup_UseProxy: String { return self._s[2353]! } + public var Wallet_Send_Confirmation: String { return self._s[2354]! } + public var EditTheme_UploadEditedTheme: String { return self._s[2355]! } + public var UserInfo_ShareMyContactInfo: String { return self._s[2356]! } + public var MessageTimer_Forever: String { return self._s[2357]! } + public var Privacy_Calls_WhoCanCallMe: String { return self._s[2358]! } + public var PhotoEditor_DiscardChanges: String { return self._s[2359]! } + public var AuthSessions_TerminateOtherSessionsHelp: String { return self._s[2360]! } + public var Passport_Language_da: String { return self._s[2361]! } + public var SocksProxySetup_PortPlaceholder: String { return self._s[2362]! } public func SecretGIF_NotViewedYet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2362]!, self._r[2362]!, [_0]) + return formatWithArgumentRanges(self._s[2363]!, self._r[2363]!, [_0]) } - public var Passport_Address_EditPassportRegistration: String { return self._s[2363]! } + public var Passport_Address_EditPassportRegistration: String { return self._s[2364]! } public func Channel_AdminLog_MessageChangedGroupAbout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2365]!, self._r[2365]!, [_0]) + return formatWithArgumentRanges(self._s[2366]!, self._r[2366]!, [_0]) } - public var Settings_AddDevice: String { return self._s[2366]! } - public var Passport_Identity_ResidenceCountryPlaceholder: String { return self._s[2368]! } - public var AuthSessions_AddDeviceIntro_Text1: String { return self._s[2369]! } - public var Conversation_SearchByName_Prefix: String { return self._s[2370]! } - public var Conversation_PinnedPoll: String { return self._s[2371]! } - public var AuthSessions_AddDeviceIntro_Text2: String { return self._s[2372]! } - public var Conversation_EmptyGifPanelPlaceholder: String { return self._s[2373]! } - public var AuthSessions_AddDeviceIntro_Text3: String { return self._s[2374]! } + public var Settings_AddDevice: String { return self._s[2367]! } + public var Passport_Identity_ResidenceCountryPlaceholder: String { return self._s[2369]! } + public var AuthSessions_AddDeviceIntro_Text1: String { return self._s[2370]! } + public var Conversation_SearchByName_Prefix: String { return self._s[2371]! } + public var Conversation_PinnedPoll: String { return self._s[2372]! } + public var AuthSessions_AddDeviceIntro_Text2: String { return self._s[2373]! } + public var Conversation_EmptyGifPanelPlaceholder: String { return self._s[2374]! } + public var AuthSessions_AddDeviceIntro_Text3: String { return self._s[2375]! } public func PUSH_ENCRYPTION_ACCEPT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2375]!, self._r[2375]!, [_1]) + return formatWithArgumentRanges(self._s[2376]!, self._r[2376]!, [_1]) } - public var WallpaperSearch_ColorPurple: String { return self._s[2376]! } - public var Cache_ByPeerHeader: String { return self._s[2377]! } + public var WallpaperSearch_ColorPurple: String { return self._s[2377]! } + public var Cache_ByPeerHeader: String { return self._s[2378]! } public func Conversation_EncryptedPlaceholderTitleIncoming(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2378]!, self._r[2378]!, [_0]) + return formatWithArgumentRanges(self._s[2379]!, self._r[2379]!, [_0]) } - public var ChatSettings_AutoDownloadDocuments: String { return self._s[2379]! } - public var Appearance_ThemePreview_Chat_3_Text: String { return self._s[2382]! } - public var Wallet_Completed_Title: String { return self._s[2383]! } - public var Notification_PinnedMessage: String { return self._s[2384]! } - public var TwoFactorSetup_EmailVerification_Placeholder: String { return self._s[2385]! } - public var VoiceOver_Chat_RecordModeVideoMessage: String { return self._s[2387]! } - public var Contacts_SortBy: String { return self._s[2388]! } + public var ChatSettings_AutoDownloadDocuments: String { return self._s[2380]! } + public var Appearance_ThemePreview_Chat_3_Text: String { return self._s[2383]! } + public var Wallet_Completed_Title: String { return self._s[2384]! } + public var Notification_PinnedMessage: String { return self._s[2385]! } + public var TwoFactorSetup_EmailVerification_Placeholder: String { return self._s[2386]! } + public var VoiceOver_Chat_RecordModeVideoMessage: String { return self._s[2388]! } + public var Contacts_SortBy: String { return self._s[2389]! } public func PUSH_CHANNEL_MESSAGE_NOTEXT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2389]!, self._r[2389]!, [_1]) + return formatWithArgumentRanges(self._s[2390]!, self._r[2390]!, [_1]) } - public var Appearance_ColorThemeNight: String { return self._s[2391]! } + public var Appearance_ColorThemeNight: String { return self._s[2392]! } public func PUSH_MESSAGE_GAME(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2392]!, self._r[2392]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2393]!, self._r[2393]!, [_1, _2]) } - public var Call_EncryptionKey_Title: String { return self._s[2393]! } - public var Watch_UserInfo_Service: String { return self._s[2394]! } - public var SettingsSearch_Synonyms_Data_SaveEditedPhotos: String { return self._s[2396]! } - public var Conversation_Unpin: String { return self._s[2398]! } - public var CancelResetAccount_Title: String { return self._s[2399]! } - public var Map_LiveLocationFor15Minutes: String { return self._s[2400]! } + public var Call_EncryptionKey_Title: String { return self._s[2394]! } + public var Watch_UserInfo_Service: String { return self._s[2395]! } + public var SettingsSearch_Synonyms_Data_SaveEditedPhotos: String { return self._s[2397]! } + public var Conversation_Unpin: String { return self._s[2399]! } + public var CancelResetAccount_Title: String { return self._s[2400]! } + public var Map_LiveLocationFor15Minutes: String { return self._s[2401]! } public func Time_PreciseDate_m8(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2402]!, self._r[2402]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2403]!, self._r[2403]!, [_1, _2, _3]) } - public var Group_Members_AddMemberBotErrorNotAllowed: String { return self._s[2403]! } - public var CallSettings_Title: String { return self._s[2404]! } - public var SettingsSearch_Synonyms_Appearance_ChatBackground: String { return self._s[2405]! } - public var PasscodeSettings_EncryptDataHelp: String { return self._s[2407]! } - public var AutoDownloadSettings_Contacts: String { return self._s[2408]! } + public var Group_Members_AddMemberBotErrorNotAllowed: String { return self._s[2404]! } + public var CallSettings_Title: String { return self._s[2405]! } + public var SettingsSearch_Synonyms_Appearance_ChatBackground: String { return self._s[2406]! } + public var PasscodeSettings_EncryptDataHelp: String { return self._s[2408]! } + public var AutoDownloadSettings_Contacts: String { return self._s[2409]! } public func Channel_AdminLog_MessageRankName(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2409]!, self._r[2409]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2410]!, self._r[2410]!, [_1, _2]) } - public var Passport_Identity_DocumentDetails: String { return self._s[2410]! } - public var LoginPassword_PasswordHelp: String { return self._s[2411]! } - public var SettingsSearch_Synonyms_Data_AutoDownloadUsingWifi: String { return self._s[2412]! } - public var PrivacyLastSeenSettings_CustomShareSettings_Delete: String { return self._s[2413]! } - public var ChatContextMenu_TextSelectionTip: String { return self._s[2414]! } - public var Checkout_TotalPaidAmount: String { return self._s[2415]! } + public var Passport_Identity_DocumentDetails: String { return self._s[2411]! } + public var LoginPassword_PasswordHelp: String { return self._s[2412]! } + public var SettingsSearch_Synonyms_Data_AutoDownloadUsingWifi: String { return self._s[2413]! } + public var PrivacyLastSeenSettings_CustomShareSettings_Delete: String { return self._s[2414]! } + public var ChatContextMenu_TextSelectionTip: String { return self._s[2415]! } + public var Checkout_TotalPaidAmount: String { return self._s[2416]! } public func FileSize_KB(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2416]!, self._r[2416]!, [_0]) + return formatWithArgumentRanges(self._s[2417]!, self._r[2417]!, [_0]) } - public var PasscodeSettings_ChangePasscode: String { return self._s[2417]! } - public var Conversation_SecretLinkPreviewAlert: String { return self._s[2419]! } - public var Privacy_SecretChatsLinkPreviews: String { return self._s[2420]! } + public var PasscodeSettings_ChangePasscode: String { return self._s[2418]! } + public var Conversation_SecretLinkPreviewAlert: String { return self._s[2420]! } + public var Privacy_SecretChatsLinkPreviews: String { return self._s[2421]! } public func PUSH_CHANNEL_MESSAGE_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2421]!, self._r[2421]!, [_1]) + return formatWithArgumentRanges(self._s[2422]!, self._r[2422]!, [_1]) } - public var VoiceOver_Chat_ReplyToYourMessage: String { return self._s[2422]! } - public var Contacts_InviteFriends: String { return self._s[2424]! } - public var Map_ChooseLocationTitle: String { return self._s[2425]! } - public var Conversation_StopPoll: String { return self._s[2427]! } + public var VoiceOver_Chat_ReplyToYourMessage: String { return self._s[2423]! } + public var Contacts_InviteFriends: String { return self._s[2425]! } + public var Map_ChooseLocationTitle: String { return self._s[2426]! } + public var Conversation_StopPoll: String { return self._s[2428]! } public func WebSearch_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2428]!, self._r[2428]!, [_0]) + return formatWithArgumentRanges(self._s[2429]!, self._r[2429]!, [_0]) } - public var Call_Camera: String { return self._s[2429]! } - public var LogoutOptions_ChangePhoneNumberTitle: String { return self._s[2430]! } - public var AppWallet_Intro_Text: String { return self._s[2431]! } - public var Calls_RatingFeedback: String { return self._s[2432]! } - public var GroupInfo_BroadcastListNamePlaceholder: String { return self._s[2434]! } - public var Wallet_Alert_OK: String { return self._s[2435]! } - public var NotificationsSound_Pulse: String { return self._s[2436]! } - public var Watch_LastSeen_Lately: String { return self._s[2437]! } - public var ReportGroupLocation_Report: String { return self._s[2440]! } - public var Widget_NoUsers: String { return self._s[2441]! } - public var Conversation_UnvotePoll: String { return self._s[2442]! } - public var SettingsSearch_Synonyms_Privacy_ProfilePhoto: String { return self._s[2444]! } - public var Privacy_ProfilePhoto_WhoCanSeeMyPhoto: String { return self._s[2445]! } - public var NotificationsSound_Circles: String { return self._s[2446]! } - public var PrivacyLastSeenSettings_AlwaysShareWith_Title: String { return self._s[2449]! } - public var Wallet_Settings_DeleteWallet: String { return self._s[2450]! } - public var TwoStepAuth_RecoveryCodeExpired: String { return self._s[2451]! } - public var Proxy_TooltipUnavailable: String { return self._s[2452]! } - public var Passport_Identity_CountryPlaceholder: String { return self._s[2454]! } - public var GroupInfo_Permissions_SlowmodeInfo: String { return self._s[2456]! } - public var Conversation_FileDropbox: String { return self._s[2457]! } - public var Notifications_ExceptionsUnmuted: String { return self._s[2458]! } - public var Tour_Text3: String { return self._s[2460]! } - public var Login_ResetAccountProtected_Title: String { return self._s[2462]! } - public var GroupPermission_NoSendMessages: String { return self._s[2463]! } - public var WallpaperSearch_ColorTitle: String { return self._s[2464]! } - public var ChatAdmins_AllMembersAreAdminsOnHelp: String { return self._s[2465]! } + public var Call_Camera: String { return self._s[2430]! } + public var LogoutOptions_ChangePhoneNumberTitle: String { return self._s[2431]! } + public var AppWallet_Intro_Text: String { return self._s[2432]! } + public var Calls_RatingFeedback: String { return self._s[2433]! } + public var GroupInfo_BroadcastListNamePlaceholder: String { return self._s[2435]! } + public var Wallet_Alert_OK: String { return self._s[2436]! } + public var NotificationsSound_Pulse: String { return self._s[2437]! } + public var Watch_LastSeen_Lately: String { return self._s[2438]! } + public var ReportGroupLocation_Report: String { return self._s[2441]! } + public var Widget_NoUsers: String { return self._s[2442]! } + public var Conversation_UnvotePoll: String { return self._s[2443]! } + public var SettingsSearch_Synonyms_Privacy_ProfilePhoto: String { return self._s[2445]! } + public var Privacy_ProfilePhoto_WhoCanSeeMyPhoto: String { return self._s[2446]! } + public var NotificationsSound_Circles: String { return self._s[2447]! } + public var PrivacyLastSeenSettings_AlwaysShareWith_Title: String { return self._s[2450]! } + public var Wallet_Settings_DeleteWallet: String { return self._s[2451]! } + public var TwoStepAuth_RecoveryCodeExpired: String { return self._s[2452]! } + public var Proxy_TooltipUnavailable: String { return self._s[2453]! } + public var Passport_Identity_CountryPlaceholder: String { return self._s[2455]! } + public var GroupInfo_Permissions_SlowmodeInfo: String { return self._s[2457]! } + public var Conversation_FileDropbox: String { return self._s[2458]! } + public var Notifications_ExceptionsUnmuted: String { return self._s[2459]! } + public var Tour_Text3: String { return self._s[2461]! } + public var Login_ResetAccountProtected_Title: String { return self._s[2463]! } + public var GroupPermission_NoSendMessages: String { return self._s[2464]! } + public var WallpaperSearch_ColorTitle: String { return self._s[2465]! } + public var ChatAdmins_AllMembersAreAdminsOnHelp: String { return self._s[2466]! } public func Conversation_LiveLocationYouAnd(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2467]!, self._r[2467]!, [_0]) + return formatWithArgumentRanges(self._s[2468]!, self._r[2468]!, [_0]) } - public var GroupInfo_AddParticipantTitle: String { return self._s[2468]! } - public var Checkout_ShippingOption_Title: String { return self._s[2469]! } - public var ChatSettings_AutoDownloadTitle: String { return self._s[2470]! } + public var GroupInfo_AddParticipantTitle: String { return self._s[2469]! } + public var Checkout_ShippingOption_Title: String { return self._s[2470]! } + public var ChatSettings_AutoDownloadTitle: String { return self._s[2471]! } public func DialogList_SingleTypingSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2471]!, self._r[2471]!, [_0]) - } - public func ChatSettings_AutoDownloadSettings_TypeVideo(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2472]!, self._r[2472]!, [_0]) } - public var Channel_Management_LabelAdministrator: String { return self._s[2473]! } - public var EditTheme_FileReadError: String { return self._s[2474]! } - public var OwnershipTransfer_ComeBackLater: String { return self._s[2475]! } - public var PrivacyLastSeenSettings_NeverShareWith_Placeholder: String { return self._s[2476]! } - public var AutoDownloadSettings_Photos: String { return self._s[2478]! } - public var Appearance_PreviewIncomingText: String { return self._s[2479]! } - public var ChatList_Context_MarkAllAsRead: String { return self._s[2480]! } - public var ChannelInfo_ConfirmLeave: String { return self._s[2481]! } - public var MediaPicker_MomentsDateRangeSameMonthYearFormat: String { return self._s[2482]! } - public var Passport_Identity_DocumentNumberPlaceholder: String { return self._s[2483]! } - public var Channel_AdminLogFilter_EventsNewMembers: String { return self._s[2484]! } - public var PasscodeSettings_AutoLock_IfAwayFor_5minutes: String { return self._s[2485]! } - public var GroupInfo_SetGroupPhotoStop: String { return self._s[2486]! } - public var Notification_SecretChatScreenshot: String { return self._s[2487]! } - public var AccessDenied_Wallpapers: String { return self._s[2488]! } - public var ChatList_Context_Mute: String { return self._s[2490]! } - public var Passport_Address_City: String { return self._s[2491]! } - public var InfoPlist_NSPhotoLibraryAddUsageDescription: String { return self._s[2492]! } - public var Appearance_ThemeCarouselClassic: String { return self._s[2493]! } - public var SocksProxySetup_SecretPlaceholder: String { return self._s[2494]! } - public var AccessDenied_LocationDisabled: String { return self._s[2495]! } - public var Group_Location_Title: String { return self._s[2496]! } - public var SocksProxySetup_HostnamePlaceholder: String { return self._s[2498]! } - public var GroupInfo_Sound: String { return self._s[2499]! } - public var SettingsSearch_Synonyms_ChatSettings_OpenLinksIn: String { return self._s[2500]! } - public var ChannelInfo_ScamChannelWarning: String { return self._s[2501]! } - public var Stickers_RemoveFromFavorites: String { return self._s[2502]! } - public var Contacts_Title: String { return self._s[2503]! } - public var EditTheme_ThemeTemplateAlertText: String { return self._s[2504]! } - public var Passport_Language_fr: String { return self._s[2505]! } - public var TwoFactorSetup_EmailVerification_Action: String { return self._s[2506]! } - public var Notifications_ResetAllNotifications: String { return self._s[2507]! } - public var IntentsSettings_SuggestedChats: String { return self._s[2509]! } - public var PrivacySettings_SecurityTitle: String { return self._s[2511]! } - public var Checkout_NewCard_Title: String { return self._s[2512]! } - public var Login_HaveNotReceivedCodeInternal: String { return self._s[2513]! } - public var Conversation_ForwardChats: String { return self._s[2514]! } - public var Wallet_SecureStorageReset_PasscodeText: String { return self._s[2516]! } - public var PasscodeSettings_4DigitCode: String { return self._s[2517]! } - public var Settings_FAQ: String { return self._s[2519]! } - public var AutoDownloadSettings_DocumentsTitle: String { return self._s[2520]! } - public var Conversation_ContextMenuForward: String { return self._s[2521]! } - public var VoiceOver_Chat_YourPhoto: String { return self._s[2524]! } - public var PrivacyPolicy_Title: String { return self._s[2527]! } - public var Notifications_TextTone: String { return self._s[2528]! } - public var Profile_CreateNewContact: String { return self._s[2529]! } - public var PrivacyPhoneNumberSettings_WhoCanSeeMyPhoneNumber: String { return self._s[2530]! } - public var TwoFactorSetup_EmailVerification_Title: String { return self._s[2532]! } - public var Call_Speaker: String { return self._s[2533]! } - public var AutoNightTheme_AutomaticSection: String { return self._s[2534]! } - public var Channel_OwnershipTransfer_EnterPassword: String { return self._s[2536]! } - public var Channel_Username_InvalidCharacters: String { return self._s[2537]! } + public func ChatSettings_AutoDownloadSettings_TypeVideo(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2473]!, self._r[2473]!, [_0]) + } + public var Channel_Management_LabelAdministrator: String { return self._s[2474]! } + public var EditTheme_FileReadError: String { return self._s[2475]! } + public var OwnershipTransfer_ComeBackLater: String { return self._s[2476]! } + public var PrivacyLastSeenSettings_NeverShareWith_Placeholder: String { return self._s[2477]! } + public var AutoDownloadSettings_Photos: String { return self._s[2479]! } + public var Appearance_PreviewIncomingText: String { return self._s[2480]! } + public var ChatList_Context_MarkAllAsRead: String { return self._s[2481]! } + public var ChannelInfo_ConfirmLeave: String { return self._s[2482]! } + public var MediaPicker_MomentsDateRangeSameMonthYearFormat: String { return self._s[2483]! } + public var Passport_Identity_DocumentNumberPlaceholder: String { return self._s[2484]! } + public var Channel_AdminLogFilter_EventsNewMembers: String { return self._s[2485]! } + public var PasscodeSettings_AutoLock_IfAwayFor_5minutes: String { return self._s[2486]! } + public var GroupInfo_SetGroupPhotoStop: String { return self._s[2487]! } + public var Notification_SecretChatScreenshot: String { return self._s[2488]! } + public var AccessDenied_Wallpapers: String { return self._s[2489]! } + public var ChatList_Context_Mute: String { return self._s[2491]! } + public var Passport_Address_City: String { return self._s[2492]! } + public var InfoPlist_NSPhotoLibraryAddUsageDescription: String { return self._s[2493]! } + public var Appearance_ThemeCarouselClassic: String { return self._s[2494]! } + public var SocksProxySetup_SecretPlaceholder: String { return self._s[2495]! } + public var AccessDenied_LocationDisabled: String { return self._s[2496]! } + public var Group_Location_Title: String { return self._s[2497]! } + public var SocksProxySetup_HostnamePlaceholder: String { return self._s[2499]! } + public var GroupInfo_Sound: String { return self._s[2500]! } + public var SettingsSearch_Synonyms_ChatSettings_OpenLinksIn: String { return self._s[2501]! } + public var ChannelInfo_ScamChannelWarning: String { return self._s[2502]! } + public var Stickers_RemoveFromFavorites: String { return self._s[2503]! } + public var Contacts_Title: String { return self._s[2504]! } + public var EditTheme_ThemeTemplateAlertText: String { return self._s[2505]! } + public var Passport_Language_fr: String { return self._s[2506]! } + public var TwoFactorSetup_EmailVerification_Action: String { return self._s[2507]! } + public var Notifications_ResetAllNotifications: String { return self._s[2508]! } + public var IntentsSettings_SuggestedChats: String { return self._s[2510]! } + public var PrivacySettings_SecurityTitle: String { return self._s[2512]! } + public var Checkout_NewCard_Title: String { return self._s[2513]! } + public var Login_HaveNotReceivedCodeInternal: String { return self._s[2514]! } + public var Conversation_ForwardChats: String { return self._s[2515]! } + public var Wallet_SecureStorageReset_PasscodeText: String { return self._s[2517]! } + public var PasscodeSettings_4DigitCode: String { return self._s[2518]! } + public var Settings_FAQ: String { return self._s[2520]! } + public var AutoDownloadSettings_DocumentsTitle: String { return self._s[2521]! } + public var Conversation_ContextMenuForward: String { return self._s[2522]! } + public var VoiceOver_Chat_YourPhoto: String { return self._s[2525]! } + public var PrivacyPolicy_Title: String { return self._s[2528]! } + public var Notifications_TextTone: String { return self._s[2529]! } + public var Profile_CreateNewContact: String { return self._s[2530]! } + public var PrivacyPhoneNumberSettings_WhoCanSeeMyPhoneNumber: String { return self._s[2531]! } + public var TwoFactorSetup_EmailVerification_Title: String { return self._s[2533]! } + public var Call_Speaker: String { return self._s[2534]! } + public var AutoNightTheme_AutomaticSection: String { return self._s[2535]! } + public var Channel_OwnershipTransfer_EnterPassword: String { return self._s[2537]! } + public var Channel_Username_InvalidCharacters: String { return self._s[2538]! } public func Channel_AdminLog_MessageChangedChannelUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2538]!, self._r[2538]!, [_0]) + return formatWithArgumentRanges(self._s[2539]!, self._r[2539]!, [_0]) } - public var AutoDownloadSettings_AutodownloadFiles: String { return self._s[2539]! } - public var PrivacySettings_LastSeenTitle: String { return self._s[2540]! } - public var Channel_AdminLog_CanInviteUsers: String { return self._s[2541]! } - public var SettingsSearch_Synonyms_Privacy_Data_ClearPaymentsInfo: String { return self._s[2542]! } - public var OwnershipTransfer_SecurityCheck: String { return self._s[2543]! } - public var Conversation_MessageDeliveryFailed: String { return self._s[2544]! } - public var Watch_ChatList_NoConversationsText: String { return self._s[2545]! } - public var Bot_Unblock: String { return self._s[2546]! } - public var TextFormat_Italic: String { return self._s[2547]! } - public var WallpaperSearch_ColorPink: String { return self._s[2548]! } - public var Settings_About_Help: String { return self._s[2550]! } - public var SearchImages_Title: String { return self._s[2551]! } - public var Weekday_Wednesday: String { return self._s[2552]! } - public var Conversation_ClousStorageInfo_Description1: String { return self._s[2553]! } - public var ExplicitContent_AlertTitle: String { return self._s[2554]! } + public var AutoDownloadSettings_AutodownloadFiles: String { return self._s[2540]! } + public var PrivacySettings_LastSeenTitle: String { return self._s[2541]! } + public var Channel_AdminLog_CanInviteUsers: String { return self._s[2542]! } + public var SettingsSearch_Synonyms_Privacy_Data_ClearPaymentsInfo: String { return self._s[2543]! } + public var OwnershipTransfer_SecurityCheck: String { return self._s[2544]! } + public var Conversation_MessageDeliveryFailed: String { return self._s[2545]! } + public var Watch_ChatList_NoConversationsText: String { return self._s[2546]! } + public var Bot_Unblock: String { return self._s[2547]! } + public var TextFormat_Italic: String { return self._s[2548]! } + public var WallpaperSearch_ColorPink: String { return self._s[2549]! } + public var Settings_About_Help: String { return self._s[2551]! } + public var SearchImages_Title: String { return self._s[2552]! } + public var Weekday_Wednesday: String { return self._s[2553]! } + public var Conversation_ClousStorageInfo_Description1: String { return self._s[2554]! } + public var ExplicitContent_AlertTitle: String { return self._s[2555]! } public func Time_PreciseDate_m5(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2555]!, self._r[2555]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2556]!, self._r[2556]!, [_1, _2, _3]) } - public var Channel_DiscussionGroup_Create: String { return self._s[2556]! } - public var Weekday_Thursday: String { return self._s[2557]! } - public var Channel_BanUser_PermissionChangeGroupInfo: String { return self._s[2558]! } - public var Channel_Members_AddMembersHelp: String { return self._s[2559]! } + public var Channel_DiscussionGroup_Create: String { return self._s[2557]! } + public var Weekday_Thursday: String { return self._s[2558]! } + public var Channel_BanUser_PermissionChangeGroupInfo: String { return self._s[2559]! } + public var Channel_Members_AddMembersHelp: String { return self._s[2560]! } public func Checkout_SavePasswordTimeout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2560]!, self._r[2560]!, [_0]) + return formatWithArgumentRanges(self._s[2561]!, self._r[2561]!, [_0]) } - public var Channel_DiscussionGroup_LinkGroup: String { return self._s[2561]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsVibrate: String { return self._s[2562]! } - public var Passport_RequestedInformation: String { return self._s[2563]! } - public var Login_PhoneAndCountryHelp: String { return self._s[2564]! } - public var Conversation_EncryptionProcessing: String { return self._s[2566]! } - public var Notifications_PermissionsSuppressWarningTitle: String { return self._s[2567]! } - public var PhotoEditor_EnhanceTool: String { return self._s[2569]! } - public var Channel_Setup_Title: String { return self._s[2570]! } - public var Conversation_SearchPlaceholder: String { return self._s[2571]! } - public var OldChannels_GroupEmptyFormat: String { return self._s[2572]! } - public var AccessDenied_LocationAlwaysDenied: String { return self._s[2573]! } - public var Checkout_ErrorGeneric: String { return self._s[2574]! } - public var Passport_Language_hu: String { return self._s[2575]! } - public var GroupPermission_EditingDisabled: String { return self._s[2576]! } - public var Wallet_Month_ShortSeptember: String { return self._s[2578]! } + public var Channel_DiscussionGroup_LinkGroup: String { return self._s[2562]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsVibrate: String { return self._s[2563]! } + public var Passport_RequestedInformation: String { return self._s[2564]! } + public var Login_PhoneAndCountryHelp: String { return self._s[2565]! } + public var Conversation_EncryptionProcessing: String { return self._s[2567]! } + public var Notifications_PermissionsSuppressWarningTitle: String { return self._s[2568]! } + public var PhotoEditor_EnhanceTool: String { return self._s[2570]! } + public var Channel_Setup_Title: String { return self._s[2571]! } + public var Conversation_SearchPlaceholder: String { return self._s[2572]! } + public var OldChannels_GroupEmptyFormat: String { return self._s[2573]! } + public var AccessDenied_LocationAlwaysDenied: String { return self._s[2574]! } + public var Checkout_ErrorGeneric: String { return self._s[2575]! } + public var Passport_Language_hu: String { return self._s[2576]! } + public var GroupPermission_EditingDisabled: String { return self._s[2577]! } + public var Wallet_Month_ShortSeptember: String { return self._s[2579]! } public func Passport_Identity_UploadOneOfScan(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2579]!, self._r[2579]!, [_0]) + return formatWithArgumentRanges(self._s[2580]!, self._r[2580]!, [_0]) } public func PUSH_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2582]!, self._r[2582]!, [_1]) + return formatWithArgumentRanges(self._s[2583]!, self._r[2583]!, [_1]) } - public var ChatList_DeleteSavedMessagesConfirmationTitle: String { return self._s[2583]! } + public var ChatList_DeleteSavedMessagesConfirmationTitle: String { return self._s[2584]! } public func UserInfo_BlockConfirmationTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2584]!, self._r[2584]!, [_0]) + return formatWithArgumentRanges(self._s[2585]!, self._r[2585]!, [_0]) } - public var Conversation_CloudStorageInfo_Title: String { return self._s[2585]! } - public var Group_Location_Info: String { return self._s[2586]! } - public var PhotoEditor_CropAspectRatioSquare: String { return self._s[2587]! } - public var Permissions_PeopleNearbyAllow_v0: String { return self._s[2588]! } + public var Conversation_CloudStorageInfo_Title: String { return self._s[2586]! } + public var Group_Location_Info: String { return self._s[2587]! } + public var PhotoEditor_CropAspectRatioSquare: String { return self._s[2588]! } + public var Permissions_PeopleNearbyAllow_v0: String { return self._s[2589]! } public func Notification_Exceptions_MutedUntil(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2589]!, self._r[2589]!, [_0]) + return formatWithArgumentRanges(self._s[2590]!, self._r[2590]!, [_0]) } - public var Conversation_ClearPrivateHistory: String { return self._s[2590]! } - public var ContactInfo_PhoneLabelHome: String { return self._s[2591]! } - public var Appearance_RemoveThemeConfirmation: String { return self._s[2592]! } - public var PrivacySettings_LastSeenContacts: String { return self._s[2593]! } + public var Conversation_ClearPrivateHistory: String { return self._s[2591]! } + public var ContactInfo_PhoneLabelHome: String { return self._s[2592]! } + public var Appearance_RemoveThemeConfirmation: String { return self._s[2593]! } + public var PrivacySettings_LastSeenContacts: String { return self._s[2594]! } public func ChangePhone_ErrorOccupied(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2594]!, self._r[2594]!, [_0]) + return formatWithArgumentRanges(self._s[2595]!, self._r[2595]!, [_0]) } - public var Passport_Language_cs: String { return self._s[2595]! } - public var Message_PinnedAnimationMessage: String { return self._s[2597]! } - public var Passport_Identity_ReverseSideHelp: String { return self._s[2599]! } - public var SettingsSearch_Synonyms_Data_Storage_Title: String { return self._s[2600]! } - public var Wallet_Info_TransactionTo: String { return self._s[2602]! } - public var ChatList_DeleteForEveryoneConfirmationText: String { return self._s[2603]! } - public var SettingsSearch_Synonyms_Privacy_PasscodeAndTouchId: String { return self._s[2604]! } - public var Embed_PlayingInPIP: String { return self._s[2605]! } - public var Appearance_ThemePreview_Chat_3_TextWithLink: String { return self._s[2606]! } - public var AutoNightTheme_ScheduleSection: String { return self._s[2607]! } + public var Passport_Language_cs: String { return self._s[2596]! } + public var Message_PinnedAnimationMessage: String { return self._s[2598]! } + public var Passport_Identity_ReverseSideHelp: String { return self._s[2600]! } + public var SettingsSearch_Synonyms_Data_Storage_Title: String { return self._s[2601]! } + public var Wallet_Info_TransactionTo: String { return self._s[2603]! } + public var ChatList_DeleteForEveryoneConfirmationText: String { return self._s[2604]! } + public var SettingsSearch_Synonyms_Privacy_PasscodeAndTouchId: String { return self._s[2605]! } + public var Embed_PlayingInPIP: String { return self._s[2606]! } + public var Appearance_ThemePreview_Chat_3_TextWithLink: String { return self._s[2607]! } + public var AutoNightTheme_ScheduleSection: String { return self._s[2608]! } public func Call_EmojiDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2608]!, self._r[2608]!, [_0]) + return formatWithArgumentRanges(self._s[2609]!, self._r[2609]!, [_0]) } - public var MediaPicker_LivePhotoDescription: String { return self._s[2609]! } + public var MediaPicker_LivePhotoDescription: String { return self._s[2610]! } public func Channel_AdminLog_MessageRestrictedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2610]!, self._r[2610]!, [_1]) + return formatWithArgumentRanges(self._s[2611]!, self._r[2611]!, [_1]) } - public var Notification_PaymentSent: String { return self._s[2611]! } - public var PhotoEditor_CurvesGreen: String { return self._s[2612]! } - public var Notification_Exceptions_PreviewAlwaysOff: String { return self._s[2613]! } - public var AutoNightTheme_System: String { return self._s[2614]! } - public var SaveIncomingPhotosSettings_Title: String { return self._s[2615]! } - public var CreatePoll_QuizTitle: String { return self._s[2616]! } - public var NotificationSettings_ShowNotificationsAllAccounts: String { return self._s[2617]! } - public var VoiceOver_Chat_PagePreview: String { return self._s[2618]! } + public var Notification_PaymentSent: String { return self._s[2612]! } + public var PhotoEditor_CurvesGreen: String { return self._s[2613]! } + public var Notification_Exceptions_PreviewAlwaysOff: String { return self._s[2614]! } + public var AutoNightTheme_System: String { return self._s[2615]! } + public var SaveIncomingPhotosSettings_Title: String { return self._s[2616]! } + public var CreatePoll_QuizTitle: String { return self._s[2617]! } + public var NotificationSettings_ShowNotificationsAllAccounts: String { return self._s[2618]! } + public var VoiceOver_Chat_PagePreview: String { return self._s[2619]! } public func PUSH_MESSAGE_SCREENSHOT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2621]!, self._r[2621]!, [_1]) - } - public func PUSH_MESSAGE_PHOTO_SECRET(_ _1: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2622]!, self._r[2622]!, [_1]) } - public func ApplyLanguage_UnsufficientDataText(_ _1: String) -> (String, [(Int, NSRange)]) { + public func PUSH_MESSAGE_PHOTO_SECRET(_ _1: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2623]!, self._r[2623]!, [_1]) } - public var NetworkUsageSettings_CallDataSection: String { return self._s[2625]! } - public var PasscodeSettings_HelpTop: String { return self._s[2626]! } - public var Conversation_WalletRequiredTitle: String { return self._s[2627]! } - public var Group_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[2628]! } - public var Passport_Address_TypeRentalAgreement: String { return self._s[2629]! } - public var EditTheme_ShortLink: String { return self._s[2630]! } - public var Theme_Colors_ColorWallpaperWarning: String { return self._s[2631]! } - public var ProxyServer_VoiceOver_Active: String { return self._s[2632]! } - public var ReportPeer_ReasonOther_Placeholder: String { return self._s[2633]! } - public var CheckoutInfo_ErrorPhoneInvalid: String { return self._s[2634]! } - public var Call_Accept: String { return self._s[2636]! } - public var GroupRemoved_RemoveInfo: String { return self._s[2637]! } - public var Month_GenMarch: String { return self._s[2639]! } - public var PhotoEditor_ShadowsTool: String { return self._s[2640]! } - public var LoginPassword_Title: String { return self._s[2641]! } - public var Call_End: String { return self._s[2642]! } - public var Watch_Conversation_GroupInfo: String { return self._s[2643]! } - public var VoiceOver_Chat_Contact: String { return self._s[2644]! } - public var EditTheme_Create_Preview_IncomingText: String { return self._s[2645]! } - public var CallSettings_Always: String { return self._s[2646]! } - public var CallFeedback_Success: String { return self._s[2647]! } - public var TwoStepAuth_SetupHint: String { return self._s[2648]! } + public func ApplyLanguage_UnsufficientDataText(_ _1: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2624]!, self._r[2624]!, [_1]) + } + public var NetworkUsageSettings_CallDataSection: String { return self._s[2626]! } + public var PasscodeSettings_HelpTop: String { return self._s[2627]! } + public var Conversation_WalletRequiredTitle: String { return self._s[2628]! } + public var Group_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[2629]! } + public var Passport_Address_TypeRentalAgreement: String { return self._s[2630]! } + public var EditTheme_ShortLink: String { return self._s[2631]! } + public var Theme_Colors_ColorWallpaperWarning: String { return self._s[2632]! } + public var ProxyServer_VoiceOver_Active: String { return self._s[2633]! } + public var ReportPeer_ReasonOther_Placeholder: String { return self._s[2634]! } + public var CheckoutInfo_ErrorPhoneInvalid: String { return self._s[2635]! } + public var Call_Accept: String { return self._s[2637]! } + public var GroupRemoved_RemoveInfo: String { return self._s[2638]! } + public var Month_GenMarch: String { return self._s[2640]! } + public var PhotoEditor_ShadowsTool: String { return self._s[2641]! } + public var LoginPassword_Title: String { return self._s[2642]! } + public var Call_End: String { return self._s[2643]! } + public var Watch_Conversation_GroupInfo: String { return self._s[2644]! } + public var VoiceOver_Chat_Contact: String { return self._s[2645]! } + public var EditTheme_Create_Preview_IncomingText: String { return self._s[2646]! } + public var CallSettings_Always: String { return self._s[2647]! } + public var CallFeedback_Success: String { return self._s[2648]! } + public var TwoStepAuth_SetupHint: String { return self._s[2649]! } public func AddContact_ContactWillBeSharedAfterMutual(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2649]!, self._r[2649]!, [_1]) + return formatWithArgumentRanges(self._s[2650]!, self._r[2650]!, [_1]) } - public var ConversationProfile_UsersTooMuchError: String { return self._s[2650]! } - public var Login_PhoneTitle: String { return self._s[2651]! } - public var Passport_FieldPhoneHelp: String { return self._s[2652]! } - public var Weekday_ShortSunday: String { return self._s[2653]! } - public var Passport_InfoFAQ_URL: String { return self._s[2654]! } - public var ContactInfo_Job: String { return self._s[2656]! } - public var UserInfo_InviteBotToGroup: String { return self._s[2657]! } - public var Appearance_ThemeCarouselNightBlue: String { return self._s[2658]! } - public var CreatePoll_QuizTip: String { return self._s[2659]! } - public var TwoFactorSetup_Email_Text: String { return self._s[2660]! } - public var TwoStepAuth_PasswordRemovePassportConfirmation: String { return self._s[2661]! } - public var Invite_ChannelsTooMuch: String { return self._s[2662]! } - public var Wallet_Send_ConfirmationConfirm: String { return self._s[2663]! } - public var Wallet_TransactionInfo_OtherFeeInfo: String { return self._s[2664]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsPreview: String { return self._s[2665]! } - public var Wallet_Receive_AmountText: String { return self._s[2666]! } - public var Passport_DeletePersonalDetailsConfirmation: String { return self._s[2667]! } - public var CallFeedback_ReasonNoise: String { return self._s[2668]! } - public var Appearance_AppIconDefault: String { return self._s[2670]! } - public var Passport_Identity_AddInternalPassport: String { return self._s[2671]! } - public var MediaPicker_AddCaption: String { return self._s[2672]! } - public var CallSettings_TabIconDescription: String { return self._s[2673]! } + public var ConversationProfile_UsersTooMuchError: String { return self._s[2651]! } + public var Login_PhoneTitle: String { return self._s[2652]! } + public var Passport_FieldPhoneHelp: String { return self._s[2653]! } + public var Weekday_ShortSunday: String { return self._s[2654]! } + public var Passport_InfoFAQ_URL: String { return self._s[2655]! } + public var ContactInfo_Job: String { return self._s[2657]! } + public var UserInfo_InviteBotToGroup: String { return self._s[2658]! } + public var Appearance_ThemeCarouselNightBlue: String { return self._s[2659]! } + public var CreatePoll_QuizTip: String { return self._s[2660]! } + public var TwoFactorSetup_Email_Text: String { return self._s[2661]! } + public var TwoStepAuth_PasswordRemovePassportConfirmation: String { return self._s[2662]! } + public var Invite_ChannelsTooMuch: String { return self._s[2663]! } + public var Wallet_Send_ConfirmationConfirm: String { return self._s[2664]! } + public var Wallet_TransactionInfo_OtherFeeInfo: String { return self._s[2665]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsPreview: String { return self._s[2666]! } + public var Wallet_Receive_AmountText: String { return self._s[2667]! } + public var Passport_DeletePersonalDetailsConfirmation: String { return self._s[2668]! } + public var CallFeedback_ReasonNoise: String { return self._s[2669]! } + public var Appearance_AppIconDefault: String { return self._s[2671]! } + public var Passport_Identity_AddInternalPassport: String { return self._s[2672]! } + public var MediaPicker_AddCaption: String { return self._s[2673]! } + public var CallSettings_TabIconDescription: String { return self._s[2674]! } public func VoiceOver_Chat_Caption(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2674]!, self._r[2674]!, [_0]) + return formatWithArgumentRanges(self._s[2675]!, self._r[2675]!, [_0]) } - public var IntentsSettings_SuggestedChatsGroups: String { return self._s[2675]! } + public var IntentsSettings_SuggestedChatsGroups: String { return self._s[2676]! } public func Map_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2676]!, self._r[2676]!, [_0]) + return formatWithArgumentRanges(self._s[2677]!, self._r[2677]!, [_0]) } - public var ChatList_UndoArchiveHiddenTitle: String { return self._s[2677]! } - public var Privacy_GroupsAndChannels_AlwaysAllow: String { return self._s[2678]! } - public var Passport_Identity_TypePersonalDetails: String { return self._s[2679]! } - public var DialogList_SearchSectionRecent: String { return self._s[2680]! } - public var PrivacyPolicy_DeclineMessage: String { return self._s[2681]! } - public var CreatePoll_Anonymous: String { return self._s[2682]! } - public var LogoutOptions_ClearCacheText: String { return self._s[2685]! } - public var LastSeen_WithinAWeek: String { return self._s[2686]! } - public var ChannelMembers_GroupAdminsTitle: String { return self._s[2687]! } - public var Conversation_CloudStorage_ChatStatus: String { return self._s[2689]! } - public var VoiceOver_Media_PlaybackRateNormal: String { return self._s[2690]! } + public var ChatList_UndoArchiveHiddenTitle: String { return self._s[2678]! } + public var Privacy_GroupsAndChannels_AlwaysAllow: String { return self._s[2679]! } + public var Passport_Identity_TypePersonalDetails: String { return self._s[2680]! } + public var DialogList_SearchSectionRecent: String { return self._s[2681]! } + public var PrivacyPolicy_DeclineMessage: String { return self._s[2682]! } + public var CreatePoll_Anonymous: String { return self._s[2683]! } + public var LogoutOptions_ClearCacheText: String { return self._s[2686]! } + public var LastSeen_WithinAWeek: String { return self._s[2687]! } + public var ChannelMembers_GroupAdminsTitle: String { return self._s[2688]! } + public var Conversation_CloudStorage_ChatStatus: String { return self._s[2690]! } + public var VoiceOver_Media_PlaybackRateNormal: String { return self._s[2691]! } public func AddContact_SharedContactExceptionInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2691]!, self._r[2691]!, [_0]) + return formatWithArgumentRanges(self._s[2692]!, self._r[2692]!, [_0]) } - public var Passport_Address_TypeResidentialAddress: String { return self._s[2692]! } - public var Conversation_StatusLeftGroup: String { return self._s[2693]! } - public var SocksProxySetup_ProxyDetailsTitle: String { return self._s[2694]! } - public var SettingsSearch_Synonyms_Calls_Title: String { return self._s[2696]! } - public var GroupPermission_AddSuccess: String { return self._s[2697]! } - public var PhotoEditor_BlurToolRadial: String { return self._s[2699]! } - public var Conversation_ContextMenuCopy: String { return self._s[2700]! } - public var AccessDenied_CallMicrophone: String { return self._s[2701]! } + public var Passport_Address_TypeResidentialAddress: String { return self._s[2693]! } + public var Conversation_StatusLeftGroup: String { return self._s[2694]! } + public var SocksProxySetup_ProxyDetailsTitle: String { return self._s[2695]! } + public var SettingsSearch_Synonyms_Calls_Title: String { return self._s[2697]! } + public var GroupPermission_AddSuccess: String { return self._s[2698]! } + public var PhotoEditor_BlurToolRadial: String { return self._s[2700]! } + public var Conversation_ContextMenuCopy: String { return self._s[2701]! } + public var AccessDenied_CallMicrophone: String { return self._s[2702]! } public func Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2702]!, self._r[2702]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2703]!, self._r[2703]!, [_1, _2, _3]) } - public var Login_InvalidFirstNameError: String { return self._s[2703]! } - public var Notifications_Badge_CountUnreadMessages_InfoOn: String { return self._s[2704]! } - public var Checkout_PaymentMethod_New: String { return self._s[2705]! } - public var ShareMenu_CopyShareLinkGame: String { return self._s[2706]! } - public var PhotoEditor_QualityTool: String { return self._s[2707]! } - public var Login_SendCodeViaSms: String { return self._s[2708]! } - public var SettingsSearch_Synonyms_Privacy_DeleteAccountIfAwayFor: String { return self._s[2709]! } - public var Chat_SlowmodeAttachmentLimitReached: String { return self._s[2710]! } - public var Wallet_Receive_CopyAddress: String { return self._s[2711]! } - public var Login_EmailNotConfiguredError: String { return self._s[2712]! } - public var SocksProxySetup_Status: String { return self._s[2713]! } - public var Conversation_ScheduleMessage_SendWhenOnline: String { return self._s[2714]! } - public var PrivacyPolicy_Accept: String { return self._s[2715]! } - public var Notifications_ExceptionsMessagePlaceholder: String { return self._s[2716]! } - public var Appearance_AppIconClassicX: String { return self._s[2717]! } + public var Login_InvalidFirstNameError: String { return self._s[2704]! } + public var Notifications_Badge_CountUnreadMessages_InfoOn: String { return self._s[2705]! } + public var Checkout_PaymentMethod_New: String { return self._s[2706]! } + public var ShareMenu_CopyShareLinkGame: String { return self._s[2707]! } + public var PhotoEditor_QualityTool: String { return self._s[2708]! } + public var Login_SendCodeViaSms: String { return self._s[2709]! } + public var SettingsSearch_Synonyms_Privacy_DeleteAccountIfAwayFor: String { return self._s[2710]! } + public var Chat_SlowmodeAttachmentLimitReached: String { return self._s[2711]! } + public var Wallet_Receive_CopyAddress: String { return self._s[2712]! } + public var Login_EmailNotConfiguredError: String { return self._s[2713]! } + public var SocksProxySetup_Status: String { return self._s[2714]! } + public var Conversation_ScheduleMessage_SendWhenOnline: String { return self._s[2715]! } + public var PrivacyPolicy_Accept: String { return self._s[2716]! } + public var Notifications_ExceptionsMessagePlaceholder: String { return self._s[2717]! } + public var Appearance_AppIconClassicX: String { return self._s[2718]! } public func PUSH_CHAT_MESSAGE_TEXT(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2718]!, self._r[2718]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2719]!, self._r[2719]!, [_1, _2, _3]) } - public var OwnershipTransfer_SecurityRequirements: String { return self._s[2719]! } - public var InfoPlist_NSLocationAlwaysUsageDescription: String { return self._s[2721]! } - public var AutoNightTheme_Automatic: String { return self._s[2722]! } - public var Channel_Username_InvalidStartsWithNumber: String { return self._s[2723]! } - public var Privacy_ContactsSyncHelp: String { return self._s[2724]! } - public var Cache_Help: String { return self._s[2725]! } - public var Group_ErrorAccessDenied: String { return self._s[2726]! } - public var Passport_Language_fa: String { return self._s[2727]! } - public var Wallet_Intro_Text: String { return self._s[2728]! } - public var Login_ResetAccountProtected_TimerTitle: String { return self._s[2729]! } - public var VoiceOver_Chat_YourVideoMessage: String { return self._s[2730]! } - public var PrivacySettings_LastSeen: String { return self._s[2731]! } + public var OwnershipTransfer_SecurityRequirements: String { return self._s[2720]! } + public var InfoPlist_NSLocationAlwaysUsageDescription: String { return self._s[2722]! } + public var AutoNightTheme_Automatic: String { return self._s[2723]! } + public var Channel_Username_InvalidStartsWithNumber: String { return self._s[2724]! } + public var Privacy_ContactsSyncHelp: String { return self._s[2725]! } + public var Cache_Help: String { return self._s[2726]! } + public var Group_ErrorAccessDenied: String { return self._s[2727]! } + public var Passport_Language_fa: String { return self._s[2728]! } + public var Wallet_Intro_Text: String { return self._s[2729]! } + public var Login_ResetAccountProtected_TimerTitle: String { return self._s[2730]! } + public var VoiceOver_Chat_YourVideoMessage: String { return self._s[2731]! } + public var PrivacySettings_LastSeen: String { return self._s[2732]! } public func DialogList_MultipleTyping(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2732]!, self._r[2732]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2733]!, self._r[2733]!, [_0, _1]) } - public var Wallet_Configuration_Apply: String { return self._s[2736]! } - public var Preview_SaveGif: String { return self._s[2737]! } - public var SettingsSearch_Synonyms_Privacy_TwoStepAuth: String { return self._s[2738]! } - public var Profile_About: String { return self._s[2739]! } - public var Channel_About_Placeholder: String { return self._s[2740]! } - public var Login_InfoTitle: String { return self._s[2741]! } + public var Wallet_Configuration_Apply: String { return self._s[2737]! } + public var Preview_SaveGif: String { return self._s[2738]! } + public var SettingsSearch_Synonyms_Privacy_TwoStepAuth: String { return self._s[2739]! } + public var Profile_About: String { return self._s[2740]! } + public var Channel_About_Placeholder: String { return self._s[2741]! } + public var Login_InfoTitle: String { return self._s[2742]! } public func TwoStepAuth_SetupPendingEmail(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2742]!, self._r[2742]!, [_0]) + return formatWithArgumentRanges(self._s[2743]!, self._r[2743]!, [_0]) } - public var EditTheme_Expand_Preview_IncomingReplyText: String { return self._s[2743]! } - public var Watch_Suggestion_CantTalk: String { return self._s[2745]! } - public var ContactInfo_Title: String { return self._s[2746]! } - public var Media_ShareThisVideo: String { return self._s[2747]! } - public var Weekday_ShortFriday: String { return self._s[2748]! } - public var AccessDenied_Contacts: String { return self._s[2750]! } - public var Notification_CallIncomingShort: String { return self._s[2751]! } - public var Group_Setup_TypePublic: String { return self._s[2752]! } - public var Notifications_MessageNotificationsExceptions: String { return self._s[2753]! } - public var Notifications_Badge_IncludeChannels: String { return self._s[2754]! } - public var Notifications_MessageNotificationsPreview: String { return self._s[2757]! } - public var ConversationProfile_ErrorCreatingConversation: String { return self._s[2758]! } - public var Group_ErrorAddTooMuchBots: String { return self._s[2759]! } - public var Privacy_GroupsAndChannels_CustomShareHelp: String { return self._s[2760]! } - public var Permissions_CellularDataAllowInSettings_v0: String { return self._s[2761]! } + public var EditTheme_Expand_Preview_IncomingReplyText: String { return self._s[2744]! } + public var Watch_Suggestion_CantTalk: String { return self._s[2746]! } + public var ContactInfo_Title: String { return self._s[2747]! } + public var Media_ShareThisVideo: String { return self._s[2748]! } + public var Weekday_ShortFriday: String { return self._s[2749]! } + public var AccessDenied_Contacts: String { return self._s[2751]! } + public var Notification_CallIncomingShort: String { return self._s[2752]! } + public var Group_Setup_TypePublic: String { return self._s[2753]! } + public var Notifications_MessageNotificationsExceptions: String { return self._s[2754]! } + public var Notifications_Badge_IncludeChannels: String { return self._s[2755]! } + public var Notifications_MessageNotificationsPreview: String { return self._s[2758]! } + public var ConversationProfile_ErrorCreatingConversation: String { return self._s[2759]! } + public var Group_ErrorAddTooMuchBots: String { return self._s[2760]! } + public var Privacy_GroupsAndChannels_CustomShareHelp: String { return self._s[2761]! } + public var Permissions_CellularDataAllowInSettings_v0: String { return self._s[2762]! } public func Wallet_SecureStorageChanged_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2762]!, self._r[2762]!, [_0]) + return formatWithArgumentRanges(self._s[2763]!, self._r[2763]!, [_0]) } - public var DialogList_Typing: String { return self._s[2763]! } - public var CallFeedback_IncludeLogs: String { return self._s[2765]! } - public var Checkout_Phone: String { return self._s[2767]! } - public var Login_InfoFirstNamePlaceholder: String { return self._s[2770]! } - public var Privacy_Calls_Integration: String { return self._s[2771]! } - public var Notifications_PermissionsAllow: String { return self._s[2772]! } - public var TwoStepAuth_AddHintDescription: String { return self._s[2776]! } - public var Settings_ChatSettings: String { return self._s[2777]! } - public var Conversation_SendingOptionsTooltip: String { return self._s[2778]! } + public var DialogList_Typing: String { return self._s[2764]! } + public var CallFeedback_IncludeLogs: String { return self._s[2766]! } + public var Checkout_Phone: String { return self._s[2768]! } + public var Login_InfoFirstNamePlaceholder: String { return self._s[2771]! } + public var Privacy_Calls_Integration: String { return self._s[2772]! } + public var Notifications_PermissionsAllow: String { return self._s[2773]! } + public var TwoStepAuth_AddHintDescription: String { return self._s[2777]! } + public var Settings_ChatSettings: String { return self._s[2778]! } + public var Conversation_SendingOptionsTooltip: String { return self._s[2779]! } public func UserInfo_StartSecretChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2780]!, self._r[2780]!, [_0]) + return formatWithArgumentRanges(self._s[2781]!, self._r[2781]!, [_0]) } public func Channel_AdminLog_MessageInvitedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2781]!, self._r[2781]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2782]!, self._r[2782]!, [_1, _2]) } - public var GroupRemoved_DeleteUser: String { return self._s[2783]! } + public var GroupRemoved_DeleteUser: String { return self._s[2784]! } public func Channel_AdminLog_PollStopped(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2784]!, self._r[2784]!, [_0]) + return formatWithArgumentRanges(self._s[2785]!, self._r[2785]!, [_0]) } public func PUSH_MESSAGE_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2785]!, self._r[2785]!, [_1]) + return formatWithArgumentRanges(self._s[2786]!, self._r[2786]!, [_1]) } - public var Login_ContinueWithLocalization: String { return self._s[2786]! } - public var Watch_Message_ForwardedFrom: String { return self._s[2787]! } - public var TwoStepAuth_EnterEmailCode: String { return self._s[2789]! } - public var Conversation_Unblock: String { return self._s[2790]! } - public var PrivacySettings_DataSettings: String { return self._s[2791]! } - public var WallpaperPreview_PatternPaternApply: String { return self._s[2792]! } - public var Group_PublicLink_Info: String { return self._s[2793]! } + public var Login_ContinueWithLocalization: String { return self._s[2787]! } + public var Watch_Message_ForwardedFrom: String { return self._s[2788]! } + public var TwoStepAuth_EnterEmailCode: String { return self._s[2790]! } + public var Conversation_Unblock: String { return self._s[2791]! } + public var PrivacySettings_DataSettings: String { return self._s[2792]! } + public var WallpaperPreview_PatternPaternApply: String { return self._s[2793]! } + public var Group_PublicLink_Info: String { return self._s[2794]! } public func Wallet_Time_PreciseDate_m1(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2794]!, self._r[2794]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2795]!, self._r[2795]!, [_1, _2, _3]) } - public var Notifications_InAppNotificationsVibrate: String { return self._s[2795]! } + public var Notifications_InAppNotificationsVibrate: String { return self._s[2796]! } public func Privacy_GroupsAndChannels_InviteToChannelError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2796]!, self._r[2796]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2797]!, self._r[2797]!, [_0, _1]) } - public var OldChannels_ChannelsHeader: String { return self._s[2798]! } - public var Wallet_RestoreFailed_CreateWallet: String { return self._s[2799]! } - public var PrivacySettings_Passcode: String { return self._s[2801]! } - public var Call_Mute: String { return self._s[2802]! } - public var Wallet_Weekday_Yesterday: String { return self._s[2803]! } - public var Passport_Language_dz: String { return self._s[2804]! } - public var Wallet_Receive_AmountHeader: String { return self._s[2805]! } - public var Wallet_TransactionInfo_OtherFeeInfoUrl: String { return self._s[2806]! } - public var Passport_Language_tk: String { return self._s[2807]! } + public var OldChannels_ChannelsHeader: String { return self._s[2799]! } + public var Wallet_RestoreFailed_CreateWallet: String { return self._s[2800]! } + public var PrivacySettings_Passcode: String { return self._s[2802]! } + public var Call_Mute: String { return self._s[2803]! } + public var Wallet_Weekday_Yesterday: String { return self._s[2804]! } + public var Passport_Language_dz: String { return self._s[2805]! } + public var Wallet_Receive_AmountHeader: String { return self._s[2806]! } + public var Wallet_TransactionInfo_OtherFeeInfoUrl: String { return self._s[2807]! } + public var Passport_Language_tk: String { return self._s[2808]! } public func Login_EmailCodeSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2808]!, self._r[2808]!, [_0]) + return formatWithArgumentRanges(self._s[2809]!, self._r[2809]!, [_0]) } - public var Settings_Search: String { return self._s[2809]! } - public var Wallet_Month_ShortFebruary: String { return self._s[2810]! } - public var InfoPlist_NSPhotoLibraryUsageDescription: String { return self._s[2811]! } - public var Wallet_Configuration_SourceJSON: String { return self._s[2812]! } - public var Conversation_ContextMenuReply: String { return self._s[2813]! } - public var WallpaperSearch_ColorBrown: String { return self._s[2814]! } - public var Chat_AttachmentMultipleForwardDisabled: String { return self._s[2815]! } - public var Tour_Title1: String { return self._s[2816]! } - public var Wallet_Alert_Cancel: String { return self._s[2817]! } - public var Conversation_ClearGroupHistory: String { return self._s[2819]! } - public var Wallet_TransactionInfo_RecipientHeader: String { return self._s[2820]! } - public var WallpaperPreview_Motion: String { return self._s[2821]! } + public var Settings_Search: String { return self._s[2810]! } + public var Wallet_Month_ShortFebruary: String { return self._s[2811]! } + public var InfoPlist_NSPhotoLibraryUsageDescription: String { return self._s[2812]! } + public var Wallet_Configuration_SourceJSON: String { return self._s[2813]! } + public var Conversation_ContextMenuReply: String { return self._s[2814]! } + public var WallpaperSearch_ColorBrown: String { return self._s[2815]! } + public var Chat_AttachmentMultipleForwardDisabled: String { return self._s[2816]! } + public var Tour_Title1: String { return self._s[2817]! } + public var Wallet_Alert_Cancel: String { return self._s[2818]! } + public var Conversation_ClearGroupHistory: String { return self._s[2820]! } + public var Wallet_TransactionInfo_RecipientHeader: String { return self._s[2821]! } + public var WallpaperPreview_Motion: String { return self._s[2822]! } public func Checkout_PasswordEntry_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2822]!, self._r[2822]!, [_0]) + return formatWithArgumentRanges(self._s[2823]!, self._r[2823]!, [_0]) } - public var Wallet_Configuration_ApplyErrorTextJSONInvalidData: String { return self._s[2823]! } - public var Call_RateCall: String { return self._s[2824]! } - public var Channel_AdminLog_BanSendStickersAndGifs: String { return self._s[2825]! } - public var Passport_PasswordCompleteSetup: String { return self._s[2826]! } - public var Conversation_InputTextSilentBroadcastPlaceholder: String { return self._s[2827]! } - public var UserInfo_LastNamePlaceholder: String { return self._s[2829]! } + public var Wallet_Configuration_ApplyErrorTextJSONInvalidData: String { return self._s[2824]! } + public var Call_RateCall: String { return self._s[2825]! } + public var Channel_AdminLog_BanSendStickersAndGifs: String { return self._s[2826]! } + public var Passport_PasswordCompleteSetup: String { return self._s[2827]! } + public var Conversation_InputTextSilentBroadcastPlaceholder: String { return self._s[2828]! } + public var UserInfo_LastNamePlaceholder: String { return self._s[2830]! } public func Login_WillCallYou(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2831]!, self._r[2831]!, [_0]) + return formatWithArgumentRanges(self._s[2832]!, self._r[2832]!, [_0]) } - public var Compose_Create: String { return self._s[2832]! } - public var Contacts_InviteToTelegram: String { return self._s[2833]! } - public var GroupInfo_Notifications: String { return self._s[2834]! } - public var ChatList_DeleteSavedMessagesConfirmationAction: String { return self._s[2836]! } - public var Message_PinnedLiveLocationMessage: String { return self._s[2837]! } - public var Month_GenApril: String { return self._s[2838]! } - public var Appearance_AutoNightTheme: String { return self._s[2839]! } - public var ChatSettings_AutomaticAudioDownload: String { return self._s[2841]! } - public var Login_CodeSentSms: String { return self._s[2843]! } + public var Compose_Create: String { return self._s[2833]! } + public var Contacts_InviteToTelegram: String { return self._s[2834]! } + public var GroupInfo_Notifications: String { return self._s[2835]! } + public var ChatList_DeleteSavedMessagesConfirmationAction: String { return self._s[2837]! } + public var Message_PinnedLiveLocationMessage: String { return self._s[2838]! } + public var Month_GenApril: String { return self._s[2839]! } + public var Appearance_AutoNightTheme: String { return self._s[2840]! } + public var ChatSettings_AutomaticAudioDownload: String { return self._s[2842]! } + public var Login_CodeSentSms: String { return self._s[2844]! } public func UserInfo_UnblockConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2844]!, self._r[2844]!, [_0]) + return formatWithArgumentRanges(self._s[2845]!, self._r[2845]!, [_0]) } - public var EmptyGroupInfo_Line3: String { return self._s[2845]! } - public var LogoutOptions_ContactSupportText: String { return self._s[2846]! } - public var Passport_Language_hr: String { return self._s[2847]! } - public var Common_ActionNotAllowedError: String { return self._s[2848]! } + public var EmptyGroupInfo_Line3: String { return self._s[2846]! } + public var LogoutOptions_ContactSupportText: String { return self._s[2847]! } + public var Passport_Language_hr: String { return self._s[2848]! } + public var Common_ActionNotAllowedError: String { return self._s[2849]! } public func Channel_AdminLog_MessageRestrictedNewSetting(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2849]!, self._r[2849]!, [_0]) + return formatWithArgumentRanges(self._s[2850]!, self._r[2850]!, [_0]) } - public var GroupInfo_InviteLink_CopyLink: String { return self._s[2850]! } - public var Wallet_Info_TransactionFrom: String { return self._s[2851]! } - public var Wallet_Send_ErrorDecryptionFailed: String { return self._s[2852]! } - public var Conversation_InputTextBroadcastPlaceholder: String { return self._s[2853]! } - public var Privacy_SecretChatsTitle: String { return self._s[2854]! } - public var Notification_SecretChatMessageScreenshotSelf: String { return self._s[2856]! } - public var GroupInfo_AddUserLeftError: String { return self._s[2857]! } - public var AutoDownloadSettings_TypePrivateChats: String { return self._s[2858]! } - public var LogoutOptions_ContactSupportTitle: String { return self._s[2859]! } - public var Appearance_ThemePreview_Chat_7_Text: String { return self._s[2860]! } - public var Channel_AddBotErrorHaveRights: String { return self._s[2861]! } - public var Preview_DeleteGif: String { return self._s[2862]! } - public var GroupInfo_Permissions_Exceptions: String { return self._s[2863]! } - public var Group_ErrorNotMutualContact: String { return self._s[2864]! } - public var Notification_MessageLifetime5s: String { return self._s[2865]! } - public var Wallet_Send_OwnAddressAlertText: String { return self._s[2866]! } - public var OldChannels_ChannelFormat: String { return self._s[2867]! } + public var GroupInfo_InviteLink_CopyLink: String { return self._s[2851]! } + public var Wallet_Info_TransactionFrom: String { return self._s[2852]! } + public var Wallet_Send_ErrorDecryptionFailed: String { return self._s[2853]! } + public var Conversation_InputTextBroadcastPlaceholder: String { return self._s[2854]! } + public var Privacy_SecretChatsTitle: String { return self._s[2855]! } + public var Notification_SecretChatMessageScreenshotSelf: String { return self._s[2857]! } + public var GroupInfo_AddUserLeftError: String { return self._s[2858]! } + public var AutoDownloadSettings_TypePrivateChats: String { return self._s[2859]! } + public var LogoutOptions_ContactSupportTitle: String { return self._s[2860]! } + public var Appearance_ThemePreview_Chat_7_Text: String { return self._s[2861]! } + public var Channel_AddBotErrorHaveRights: String { return self._s[2862]! } + public var Preview_DeleteGif: String { return self._s[2863]! } + public var GroupInfo_Permissions_Exceptions: String { return self._s[2864]! } + public var Group_ErrorNotMutualContact: String { return self._s[2865]! } + public var Notification_MessageLifetime5s: String { return self._s[2866]! } + public var Wallet_Send_OwnAddressAlertText: String { return self._s[2867]! } + public var OldChannels_ChannelFormat: String { return self._s[2868]! } public func Watch_LastSeen_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2868]!, self._r[2868]!, [_0]) + return formatWithArgumentRanges(self._s[2869]!, self._r[2869]!, [_0]) } - public var VoiceOver_Chat_Video: String { return self._s[2869]! } - public var Channel_OwnershipTransfer_ErrorPublicChannelsTooMuch: String { return self._s[2871]! } - public var ReportSpam_DeleteThisChat: String { return self._s[2872]! } - public var Passport_Address_AddBankStatement: String { return self._s[2873]! } - public var Notification_CallIncoming: String { return self._s[2874]! } - public var Wallet_Words_NotDoneTitle: String { return self._s[2875]! } - public var Compose_NewGroupTitle: String { return self._s[2876]! } - public var TwoStepAuth_RecoveryCodeHelp: String { return self._s[2878]! } - public var Passport_Address_Postcode: String { return self._s[2880]! } + public var VoiceOver_Chat_Video: String { return self._s[2870]! } + public var Channel_OwnershipTransfer_ErrorPublicChannelsTooMuch: String { return self._s[2872]! } + public var ReportSpam_DeleteThisChat: String { return self._s[2873]! } + public var Passport_Address_AddBankStatement: String { return self._s[2874]! } + public var Notification_CallIncoming: String { return self._s[2875]! } + public var Wallet_Words_NotDoneTitle: String { return self._s[2876]! } + public var Compose_NewGroupTitle: String { return self._s[2877]! } + public var TwoStepAuth_RecoveryCodeHelp: String { return self._s[2879]! } + public var Passport_Address_Postcode: String { return self._s[2881]! } public func LastSeen_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2881]!, self._r[2881]!, [_0]) + return formatWithArgumentRanges(self._s[2882]!, self._r[2882]!, [_0]) } - public var Checkout_NewCard_SaveInfoHelp: String { return self._s[2882]! } - public var Wallet_Month_ShortOctober: String { return self._s[2883]! } - public var VoiceOver_Chat_YourMusic: String { return self._s[2884]! } - public var WallpaperColors_Title: String { return self._s[2885]! } - public var SocksProxySetup_ShareQRCodeInfo: String { return self._s[2886]! } - public var VoiceOver_MessageContextForward: String { return self._s[2887]! } - public var GroupPermission_Duration: String { return self._s[2888]! } + public var Checkout_NewCard_SaveInfoHelp: String { return self._s[2883]! } + public var Wallet_Month_ShortOctober: String { return self._s[2884]! } + public var VoiceOver_Chat_YourMusic: String { return self._s[2885]! } + public var WallpaperColors_Title: String { return self._s[2886]! } + public var SocksProxySetup_ShareQRCodeInfo: String { return self._s[2887]! } + public var VoiceOver_MessageContextForward: String { return self._s[2888]! } + public var GroupPermission_Duration: String { return self._s[2889]! } public func Cache_Clear(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2889]!, self._r[2889]!, [_0]) + return formatWithArgumentRanges(self._s[2890]!, self._r[2890]!, [_0]) } - public var Bot_GroupStatusDoesNotReadHistory: String { return self._s[2890]! } - public var Username_Placeholder: String { return self._s[2891]! } - public var CallFeedback_WhatWentWrong: String { return self._s[2892]! } - public var Passport_FieldAddressUploadHelp: String { return self._s[2893]! } - public var Permissions_NotificationsAllowInSettings_v0: String { return self._s[2894]! } + public var Bot_GroupStatusDoesNotReadHistory: String { return self._s[2891]! } + public var Username_Placeholder: String { return self._s[2892]! } + public var CallFeedback_WhatWentWrong: String { return self._s[2893]! } + public var Passport_FieldAddressUploadHelp: String { return self._s[2894]! } + public var Permissions_NotificationsAllowInSettings_v0: String { return self._s[2895]! } public func Channel_AdminLog_MessageChangedUnlinkedChannel(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2896]!, self._r[2896]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2897]!, self._r[2897]!, [_1, _2]) } - public var Passport_PasswordDescription: String { return self._s[2897]! } - public var Channel_MessagePhotoUpdated: String { return self._s[2898]! } - public var MediaPicker_TapToUngroupDescription: String { return self._s[2899]! } - public var SettingsSearch_Synonyms_Notifications_BadgeCountUnreadMessages: String { return self._s[2900]! } - public var AttachmentMenu_PhotoOrVideo: String { return self._s[2901]! } - public var Conversation_ContextMenuMore: String { return self._s[2902]! } - public var Privacy_PaymentsClearInfo: String { return self._s[2903]! } - public var CallSettings_TabIcon: String { return self._s[2904]! } - public var KeyCommand_Find: String { return self._s[2905]! } - public var ClearCache_FreeSpaceDescription: String { return self._s[2906]! } - public var Appearance_ThemePreview_ChatList_7_Text: String { return self._s[2907]! } - public var EditTheme_Edit_Preview_IncomingText: String { return self._s[2908]! } - public var Message_PinnedGame: String { return self._s[2909]! } - public var VoiceOver_Chat_ForwardedFromYou: String { return self._s[2910]! } - public var Notifications_Badge_CountUnreadMessages_InfoOff: String { return self._s[2912]! } - public var Login_CallRequestState2: String { return self._s[2914]! } - public var CheckoutInfo_ReceiverInfoNamePlaceholder: String { return self._s[2916]! } + public var Passport_PasswordDescription: String { return self._s[2898]! } + public var Channel_MessagePhotoUpdated: String { return self._s[2899]! } + public var MediaPicker_TapToUngroupDescription: String { return self._s[2900]! } + public var SettingsSearch_Synonyms_Notifications_BadgeCountUnreadMessages: String { return self._s[2901]! } + public var AttachmentMenu_PhotoOrVideo: String { return self._s[2902]! } + public var Conversation_ContextMenuMore: String { return self._s[2903]! } + public var Privacy_PaymentsClearInfo: String { return self._s[2904]! } + public var CallSettings_TabIcon: String { return self._s[2905]! } + public var KeyCommand_Find: String { return self._s[2906]! } + public var ClearCache_FreeSpaceDescription: String { return self._s[2907]! } + public var Appearance_ThemePreview_ChatList_7_Text: String { return self._s[2908]! } + public var EditTheme_Edit_Preview_IncomingText: String { return self._s[2909]! } + public var Message_PinnedGame: String { return self._s[2910]! } + public var VoiceOver_Chat_ForwardedFromYou: String { return self._s[2911]! } + public var Notifications_Badge_CountUnreadMessages_InfoOff: String { return self._s[2913]! } + public var Login_CallRequestState2: String { return self._s[2915]! } + public var CheckoutInfo_ReceiverInfoNamePlaceholder: String { return self._s[2917]! } public func VoiceOver_Chat_PhotoFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2917]!, self._r[2917]!, [_0]) + return formatWithArgumentRanges(self._s[2918]!, self._r[2918]!, [_0]) } public func Checkout_PayPrice(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2919]!, self._r[2919]!, [_0]) + return formatWithArgumentRanges(self._s[2920]!, self._r[2920]!, [_0]) } - public var AuthSessions_AddDevice: String { return self._s[2920]! } - public var WallpaperPreview_Blurred: String { return self._s[2921]! } - public var Conversation_InstantPagePreview: String { return self._s[2922]! } + public var AuthSessions_AddDevice: String { return self._s[2921]! } + public var WallpaperPreview_Blurred: String { return self._s[2922]! } + public var Conversation_InstantPagePreview: String { return self._s[2923]! } public func DialogList_SingleUploadingVideoSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2923]!, self._r[2923]!, [_0]) + return formatWithArgumentRanges(self._s[2924]!, self._r[2924]!, [_0]) } - public var SecretTimer_VideoDescription: String { return self._s[2926]! } - public var WallpaperSearch_ColorRed: String { return self._s[2927]! } - public var GroupPermission_NoPinMessages: String { return self._s[2928]! } - public var Passport_Language_es: String { return self._s[2929]! } - public var Permissions_ContactsAllow_v0: String { return self._s[2931]! } - public var Conversation_EditingMessageMediaEditCurrentVideo: String { return self._s[2932]! } + public var SecretTimer_VideoDescription: String { return self._s[2927]! } + public var WallpaperSearch_ColorRed: String { return self._s[2928]! } + public var GroupPermission_NoPinMessages: String { return self._s[2929]! } + public var Passport_Language_es: String { return self._s[2930]! } + public var Permissions_ContactsAllow_v0: String { return self._s[2932]! } + public var Conversation_EditingMessageMediaEditCurrentVideo: String { return self._s[2933]! } public func PUSH_CHAT_MESSAGE_CONTACT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2933]!, self._r[2933]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2934]!, self._r[2934]!, [_1, _2]) } - public var Privacy_Forwards_CustomHelp: String { return self._s[2934]! } - public var WebPreview_GettingLinkInfo: String { return self._s[2935]! } - public var Watch_UserInfo_Unmute: String { return self._s[2936]! } - public var GroupInfo_ChannelListNamePlaceholder: String { return self._s[2937]! } - public var AccessDenied_CameraRestricted: String { return self._s[2939]! } + public var Privacy_Forwards_CustomHelp: String { return self._s[2935]! } + public var WebPreview_GettingLinkInfo: String { return self._s[2936]! } + public var Watch_UserInfo_Unmute: String { return self._s[2937]! } + public var GroupInfo_ChannelListNamePlaceholder: String { return self._s[2938]! } + public var AccessDenied_CameraRestricted: String { return self._s[2940]! } public func Conversation_Kilobytes(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2940]!, self._r[2940]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[2941]!, self._r[2941]!, ["\(_0)"]) } - public var ChatList_ReadAll: String { return self._s[2942]! } - public var Settings_CopyUsername: String { return self._s[2943]! } - public var Contacts_SearchLabel: String { return self._s[2944]! } - public var Map_OpenInYandexNavigator: String { return self._s[2946]! } - public var PasscodeSettings_EncryptData: String { return self._s[2947]! } - public var Settings_Wallet: String { return self._s[2948]! } - public var Group_ErrorSupergroupConversionNotPossible: String { return self._s[2949]! } - public var WallpaperSearch_ColorPrefix: String { return self._s[2950]! } - public var Notifications_GroupNotificationsPreview: String { return self._s[2951]! } - public var DialogList_AdNoticeAlert: String { return self._s[2952]! } - public var Wallet_Month_GenMay: String { return self._s[2954]! } - public var CheckoutInfo_ShippingInfoAddress1: String { return self._s[2955]! } - public var CheckoutInfo_ShippingInfoAddress2: String { return self._s[2956]! } - public var Localization_LanguageCustom: String { return self._s[2957]! } - public var Passport_Identity_TypeDriversLicenseUploadScan: String { return self._s[2958]! } - public var CallFeedback_Title: String { return self._s[2959]! } - public var VoiceOver_Chat_RecordPreviewVoiceMessage: String { return self._s[2962]! } - public var Passport_Address_OneOfTypePassportRegistration: String { return self._s[2963]! } - public var Wallet_Intro_CreateErrorTitle: String { return self._s[2964]! } - public var Conversation_InfoGroup: String { return self._s[2965]! } - public var Compose_NewMessage: String { return self._s[2966]! } - public var FastTwoStepSetup_HintPlaceholder: String { return self._s[2967]! } - public var ChatSettings_AutoDownloadVideoMessages: String { return self._s[2968]! } - public var Wallet_SecureStorageReset_BiometryFaceId: String { return self._s[2969]! } - public var Channel_DiscussionGroup_UnlinkChannel: String { return self._s[2970]! } + public var ChatList_ReadAll: String { return self._s[2943]! } + public var Settings_CopyUsername: String { return self._s[2944]! } + public var Contacts_SearchLabel: String { return self._s[2945]! } + public var Map_OpenInYandexNavigator: String { return self._s[2947]! } + public var PasscodeSettings_EncryptData: String { return self._s[2948]! } + public var Settings_Wallet: String { return self._s[2949]! } + public var Group_ErrorSupergroupConversionNotPossible: String { return self._s[2950]! } + public var WallpaperSearch_ColorPrefix: String { return self._s[2951]! } + public var Notifications_GroupNotificationsPreview: String { return self._s[2952]! } + public var DialogList_AdNoticeAlert: String { return self._s[2953]! } + public var Wallet_Month_GenMay: String { return self._s[2955]! } + public var CheckoutInfo_ShippingInfoAddress1: String { return self._s[2956]! } + public var CheckoutInfo_ShippingInfoAddress2: String { return self._s[2957]! } + public var Localization_LanguageCustom: String { return self._s[2958]! } + public var Passport_Identity_TypeDriversLicenseUploadScan: String { return self._s[2959]! } + public var CallFeedback_Title: String { return self._s[2960]! } + public var VoiceOver_Chat_RecordPreviewVoiceMessage: String { return self._s[2963]! } + public var Passport_Address_OneOfTypePassportRegistration: String { return self._s[2964]! } + public var Wallet_Intro_CreateErrorTitle: String { return self._s[2965]! } + public var Conversation_InfoGroup: String { return self._s[2966]! } + public var Compose_NewMessage: String { return self._s[2967]! } + public var FastTwoStepSetup_HintPlaceholder: String { return self._s[2968]! } + public var ChatSettings_AutoDownloadVideoMessages: String { return self._s[2969]! } + public var Wallet_SecureStorageReset_BiometryFaceId: String { return self._s[2970]! } + public var Channel_DiscussionGroup_UnlinkChannel: String { return self._s[2971]! } public func Passport_Scans_ScanIndex(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2971]!, self._r[2971]!, [_0]) + return formatWithArgumentRanges(self._s[2972]!, self._r[2972]!, [_0]) } - public var Channel_AdminLog_CanDeleteMessages: String { return self._s[2972]! } - public var Login_CancelSignUpConfirmation: String { return self._s[2973]! } - public var ChangePhoneNumberCode_Help: String { return self._s[2974]! } - public var PrivacySettings_DeleteAccountHelp: String { return self._s[2975]! } - public var Channel_BlackList_Title: String { return self._s[2976]! } - public var UserInfo_PhoneCall: String { return self._s[2977]! } - public var Passport_Address_OneOfTypeBankStatement: String { return self._s[2979]! } - public var Wallet_Month_ShortJanuary: String { return self._s[2980]! } - public var State_connecting: String { return self._s[2981]! } - public var Appearance_ThemePreview_ChatList_6_Text: String { return self._s[2982]! } - public var Wallet_Month_GenMarch: String { return self._s[2983]! } - public var EditTheme_Expand_BottomInfo: String { return self._s[2984]! } - public var AuthSessions_AddedDeviceTerminate: String { return self._s[2985]! } + public var Channel_AdminLog_CanDeleteMessages: String { return self._s[2973]! } + public var Login_CancelSignUpConfirmation: String { return self._s[2974]! } + public var ChangePhoneNumberCode_Help: String { return self._s[2975]! } + public var PrivacySettings_DeleteAccountHelp: String { return self._s[2976]! } + public var Channel_BlackList_Title: String { return self._s[2977]! } + public var UserInfo_PhoneCall: String { return self._s[2978]! } + public var Passport_Address_OneOfTypeBankStatement: String { return self._s[2980]! } + public var Wallet_Month_ShortJanuary: String { return self._s[2981]! } + public var State_connecting: String { return self._s[2982]! } + public var Appearance_ThemePreview_ChatList_6_Text: String { return self._s[2983]! } + public var Wallet_Month_GenMarch: String { return self._s[2984]! } + public var EditTheme_Expand_BottomInfo: String { return self._s[2985]! } + public var AuthSessions_AddedDeviceTerminate: String { return self._s[2986]! } public func LastSeen_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2986]!, self._r[2986]!, [_0]) - } - public func DialogList_SingleRecordingAudioSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2987]!, self._r[2987]!, [_0]) } - public var Notifications_GroupNotifications: String { return self._s[2988]! } - public var Conversation_SendMessageErrorTooMuchScheduled: String { return self._s[2989]! } - public var Passport_Identity_EditPassport: String { return self._s[2990]! } - public var EnterPasscode_RepeatNewPasscode: String { return self._s[2992]! } - public var Localization_EnglishLanguageName: String { return self._s[2993]! } - public var Share_AuthDescription: String { return self._s[2994]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsAlert: String { return self._s[2995]! } - public var Passport_Identity_Surname: String { return self._s[2996]! } - public var Compose_TokenListPlaceholder: String { return self._s[2997]! } - public var Wallet_AccessDenied_Camera: String { return self._s[2998]! } - public var Passport_Identity_OneOfTypePassport: String { return self._s[2999]! } - public var Settings_AboutEmpty: String { return self._s[3000]! } - public var Conversation_Unmute: String { return self._s[3001]! } - public var CreateGroup_ChannelsTooMuch: String { return self._s[3003]! } - public var Wallet_Sending_Text: String { return self._s[3004]! } - public func PUSH_CONTACT_JOINED(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3005]!, self._r[3005]!, [_1]) + public func DialogList_SingleRecordingAudioSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2988]!, self._r[2988]!, [_0]) } - public var Login_CodeSentCall: String { return self._s[3006]! } - public var ContactInfo_PhoneLabelHomeFax: String { return self._s[3008]! } - public var ChatSettings_Appearance: String { return self._s[3009]! } - public var ClearCache_StorageUsage: String { return self._s[3010]! } - public var Appearance_PickAccentColor: String { return self._s[3011]! } + public var Notifications_GroupNotifications: String { return self._s[2989]! } + public var Conversation_SendMessageErrorTooMuchScheduled: String { return self._s[2990]! } + public var Passport_Identity_EditPassport: String { return self._s[2991]! } + public var EnterPasscode_RepeatNewPasscode: String { return self._s[2993]! } + public var Localization_EnglishLanguageName: String { return self._s[2994]! } + public var Share_AuthDescription: String { return self._s[2995]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsAlert: String { return self._s[2996]! } + public var Passport_Identity_Surname: String { return self._s[2997]! } + public var Compose_TokenListPlaceholder: String { return self._s[2998]! } + public var Wallet_AccessDenied_Camera: String { return self._s[2999]! } + public var Passport_Identity_OneOfTypePassport: String { return self._s[3000]! } + public var Settings_AboutEmpty: String { return self._s[3001]! } + public var Conversation_Unmute: String { return self._s[3002]! } + public var CreateGroup_ChannelsTooMuch: String { return self._s[3004]! } + public var Wallet_Sending_Text: String { return self._s[3005]! } + public func PUSH_CONTACT_JOINED(_ _1: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3006]!, self._r[3006]!, [_1]) + } + public var Login_CodeSentCall: String { return self._s[3007]! } + public var ContactInfo_PhoneLabelHomeFax: String { return self._s[3009]! } + public var ChatSettings_Appearance: String { return self._s[3010]! } + public var ClearCache_StorageUsage: String { return self._s[3011]! } + public var Appearance_PickAccentColor: String { return self._s[3012]! } public func PUSH_CHAT_MESSAGE_NOTEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3012]!, self._r[3012]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3013]!, self._r[3013]!, [_1, _2]) } public func PUSH_MESSAGE_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3013]!, self._r[3013]!, [_1]) + return formatWithArgumentRanges(self._s[3014]!, self._r[3014]!, [_1]) } - public var Notification_CallMissed: String { return self._s[3014]! } - public var SettingsSearch_Synonyms_Appearance_ChatBackground_Custom: String { return self._s[3015]! } - public var Channel_AdminLogFilter_EventsInfo: String { return self._s[3016]! } - public var Wallet_Month_GenOctober: String { return self._s[3018]! } - public var ChatAdmins_AdminLabel: String { return self._s[3019]! } - public var KeyCommand_JumpToNextChat: String { return self._s[3020]! } - public var Conversation_StopPollConfirmationTitle: String { return self._s[3022]! } - public var ChangePhoneNumberCode_CodePlaceholder: String { return self._s[3023]! } - public var Month_GenJune: String { return self._s[3024]! } - public var IntentsSettings_MainAccountInfo: String { return self._s[3025]! } - public var Watch_Location_Current: String { return self._s[3026]! } - public var Wallet_Receive_CopyInvoiceUrl: String { return self._s[3027]! } - public var Conversation_TitleMute: String { return self._s[3028]! } - public var Map_PlacesInThisArea: String { return self._s[3029]! } + public var Notification_CallMissed: String { return self._s[3015]! } + public var SettingsSearch_Synonyms_Appearance_ChatBackground_Custom: String { return self._s[3016]! } + public var Channel_AdminLogFilter_EventsInfo: String { return self._s[3017]! } + public var Wallet_Month_GenOctober: String { return self._s[3019]! } + public var ChatAdmins_AdminLabel: String { return self._s[3020]! } + public var KeyCommand_JumpToNextChat: String { return self._s[3021]! } + public var Conversation_StopPollConfirmationTitle: String { return self._s[3023]! } + public var ChangePhoneNumberCode_CodePlaceholder: String { return self._s[3024]! } + public var Month_GenJune: String { return self._s[3025]! } + public var IntentsSettings_MainAccountInfo: String { return self._s[3026]! } + public var Watch_Location_Current: String { return self._s[3027]! } + public var Wallet_Receive_CopyInvoiceUrl: String { return self._s[3028]! } + public var Conversation_TitleMute: String { return self._s[3029]! } + public var Map_PlacesInThisArea: String { return self._s[3030]! } public func PUSH_CHANNEL_MESSAGE_ROUND(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3030]!, self._r[3030]!, [_1]) + return formatWithArgumentRanges(self._s[3031]!, self._r[3031]!, [_1]) } - public var GroupInfo_DeleteAndExit: String { return self._s[3031]! } + public var GroupInfo_DeleteAndExit: String { return self._s[3032]! } public func Conversation_Moderate_DeleteAllMessages(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3032]!, self._r[3032]!, [_0]) + return formatWithArgumentRanges(self._s[3033]!, self._r[3033]!, [_0]) } - public var Call_ReportPlaceholder: String { return self._s[3033]! } - public var Chat_SlowmodeSendError: String { return self._s[3034]! } - public var MaskStickerSettings_Info: String { return self._s[3035]! } - public var EditTheme_Expand_TopInfo: String { return self._s[3036]! } + public var Call_ReportPlaceholder: String { return self._s[3034]! } + public var Chat_SlowmodeSendError: String { return self._s[3035]! } + public var MaskStickerSettings_Info: String { return self._s[3036]! } + public var EditTheme_Expand_TopInfo: String { return self._s[3037]! } public func GroupInfo_AddParticipantConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3037]!, self._r[3037]!, [_0]) + return formatWithArgumentRanges(self._s[3038]!, self._r[3038]!, [_0]) } - public var Checkout_NewCard_PostcodeTitle: String { return self._s[3038]! } - public var Passport_Address_RegionPlaceholder: String { return self._s[3040]! } - public var Contacts_ShareTelegram: String { return self._s[3041]! } - public var EnterPasscode_EnterNewPasscodeNew: String { return self._s[3042]! } - public var Map_AddressOnMap: String { return self._s[3043]! } - public var Channel_ErrorAccessDenied: String { return self._s[3044]! } - public var UserInfo_ScamBotWarning: String { return self._s[3046]! } - public var Stickers_GroupChooseStickerPack: String { return self._s[3047]! } - public var Call_ConnectionErrorTitle: String { return self._s[3048]! } - public var UserInfo_NotificationsEnable: String { return self._s[3049]! } - public var ArchivedChats_IntroText1: String { return self._s[3050]! } - public var Tour_Text4: String { return self._s[3053]! } - public var WallpaperSearch_Recent: String { return self._s[3054]! } - public var GroupInfo_ScamGroupWarning: String { return self._s[3055]! } - public var Profile_MessageLifetime2s: String { return self._s[3057]! } - public var Appearance_ThemePreview_ChatList_5_Text: String { return self._s[3058]! } - public var Notification_MessageLifetime2s: String { return self._s[3059]! } + public var Checkout_NewCard_PostcodeTitle: String { return self._s[3039]! } + public var Passport_Address_RegionPlaceholder: String { return self._s[3041]! } + public var Contacts_ShareTelegram: String { return self._s[3042]! } + public var EnterPasscode_EnterNewPasscodeNew: String { return self._s[3043]! } + public var Map_AddressOnMap: String { return self._s[3044]! } + public var Channel_ErrorAccessDenied: String { return self._s[3045]! } + public var UserInfo_ScamBotWarning: String { return self._s[3047]! } + public var Stickers_GroupChooseStickerPack: String { return self._s[3048]! } + public var Call_ConnectionErrorTitle: String { return self._s[3049]! } + public var UserInfo_NotificationsEnable: String { return self._s[3050]! } + public var ArchivedChats_IntroText1: String { return self._s[3051]! } + public var Tour_Text4: String { return self._s[3054]! } + public var WallpaperSearch_Recent: String { return self._s[3055]! } + public var GroupInfo_ScamGroupWarning: String { return self._s[3056]! } + public var Profile_MessageLifetime2s: String { return self._s[3058]! } + public var Appearance_ThemePreview_ChatList_5_Text: String { return self._s[3059]! } + public var Notification_MessageLifetime2s: String { return self._s[3060]! } public func Time_PreciseDate_m10(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3060]!, self._r[3060]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3061]!, self._r[3061]!, [_1, _2, _3]) } - public var Cache_ClearCache: String { return self._s[3061]! } - public var AutoNightTheme_UpdateLocation: String { return self._s[3062]! } - public var Permissions_NotificationsUnreachableText_v0: String { return self._s[3063]! } + public var Cache_ClearCache: String { return self._s[3062]! } + public var AutoNightTheme_UpdateLocation: String { return self._s[3063]! } + public var Permissions_NotificationsUnreachableText_v0: String { return self._s[3064]! } public func Channel_AdminLog_MessageChangedGroupUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3067]!, self._r[3067]!, [_0]) + return formatWithArgumentRanges(self._s[3068]!, self._r[3068]!, [_0]) } public func Conversation_ShareMyPhoneNumber_StatusSuccess(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3069]!, self._r[3069]!, [_0]) + return formatWithArgumentRanges(self._s[3070]!, self._r[3070]!, [_0]) } - public var LocalGroup_Text: String { return self._s[3070]! } - public var Channel_AdminLog_EmptyFilterTitle: String { return self._s[3071]! } - public var SocksProxySetup_TypeSocks: String { return self._s[3072]! } - public var ChatList_UnarchiveAction: String { return self._s[3073]! } - public var AutoNightTheme_Title: String { return self._s[3074]! } - public var InstantPage_FeedbackButton: String { return self._s[3075]! } - public var Passport_FieldAddress: String { return self._s[3076]! } + public var LocalGroup_Text: String { return self._s[3071]! } + public var Channel_AdminLog_EmptyFilterTitle: String { return self._s[3072]! } + public var SocksProxySetup_TypeSocks: String { return self._s[3073]! } + public var ChatList_UnarchiveAction: String { return self._s[3074]! } + public var AutoNightTheme_Title: String { return self._s[3075]! } + public var InstantPage_FeedbackButton: String { return self._s[3076]! } + public var Passport_FieldAddress: String { return self._s[3077]! } public func Channel_AdminLog_SetSlowmode(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3077]!, self._r[3077]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3078]!, self._r[3078]!, [_1, _2]) } - public var Month_ShortMarch: String { return self._s[3078]! } + public var Month_ShortMarch: String { return self._s[3079]! } public func PUSH_MESSAGE_INVOICE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3079]!, self._r[3079]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3080]!, self._r[3080]!, [_1, _2]) } - public var SocksProxySetup_UsernamePlaceholder: String { return self._s[3080]! } - public var Conversation_ShareInlineBotLocationConfirmation: String { return self._s[3081]! } - public var Passport_FloodError: String { return self._s[3082]! } - public var SecretGif_Title: String { return self._s[3083]! } - public var NotificationSettings_ShowNotificationsAllAccountsInfoOn: String { return self._s[3084]! } - public var ChatList_Context_UnhideArchive: String { return self._s[3085]! } - public var Passport_Language_th: String { return self._s[3087]! } - public var Passport_Address_Address: String { return self._s[3088]! } - public var Login_InvalidLastNameError: String { return self._s[3089]! } - public var Notifications_InAppNotificationsPreview: String { return self._s[3090]! } - public var Notifications_PermissionsUnreachableTitle: String { return self._s[3091]! } - public var ChatList_Context_Archive: String { return self._s[3092]! } - public var SettingsSearch_FAQ: String { return self._s[3093]! } - public var ShareMenu_Send: String { return self._s[3094]! } - public var WallpaperSearch_ColorYellow: String { return self._s[3096]! } - public var Month_GenNovember: String { return self._s[3098]! } - public var SettingsSearch_Synonyms_Appearance_LargeEmoji: String { return self._s[3100]! } + public var SocksProxySetup_UsernamePlaceholder: String { return self._s[3081]! } + public var Conversation_ShareInlineBotLocationConfirmation: String { return self._s[3082]! } + public var Passport_FloodError: String { return self._s[3083]! } + public var SecretGif_Title: String { return self._s[3084]! } + public var NotificationSettings_ShowNotificationsAllAccountsInfoOn: String { return self._s[3085]! } + public var ChatList_Context_UnhideArchive: String { return self._s[3086]! } + public var Passport_Language_th: String { return self._s[3088]! } + public var Passport_Address_Address: String { return self._s[3089]! } + public var Login_InvalidLastNameError: String { return self._s[3090]! } + public var Notifications_InAppNotificationsPreview: String { return self._s[3091]! } + public var Notifications_PermissionsUnreachableTitle: String { return self._s[3092]! } + public var ChatList_Context_Archive: String { return self._s[3093]! } + public var SettingsSearch_FAQ: String { return self._s[3094]! } + public var ShareMenu_Send: String { return self._s[3095]! } + public var WallpaperSearch_ColorYellow: String { return self._s[3097]! } + public var Month_GenNovember: String { return self._s[3099]! } + public var SettingsSearch_Synonyms_Appearance_LargeEmoji: String { return self._s[3101]! } public func Conversation_ShareMyPhoneNumberConfirmation(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3101]!, self._r[3101]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3102]!, self._r[3102]!, [_1, _2]) } - public var Conversation_SwipeToReplyHintText: String { return self._s[3102]! } - public var Checkout_Email: String { return self._s[3103]! } - public var NotificationsSound_Tritone: String { return self._s[3104]! } - public var StickerPacksSettings_ManagingHelp: String { return self._s[3106]! } - public var Wallet_ContextMenuCopy: String { return self._s[3108]! } + public var Conversation_SwipeToReplyHintText: String { return self._s[3103]! } + public var Checkout_Email: String { return self._s[3104]! } + public var NotificationsSound_Tritone: String { return self._s[3105]! } + public var StickerPacksSettings_ManagingHelp: String { return self._s[3107]! } + public var Wallet_ContextMenuCopy: String { return self._s[3109]! } public func Wallet_Time_PreciseDate_m6(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3110]!, self._r[3110]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3111]!, self._r[3111]!, [_1, _2, _3]) } - public var Appearance_TextSize_Automatic: String { return self._s[3111]! } + public var Appearance_TextSize_Automatic: String { return self._s[3112]! } public func PUSH_PINNED_ROUND(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3112]!, self._r[3112]!, [_1]) + return formatWithArgumentRanges(self._s[3113]!, self._r[3113]!, [_1]) } public func StickerPackActionInfo_AddedText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3113]!, self._r[3113]!, [_0]) + return formatWithArgumentRanges(self._s[3114]!, self._r[3114]!, [_0]) } - public var ChangePhoneNumberNumber_Help: String { return self._s[3114]! } + public var ChangePhoneNumberNumber_Help: String { return self._s[3115]! } public func Checkout_LiabilityAlert(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3115]!, self._r[3115]!, [_1, _1, _1, _2]) + return formatWithArgumentRanges(self._s[3116]!, self._r[3116]!, [_1, _1, _1, _2]) } - public var ChatList_UndoArchiveTitle: String { return self._s[3116]! } - public var Notification_Exceptions_Add: String { return self._s[3117]! } - public var DialogList_You: String { return self._s[3118]! } - public var MediaPicker_Send: String { return self._s[3121]! } - public var SettingsSearch_Synonyms_Stickers_Title: String { return self._s[3122]! } - public var Appearance_ThemePreview_ChatList_4_Text: String { return self._s[3123]! } - public var Call_AudioRouteSpeaker: String { return self._s[3124]! } - public var Watch_UserInfo_Title: String { return self._s[3125]! } - public var VoiceOver_Chat_PollFinalResults: String { return self._s[3126]! } - public var Appearance_AccentColor: String { return self._s[3128]! } + public var ChatList_UndoArchiveTitle: String { return self._s[3117]! } + public var Notification_Exceptions_Add: String { return self._s[3118]! } + public var DialogList_You: String { return self._s[3119]! } + public var MediaPicker_Send: String { return self._s[3122]! } + public var SettingsSearch_Synonyms_Stickers_Title: String { return self._s[3123]! } + public var Appearance_ThemePreview_ChatList_4_Text: String { return self._s[3124]! } + public var Call_AudioRouteSpeaker: String { return self._s[3125]! } + public var Watch_UserInfo_Title: String { return self._s[3126]! } + public var VoiceOver_Chat_PollFinalResults: String { return self._s[3127]! } + public var Appearance_AccentColor: String { return self._s[3129]! } public func Login_EmailPhoneSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3129]!, self._r[3129]!, [_0]) + return formatWithArgumentRanges(self._s[3130]!, self._r[3130]!, [_0]) } - public var Permissions_ContactsAllowInSettings_v0: String { return self._s[3130]! } + public var Permissions_ContactsAllowInSettings_v0: String { return self._s[3131]! } public func PUSH_CHANNEL_MESSAGE_GAME(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3131]!, self._r[3131]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3132]!, self._r[3132]!, [_1, _2]) } - public var Conversation_ClousStorageInfo_Description2: String { return self._s[3132]! } - public var WebSearch_RecentClearConfirmation: String { return self._s[3133]! } - public var Notification_CallOutgoing: String { return self._s[3134]! } - public var PrivacySettings_PasscodeAndFaceId: String { return self._s[3135]! } - public var Channel_DiscussionGroup_MakeHistoryPublic: String { return self._s[3136]! } - public var Call_RecordingDisabledMessage: String { return self._s[3137]! } - public var Message_Game: String { return self._s[3138]! } - public var Conversation_PressVolumeButtonForSound: String { return self._s[3139]! } - public var PrivacyLastSeenSettings_CustomHelp: String { return self._s[3140]! } - public var Channel_DiscussionGroup_PrivateGroup: String { return self._s[3141]! } - public var Channel_EditAdmin_PermissionAddAdmins: String { return self._s[3142]! } - public var Date_DialogDateFormat: String { return self._s[3144]! } - public var WallpaperColors_SetCustomColor: String { return self._s[3145]! } - public var Notifications_InAppNotifications: String { return self._s[3146]! } + public var Conversation_ClousStorageInfo_Description2: String { return self._s[3133]! } + public var WebSearch_RecentClearConfirmation: String { return self._s[3134]! } + public var Notification_CallOutgoing: String { return self._s[3135]! } + public var PrivacySettings_PasscodeAndFaceId: String { return self._s[3136]! } + public var Channel_DiscussionGroup_MakeHistoryPublic: String { return self._s[3137]! } + public var Call_RecordingDisabledMessage: String { return self._s[3138]! } + public var Message_Game: String { return self._s[3139]! } + public var Conversation_PressVolumeButtonForSound: String { return self._s[3140]! } + public var PrivacyLastSeenSettings_CustomHelp: String { return self._s[3141]! } + public var Channel_DiscussionGroup_PrivateGroup: String { return self._s[3142]! } + public var Channel_EditAdmin_PermissionAddAdmins: String { return self._s[3143]! } + public var Date_DialogDateFormat: String { return self._s[3145]! } + public var WallpaperColors_SetCustomColor: String { return self._s[3146]! } + public var Notifications_InAppNotifications: String { return self._s[3147]! } public func Channel_Management_RemovedBy(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3147]!, self._r[3147]!, [_0]) + return formatWithArgumentRanges(self._s[3148]!, self._r[3148]!, [_0]) } public func Settings_ApplyProxyAlert(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3148]!, self._r[3148]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3149]!, self._r[3149]!, [_1, _2]) } - public var NewContact_Title: String { return self._s[3149]! } + public var NewContact_Title: String { return self._s[3150]! } public func AutoDownloadSettings_UpToForAll(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3150]!, self._r[3150]!, [_0]) + return formatWithArgumentRanges(self._s[3151]!, self._r[3151]!, [_0]) } - public var Conversation_ViewContactDetails: String { return self._s[3151]! } + public var Conversation_ViewContactDetails: String { return self._s[3152]! } public func PUSH_CHANNEL_MESSAGE_CONTACT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3153]!, self._r[3153]!, [_1]) + return formatWithArgumentRanges(self._s[3154]!, self._r[3154]!, [_1]) } - public var Checkout_NewCard_CardholderNameTitle: String { return self._s[3154]! } - public var Passport_Identity_ExpiryDateNone: String { return self._s[3155]! } - public var PrivacySettings_Title: String { return self._s[3156]! } - public var Conversation_SilentBroadcastTooltipOff: String { return self._s[3159]! } - public var GroupRemoved_UsersSectionTitle: String { return self._s[3160]! } - public var VoiceOver_Chat_ContactEmail: String { return self._s[3161]! } - public var Contacts_PhoneNumber: String { return self._s[3162]! } - public var TwoFactorSetup_Password_PlaceholderConfirmPassword: String { return self._s[3164]! } - public var Map_ShowPlaces: String { return self._s[3165]! } - public var ChatAdmins_Title: String { return self._s[3166]! } - public var InstantPage_Reference: String { return self._s[3168]! } - public var Wallet_Info_Updating: String { return self._s[3169]! } - public var ReportGroupLocation_Text: String { return self._s[3170]! } + public var Checkout_NewCard_CardholderNameTitle: String { return self._s[3155]! } + public var Passport_Identity_ExpiryDateNone: String { return self._s[3156]! } + public var PrivacySettings_Title: String { return self._s[3157]! } + public var Conversation_SilentBroadcastTooltipOff: String { return self._s[3160]! } + public var GroupRemoved_UsersSectionTitle: String { return self._s[3161]! } + public var VoiceOver_Chat_ContactEmail: String { return self._s[3162]! } + public var Contacts_PhoneNumber: String { return self._s[3163]! } + public var TwoFactorSetup_Password_PlaceholderConfirmPassword: String { return self._s[3165]! } + public var Map_ShowPlaces: String { return self._s[3166]! } + public var ChatAdmins_Title: String { return self._s[3167]! } + public var InstantPage_Reference: String { return self._s[3169]! } + public var Wallet_Info_Updating: String { return self._s[3170]! } + public var ReportGroupLocation_Text: String { return self._s[3171]! } public func PUSH_CHAT_MESSAGE_FWD(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3171]!, self._r[3171]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3172]!, self._r[3172]!, [_1, _2]) } - public var Camera_FlashOff: String { return self._s[3172]! } - public var Watch_UserInfo_Block: String { return self._s[3173]! } - public var ChatSettings_Stickers: String { return self._s[3174]! } - public var ChatSettings_DownloadInBackground: String { return self._s[3175]! } - public var Appearance_ThemeCarouselTintedNight: String { return self._s[3176]! } + public var Camera_FlashOff: String { return self._s[3173]! } + public var Watch_UserInfo_Block: String { return self._s[3174]! } + public var ChatSettings_Stickers: String { return self._s[3175]! } + public var ChatSettings_DownloadInBackground: String { return self._s[3176]! } + public var Appearance_ThemeCarouselTintedNight: String { return self._s[3177]! } public func UserInfo_BlockConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3177]!, self._r[3177]!, [_0]) + return formatWithArgumentRanges(self._s[3178]!, self._r[3178]!, [_0]) } - public var Settings_ViewPhoto: String { return self._s[3178]! } - public var Login_CheckOtherSessionMessages: String { return self._s[3179]! } - public var AutoDownloadSettings_Cellular: String { return self._s[3180]! } - public var Wallet_Created_ExportErrorTitle: String { return self._s[3181]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsExceptions: String { return self._s[3182]! } - public var VoiceOver_MessageContextShare: String { return self._s[3183]! } + public var Settings_ViewPhoto: String { return self._s[3179]! } + public var Login_CheckOtherSessionMessages: String { return self._s[3180]! } + public var AutoDownloadSettings_Cellular: String { return self._s[3181]! } + public var Wallet_Created_ExportErrorTitle: String { return self._s[3182]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsExceptions: String { return self._s[3183]! } + public var VoiceOver_MessageContextShare: String { return self._s[3184]! } public func Target_InviteToGroupConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3185]!, self._r[3185]!, [_0]) + return formatWithArgumentRanges(self._s[3186]!, self._r[3186]!, [_0]) } - public var Privacy_DeleteDrafts: String { return self._s[3186]! } - public var Wallpaper_SetCustomBackgroundInfo: String { return self._s[3187]! } + public var Privacy_DeleteDrafts: String { return self._s[3187]! } + public var Wallpaper_SetCustomBackgroundInfo: String { return self._s[3188]! } public func LastSeen_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3188]!, self._r[3188]!, [_0]) + return formatWithArgumentRanges(self._s[3189]!, self._r[3189]!, [_0]) } - public var DialogList_SavedMessagesHelp: String { return self._s[3189]! } - public var Wallet_SecureStorageNotAvailable_Title: String { return self._s[3190]! } - public var DialogList_SavedMessages: String { return self._s[3191]! } - public var GroupInfo_UpgradeButton: String { return self._s[3192]! } - public var Appearance_ThemePreview_ChatList_3_Text: String { return self._s[3194]! } - public var DialogList_Pin: String { return self._s[3195]! } + public var DialogList_SavedMessagesHelp: String { return self._s[3190]! } + public var Wallet_SecureStorageNotAvailable_Title: String { return self._s[3191]! } + public var DialogList_SavedMessages: String { return self._s[3192]! } + public var GroupInfo_UpgradeButton: String { return self._s[3193]! } + public var Appearance_ThemePreview_ChatList_3_Text: String { return self._s[3195]! } + public var DialogList_Pin: String { return self._s[3196]! } public func ForwardedAuthors2(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3196]!, self._r[3196]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3197]!, self._r[3197]!, [_0, _1]) } public func Login_PhoneGenericEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3197]!, self._r[3197]!, [_0]) + return formatWithArgumentRanges(self._s[3198]!, self._r[3198]!, [_0]) } - public var Notification_Exceptions_AlwaysOn: String { return self._s[3198]! } - public var UserInfo_NotificationsDisable: String { return self._s[3199]! } - public var Conversation_ContextMenuCancelEditing: String { return self._s[3200]! } - public var Paint_Outlined: String { return self._s[3201]! } - public var Activity_PlayingGame: String { return self._s[3202]! } - public var SearchImages_NoImagesFound: String { return self._s[3203]! } - public var SocksProxySetup_ProxyType: String { return self._s[3204]! } - public var AppleWatch_ReplyPresetsHelp: String { return self._s[3206]! } - public var Conversation_ContextMenuCancelSending: String { return self._s[3207]! } - public var Settings_AppLanguage: String { return self._s[3208]! } - public var TwoStepAuth_ResetAccountHelp: String { return self._s[3209]! } - public var Common_ChoosePhoto: String { return self._s[3210]! } - public var AuthSessions_AddDevice_InvalidQRCode: String { return self._s[3211]! } - public var CallFeedback_ReasonEcho: String { return self._s[3212]! } + public var Notification_Exceptions_AlwaysOn: String { return self._s[3199]! } + public var UserInfo_NotificationsDisable: String { return self._s[3200]! } + public var Conversation_ContextMenuCancelEditing: String { return self._s[3201]! } + public var Paint_Outlined: String { return self._s[3202]! } + public var Activity_PlayingGame: String { return self._s[3203]! } + public var SearchImages_NoImagesFound: String { return self._s[3204]! } + public var SocksProxySetup_ProxyType: String { return self._s[3205]! } + public var AppleWatch_ReplyPresetsHelp: String { return self._s[3207]! } + public var Conversation_ContextMenuCancelSending: String { return self._s[3208]! } + public var Settings_AppLanguage: String { return self._s[3209]! } + public var TwoStepAuth_ResetAccountHelp: String { return self._s[3210]! } + public var Common_ChoosePhoto: String { return self._s[3211]! } + public var AuthSessions_AddDevice_InvalidQRCode: String { return self._s[3212]! } + public var CallFeedback_ReasonEcho: String { return self._s[3213]! } public func PUSH_PINNED_AUDIO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3213]!, self._r[3213]!, [_1]) + return formatWithArgumentRanges(self._s[3214]!, self._r[3214]!, [_1]) } - public var Privacy_Calls_AlwaysAllow: String { return self._s[3214]! } - public var PollResults_Collapse: String { return self._s[3215]! } - public var Activity_UploadingVideo: String { return self._s[3216]! } - public var Conversation_WalletRequiredNotNow: String { return self._s[3217]! } - public var ChannelInfo_DeleteChannelConfirmation: String { return self._s[3218]! } - public var NetworkUsageSettings_Wifi: String { return self._s[3219]! } - public var VoiceOver_Editing_ClearText: String { return self._s[3220]! } - public var PUSH_SENDER_YOU: String { return self._s[3221]! } - public var Channel_BanUser_PermissionReadMessages: String { return self._s[3222]! } - public var Checkout_PayWithTouchId: String { return self._s[3223]! } - public var Wallpaper_ResetWallpapersConfirmation: String { return self._s[3224]! } + public var Privacy_Calls_AlwaysAllow: String { return self._s[3215]! } + public var PollResults_Collapse: String { return self._s[3216]! } + public var Activity_UploadingVideo: String { return self._s[3217]! } + public var Conversation_WalletRequiredNotNow: String { return self._s[3218]! } + public var ChannelInfo_DeleteChannelConfirmation: String { return self._s[3219]! } + public var NetworkUsageSettings_Wifi: String { return self._s[3220]! } + public var VoiceOver_Editing_ClearText: String { return self._s[3221]! } + public var PUSH_SENDER_YOU: String { return self._s[3222]! } + public var Channel_BanUser_PermissionReadMessages: String { return self._s[3223]! } + public var Checkout_PayWithTouchId: String { return self._s[3224]! } + public var Wallpaper_ResetWallpapersConfirmation: String { return self._s[3225]! } public func PUSH_LOCKED_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3226]!, self._r[3226]!, [_1]) + return formatWithArgumentRanges(self._s[3227]!, self._r[3227]!, [_1]) } - public var Notifications_ExceptionsNone: String { return self._s[3227]! } + public var Notifications_ExceptionsNone: String { return self._s[3228]! } public func Message_ForwardedMessageShort(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3228]!, self._r[3228]!, [_0]) + return formatWithArgumentRanges(self._s[3229]!, self._r[3229]!, [_0]) } public func PUSH_PINNED_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3229]!, self._r[3229]!, [_1]) + return formatWithArgumentRanges(self._s[3230]!, self._r[3230]!, [_1]) } - public var AuthSessions_IncompleteAttempts: String { return self._s[3231]! } - public var Passport_Address_Region: String { return self._s[3234]! } - public var ChatList_DeleteChat: String { return self._s[3235]! } - public var LogoutOptions_ClearCacheTitle: String { return self._s[3236]! } - public var PhotoEditor_TiltShift: String { return self._s[3237]! } - public var Settings_FAQ_URL: String { return self._s[3238]! } - public var TwoFactorSetup_EmailVerification_ChangeAction: String { return self._s[3239]! } - public var Passport_Language_sl: String { return self._s[3240]! } - public var Settings_PrivacySettings: String { return self._s[3242]! } - public var SharedMedia_TitleLink: String { return self._s[3243]! } - public var Passport_Identity_TypePassportUploadScan: String { return self._s[3244]! } - public var Settings_SetProfilePhoto: String { return self._s[3245]! } - public var Channel_About_Help: String { return self._s[3246]! } - public var Contacts_PermissionsEnable: String { return self._s[3247]! } - public var Wallet_Sending_Title: String { return self._s[3248]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsAlert: String { return self._s[3249]! } - public var AttachmentMenu_SendAsFiles: String { return self._s[3250]! } - public var CallFeedback_ReasonInterruption: String { return self._s[3252]! } - public var Passport_Address_AddTemporaryRegistration: String { return self._s[3253]! } - public var AutoDownloadSettings_AutodownloadVideos: String { return self._s[3254]! } - public var ChatSettings_AutoDownloadSettings_Delimeter: String { return self._s[3255]! } - public var OldChannels_Title: String { return self._s[3256]! } - public var PrivacySettings_DeleteAccountTitle: String { return self._s[3257]! } - public var AccessDenied_VideoMessageCamera: String { return self._s[3259]! } - public var Map_OpenInYandexMaps: String { return self._s[3261]! } - public var CreateGroup_ErrorLocatedGroupsTooMuch: String { return self._s[3262]! } - public var VoiceOver_MessageContextReply: String { return self._s[3263]! } - public var PhotoEditor_SaturationTool: String { return self._s[3265]! } + public var AuthSessions_IncompleteAttempts: String { return self._s[3232]! } + public var Passport_Address_Region: String { return self._s[3235]! } + public var ChatList_DeleteChat: String { return self._s[3236]! } + public var LogoutOptions_ClearCacheTitle: String { return self._s[3237]! } + public var PhotoEditor_TiltShift: String { return self._s[3238]! } + public var Settings_FAQ_URL: String { return self._s[3239]! } + public var TwoFactorSetup_EmailVerification_ChangeAction: String { return self._s[3240]! } + public var Passport_Language_sl: String { return self._s[3241]! } + public var Settings_PrivacySettings: String { return self._s[3243]! } + public var SharedMedia_TitleLink: String { return self._s[3244]! } + public var Passport_Identity_TypePassportUploadScan: String { return self._s[3245]! } + public var Settings_SetProfilePhoto: String { return self._s[3246]! } + public var Channel_About_Help: String { return self._s[3247]! } + public var Contacts_PermissionsEnable: String { return self._s[3248]! } + public var Wallet_Sending_Title: String { return self._s[3249]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsAlert: String { return self._s[3250]! } + public var AttachmentMenu_SendAsFiles: String { return self._s[3251]! } + public var CallFeedback_ReasonInterruption: String { return self._s[3253]! } + public var Passport_Address_AddTemporaryRegistration: String { return self._s[3254]! } + public var AutoDownloadSettings_AutodownloadVideos: String { return self._s[3255]! } + public var ChatSettings_AutoDownloadSettings_Delimeter: String { return self._s[3256]! } + public var OldChannels_Title: String { return self._s[3257]! } + public var PrivacySettings_DeleteAccountTitle: String { return self._s[3258]! } + public var AccessDenied_VideoMessageCamera: String { return self._s[3260]! } + public var Map_OpenInYandexMaps: String { return self._s[3262]! } + public var CreateGroup_ErrorLocatedGroupsTooMuch: String { return self._s[3263]! } + public var VoiceOver_MessageContextReply: String { return self._s[3264]! } + public var PhotoEditor_SaturationTool: String { return self._s[3266]! } public func PUSH_MESSAGE_STICKER(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3266]!, self._r[3266]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3267]!, self._r[3267]!, [_1, _2]) } - public var PrivacyPhoneNumberSettings_CustomHelp: String { return self._s[3267]! } - public var Notification_Exceptions_NewException_NotificationHeader: String { return self._s[3268]! } - public var Group_OwnershipTransfer_ErrorLocatedGroupsTooMuch: String { return self._s[3269]! } + public var PrivacyPhoneNumberSettings_CustomHelp: String { return self._s[3268]! } + public var Notification_Exceptions_NewException_NotificationHeader: String { return self._s[3269]! } + public var Group_OwnershipTransfer_ErrorLocatedGroupsTooMuch: String { return self._s[3270]! } public func LOCAL_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3270]!, self._r[3270]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[3271]!, self._r[3271]!, [_1, "\(_2)"]) } - public var Appearance_ThemePreview_ChatList_2_Text: String { return self._s[3271]! } - public var Channel_Username_InvalidTooShort: String { return self._s[3273]! } - public var SettingsSearch_Synonyms_Wallet: String { return self._s[3274]! } + public var Appearance_ThemePreview_ChatList_2_Text: String { return self._s[3272]! } + public var Channel_Username_InvalidTooShort: String { return self._s[3274]! } + public var SettingsSearch_Synonyms_Wallet: String { return self._s[3275]! } public func Group_OwnershipTransfer_DescriptionInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3275]!, self._r[3275]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3276]!, self._r[3276]!, [_1, _2]) } - public var Forward_ErrorPublicPollDisabledInChannels: String { return self._s[3276]! } + public var Forward_ErrorPublicPollDisabledInChannels: String { return self._s[3277]! } public func PUSH_CHAT_MESSAGE_GAME(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3277]!, self._r[3277]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3278]!, self._r[3278]!, [_1, _2, _3]) } - public var WallpaperPreview_PatternTitle: String { return self._s[3278]! } - public var GroupInfo_PublicLinkAdd: String { return self._s[3279]! } - public var Passport_PassportInformation: String { return self._s[3282]! } - public var Theme_Unsupported: String { return self._s[3283]! } - public var WatchRemote_AlertTitle: String { return self._s[3284]! } - public var Privacy_GroupsAndChannels_NeverAllow: String { return self._s[3285]! } - public var ConvertToSupergroup_HelpText: String { return self._s[3287]! } + public var WallpaperPreview_PatternTitle: String { return self._s[3279]! } + public var GroupInfo_PublicLinkAdd: String { return self._s[3280]! } + public var Passport_PassportInformation: String { return self._s[3283]! } + public var Theme_Unsupported: String { return self._s[3284]! } + public var WatchRemote_AlertTitle: String { return self._s[3285]! } + public var Privacy_GroupsAndChannels_NeverAllow: String { return self._s[3286]! } + public var ConvertToSupergroup_HelpText: String { return self._s[3288]! } public func Time_MonthOfYear_m7(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3288]!, self._r[3288]!, [_0]) + return formatWithArgumentRanges(self._s[3289]!, self._r[3289]!, [_0]) } public func PUSH_PHONE_CALL_REQUEST(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3289]!, self._r[3289]!, [_1]) + return formatWithArgumentRanges(self._s[3290]!, self._r[3290]!, [_1]) } - public var Privacy_GroupsAndChannels_CustomHelp: String { return self._s[3290]! } - public var Wallet_Navigation_Done: String { return self._s[3292]! } - public var TwoStepAuth_RecoveryCodeInvalid: String { return self._s[3293]! } - public var AccessDenied_CameraDisabled: String { return self._s[3294]! } + public var Privacy_GroupsAndChannels_CustomHelp: String { return self._s[3291]! } + public var Wallet_Navigation_Done: String { return self._s[3293]! } + public var TwoStepAuth_RecoveryCodeInvalid: String { return self._s[3294]! } + public var AccessDenied_CameraDisabled: String { return self._s[3295]! } public func Channel_Username_UsernameIsAvailable(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3295]!, self._r[3295]!, [_0]) + return formatWithArgumentRanges(self._s[3296]!, self._r[3296]!, [_0]) } - public var ClearCache_Forever: String { return self._s[3296]! } - public var AuthSessions_AddDeviceIntro_Title: String { return self._s[3297]! } - public var CreatePoll_Quiz: String { return self._s[3298]! } - public var PhotoEditor_ContrastTool: String { return self._s[3301]! } + public var ClearCache_Forever: String { return self._s[3297]! } + public var AuthSessions_AddDeviceIntro_Title: String { return self._s[3298]! } + public var CreatePoll_Quiz: String { return self._s[3299]! } + public var PhotoEditor_ContrastTool: String { return self._s[3302]! } public func PUSH_PINNED_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3302]!, self._r[3302]!, [_1]) + return formatWithArgumentRanges(self._s[3303]!, self._r[3303]!, [_1]) } - public var DialogList_Draft: String { return self._s[3303]! } - public var Wallet_Configuration_BlockchainIdInfo: String { return self._s[3304]! } - public var Privacy_TopPeersDelete: String { return self._s[3306]! } - public var LoginPassword_PasswordPlaceholder: String { return self._s[3307]! } - public var Passport_Identity_TypeIdentityCardUploadScan: String { return self._s[3308]! } - public var WebSearch_RecentSectionClear: String { return self._s[3309]! } - public var EditTheme_ErrorInvalidCharacters: String { return self._s[3310]! } - public var Watch_ChatList_NoConversationsTitle: String { return self._s[3312]! } - public var Common_Done: String { return self._s[3314]! } - public var Shortcut_SwitchAccount: String { return self._s[3315]! } - public var AuthSessions_EmptyText: String { return self._s[3316]! } - public var Wallet_Configuration_BlockchainNameChangedTitle: String { return self._s[3317]! } - public var Conversation_ShareBotContactConfirmation: String { return self._s[3318]! } - public var Tour_Title5: String { return self._s[3319]! } - public var Wallet_Settings_Title: String { return self._s[3320]! } + public var DialogList_Draft: String { return self._s[3304]! } + public var Wallet_Configuration_BlockchainIdInfo: String { return self._s[3305]! } + public var Privacy_TopPeersDelete: String { return self._s[3307]! } + public var LoginPassword_PasswordPlaceholder: String { return self._s[3308]! } + public var Passport_Identity_TypeIdentityCardUploadScan: String { return self._s[3309]! } + public var WebSearch_RecentSectionClear: String { return self._s[3310]! } + public var EditTheme_ErrorInvalidCharacters: String { return self._s[3311]! } + public var Watch_ChatList_NoConversationsTitle: String { return self._s[3313]! } + public var Common_Done: String { return self._s[3315]! } + public var Shortcut_SwitchAccount: String { return self._s[3316]! } + public var AuthSessions_EmptyText: String { return self._s[3317]! } + public var Wallet_Configuration_BlockchainNameChangedTitle: String { return self._s[3318]! } + public var Conversation_ShareBotContactConfirmation: String { return self._s[3319]! } + public var Tour_Title5: String { return self._s[3320]! } + public var Wallet_Settings_Title: String { return self._s[3321]! } public func Map_DirectionsDriveEta(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3321]!, self._r[3321]!, [_0]) + return formatWithArgumentRanges(self._s[3322]!, self._r[3322]!, [_0]) } - public var ApplyLanguage_UnsufficientDataTitle: String { return self._s[3322]! } - public var Conversation_LinkDialogSave: String { return self._s[3323]! } - public var GroupInfo_ActionRestrict: String { return self._s[3324]! } - public var Checkout_Title: String { return self._s[3325]! } - public var Channel_DiscussionGroup_HeaderLabel: String { return self._s[3327]! } - public var Channel_AdminLog_CanChangeInfo: String { return self._s[3329]! } - public var Notification_RenamedGroup: String { return self._s[3330]! } - public var PeopleNearby_Groups: String { return self._s[3331]! } - public var Checkout_PayWithFaceId: String { return self._s[3332]! } - public var Channel_BanList_BlockedTitle: String { return self._s[3333]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsSound: String { return self._s[3335]! } - public var Checkout_WebConfirmation_Title: String { return self._s[3336]! } - public var Notifications_MessageNotificationsAlert: String { return self._s[3337]! } + public var ApplyLanguage_UnsufficientDataTitle: String { return self._s[3323]! } + public var Conversation_LinkDialogSave: String { return self._s[3324]! } + public var GroupInfo_ActionRestrict: String { return self._s[3325]! } + public var Checkout_Title: String { return self._s[3326]! } + public var Channel_DiscussionGroup_HeaderLabel: String { return self._s[3328]! } + public var Channel_AdminLog_CanChangeInfo: String { return self._s[3330]! } + public var Notification_RenamedGroup: String { return self._s[3331]! } + public var PeopleNearby_Groups: String { return self._s[3332]! } + public var Checkout_PayWithFaceId: String { return self._s[3333]! } + public var Channel_BanList_BlockedTitle: String { return self._s[3334]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsSound: String { return self._s[3336]! } + public var Checkout_WebConfirmation_Title: String { return self._s[3337]! } + public var Notifications_MessageNotificationsAlert: String { return self._s[3338]! } public func Activity_RemindAboutGroup(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3338]!, self._r[3338]!, [_0]) + return formatWithArgumentRanges(self._s[3339]!, self._r[3339]!, [_0]) } - public var Profile_AddToExisting: String { return self._s[3340]! } + public var Profile_AddToExisting: String { return self._s[3341]! } public func Profile_CreateEncryptedChatOutdatedError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3341]!, self._r[3341]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3342]!, self._r[3342]!, [_0, _1]) } - public var Cache_Files: String { return self._s[3343]! } - public var Permissions_PrivacyPolicy: String { return self._s[3344]! } - public var SocksProxySetup_ConnectAndSave: String { return self._s[3345]! } - public var UserInfo_NotificationsDefaultDisabled: String { return self._s[3346]! } - public var AutoDownloadSettings_TypeContacts: String { return self._s[3348]! } - public var Appearance_ThemePreview_ChatList_1_Text: String { return self._s[3350]! } - public var Calls_NoCallsPlaceholder: String { return self._s[3351]! } + public var Cache_Files: String { return self._s[3344]! } + public var Permissions_PrivacyPolicy: String { return self._s[3345]! } + public var SocksProxySetup_ConnectAndSave: String { return self._s[3346]! } + public var UserInfo_NotificationsDefaultDisabled: String { return self._s[3347]! } + public var AutoDownloadSettings_TypeContacts: String { return self._s[3349]! } + public var Appearance_ThemePreview_ChatList_1_Text: String { return self._s[3351]! } + public var Calls_NoCallsPlaceholder: String { return self._s[3352]! } public func Wallet_Receive_ShareInvoiceUrlInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3352]!, self._r[3352]!, [_0]) + return formatWithArgumentRanges(self._s[3353]!, self._r[3353]!, [_0]) } - public var Channel_Username_RevokeExistingUsernamesInfo: String { return self._s[3353]! } - public var VoiceOver_AttachMedia: String { return self._s[3356]! } - public var Notifications_ExceptionsGroupPlaceholder: String { return self._s[3357]! } + public var Channel_Username_RevokeExistingUsernamesInfo: String { return self._s[3354]! } + public var VoiceOver_AttachMedia: String { return self._s[3357]! } + public var Notifications_ExceptionsGroupPlaceholder: String { return self._s[3358]! } public func PUSH_CHAT_MESSAGE_INVOICE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3358]!, self._r[3358]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3359]!, self._r[3359]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsSound: String { return self._s[3359]! } - public var Conversation_SetReminder_Title: String { return self._s[3360]! } - public var Passport_FieldAddressHelp: String { return self._s[3361]! } - public var Privacy_GroupsAndChannels_InviteToChannelMultipleError: String { return self._s[3362]! } - public var PUSH_REMINDER_TITLE: String { return self._s[3363]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsSound: String { return self._s[3360]! } + public var Conversation_SetReminder_Title: String { return self._s[3361]! } + public var Passport_FieldAddressHelp: String { return self._s[3362]! } + public var Privacy_GroupsAndChannels_InviteToChannelMultipleError: String { return self._s[3363]! } + public var PUSH_REMINDER_TITLE: String { return self._s[3364]! } public func Login_TermsOfService_ProceedBot(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3364]!, self._r[3364]!, [_0]) + return formatWithArgumentRanges(self._s[3365]!, self._r[3365]!, [_0]) } - public var Channel_AdminLog_EmptyTitle: String { return self._s[3365]! } - public var Privacy_Calls_NeverAllow_Title: String { return self._s[3366]! } - public var Login_UnknownError: String { return self._s[3367]! } - public var Group_UpgradeNoticeText2: String { return self._s[3370]! } - public var Watch_Compose_AddContact: String { return self._s[3371]! } - public var ClearCache_StorageServiceFiles: String { return self._s[3372]! } - public var Web_Error: String { return self._s[3373]! } - public var Gif_Search: String { return self._s[3374]! } - public var Profile_MessageLifetime1h: String { return self._s[3375]! } - public var CheckoutInfo_ReceiverInfoEmailPlaceholder: String { return self._s[3376]! } - public var Channel_Username_CheckingUsername: String { return self._s[3377]! } - public var CallFeedback_ReasonSilentRemote: String { return self._s[3378]! } - public var AutoDownloadSettings_TypeChannels: String { return self._s[3379]! } - public var Channel_AboutItem: String { return self._s[3380]! } - public var Privacy_GroupsAndChannels_AlwaysAllow_Placeholder: String { return self._s[3382]! } - public var VoiceOver_Chat_VoiceMessage: String { return self._s[3383]! } - public var GroupInfo_SharedMedia: String { return self._s[3384]! } + public var Channel_AdminLog_EmptyTitle: String { return self._s[3366]! } + public var Privacy_Calls_NeverAllow_Title: String { return self._s[3367]! } + public var Login_UnknownError: String { return self._s[3368]! } + public var Group_UpgradeNoticeText2: String { return self._s[3371]! } + public var Watch_Compose_AddContact: String { return self._s[3372]! } + public var ClearCache_StorageServiceFiles: String { return self._s[3373]! } + public var Web_Error: String { return self._s[3374]! } + public var Gif_Search: String { return self._s[3375]! } + public var Profile_MessageLifetime1h: String { return self._s[3376]! } + public var CheckoutInfo_ReceiverInfoEmailPlaceholder: String { return self._s[3377]! } + public var Channel_Username_CheckingUsername: String { return self._s[3378]! } + public var CallFeedback_ReasonSilentRemote: String { return self._s[3379]! } + public var AutoDownloadSettings_TypeChannels: String { return self._s[3380]! } + public var Channel_AboutItem: String { return self._s[3381]! } + public var Privacy_GroupsAndChannels_AlwaysAllow_Placeholder: String { return self._s[3383]! } + public var VoiceOver_Chat_VoiceMessage: String { return self._s[3384]! } + public var GroupInfo_SharedMedia: String { return self._s[3385]! } public func Channel_AdminLog_MessagePromotedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3385]!, self._r[3385]!, [_1]) + return formatWithArgumentRanges(self._s[3386]!, self._r[3386]!, [_1]) } - public var Call_PhoneCallInProgressMessage: String { return self._s[3386]! } + public var Call_PhoneCallInProgressMessage: String { return self._s[3387]! } public func PUSH_CHANNEL_ALBUM(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3387]!, self._r[3387]!, [_1]) + return formatWithArgumentRanges(self._s[3388]!, self._r[3388]!, [_1]) } - public var ChatList_UndoArchiveRevealedText: String { return self._s[3388]! } - public var GroupInfo_InviteLink_RevokeAlert_Text: String { return self._s[3389]! } - public var Conversation_SearchByName_Placeholder: String { return self._s[3390]! } - public var CreatePoll_AddOption: String { return self._s[3391]! } - public var GroupInfo_Permissions_SearchPlaceholder: String { return self._s[3392]! } - public var Group_UpgradeNoticeHeader: String { return self._s[3393]! } - public var Channel_Management_AddModerator: String { return self._s[3394]! } - public var AutoDownloadSettings_MaxFileSize: String { return self._s[3395]! } - public var StickerPacksSettings_ShowStickersButton: String { return self._s[3396]! } - public var Wallet_Info_RefreshErrorNetworkText: String { return self._s[3397]! } - public var Theme_Colors_Background: String { return self._s[3398]! } - public var NotificationsSound_Hello: String { return self._s[3400]! } - public var SocksProxySetup_SavedProxies: String { return self._s[3401]! } - public var Channel_Stickers_Placeholder: String { return self._s[3403]! } + public var ChatList_UndoArchiveRevealedText: String { return self._s[3389]! } + public var GroupInfo_InviteLink_RevokeAlert_Text: String { return self._s[3390]! } + public var Conversation_SearchByName_Placeholder: String { return self._s[3391]! } + public var CreatePoll_AddOption: String { return self._s[3392]! } + public var GroupInfo_Permissions_SearchPlaceholder: String { return self._s[3393]! } + public var Group_UpgradeNoticeHeader: String { return self._s[3394]! } + public var Channel_Management_AddModerator: String { return self._s[3395]! } + public var AutoDownloadSettings_MaxFileSize: String { return self._s[3396]! } + public var StickerPacksSettings_ShowStickersButton: String { return self._s[3397]! } + public var Wallet_Info_RefreshErrorNetworkText: String { return self._s[3398]! } + public var Theme_Colors_Background: String { return self._s[3399]! } + public var NotificationsSound_Hello: String { return self._s[3401]! } + public var SocksProxySetup_SavedProxies: String { return self._s[3402]! } + public var Channel_Stickers_Placeholder: String { return self._s[3404]! } public func Login_EmailCodeBody(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3404]!, self._r[3404]!, [_0]) + return formatWithArgumentRanges(self._s[3405]!, self._r[3405]!, [_0]) } - public var PrivacyPolicy_DeclineDeclineAndDelete: String { return self._s[3405]! } - public var Channel_Management_AddModeratorHelp: String { return self._s[3406]! } - public var ContactInfo_BirthdayLabel: String { return self._s[3407]! } - public var ChangePhoneNumberCode_RequestingACall: String { return self._s[3408]! } - public var AutoDownloadSettings_Channels: String { return self._s[3409]! } - public var Passport_Language_mn: String { return self._s[3410]! } - public var Notifications_ResetAllNotificationsHelp: String { return self._s[3413]! } - public var GroupInfo_Permissions_SlowmodeValue_Off: String { return self._s[3414]! } - public var Passport_Language_ja: String { return self._s[3416]! } - public var Settings_About_Title: String { return self._s[3417]! } - public var Settings_NotificationsAndSounds: String { return self._s[3418]! } - public var ChannelInfo_DeleteGroup: String { return self._s[3419]! } - public var Settings_BlockedUsers: String { return self._s[3420]! } + public var PrivacyPolicy_DeclineDeclineAndDelete: String { return self._s[3406]! } + public var Channel_Management_AddModeratorHelp: String { return self._s[3407]! } + public var ContactInfo_BirthdayLabel: String { return self._s[3408]! } + public var ChangePhoneNumberCode_RequestingACall: String { return self._s[3409]! } + public var AutoDownloadSettings_Channels: String { return self._s[3410]! } + public var Passport_Language_mn: String { return self._s[3411]! } + public var Notifications_ResetAllNotificationsHelp: String { return self._s[3414]! } + public var GroupInfo_Permissions_SlowmodeValue_Off: String { return self._s[3415]! } + public var Passport_Language_ja: String { return self._s[3417]! } + public var Settings_About_Title: String { return self._s[3418]! } + public var Settings_NotificationsAndSounds: String { return self._s[3419]! } + public var ChannelInfo_DeleteGroup: String { return self._s[3420]! } + public var Settings_BlockedUsers: String { return self._s[3421]! } public func Time_MonthOfYear_m4(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3421]!, self._r[3421]!, [_0]) + return formatWithArgumentRanges(self._s[3422]!, self._r[3422]!, [_0]) } - public var EditTheme_Create_Preview_OutgoingText: String { return self._s[3422]! } - public var Wallet_Weekday_Today: String { return self._s[3423]! } - public var AutoDownloadSettings_PreloadVideo: String { return self._s[3424]! } - public var Widget_ApplicationLocked: String { return self._s[3425]! } - public var Passport_Address_AddResidentialAddress: String { return self._s[3426]! } - public var Channel_Username_Title: String { return self._s[3427]! } + public var EditTheme_Create_Preview_OutgoingText: String { return self._s[3423]! } + public var Wallet_Weekday_Today: String { return self._s[3424]! } + public var AutoDownloadSettings_PreloadVideo: String { return self._s[3425]! } + public var Widget_ApplicationLocked: String { return self._s[3426]! } + public var Passport_Address_AddResidentialAddress: String { return self._s[3427]! } + public var Channel_Username_Title: String { return self._s[3428]! } public func Notification_RemovedGroupPhoto(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3428]!, self._r[3428]!, [_0]) + return formatWithArgumentRanges(self._s[3429]!, self._r[3429]!, [_0]) } - public var AttachmentMenu_File: String { return self._s[3430]! } - public var AppleWatch_Title: String { return self._s[3431]! } - public var Activity_RecordingVideoMessage: String { return self._s[3432]! } + public var AttachmentMenu_File: String { return self._s[3431]! } + public var AppleWatch_Title: String { return self._s[3432]! } + public var Activity_RecordingVideoMessage: String { return self._s[3433]! } public func Channel_DiscussionGroup_PublicChannelLink(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3433]!, self._r[3433]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3434]!, self._r[3434]!, [_1, _2]) } - public var Theme_Colors_Messages: String { return self._s[3434]! } - public var Weekday_Saturday: String { return self._s[3435]! } - public var WallpaperPreview_SwipeColorsTopText: String { return self._s[3436]! } - public var Profile_CreateEncryptedChatError: String { return self._s[3437]! } - public var Common_Next: String { return self._s[3439]! } - public var Channel_Stickers_YourStickers: String { return self._s[3441]! } - public var Message_Theme: String { return self._s[3442]! } - public var Call_AudioRouteHeadphones: String { return self._s[3443]! } - public var TwoStepAuth_EnterPasswordForgot: String { return self._s[3445]! } - public var Watch_Contacts_NoResults: String { return self._s[3447]! } - public var PhotoEditor_TintTool: String { return self._s[3450]! } - public var LoginPassword_ResetAccount: String { return self._s[3452]! } - public var Settings_SavedMessages: String { return self._s[3453]! } - public var SettingsSearch_Synonyms_Appearance_Animations: String { return self._s[3454]! } - public var Bot_GenericSupportStatus: String { return self._s[3455]! } - public var StickerPack_Add: String { return self._s[3456]! } - public var Checkout_TotalAmount: String { return self._s[3457]! } - public var Your_cards_number_is_invalid: String { return self._s[3458]! } - public var SettingsSearch_Synonyms_Appearance_AutoNightTheme: String { return self._s[3459]! } - public var VoiceOver_Chat_VideoMessage: String { return self._s[3460]! } + public var Theme_Colors_Messages: String { return self._s[3435]! } + public var Weekday_Saturday: String { return self._s[3436]! } + public var WallpaperPreview_SwipeColorsTopText: String { return self._s[3437]! } + public var Profile_CreateEncryptedChatError: String { return self._s[3438]! } + public var Common_Next: String { return self._s[3440]! } + public var Channel_Stickers_YourStickers: String { return self._s[3442]! } + public var Message_Theme: String { return self._s[3443]! } + public var Call_AudioRouteHeadphones: String { return self._s[3444]! } + public var TwoStepAuth_EnterPasswordForgot: String { return self._s[3446]! } + public var Watch_Contacts_NoResults: String { return self._s[3448]! } + public var PhotoEditor_TintTool: String { return self._s[3451]! } + public var LoginPassword_ResetAccount: String { return self._s[3453]! } + public var Settings_SavedMessages: String { return self._s[3454]! } + public var SettingsSearch_Synonyms_Appearance_Animations: String { return self._s[3455]! } + public var Bot_GenericSupportStatus: String { return self._s[3456]! } + public var StickerPack_Add: String { return self._s[3457]! } + public var Checkout_TotalAmount: String { return self._s[3458]! } + public var Your_cards_number_is_invalid: String { return self._s[3459]! } + public var SettingsSearch_Synonyms_Appearance_AutoNightTheme: String { return self._s[3460]! } + public var VoiceOver_Chat_VideoMessage: String { return self._s[3461]! } public func ChangePhoneNumberCode_CallTimer(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3461]!, self._r[3461]!, [_0]) + return formatWithArgumentRanges(self._s[3462]!, self._r[3462]!, [_0]) } public func GroupPermission_AddedInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3462]!, self._r[3462]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3463]!, self._r[3463]!, [_1, _2]) } - public var ChatSettings_ConnectionType_UseSocks5: String { return self._s[3463]! } + public var ChatSettings_ConnectionType_UseSocks5: String { return self._s[3464]! } public func PUSH_CHAT_PHOTO_EDITED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3465]!, self._r[3465]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3466]!, self._r[3466]!, [_1, _2]) } public func Conversation_RestrictedTextTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3466]!, self._r[3466]!, [_0]) + return formatWithArgumentRanges(self._s[3467]!, self._r[3467]!, [_0]) } - public var GroupInfo_InviteLink_ShareLink: String { return self._s[3467]! } - public var StickerPack_Share: String { return self._s[3468]! } - public var Passport_DeleteAddress: String { return self._s[3469]! } - public var Settings_Passport: String { return self._s[3470]! } - public var SharedMedia_EmptyFilesText: String { return self._s[3471]! } - public var Conversation_DeleteMessagesForMe: String { return self._s[3472]! } - public var PasscodeSettings_AutoLock_IfAwayFor_1hour: String { return self._s[3473]! } - public var Contacts_PermissionsText: String { return self._s[3474]! } - public var Group_Setup_HistoryVisible: String { return self._s[3475]! } - public var Wallet_Month_ShortDecember: String { return self._s[3477]! } - public var Channel_EditAdmin_PermissionEnabledByDefault: String { return self._s[3478]! } - public var Passport_Address_AddRentalAgreement: String { return self._s[3479]! } - public var SocksProxySetup_Title: String { return self._s[3480]! } - public var Notification_Mute1h: String { return self._s[3481]! } + public var GroupInfo_InviteLink_ShareLink: String { return self._s[3468]! } + public var StickerPack_Share: String { return self._s[3469]! } + public var Passport_DeleteAddress: String { return self._s[3470]! } + public var Settings_Passport: String { return self._s[3471]! } + public var SharedMedia_EmptyFilesText: String { return self._s[3472]! } + public var Conversation_DeleteMessagesForMe: String { return self._s[3473]! } + public var PasscodeSettings_AutoLock_IfAwayFor_1hour: String { return self._s[3474]! } + public var Contacts_PermissionsText: String { return self._s[3475]! } + public var Group_Setup_HistoryVisible: String { return self._s[3476]! } + public var Wallet_Month_ShortDecember: String { return self._s[3478]! } + public var Channel_EditAdmin_PermissionEnabledByDefault: String { return self._s[3479]! } + public var Passport_Address_AddRentalAgreement: String { return self._s[3480]! } + public var SocksProxySetup_Title: String { return self._s[3481]! } + public var Notification_Mute1h: String { return self._s[3482]! } public func Passport_Email_CodeHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3482]!, self._r[3482]!, [_0]) + return formatWithArgumentRanges(self._s[3483]!, self._r[3483]!, [_0]) } - public var NotificationSettings_ShowNotificationsAllAccountsInfoOff: String { return self._s[3483]! } + public var NotificationSettings_ShowNotificationsAllAccountsInfoOff: String { return self._s[3484]! } public func PUSH_PINNED_GEOLIVE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3484]!, self._r[3484]!, [_1]) + return formatWithArgumentRanges(self._s[3485]!, self._r[3485]!, [_1]) } - public var FastTwoStepSetup_PasswordSection: String { return self._s[3485]! } - public var NetworkUsageSettings_ResetStatsConfirmation: String { return self._s[3488]! } - public var InfoPlist_NSFaceIDUsageDescription: String { return self._s[3490]! } - public var DialogList_NoMessagesText: String { return self._s[3491]! } - public var Privacy_ContactsResetConfirmation: String { return self._s[3492]! } - public var Privacy_Calls_P2PHelp: String { return self._s[3493]! } - public var Channel_DiscussionGroup_SearchPlaceholder: String { return self._s[3495]! } - public var Your_cards_expiration_year_is_invalid: String { return self._s[3496]! } - public var Common_TakePhotoOrVideo: String { return self._s[3497]! } - public var Wallet_Words_Text: String { return self._s[3498]! } - public var Call_StatusBusy: String { return self._s[3499]! } - public var Conversation_PinnedMessage: String { return self._s[3500]! } - public var AutoDownloadSettings_VoiceMessagesTitle: String { return self._s[3501]! } - public var Wallet_Configuration_BlockchainNameChangedProceed: String { return self._s[3502]! } - public var TwoStepAuth_SetupPasswordConfirmFailed: String { return self._s[3503]! } - public var Undo_ChatCleared: String { return self._s[3504]! } - public var AppleWatch_ReplyPresets: String { return self._s[3505]! } - public var Passport_DiscardMessageDescription: String { return self._s[3507]! } - public var Login_NetworkError: String { return self._s[3508]! } + public var FastTwoStepSetup_PasswordSection: String { return self._s[3486]! } + public var NetworkUsageSettings_ResetStatsConfirmation: String { return self._s[3489]! } + public var InfoPlist_NSFaceIDUsageDescription: String { return self._s[3491]! } + public var DialogList_NoMessagesText: String { return self._s[3492]! } + public var Privacy_ContactsResetConfirmation: String { return self._s[3493]! } + public var Privacy_Calls_P2PHelp: String { return self._s[3494]! } + public var Channel_DiscussionGroup_SearchPlaceholder: String { return self._s[3496]! } + public var Your_cards_expiration_year_is_invalid: String { return self._s[3497]! } + public var Common_TakePhotoOrVideo: String { return self._s[3498]! } + public var Wallet_Words_Text: String { return self._s[3499]! } + public var Call_StatusBusy: String { return self._s[3500]! } + public var Conversation_PinnedMessage: String { return self._s[3501]! } + public var AutoDownloadSettings_VoiceMessagesTitle: String { return self._s[3502]! } + public var Wallet_Configuration_BlockchainNameChangedProceed: String { return self._s[3503]! } + public var TwoStepAuth_SetupPasswordConfirmFailed: String { return self._s[3504]! } + public var Undo_ChatCleared: String { return self._s[3505]! } + public var AppleWatch_ReplyPresets: String { return self._s[3506]! } + public var Passport_DiscardMessageDescription: String { return self._s[3508]! } + public var Login_NetworkError: String { return self._s[3509]! } public func Notification_PinnedRoundMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3509]!, self._r[3509]!, [_0]) - } - public func Channel_AdminLog_MessageRemovedChannelUsername(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3510]!, self._r[3510]!, [_0]) } - public var SocksProxySetup_PasswordPlaceholder: String { return self._s[3511]! } - public var Wallet_WordCheck_ViewWords: String { return self._s[3513]! } - public var Login_ResetAccountProtected_LimitExceeded: String { return self._s[3514]! } + public func Channel_AdminLog_MessageRemovedChannelUsername(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3511]!, self._r[3511]!, [_0]) + } + public var SocksProxySetup_PasswordPlaceholder: String { return self._s[3512]! } + public var Wallet_WordCheck_ViewWords: String { return self._s[3514]! } + public var Login_ResetAccountProtected_LimitExceeded: String { return self._s[3515]! } public func Watch_LastSeen_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3516]!, self._r[3516]!, [_0]) + return formatWithArgumentRanges(self._s[3517]!, self._r[3517]!, [_0]) } - public var Call_ConnectionErrorMessage: String { return self._s[3517]! } - public var VoiceOver_Chat_Music: String { return self._s[3518]! } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsSound: String { return self._s[3519]! } - public var Compose_GroupTokenListPlaceholder: String { return self._s[3521]! } - public var ConversationMedia_Title: String { return self._s[3522]! } - public var EncryptionKey_Title: String { return self._s[3524]! } - public var TwoStepAuth_EnterPasswordTitle: String { return self._s[3525]! } - public var Notification_Exceptions_AddException: String { return self._s[3526]! } - public var PrivacySettings_BlockedPeersEmpty: String { return self._s[3527]! } - public var Profile_MessageLifetime1m: String { return self._s[3528]! } + public var Call_ConnectionErrorMessage: String { return self._s[3518]! } + public var VoiceOver_Chat_Music: String { return self._s[3519]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsSound: String { return self._s[3520]! } + public var Compose_GroupTokenListPlaceholder: String { return self._s[3522]! } + public var ConversationMedia_Title: String { return self._s[3523]! } + public var EncryptionKey_Title: String { return self._s[3525]! } + public var TwoStepAuth_EnterPasswordTitle: String { return self._s[3526]! } + public var Notification_Exceptions_AddException: String { return self._s[3527]! } + public var PrivacySettings_BlockedPeersEmpty: String { return self._s[3528]! } + public var Profile_MessageLifetime1m: String { return self._s[3529]! } public func Channel_AdminLog_MessageUnkickedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3529]!, self._r[3529]!, [_1]) + return formatWithArgumentRanges(self._s[3530]!, self._r[3530]!, [_1]) } - public var Month_GenMay: String { return self._s[3530]! } + public var Month_GenMay: String { return self._s[3531]! } public func LiveLocationUpdated_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3531]!, self._r[3531]!, [_0]) + return formatWithArgumentRanges(self._s[3532]!, self._r[3532]!, [_0]) } - public var PeopleNearby_Users: String { return self._s[3532]! } - public var Wallet_Send_AddressInfo: String { return self._s[3533]! } - public var ChannelMembers_WhoCanAddMembersAllHelp: String { return self._s[3534]! } - public var AutoDownloadSettings_ResetSettings: String { return self._s[3535]! } + public var PeopleNearby_Users: String { return self._s[3533]! } + public var Wallet_Send_AddressInfo: String { return self._s[3534]! } + public var ChannelMembers_WhoCanAddMembersAllHelp: String { return self._s[3535]! } + public var AutoDownloadSettings_ResetSettings: String { return self._s[3536]! } public func Wallet_Updated_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3537]!, self._r[3537]!, [_0]) + return formatWithArgumentRanges(self._s[3538]!, self._r[3538]!, [_0]) } - public var Conversation_EmptyPlaceholder: String { return self._s[3538]! } - public var Passport_Address_AddPassportRegistration: String { return self._s[3539]! } - public var Notifications_ChannelNotificationsAlert: String { return self._s[3540]! } - public var ChatSettings_AutoDownloadUsingCellular: String { return self._s[3541]! } - public var Camera_TapAndHoldForVideo: String { return self._s[3542]! } - public var Channel_JoinChannel: String { return self._s[3544]! } - public var Appearance_Animations: String { return self._s[3547]! } + public var Conversation_EmptyPlaceholder: String { return self._s[3539]! } + public var Passport_Address_AddPassportRegistration: String { return self._s[3540]! } + public var Notifications_ChannelNotificationsAlert: String { return self._s[3541]! } + public var ChatSettings_AutoDownloadUsingCellular: String { return self._s[3542]! } + public var Camera_TapAndHoldForVideo: String { return self._s[3543]! } + public var Channel_JoinChannel: String { return self._s[3545]! } + public var Appearance_Animations: String { return self._s[3548]! } public func Notification_MessageLifetimeChanged(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3548]!, self._r[3548]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3549]!, self._r[3549]!, [_1, _2]) } - public var Stickers_GroupStickers: String { return self._s[3550]! } - public var Appearance_ShareTheme: String { return self._s[3551]! } - public var TwoFactorSetup_Hint_Placeholder: String { return self._s[3552]! } - public var ConvertToSupergroup_HelpTitle: String { return self._s[3554]! } - public var StickerPackActionInfo_RemovedTitle: String { return self._s[3555]! } - public var Passport_Address_Street: String { return self._s[3556]! } - public var Conversation_AddContact: String { return self._s[3557]! } - public var Login_PhonePlaceholder: String { return self._s[3558]! } - public var Channel_Members_InviteLink: String { return self._s[3560]! } - public var Bot_Stop: String { return self._s[3561]! } - public var SettingsSearch_Synonyms_Proxy_UseForCalls: String { return self._s[3563]! } - public var Notification_PassportValueAddress: String { return self._s[3564]! } - public var Month_ShortJuly: String { return self._s[3565]! } - public var Passport_Address_TypeTemporaryRegistrationUploadScan: String { return self._s[3566]! } - public var Channel_AdminLog_BanSendMedia: String { return self._s[3567]! } - public var Passport_Identity_ReverseSide: String { return self._s[3568]! } - public var Watch_Stickers_Recents: String { return self._s[3571]! } - public var PrivacyLastSeenSettings_EmpryUsersPlaceholder: String { return self._s[3573]! } - public var Map_SendThisLocation: String { return self._s[3574]! } + public var Stickers_GroupStickers: String { return self._s[3551]! } + public var Appearance_ShareTheme: String { return self._s[3552]! } + public var TwoFactorSetup_Hint_Placeholder: String { return self._s[3553]! } + public var ConvertToSupergroup_HelpTitle: String { return self._s[3555]! } + public var StickerPackActionInfo_RemovedTitle: String { return self._s[3556]! } + public var Passport_Address_Street: String { return self._s[3557]! } + public var Conversation_AddContact: String { return self._s[3558]! } + public var Login_PhonePlaceholder: String { return self._s[3559]! } + public var Channel_Members_InviteLink: String { return self._s[3561]! } + public var Bot_Stop: String { return self._s[3562]! } + public var SettingsSearch_Synonyms_Proxy_UseForCalls: String { return self._s[3564]! } + public var Notification_PassportValueAddress: String { return self._s[3565]! } + public var Month_ShortJuly: String { return self._s[3566]! } + public var Passport_Address_TypeTemporaryRegistrationUploadScan: String { return self._s[3567]! } + public var Channel_AdminLog_BanSendMedia: String { return self._s[3568]! } + public var Passport_Identity_ReverseSide: String { return self._s[3569]! } + public var Watch_Stickers_Recents: String { return self._s[3572]! } + public var PrivacyLastSeenSettings_EmpryUsersPlaceholder: String { return self._s[3574]! } + public var Map_SendThisLocation: String { return self._s[3575]! } public func Time_MonthOfYear_m1(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3575]!, self._r[3575]!, [_0]) - } - public func InviteText_SingleContact(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3576]!, self._r[3576]!, [_0]) } - public var ConvertToSupergroup_Note: String { return self._s[3577]! } - public var Wallet_Intro_NotNow: String { return self._s[3578]! } + public func InviteText_SingleContact(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3577]!, self._r[3577]!, [_0]) + } + public var ConvertToSupergroup_Note: String { return self._s[3578]! } + public var Wallet_Intro_NotNow: String { return self._s[3579]! } public func FileSize_MB(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3579]!, self._r[3579]!, [_0]) + return formatWithArgumentRanges(self._s[3580]!, self._r[3580]!, [_0]) } - public var NetworkUsageSettings_GeneralDataSection: String { return self._s[3580]! } + public var NetworkUsageSettings_GeneralDataSection: String { return self._s[3581]! } public func Compatibility_SecretMediaVersionTooLow(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3581]!, self._r[3581]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3582]!, self._r[3582]!, [_0, _1]) } - public var Login_CallRequestState3: String { return self._s[3583]! } - public var Wallpaper_SearchShort: String { return self._s[3584]! } - public var SettingsSearch_Synonyms_Appearance_ColorTheme: String { return self._s[3586]! } - public var PasscodeSettings_UnlockWithFaceId: String { return self._s[3587]! } - public var Channel_BotDoesntSupportGroups: String { return self._s[3588]! } + public var Login_CallRequestState3: String { return self._s[3584]! } + public var Wallpaper_SearchShort: String { return self._s[3585]! } + public var SettingsSearch_Synonyms_Appearance_ColorTheme: String { return self._s[3587]! } + public var PasscodeSettings_UnlockWithFaceId: String { return self._s[3588]! } + public var Channel_BotDoesntSupportGroups: String { return self._s[3589]! } public func PUSH_CHAT_MESSAGE_GEOLIVE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3589]!, self._r[3589]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3590]!, self._r[3590]!, [_1, _2]) } - public var Channel_AdminLogFilter_Title: String { return self._s[3590]! } - public var Appearance_ThemePreview_Chat_4_Text: String { return self._s[3592]! } - public var Notifications_GroupNotificationsExceptions: String { return self._s[3595]! } + public var Channel_AdminLogFilter_Title: String { return self._s[3591]! } + public var Appearance_ThemePreview_Chat_4_Text: String { return self._s[3593]! } + public var Notifications_GroupNotificationsExceptions: String { return self._s[3596]! } public func FileSize_B(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3596]!, self._r[3596]!, [_0]) + return formatWithArgumentRanges(self._s[3597]!, self._r[3597]!, [_0]) } - public var Passport_CorrectErrors: String { return self._s[3597]! } - public var VoiceOver_Chat_YourAnonymousPoll: String { return self._s[3598]! } + public var Passport_CorrectErrors: String { return self._s[3598]! } + public var VoiceOver_Chat_YourAnonymousPoll: String { return self._s[3599]! } public func Channel_MessageTitleUpdated(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3599]!, self._r[3599]!, [_0]) + return formatWithArgumentRanges(self._s[3600]!, self._r[3600]!, [_0]) } - public var Map_SendMyCurrentLocation: String { return self._s[3600]! } - public var Channel_DiscussionGroup: String { return self._s[3601]! } - public var TwoFactorSetup_Email_SkipConfirmationSkip: String { return self._s[3602]! } + public var Map_SendMyCurrentLocation: String { return self._s[3601]! } + public var Channel_DiscussionGroup: String { return self._s[3602]! } + public var TwoFactorSetup_Email_SkipConfirmationSkip: String { return self._s[3603]! } public func PUSH_PINNED_CONTACT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3603]!, self._r[3603]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3604]!, self._r[3604]!, [_1, _2]) } - public var SharedMedia_SearchNoResults: String { return self._s[3604]! } - public var Permissions_NotificationsText_v0: String { return self._s[3605]! } - public var Channel_EditAdmin_PermissionDeleteMessagesOfOthers: String { return self._s[3606]! } - public var Appearance_AppIcon: String { return self._s[3607]! } - public var Appearance_ThemePreview_ChatList_3_AuthorName: String { return self._s[3608]! } - public var LoginPassword_FloodError: String { return self._s[3609]! } - public var Wallet_Send_OwnAddressAlertProceed: String { return self._s[3611]! } - public var Group_Setup_HistoryHiddenHelp: String { return self._s[3612]! } + public var SharedMedia_SearchNoResults: String { return self._s[3605]! } + public var Permissions_NotificationsText_v0: String { return self._s[3606]! } + public var Channel_EditAdmin_PermissionDeleteMessagesOfOthers: String { return self._s[3607]! } + public var Appearance_AppIcon: String { return self._s[3608]! } + public var Appearance_ThemePreview_ChatList_3_AuthorName: String { return self._s[3609]! } + public var LoginPassword_FloodError: String { return self._s[3610]! } + public var Wallet_Send_OwnAddressAlertProceed: String { return self._s[3612]! } + public var Group_Setup_HistoryHiddenHelp: String { return self._s[3613]! } public func TwoStepAuth_PendingEmailHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3613]!, self._r[3613]!, [_0]) + return formatWithArgumentRanges(self._s[3614]!, self._r[3614]!, [_0]) } - public var Passport_Language_bn: String { return self._s[3614]! } + public var Passport_Language_bn: String { return self._s[3615]! } public func DialogList_SingleUploadingPhotoSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3615]!, self._r[3615]!, [_0]) + return formatWithArgumentRanges(self._s[3616]!, self._r[3616]!, [_0]) } - public var ChatList_Context_Pin: String { return self._s[3616]! } + public var ChatList_Context_Pin: String { return self._s[3617]! } public func Notification_PinnedAudioMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3617]!, self._r[3617]!, [_0]) - } - public func Channel_AdminLog_MessageChangedGroupStickerPack(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3618]!, self._r[3618]!, [_0]) } - public var Wallet_Navigation_Close: String { return self._s[3619]! } - public var GroupInfo_InvitationLinkGroupFull: String { return self._s[3623]! } - public var Group_EditAdmin_PermissionChangeInfo: String { return self._s[3625]! } - public var Wallet_Month_GenDecember: String { return self._s[3626]! } - public var Contacts_PermissionsAllow: String { return self._s[3627]! } - public var ReportPeer_ReasonCopyright: String { return self._s[3628]! } - public var Channel_EditAdmin_PermissinAddAdminOn: String { return self._s[3629]! } - public var WallpaperPreview_Pattern: String { return self._s[3630]! } - public var Paint_Duplicate: String { return self._s[3631]! } - public var Passport_Address_Country: String { return self._s[3632]! } - public var Notification_RenamedChannel: String { return self._s[3634]! } - public var ChatList_Context_Unmute: String { return self._s[3635]! } - public var CheckoutInfo_ErrorPostcodeInvalid: String { return self._s[3636]! } - public var Group_MessagePhotoUpdated: String { return self._s[3637]! } - public var Channel_BanUser_PermissionSendMedia: String { return self._s[3638]! } - public var Conversation_ContextMenuBan: String { return self._s[3639]! } - public var TwoStepAuth_EmailSent: String { return self._s[3640]! } - public var MessagePoll_NoVotes: String { return self._s[3641]! } - public var Wallet_Send_ErrorNotEnoughFundsTitle: String { return self._s[3642]! } - public var Passport_Language_is: String { return self._s[3644]! } - public var PeopleNearby_UsersEmpty: String { return self._s[3646]! } - public var Tour_Text5: String { return self._s[3647]! } + public func Channel_AdminLog_MessageChangedGroupStickerPack(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3619]!, self._r[3619]!, [_0]) + } + public var Wallet_Navigation_Close: String { return self._s[3620]! } + public var GroupInfo_InvitationLinkGroupFull: String { return self._s[3624]! } + public var Group_EditAdmin_PermissionChangeInfo: String { return self._s[3626]! } + public var Wallet_Month_GenDecember: String { return self._s[3627]! } + public var Contacts_PermissionsAllow: String { return self._s[3628]! } + public var ReportPeer_ReasonCopyright: String { return self._s[3629]! } + public var Channel_EditAdmin_PermissinAddAdminOn: String { return self._s[3630]! } + public var WallpaperPreview_Pattern: String { return self._s[3631]! } + public var Paint_Duplicate: String { return self._s[3632]! } + public var Passport_Address_Country: String { return self._s[3633]! } + public var Notification_RenamedChannel: String { return self._s[3635]! } + public var ChatList_Context_Unmute: String { return self._s[3636]! } + public var CheckoutInfo_ErrorPostcodeInvalid: String { return self._s[3637]! } + public var Group_MessagePhotoUpdated: String { return self._s[3638]! } + public var Channel_BanUser_PermissionSendMedia: String { return self._s[3639]! } + public var Conversation_ContextMenuBan: String { return self._s[3640]! } + public var TwoStepAuth_EmailSent: String { return self._s[3641]! } + public var MessagePoll_NoVotes: String { return self._s[3642]! } + public var Wallet_Send_ErrorNotEnoughFundsTitle: String { return self._s[3643]! } + public var Passport_Language_is: String { return self._s[3645]! } + public var PeopleNearby_UsersEmpty: String { return self._s[3647]! } + public var Tour_Text5: String { return self._s[3648]! } public func Call_GroupFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3650]!, self._r[3650]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3651]!, self._r[3651]!, [_1, _2]) } - public var Undo_SecretChatDeleted: String { return self._s[3651]! } - public var SocksProxySetup_ShareQRCode: String { return self._s[3652]! } + public var Undo_SecretChatDeleted: String { return self._s[3652]! } + public var SocksProxySetup_ShareQRCode: String { return self._s[3653]! } public func VoiceOver_Chat_Size(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3653]!, self._r[3653]!, [_0]) + return formatWithArgumentRanges(self._s[3654]!, self._r[3654]!, [_0]) } - public var Forward_ErrorDisabledForChat: String { return self._s[3654]! } - public var LogoutOptions_ChangePhoneNumberText: String { return self._s[3655]! } - public var Paint_Edit: String { return self._s[3657]! } - public var ScheduledMessages_ReminderNotification: String { return self._s[3659]! } - public var Undo_DeletedGroup: String { return self._s[3661]! } - public var LoginPassword_ForgotPassword: String { return self._s[3662]! } - public var Wallet_WordImport_IncorrectTitle: String { return self._s[3663]! } - public var GroupInfo_GroupNamePlaceholder: String { return self._s[3664]! } + public var Forward_ErrorDisabledForChat: String { return self._s[3655]! } + public var LogoutOptions_ChangePhoneNumberText: String { return self._s[3656]! } + public var Paint_Edit: String { return self._s[3658]! } + public var ScheduledMessages_ReminderNotification: String { return self._s[3660]! } + public var Undo_DeletedGroup: String { return self._s[3662]! } + public var LoginPassword_ForgotPassword: String { return self._s[3663]! } + public var Wallet_WordImport_IncorrectTitle: String { return self._s[3664]! } + public var GroupInfo_GroupNamePlaceholder: String { return self._s[3665]! } public func Notification_Kicked(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3665]!, self._r[3665]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3666]!, self._r[3666]!, [_0, _1]) } - public var AppWallet_TransactionInfo_FeeInfoURL: String { return self._s[3666]! } - public var Conversation_InputTextCaptionPlaceholder: String { return self._s[3667]! } - public var AutoDownloadSettings_VideoMessagesTitle: String { return self._s[3668]! } - public var Passport_Language_uz: String { return self._s[3669]! } - public var Conversation_PinMessageAlertGroup: String { return self._s[3670]! } - public var SettingsSearch_Synonyms_Privacy_GroupsAndChannels: String { return self._s[3671]! } - public var Map_StopLiveLocation: String { return self._s[3673]! } - public var VoiceOver_MessageContextSend: String { return self._s[3675]! } - public var PasscodeSettings_Help: String { return self._s[3676]! } - public var NotificationsSound_Input: String { return self._s[3677]! } - public var Share_Title: String { return self._s[3680]! } - public var LogoutOptions_Title: String { return self._s[3681]! } - public var Wallet_Send_AddressText: String { return self._s[3682]! } - public var Login_TermsOfServiceAgree: String { return self._s[3683]! } - public var Compose_NewEncryptedChatTitle: String { return self._s[3684]! } - public var Channel_AdminLog_TitleSelectedEvents: String { return self._s[3685]! } - public var Channel_EditAdmin_PermissionEditMessages: String { return self._s[3686]! } - public var EnterPasscode_EnterTitle: String { return self._s[3687]! } + public var AppWallet_TransactionInfo_FeeInfoURL: String { return self._s[3667]! } + public var Conversation_InputTextCaptionPlaceholder: String { return self._s[3668]! } + public var AutoDownloadSettings_VideoMessagesTitle: String { return self._s[3669]! } + public var Passport_Language_uz: String { return self._s[3670]! } + public var Conversation_PinMessageAlertGroup: String { return self._s[3671]! } + public var SettingsSearch_Synonyms_Privacy_GroupsAndChannels: String { return self._s[3672]! } + public var Map_StopLiveLocation: String { return self._s[3674]! } + public var VoiceOver_MessageContextSend: String { return self._s[3676]! } + public var PasscodeSettings_Help: String { return self._s[3677]! } + public var NotificationsSound_Input: String { return self._s[3678]! } + public var Share_Title: String { return self._s[3681]! } + public var LogoutOptions_Title: String { return self._s[3682]! } + public var Wallet_Send_AddressText: String { return self._s[3683]! } + public var Login_TermsOfServiceAgree: String { return self._s[3684]! } + public var Compose_NewEncryptedChatTitle: String { return self._s[3685]! } + public var Channel_AdminLog_TitleSelectedEvents: String { return self._s[3686]! } + public var Channel_EditAdmin_PermissionEditMessages: String { return self._s[3687]! } + public var EnterPasscode_EnterTitle: String { return self._s[3688]! } public func Call_PrivacyErrorMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3688]!, self._r[3688]!, [_0]) + return formatWithArgumentRanges(self._s[3689]!, self._r[3689]!, [_0]) } - public var Settings_CopyPhoneNumber: String { return self._s[3689]! } - public var Conversation_AddToContacts: String { return self._s[3690]! } + public var Settings_CopyPhoneNumber: String { return self._s[3690]! } + public var Conversation_AddToContacts: String { return self._s[3691]! } public func VoiceOver_Chat_ReplyFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3691]!, self._r[3691]!, [_0]) + return formatWithArgumentRanges(self._s[3692]!, self._r[3692]!, [_0]) } - public var NotificationsSound_Keys: String { return self._s[3692]! } + public var NotificationsSound_Keys: String { return self._s[3693]! } public func Call_ParticipantVersionOutdatedError(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3693]!, self._r[3693]!, [_0]) + return formatWithArgumentRanges(self._s[3694]!, self._r[3694]!, [_0]) } - public var Notification_MessageLifetime1w: String { return self._s[3694]! } - public var Message_Video: String { return self._s[3695]! } - public var AutoDownloadSettings_CellularTitle: String { return self._s[3696]! } + public var Notification_MessageLifetime1w: String { return self._s[3695]! } + public var Message_Video: String { return self._s[3696]! } + public var AutoDownloadSettings_CellularTitle: String { return self._s[3697]! } public func PUSH_CHANNEL_MESSAGE_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3697]!, self._r[3697]!, [_1]) + return formatWithArgumentRanges(self._s[3698]!, self._r[3698]!, [_1]) } - public var Wallet_Receive_AmountInfo: String { return self._s[3700]! } + public var Wallet_Receive_AmountInfo: String { return self._s[3701]! } public func Notification_JoinedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3701]!, self._r[3701]!, [_0]) - } - public func PrivacySettings_LastSeenContactsPlus(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3702]!, self._r[3702]!, [_0]) } - public var Passport_Language_mk: String { return self._s[3703]! } - public func Wallet_Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3704]!, self._r[3704]!, [_1, _2, _3]) + public func PrivacySettings_LastSeenContactsPlus(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3703]!, self._r[3703]!, [_0]) } - public var CreatePoll_CancelConfirmation: String { return self._s[3705]! } - public var MessagePoll_LabelAnonymousQuiz: String { return self._s[3706]! } - public var Conversation_SilentBroadcastTooltipOn: String { return self._s[3708]! } - public var PrivacyPolicy_Decline: String { return self._s[3709]! } - public var Passport_Identity_DoesNotExpire: String { return self._s[3710]! } - public var Channel_AdminLogFilter_EventsRestrictions: String { return self._s[3711]! } - public var AuthSessions_AddDeviceIntro_Action: String { return self._s[3712]! } - public var Permissions_SiriAllow_v0: String { return self._s[3714]! } - public var Wallet_Month_ShortAugust: String { return self._s[3715]! } - public var Appearance_ThemeCarouselNight: String { return self._s[3716]! } + public var Passport_Language_mk: String { return self._s[3704]! } + public func Wallet_Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3705]!, self._r[3705]!, [_1, _2, _3]) + } + public var CreatePoll_CancelConfirmation: String { return self._s[3706]! } + public var MessagePoll_LabelAnonymousQuiz: String { return self._s[3707]! } + public var Conversation_SilentBroadcastTooltipOn: String { return self._s[3709]! } + public var PrivacyPolicy_Decline: String { return self._s[3710]! } + public var Passport_Identity_DoesNotExpire: String { return self._s[3711]! } + public var Channel_AdminLogFilter_EventsRestrictions: String { return self._s[3712]! } + public var AuthSessions_AddDeviceIntro_Action: String { return self._s[3713]! } + public var Permissions_SiriAllow_v0: String { return self._s[3715]! } + public var Wallet_Month_ShortAugust: String { return self._s[3716]! } + public var Appearance_ThemeCarouselNight: String { return self._s[3717]! } public func LOCAL_CHAT_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3717]!, self._r[3717]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[3718]!, self._r[3718]!, [_1, "\(_2)"]) } public func Notification_RenamedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3718]!, self._r[3718]!, [_0]) + return formatWithArgumentRanges(self._s[3719]!, self._r[3719]!, [_0]) } - public var Paint_Regular: String { return self._s[3719]! } - public var ChatSettings_AutoDownloadReset: String { return self._s[3720]! } - public var SocksProxySetup_ShareLink: String { return self._s[3721]! } - public var Wallet_Qr_Title: String { return self._s[3722]! } - public var BlockedUsers_SelectUserTitle: String { return self._s[3723]! } - public var VoiceOver_Chat_RecordModeVoiceMessage: String { return self._s[3725]! } - public var Wallet_Settings_Configuration: String { return self._s[3726]! } - public var GroupInfo_InviteByLink: String { return self._s[3727]! } - public var MessageTimer_Custom: String { return self._s[3728]! } - public var UserInfo_NotificationsDefaultEnabled: String { return self._s[3729]! } - public var Conversation_StopQuizConfirmationTitle: String { return self._s[3730]! } - public var Passport_Address_TypeTemporaryRegistration: String { return self._s[3732]! } - public var Conversation_SendMessage_SetReminder: String { return self._s[3733]! } - public var VoiceOver_Chat_Selected: String { return self._s[3734]! } - public var ChatSettings_AutoDownloadUsingWiFi: String { return self._s[3735]! } - public var Channel_Username_InvalidTaken: String { return self._s[3736]! } - public var Conversation_ClousStorageInfo_Description3: String { return self._s[3737]! } - public var Wallet_WordCheck_TryAgain: String { return self._s[3738]! } - public var Wallet_Info_TransactionPendingHeader: String { return self._s[3739]! } - public var Settings_ChatBackground: String { return self._s[3740]! } - public var Channel_Subscribers_Title: String { return self._s[3741]! } - public var Wallet_Receive_InvoiceUrlHeader: String { return self._s[3742]! } - public var ApplyLanguage_ChangeLanguageTitle: String { return self._s[3743]! } - public var Watch_ConnectionDescription: String { return self._s[3744]! } - public var OldChannels_NoticeText: String { return self._s[3747]! } - public var Wallet_Configuration_ApplyErrorTitle: String { return self._s[3748]! } - public var IntentsSettings_SuggestBy: String { return self._s[3750]! } - public var Theme_ThemeChangedText: String { return self._s[3751]! } - public var ChatList_ArchivedChatsTitle: String { return self._s[3752]! } - public var Wallpaper_ResetWallpapers: String { return self._s[3753]! } - public var Wallet_Send_TransactionInProgress: String { return self._s[3754]! } - public var EditProfile_Title: String { return self._s[3755]! } - public var NotificationsSound_Bamboo: String { return self._s[3757]! } - public var Channel_AdminLog_MessagePreviousMessage: String { return self._s[3759]! } - public var Login_SmsRequestState2: String { return self._s[3760]! } - public var Passport_Language_ar: String { return self._s[3761]! } + public var Paint_Regular: String { return self._s[3720]! } + public var ChatSettings_AutoDownloadReset: String { return self._s[3721]! } + public var SocksProxySetup_ShareLink: String { return self._s[3722]! } + public var Wallet_Qr_Title: String { return self._s[3723]! } + public var BlockedUsers_SelectUserTitle: String { return self._s[3724]! } + public var VoiceOver_Chat_RecordModeVoiceMessage: String { return self._s[3726]! } + public var Wallet_Settings_Configuration: String { return self._s[3727]! } + public var GroupInfo_InviteByLink: String { return self._s[3728]! } + public var MessageTimer_Custom: String { return self._s[3729]! } + public var UserInfo_NotificationsDefaultEnabled: String { return self._s[3730]! } + public var Conversation_StopQuizConfirmationTitle: String { return self._s[3731]! } + public var Passport_Address_TypeTemporaryRegistration: String { return self._s[3733]! } + public var Conversation_SendMessage_SetReminder: String { return self._s[3734]! } + public var VoiceOver_Chat_Selected: String { return self._s[3735]! } + public var ChatSettings_AutoDownloadUsingWiFi: String { return self._s[3736]! } + public var Channel_Username_InvalidTaken: String { return self._s[3737]! } + public var Conversation_ClousStorageInfo_Description3: String { return self._s[3738]! } + public var Wallet_WordCheck_TryAgain: String { return self._s[3739]! } + public var Wallet_Info_TransactionPendingHeader: String { return self._s[3740]! } + public var Settings_ChatBackground: String { return self._s[3741]! } + public var Channel_Subscribers_Title: String { return self._s[3742]! } + public var Wallet_Receive_InvoiceUrlHeader: String { return self._s[3743]! } + public var ApplyLanguage_ChangeLanguageTitle: String { return self._s[3744]! } + public var Watch_ConnectionDescription: String { return self._s[3745]! } + public var OldChannels_NoticeText: String { return self._s[3748]! } + public var Wallet_Configuration_ApplyErrorTitle: String { return self._s[3749]! } + public var IntentsSettings_SuggestBy: String { return self._s[3751]! } + public var Theme_ThemeChangedText: String { return self._s[3752]! } + public var ChatList_ArchivedChatsTitle: String { return self._s[3753]! } + public var Wallpaper_ResetWallpapers: String { return self._s[3754]! } + public var Wallet_Send_TransactionInProgress: String { return self._s[3755]! } + public var EditProfile_Title: String { return self._s[3756]! } + public var NotificationsSound_Bamboo: String { return self._s[3758]! } + public var Channel_AdminLog_MessagePreviousMessage: String { return self._s[3760]! } + public var Login_SmsRequestState2: String { return self._s[3761]! } + public var Passport_Language_ar: String { return self._s[3762]! } public func Message_AuthorPinnedGame(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3762]!, self._r[3762]!, [_0]) + return formatWithArgumentRanges(self._s[3763]!, self._r[3763]!, [_0]) } - public var SettingsSearch_Synonyms_EditProfile_Title: String { return self._s[3763]! } - public var Wallet_Created_Text: String { return self._s[3764]! } - public var Conversation_MessageDialogEdit: String { return self._s[3766]! } - public var Wallet_Created_Proceed: String { return self._s[3767]! } - public var Wallet_Words_Done: String { return self._s[3768]! } - public var VoiceOver_Media_PlaybackPause: String { return self._s[3769]! } + public var SettingsSearch_Synonyms_EditProfile_Title: String { return self._s[3764]! } + public var Wallet_Created_Text: String { return self._s[3765]! } + public var Conversation_MessageDialogEdit: String { return self._s[3767]! } + public var Wallet_Created_Proceed: String { return self._s[3768]! } + public var Wallet_Words_Done: String { return self._s[3769]! } + public var VoiceOver_Media_PlaybackPause: String { return self._s[3770]! } public func PUSH_AUTH_UNKNOWN(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3770]!, self._r[3770]!, [_1]) + return formatWithArgumentRanges(self._s[3771]!, self._r[3771]!, [_1]) } - public var Common_Close: String { return self._s[3771]! } - public var GroupInfo_PublicLink: String { return self._s[3772]! } - public var Channel_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[3773]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsPreview: String { return self._s[3774]! } + public var Common_Close: String { return self._s[3772]! } + public var GroupInfo_PublicLink: String { return self._s[3773]! } + public var Channel_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[3774]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsPreview: String { return self._s[3775]! } public func Channel_AdminLog_MessageToggleInvitesOff(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3778]!, self._r[3778]!, [_0]) + return formatWithArgumentRanges(self._s[3779]!, self._r[3779]!, [_0]) } - public var UserInfo_About_Placeholder: String { return self._s[3779]! } + public var UserInfo_About_Placeholder: String { return self._s[3780]! } public func Conversation_FileHowToText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3780]!, self._r[3780]!, [_0]) + return formatWithArgumentRanges(self._s[3781]!, self._r[3781]!, [_0]) } - public var GroupInfo_Permissions_SectionTitle: String { return self._s[3781]! } - public var Channel_Info_Banned: String { return self._s[3783]! } + public var GroupInfo_Permissions_SectionTitle: String { return self._s[3782]! } + public var Channel_Info_Banned: String { return self._s[3784]! } public func Time_MonthOfYear_m11(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3784]!, self._r[3784]!, [_0]) + return formatWithArgumentRanges(self._s[3785]!, self._r[3785]!, [_0]) } - public var Appearance_Other: String { return self._s[3785]! } - public var Passport_Language_my: String { return self._s[3786]! } - public var Group_Setup_BasicHistoryHiddenHelp: String { return self._s[3787]! } + public var Appearance_Other: String { return self._s[3786]! } + public var Passport_Language_my: String { return self._s[3787]! } + public var Group_Setup_BasicHistoryHiddenHelp: String { return self._s[3788]! } public func Time_PreciseDate_m9(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3788]!, self._r[3788]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3789]!, self._r[3789]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Privacy_PasscodeAndFaceId: String { return self._s[3789]! } - public var IntentsSettings_SuggestedAndSpotlightChatsInfo: String { return self._s[3790]! } - public var Preview_CopyAddress: String { return self._s[3791]! } + public var SettingsSearch_Synonyms_Privacy_PasscodeAndFaceId: String { return self._s[3790]! } + public var IntentsSettings_SuggestedAndSpotlightChatsInfo: String { return self._s[3791]! } + public var Preview_CopyAddress: String { return self._s[3792]! } public func DialogList_SinglePlayingGameSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3792]!, self._r[3792]!, [_0]) + return formatWithArgumentRanges(self._s[3793]!, self._r[3793]!, [_0]) } - public var KeyCommand_JumpToPreviousChat: String { return self._s[3793]! } - public var UserInfo_BotSettings: String { return self._s[3794]! } - public var LiveLocation_MenuStopAll: String { return self._s[3796]! } - public var Passport_PasswordCreate: String { return self._s[3797]! } - public var StickerSettings_MaskContextInfo: String { return self._s[3798]! } - public var Message_PinnedLocationMessage: String { return self._s[3799]! } - public var Map_Satellite: String { return self._s[3800]! } - public var Watch_Message_Unsupported: String { return self._s[3801]! } - public var Username_TooManyPublicUsernamesError: String { return self._s[3802]! } - public var TwoStepAuth_EnterPasswordInvalid: String { return self._s[3803]! } + public var KeyCommand_JumpToPreviousChat: String { return self._s[3794]! } + public var UserInfo_BotSettings: String { return self._s[3795]! } + public var LiveLocation_MenuStopAll: String { return self._s[3797]! } + public var Passport_PasswordCreate: String { return self._s[3798]! } + public var StickerSettings_MaskContextInfo: String { return self._s[3799]! } + public var Message_PinnedLocationMessage: String { return self._s[3800]! } + public var Map_Satellite: String { return self._s[3801]! } + public var Watch_Message_Unsupported: String { return self._s[3802]! } + public var Username_TooManyPublicUsernamesError: String { return self._s[3803]! } + public var TwoStepAuth_EnterPasswordInvalid: String { return self._s[3804]! } public func Notification_PinnedTextMessage(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3804]!, self._r[3804]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3805]!, self._r[3805]!, [_0, _1]) } public func Conversation_OpenBotLinkText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3805]!, self._r[3805]!, [_0]) + return formatWithArgumentRanges(self._s[3806]!, self._r[3806]!, [_0]) } - public var Wallet_WordImport_Continue: String { return self._s[3806]! } + public var Wallet_WordImport_Continue: String { return self._s[3807]! } public func TwoFactorSetup_EmailVerification_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3807]!, self._r[3807]!, [_0]) + return formatWithArgumentRanges(self._s[3808]!, self._r[3808]!, [_0]) } - public var Notifications_ChannelNotificationsHelp: String { return self._s[3808]! } - public var Privacy_Calls_P2PContacts: String { return self._s[3809]! } - public var NotificationsSound_None: String { return self._s[3810]! } - public var Wallet_TransactionInfo_StorageFeeHeader: String { return self._s[3811]! } - public var Channel_DiscussionGroup_UnlinkGroup: String { return self._s[3813]! } - public var AccessDenied_VoiceMicrophone: String { return self._s[3814]! } + public var Notifications_ChannelNotificationsHelp: String { return self._s[3809]! } + public var Privacy_Calls_P2PContacts: String { return self._s[3810]! } + public var NotificationsSound_None: String { return self._s[3811]! } + public var Wallet_TransactionInfo_StorageFeeHeader: String { return self._s[3812]! } + public var Channel_DiscussionGroup_UnlinkGroup: String { return self._s[3814]! } + public var AccessDenied_VoiceMicrophone: String { return self._s[3815]! } public func ApplyLanguage_ChangeLanguageAlreadyActive(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3815]!, self._r[3815]!, [_1]) + return formatWithArgumentRanges(self._s[3816]!, self._r[3816]!, [_1]) } - public var Cache_Indexing: String { return self._s[3816]! } - public var DialogList_RecentTitlePeople: String { return self._s[3818]! } - public var DialogList_EncryptionRejected: String { return self._s[3819]! } - public var GroupInfo_Administrators: String { return self._s[3820]! } - public var Passport_ScanPassportHelp: String { return self._s[3821]! } - public var Application_Name: String { return self._s[3822]! } - public var Channel_AdminLogFilter_ChannelEventsInfo: String { return self._s[3823]! } - public var Appearance_ThemeCarouselDay: String { return self._s[3825]! } - public var Passport_Identity_TranslationHelp: String { return self._s[3826]! } + public var Cache_Indexing: String { return self._s[3817]! } + public var DialogList_RecentTitlePeople: String { return self._s[3819]! } + public var DialogList_EncryptionRejected: String { return self._s[3820]! } + public var GroupInfo_Administrators: String { return self._s[3821]! } + public var Passport_ScanPassportHelp: String { return self._s[3822]! } + public var Application_Name: String { return self._s[3823]! } + public var Channel_AdminLogFilter_ChannelEventsInfo: String { return self._s[3824]! } + public var Appearance_ThemeCarouselDay: String { return self._s[3826]! } + public var Passport_Identity_TranslationHelp: String { return self._s[3827]! } public func VoiceOver_Chat_VideoMessageFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3827]!, self._r[3827]!, [_0]) - } - public func Notification_JoinedGroupByLink(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3828]!, self._r[3828]!, [_0]) } - public func DialogList_EncryptedChatStartedOutgoing(_ _0: String) -> (String, [(Int, NSRange)]) { + public func Notification_JoinedGroupByLink(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3829]!, self._r[3829]!, [_0]) } - public var Channel_EditAdmin_PermissionDeleteMessages: String { return self._s[3830]! } - public var Privacy_ChatsTitle: String { return self._s[3831]! } - public var DialogList_ClearHistoryConfirmation: String { return self._s[3832]! } - public var SettingsSearch_Synonyms_Data_Storage_ClearCache: String { return self._s[3833]! } - public var Watch_Suggestion_HoldOn: String { return self._s[3834]! } - public var Group_EditAdmin_TransferOwnership: String { return self._s[3835]! } - public var WebBrowser_Title: String { return self._s[3836]! } - public var Group_LinkedChannel: String { return self._s[3837]! } - public var VoiceOver_Chat_SeenByRecipient: String { return self._s[3838]! } - public var SocksProxySetup_RequiredCredentials: String { return self._s[3839]! } - public var Passport_Address_TypeRentalAgreementUploadScan: String { return self._s[3840]! } - public var Appearance_TextSize_UseSystem: String { return self._s[3841]! } - public var TwoStepAuth_EmailSkipAlert: String { return self._s[3842]! } - public var ScheduledMessages_RemindersTitle: String { return self._s[3844]! } - public var Channel_Setup_TypePublic: String { return self._s[3846]! } + public func DialogList_EncryptedChatStartedOutgoing(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3830]!, self._r[3830]!, [_0]) + } + public var Channel_EditAdmin_PermissionDeleteMessages: String { return self._s[3831]! } + public var Privacy_ChatsTitle: String { return self._s[3832]! } + public var DialogList_ClearHistoryConfirmation: String { return self._s[3833]! } + public var SettingsSearch_Synonyms_Data_Storage_ClearCache: String { return self._s[3834]! } + public var Watch_Suggestion_HoldOn: String { return self._s[3835]! } + public var Group_EditAdmin_TransferOwnership: String { return self._s[3836]! } + public var WebBrowser_Title: String { return self._s[3837]! } + public var Group_LinkedChannel: String { return self._s[3838]! } + public var VoiceOver_Chat_SeenByRecipient: String { return self._s[3839]! } + public var SocksProxySetup_RequiredCredentials: String { return self._s[3840]! } + public var Passport_Address_TypeRentalAgreementUploadScan: String { return self._s[3841]! } + public var Appearance_TextSize_UseSystem: String { return self._s[3842]! } + public var TwoStepAuth_EmailSkipAlert: String { return self._s[3843]! } + public var ScheduledMessages_RemindersTitle: String { return self._s[3845]! } + public var Channel_Setup_TypePublic: String { return self._s[3847]! } public func Channel_AdminLog_MessageToggleInvitesOn(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3847]!, self._r[3847]!, [_0]) + return formatWithArgumentRanges(self._s[3848]!, self._r[3848]!, [_0]) } - public var Channel_TypeSetup_Title: String { return self._s[3849]! } - public var MessagePoll_ViewResults: String { return self._s[3850]! } - public var Map_OpenInMaps: String { return self._s[3852]! } + public var Channel_TypeSetup_Title: String { return self._s[3850]! } + public var MessagePoll_ViewResults: String { return self._s[3851]! } + public var Map_OpenInMaps: String { return self._s[3853]! } public func PUSH_PINNED_NOTEXT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3853]!, self._r[3853]!, [_1]) + return formatWithArgumentRanges(self._s[3854]!, self._r[3854]!, [_1]) } - public var NotificationsSound_Tremolo: String { return self._s[3855]! } + public var NotificationsSound_Tremolo: String { return self._s[3856]! } public func Date_ChatDateHeaderYear(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3856]!, self._r[3856]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3857]!, self._r[3857]!, [_1, _2, _3]) } - public var ConversationProfile_UnknownAddMemberError: String { return self._s[3857]! } - public var Channel_OwnershipTransfer_PasswordPlaceholder: String { return self._s[3858]! } - public var Passport_PasswordHelp: String { return self._s[3859]! } - public var Login_CodeExpiredError: String { return self._s[3860]! } - public var Channel_EditAdmin_PermissionChangeInfo: String { return self._s[3861]! } - public var Conversation_TitleUnmute: String { return self._s[3862]! } - public var Passport_Identity_ScansHelp: String { return self._s[3863]! } - public var Passport_Language_lo: String { return self._s[3864]! } - public var Camera_FlashAuto: String { return self._s[3865]! } - public var Conversation_OpenBotLinkOpen: String { return self._s[3866]! } - public var Common_Cancel: String { return self._s[3867]! } - public var DialogList_SavedMessagesTooltip: String { return self._s[3868]! } - public var TwoStepAuth_SetupPasswordTitle: String { return self._s[3869]! } - public var Appearance_TintAllColors: String { return self._s[3870]! } + public var ConversationProfile_UnknownAddMemberError: String { return self._s[3858]! } + public var Channel_OwnershipTransfer_PasswordPlaceholder: String { return self._s[3859]! } + public var Passport_PasswordHelp: String { return self._s[3860]! } + public var Login_CodeExpiredError: String { return self._s[3861]! } + public var Channel_EditAdmin_PermissionChangeInfo: String { return self._s[3862]! } + public var Conversation_TitleUnmute: String { return self._s[3863]! } + public var Passport_Identity_ScansHelp: String { return self._s[3864]! } + public var Passport_Language_lo: String { return self._s[3865]! } + public var Camera_FlashAuto: String { return self._s[3866]! } + public var Conversation_OpenBotLinkOpen: String { return self._s[3867]! } + public var Common_Cancel: String { return self._s[3868]! } + public var DialogList_SavedMessagesTooltip: String { return self._s[3869]! } + public var TwoStepAuth_SetupPasswordTitle: String { return self._s[3870]! } + public var Appearance_TintAllColors: String { return self._s[3871]! } public func PUSH_MESSAGE_FWD(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3871]!, self._r[3871]!, [_1]) + return formatWithArgumentRanges(self._s[3872]!, self._r[3872]!, [_1]) } - public var Conversation_ReportSpamConfirmation: String { return self._s[3872]! } - public var ChatSettings_Title: String { return self._s[3874]! } - public var Passport_PasswordReset: String { return self._s[3875]! } - public var SocksProxySetup_TypeNone: String { return self._s[3876]! } - public var EditTheme_Title: String { return self._s[3879]! } - public var PhoneNumberHelp_Help: String { return self._s[3880]! } - public var Checkout_EnterPassword: String { return self._s[3881]! } - public var Share_AuthTitle: String { return self._s[3883]! } - public var Activity_UploadingDocument: String { return self._s[3884]! } - public var State_Connecting: String { return self._s[3885]! } - public var Profile_MessageLifetime1w: String { return self._s[3886]! } - public var Conversation_ContextMenuReport: String { return self._s[3887]! } - public var CheckoutInfo_ReceiverInfoPhone: String { return self._s[3888]! } - public var AutoNightTheme_ScheduledTo: String { return self._s[3889]! } + public var Conversation_ReportSpamConfirmation: String { return self._s[3873]! } + public var ChatSettings_Title: String { return self._s[3875]! } + public var Passport_PasswordReset: String { return self._s[3876]! } + public var SocksProxySetup_TypeNone: String { return self._s[3877]! } + public var EditTheme_Title: String { return self._s[3880]! } + public var PhoneNumberHelp_Help: String { return self._s[3881]! } + public var Checkout_EnterPassword: String { return self._s[3882]! } + public var Share_AuthTitle: String { return self._s[3884]! } + public var Activity_UploadingDocument: String { return self._s[3885]! } + public var State_Connecting: String { return self._s[3886]! } + public var Profile_MessageLifetime1w: String { return self._s[3887]! } + public var Conversation_ContextMenuReport: String { return self._s[3888]! } + public var CheckoutInfo_ReceiverInfoPhone: String { return self._s[3889]! } + public var AutoNightTheme_ScheduledTo: String { return self._s[3890]! } public func VoiceOver_Chat_AnonymousPollFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3890]!, self._r[3890]!, [_0]) + return formatWithArgumentRanges(self._s[3891]!, self._r[3891]!, [_0]) } - public var AuthSessions_Terminate: String { return self._s[3891]! } - public var Wallet_WordImport_CanNotRemember: String { return self._s[3892]! } - public var Checkout_NewCard_CardholderNamePlaceholder: String { return self._s[3894]! } - public var KeyCommand_JumpToPreviousUnreadChat: String { return self._s[3895]! } - public var PhotoEditor_Set: String { return self._s[3896]! } - public var EmptyGroupInfo_Title: String { return self._s[3897]! } - public var Login_PadPhoneHelp: String { return self._s[3898]! } - public var AutoDownloadSettings_TypeGroupChats: String { return self._s[3900]! } - public var PrivacyPolicy_DeclineLastWarning: String { return self._s[3902]! } - public var NotificationsSound_Complete: String { return self._s[3903]! } - public var SettingsSearch_Synonyms_Privacy_Data_Title: String { return self._s[3904]! } - public var Group_Info_AdminLog: String { return self._s[3905]! } - public var GroupPermission_NotAvailableInPublicGroups: String { return self._s[3906]! } + public var AuthSessions_Terminate: String { return self._s[3892]! } + public var Wallet_WordImport_CanNotRemember: String { return self._s[3893]! } + public var Checkout_NewCard_CardholderNamePlaceholder: String { return self._s[3895]! } + public var KeyCommand_JumpToPreviousUnreadChat: String { return self._s[3896]! } + public var PhotoEditor_Set: String { return self._s[3897]! } + public var EmptyGroupInfo_Title: String { return self._s[3898]! } + public var Login_PadPhoneHelp: String { return self._s[3899]! } + public var AutoDownloadSettings_TypeGroupChats: String { return self._s[3901]! } + public var PrivacyPolicy_DeclineLastWarning: String { return self._s[3903]! } + public var NotificationsSound_Complete: String { return self._s[3904]! } + public var SettingsSearch_Synonyms_Privacy_Data_Title: String { return self._s[3905]! } + public var Group_Info_AdminLog: String { return self._s[3906]! } + public var GroupPermission_NotAvailableInPublicGroups: String { return self._s[3907]! } public func Wallet_Time_PreciseDate_m11(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3907]!, self._r[3907]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3908]!, self._r[3908]!, [_1, _2, _3]) } - public var Channel_AdminLog_InfoPanelAlertText: String { return self._s[3908]! } - public var Group_Location_CreateInThisPlace: String { return self._s[3910]! } - public var Conversation_Admin: String { return self._s[3911]! } - public var Conversation_GifTooltip: String { return self._s[3912]! } - public var Passport_NotLoggedInMessage: String { return self._s[3913]! } + public var Channel_AdminLog_InfoPanelAlertText: String { return self._s[3909]! } + public var Group_Location_CreateInThisPlace: String { return self._s[3911]! } + public var Conversation_Admin: String { return self._s[3912]! } + public var Conversation_GifTooltip: String { return self._s[3913]! } + public var Passport_NotLoggedInMessage: String { return self._s[3914]! } public func AutoDownloadSettings_OnFor(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3915]!, self._r[3915]!, [_0]) + return formatWithArgumentRanges(self._s[3916]!, self._r[3916]!, [_0]) } - public var Profile_MessageLifetimeForever: String { return self._s[3916]! } - public var SharedMedia_EmptyTitle: String { return self._s[3918]! } - public var Channel_Edit_PrivatePublicLinkAlert: String { return self._s[3920]! } - public var Username_Help: String { return self._s[3921]! } - public var DialogList_LanguageTooltip: String { return self._s[3923]! } - public var Map_LoadError: String { return self._s[3924]! } - public var Login_PhoneNumberAlreadyAuthorized: String { return self._s[3925]! } - public var Channel_AdminLog_AddMembers: String { return self._s[3926]! } - public var ArchivedChats_IntroTitle2: String { return self._s[3927]! } - public var Notification_Exceptions_NewException: String { return self._s[3928]! } - public var TwoStepAuth_EmailTitle: String { return self._s[3929]! } - public var WatchRemote_AlertText: String { return self._s[3930]! } + public var Profile_MessageLifetimeForever: String { return self._s[3917]! } + public var SharedMedia_EmptyTitle: String { return self._s[3919]! } + public var Channel_Edit_PrivatePublicLinkAlert: String { return self._s[3921]! } + public var Username_Help: String { return self._s[3922]! } + public var DialogList_LanguageTooltip: String { return self._s[3924]! } + public var Map_LoadError: String { return self._s[3925]! } + public var Login_PhoneNumberAlreadyAuthorized: String { return self._s[3926]! } + public var Channel_AdminLog_AddMembers: String { return self._s[3927]! } + public var ArchivedChats_IntroTitle2: String { return self._s[3928]! } + public var Notification_Exceptions_NewException: String { return self._s[3929]! } + public var TwoStepAuth_EmailTitle: String { return self._s[3930]! } + public var WatchRemote_AlertText: String { return self._s[3931]! } public func Wallet_Send_ConfirmationText(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3931]!, self._r[3931]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3932]!, self._r[3932]!, [_1, _2, _3]) } - public var ChatSettings_ConnectionType_Title: String { return self._s[3935]! } - public var WebBrowser_DefaultBrowser: String { return self._s[3936]! } + public var ChatSettings_ConnectionType_Title: String { return self._s[3936]! } + public var WebBrowser_DefaultBrowser: String { return self._s[3937]! } public func Settings_CheckPhoneNumberTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3937]!, self._r[3937]!, [_0]) + return formatWithArgumentRanges(self._s[3938]!, self._r[3938]!, [_0]) } - public var SettingsSearch_Synonyms_Calls_CallTab: String { return self._s[3938]! } - public var Passport_Address_CountryPlaceholder: String { return self._s[3939]! } + public var SettingsSearch_Synonyms_Calls_CallTab: String { return self._s[3939]! } + public var Passport_Address_CountryPlaceholder: String { return self._s[3940]! } public func DialogList_AwaitingEncryption(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3940]!, self._r[3940]!, [_0]) + return formatWithArgumentRanges(self._s[3941]!, self._r[3941]!, [_0]) } public func Time_PreciseDate_m6(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3941]!, self._r[3941]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3942]!, self._r[3942]!, [_1, _2, _3]) } - public var Group_AdminLog_EmptyText: String { return self._s[3942]! } - public var SettingsSearch_Synonyms_Appearance_Title: String { return self._s[3943]! } - public var Conversation_PrivateChannelTooltip: String { return self._s[3945]! } - public var Wallet_Created_ExportErrorText: String { return self._s[3946]! } - public var ChatList_UndoArchiveText1: String { return self._s[3947]! } - public var AccessDenied_VideoMicrophone: String { return self._s[3948]! } - public var Conversation_ContextMenuStickerPackAdd: String { return self._s[3949]! } - public var Cache_ClearNone: String { return self._s[3950]! } - public var SocksProxySetup_FailedToConnect: String { return self._s[3951]! } - public var Permissions_NotificationsTitle_v0: String { return self._s[3952]! } + public var Group_AdminLog_EmptyText: String { return self._s[3943]! } + public var SettingsSearch_Synonyms_Appearance_Title: String { return self._s[3944]! } + public var Conversation_PrivateChannelTooltip: String { return self._s[3946]! } + public var Wallet_Created_ExportErrorText: String { return self._s[3947]! } + public var ChatList_UndoArchiveText1: String { return self._s[3948]! } + public var AccessDenied_VideoMicrophone: String { return self._s[3949]! } + public var Conversation_ContextMenuStickerPackAdd: String { return self._s[3950]! } + public var Cache_ClearNone: String { return self._s[3951]! } + public var SocksProxySetup_FailedToConnect: String { return self._s[3952]! } + public var Permissions_NotificationsTitle_v0: String { return self._s[3953]! } public func Channel_AdminLog_MessageEdited(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3953]!, self._r[3953]!, [_0]) + return formatWithArgumentRanges(self._s[3954]!, self._r[3954]!, [_0]) } - public var Passport_Identity_Country: String { return self._s[3954]! } + public var Passport_Identity_Country: String { return self._s[3955]! } public func ChatSettings_AutoDownloadSettings_TypeFile(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3955]!, self._r[3955]!, [_0]) - } - public func Notification_CreatedChat(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3956]!, self._r[3956]!, [_0]) } - public var Exceptions_AddToExceptions: String { return self._s[3957]! } - public var AccessDenied_Settings: String { return self._s[3958]! } - public var Passport_Address_TypeUtilityBillUploadScan: String { return self._s[3959]! } - public var Month_ShortMay: String { return self._s[3960]! } - public var Compose_NewGroup: String { return self._s[3962]! } - public var Group_Setup_TypePrivate: String { return self._s[3964]! } - public var Login_PadPhoneHelpTitle: String { return self._s[3966]! } - public var Appearance_ThemeDayClassic: String { return self._s[3967]! } - public var Channel_AdminLog_MessagePreviousCaption: String { return self._s[3968]! } - public var AutoDownloadSettings_OffForAll: String { return self._s[3969]! } - public var Privacy_GroupsAndChannels_WhoCanAddMe: String { return self._s[3970]! } - public var Conversation_typing: String { return self._s[3972]! } - public var Undo_ScheduledMessagesCleared: String { return self._s[3973]! } - public var Paint_Masks: String { return self._s[3974]! } - public var Contacts_DeselectAll: String { return self._s[3975]! } - public func Wallet_Updated_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3976]!, self._r[3976]!, [_0]) + public func Notification_CreatedChat(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3957]!, self._r[3957]!, [_0]) } - public var CreatePoll_MultipleChoiceQuizAlert: String { return self._s[3977]! } - public var Username_InvalidTaken: String { return self._s[3978]! } - public var Call_StatusNoAnswer: String { return self._s[3979]! } - public var TwoStepAuth_EmailAddSuccess: String { return self._s[3980]! } - public var SettingsSearch_Synonyms_Privacy_BlockedUsers: String { return self._s[3981]! } - public var Passport_Identity_Selfie: String { return self._s[3982]! } - public var Login_InfoLastNamePlaceholder: String { return self._s[3983]! } - public var Privacy_SecretChatsLinkPreviewsHelp: String { return self._s[3984]! } - public var Conversation_ClearSecretHistory: String { return self._s[3985]! } - public var PeopleNearby_Description: String { return self._s[3987]! } - public var NetworkUsageSettings_Title: String { return self._s[3988]! } - public var Your_cards_security_code_is_invalid: String { return self._s[3990]! } + public var Exceptions_AddToExceptions: String { return self._s[3958]! } + public var AccessDenied_Settings: String { return self._s[3959]! } + public var Passport_Address_TypeUtilityBillUploadScan: String { return self._s[3960]! } + public var Month_ShortMay: String { return self._s[3961]! } + public var Compose_NewGroup: String { return self._s[3963]! } + public var Group_Setup_TypePrivate: String { return self._s[3965]! } + public var Login_PadPhoneHelpTitle: String { return self._s[3967]! } + public var Appearance_ThemeDayClassic: String { return self._s[3968]! } + public var Channel_AdminLog_MessagePreviousCaption: String { return self._s[3969]! } + public var AutoDownloadSettings_OffForAll: String { return self._s[3970]! } + public var Privacy_GroupsAndChannels_WhoCanAddMe: String { return self._s[3971]! } + public var Conversation_typing: String { return self._s[3973]! } + public var Undo_ScheduledMessagesCleared: String { return self._s[3974]! } + public var Paint_Masks: String { return self._s[3975]! } + public var Contacts_DeselectAll: String { return self._s[3976]! } + public func Wallet_Updated_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3977]!, self._r[3977]!, [_0]) + } + public var CreatePoll_MultipleChoiceQuizAlert: String { return self._s[3978]! } + public var Username_InvalidTaken: String { return self._s[3979]! } + public var Call_StatusNoAnswer: String { return self._s[3980]! } + public var TwoStepAuth_EmailAddSuccess: String { return self._s[3981]! } + public var SettingsSearch_Synonyms_Privacy_BlockedUsers: String { return self._s[3982]! } + public var Passport_Identity_Selfie: String { return self._s[3983]! } + public var Login_InfoLastNamePlaceholder: String { return self._s[3984]! } + public var Privacy_SecretChatsLinkPreviewsHelp: String { return self._s[3985]! } + public var Conversation_ClearSecretHistory: String { return self._s[3986]! } + public var PeopleNearby_Description: String { return self._s[3988]! } + public var NetworkUsageSettings_Title: String { return self._s[3989]! } + public var Your_cards_security_code_is_invalid: String { return self._s[3991]! } public func Notification_LeftChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3992]!, self._r[3992]!, [_0]) + return formatWithArgumentRanges(self._s[3993]!, self._r[3993]!, [_0]) } public func Call_CallInProgressMessage(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3993]!, self._r[3993]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3994]!, self._r[3994]!, [_1, _2]) } - public var SaveIncomingPhotosSettings_From: String { return self._s[3995]! } - public var VoiceOver_Navigation_Search: String { return self._s[3996]! } - public var Map_LiveLocationTitle: String { return self._s[3997]! } - public var Login_InfoAvatarAdd: String { return self._s[3998]! } - public var Passport_Identity_FilesView: String { return self._s[3999]! } - public var UserInfo_GenericPhoneLabel: String { return self._s[4000]! } - public var Privacy_Calls_NeverAllow: String { return self._s[4001]! } - public var VoiceOver_Chat_File: String { return self._s[4002]! } - public var Wallet_Settings_DeleteWalletInfo: String { return self._s[4003]! } + public var SaveIncomingPhotosSettings_From: String { return self._s[3996]! } + public var VoiceOver_Navigation_Search: String { return self._s[3997]! } + public var Map_LiveLocationTitle: String { return self._s[3998]! } + public var Login_InfoAvatarAdd: String { return self._s[3999]! } + public var Passport_Identity_FilesView: String { return self._s[4000]! } + public var UserInfo_GenericPhoneLabel: String { return self._s[4001]! } + public var Privacy_Calls_NeverAllow: String { return self._s[4002]! } + public var VoiceOver_Chat_File: String { return self._s[4003]! } + public var Wallet_Settings_DeleteWalletInfo: String { return self._s[4004]! } public func Contacts_AddPhoneNumber(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4004]!, self._r[4004]!, [_0]) + return formatWithArgumentRanges(self._s[4005]!, self._r[4005]!, [_0]) } - public var ContactInfo_PhoneNumberHidden: String { return self._s[4005]! } - public var TwoStepAuth_ConfirmationText: String { return self._s[4006]! } - public var ChatSettings_AutomaticVideoMessageDownload: String { return self._s[4007]! } + public var ContactInfo_PhoneNumberHidden: String { return self._s[4006]! } + public var TwoStepAuth_ConfirmationText: String { return self._s[4007]! } + public var ChatSettings_AutomaticVideoMessageDownload: String { return self._s[4008]! } public func PUSH_CHAT_MESSAGE_VIDEOS(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4008]!, self._r[4008]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4009]!, self._r[4009]!, [_1, _2, _3]) } - public var Channel_AdminLogFilter_AdminsAll: String { return self._s[4009]! } - public var Wallet_Intro_CreateErrorText: String { return self._s[4010]! } - public var Tour_Title2: String { return self._s[4011]! } - public var Wallet_Sent_ViewWallet: String { return self._s[4012]! } - public var Conversation_FileOpenIn: String { return self._s[4013]! } - public var Checkout_ErrorPrecheckoutFailed: String { return self._s[4014]! } - public var Wallet_Send_ErrorInvalidAddress: String { return self._s[4015]! } - public var Wallpaper_Set: String { return self._s[4016]! } - public var Passport_Identity_Translations: String { return self._s[4018]! } + public var Channel_AdminLogFilter_AdminsAll: String { return self._s[4010]! } + public var Wallet_Intro_CreateErrorText: String { return self._s[4011]! } + public var Tour_Title2: String { return self._s[4012]! } + public var Wallet_Sent_ViewWallet: String { return self._s[4013]! } + public var Conversation_FileOpenIn: String { return self._s[4014]! } + public var Checkout_ErrorPrecheckoutFailed: String { return self._s[4015]! } + public var Wallet_Send_ErrorInvalidAddress: String { return self._s[4016]! } + public var Wallpaper_Set: String { return self._s[4017]! } + public var Passport_Identity_Translations: String { return self._s[4019]! } public func Channel_AdminLog_MessageChangedChannelAbout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4019]!, self._r[4019]!, [_0]) + return formatWithArgumentRanges(self._s[4020]!, self._r[4020]!, [_0]) } - public var Channel_LeaveChannel: String { return self._s[4020]! } + public var Channel_LeaveChannel: String { return self._s[4021]! } public func PINNED_INVOICE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4021]!, self._r[4021]!, [_1]) + return formatWithArgumentRanges(self._s[4022]!, self._r[4022]!, [_1]) } - public var SettingsSearch_Synonyms_Proxy_AddProxy: String { return self._s[4023]! } - public var PhotoEditor_HighlightsTint: String { return self._s[4024]! } - public var MessagePoll_LabelPoll: String { return self._s[4025]! } - public var Passport_Email_Delete: String { return self._s[4026]! } - public var Conversation_Mute: String { return self._s[4028]! } - public var Channel_AddBotAsAdmin: String { return self._s[4029]! } - public var Channel_AdminLog_CanSendMessages: String { return self._s[4031]! } - public var Wallet_Configuration_BlockchainNameChangedText: String { return self._s[4032]! } - public var ChatSettings_IntentsSettings: String { return self._s[4034]! } - public var Channel_Management_LabelOwner: String { return self._s[4035]! } + public var SettingsSearch_Synonyms_Proxy_AddProxy: String { return self._s[4024]! } + public var PhotoEditor_HighlightsTint: String { return self._s[4025]! } + public var MessagePoll_LabelPoll: String { return self._s[4026]! } + public var Passport_Email_Delete: String { return self._s[4027]! } + public var Conversation_Mute: String { return self._s[4029]! } + public var Channel_AddBotAsAdmin: String { return self._s[4030]! } + public var Channel_AdminLog_CanSendMessages: String { return self._s[4032]! } + public var Wallet_Configuration_BlockchainNameChangedText: String { return self._s[4033]! } + public var ChatSettings_IntentsSettings: String { return self._s[4035]! } + public var Channel_Management_LabelOwner: String { return self._s[4036]! } public func Notification_PassportValuesSentMessage(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4036]!, self._r[4036]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4037]!, self._r[4037]!, [_1, _2]) } - public var Calls_CallTabDescription: String { return self._s[4037]! } - public var Passport_Identity_NativeNameHelp: String { return self._s[4038]! } - public var Common_No: String { return self._s[4039]! } - public var Weekday_Sunday: String { return self._s[4040]! } - public var Notification_Reply: String { return self._s[4041]! } - public var Conversation_ViewMessage: String { return self._s[4042]! } + public var Calls_CallTabDescription: String { return self._s[4038]! } + public var Passport_Identity_NativeNameHelp: String { return self._s[4039]! } + public var Common_No: String { return self._s[4040]! } + public var Weekday_Sunday: String { return self._s[4041]! } + public var Notification_Reply: String { return self._s[4042]! } + public var Conversation_ViewMessage: String { return self._s[4043]! } public func Checkout_SavePasswordTimeoutAndFaceId(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4043]!, self._r[4043]!, [_0]) - } - public func Map_LiveLocationPrivateDescription(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[4044]!, self._r[4044]!, [_0]) } + public func Map_LiveLocationPrivateDescription(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[4045]!, self._r[4045]!, [_0]) + } public func Wallet_Time_PreciseDate_m7(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4045]!, self._r[4045]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4046]!, self._r[4046]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_EditProfile_AddAccount: String { return self._s[4046]! } - public var Wallet_Send_Title: String { return self._s[4047]! } - public var Message_PinnedDocumentMessage: String { return self._s[4048]! } - public var Wallet_Info_RefreshErrorText: String { return self._s[4049]! } - public var DialogList_TabTitle: String { return self._s[4051]! } - public var ChatSettings_AutoPlayTitle: String { return self._s[4052]! } - public var Passport_FieldEmail: String { return self._s[4053]! } - public var Conversation_UnpinMessageAlert: String { return self._s[4054]! } - public var Passport_Address_TypeBankStatement: String { return self._s[4055]! } - public var Wallet_SecureStorageReset_Title: String { return self._s[4056]! } - public var Passport_Identity_ExpiryDate: String { return self._s[4057]! } - public var Privacy_Calls_P2P: String { return self._s[4058]! } + public var SettingsSearch_Synonyms_EditProfile_AddAccount: String { return self._s[4047]! } + public var Wallet_Send_Title: String { return self._s[4048]! } + public var Message_PinnedDocumentMessage: String { return self._s[4049]! } + public var Wallet_Info_RefreshErrorText: String { return self._s[4050]! } + public var DialogList_TabTitle: String { return self._s[4052]! } + public var ChatSettings_AutoPlayTitle: String { return self._s[4053]! } + public var Passport_FieldEmail: String { return self._s[4054]! } + public var Conversation_UnpinMessageAlert: String { return self._s[4055]! } + public var Passport_Address_TypeBankStatement: String { return self._s[4056]! } + public var Wallet_SecureStorageReset_Title: String { return self._s[4057]! } + public var Passport_Identity_ExpiryDate: String { return self._s[4058]! } + public var Privacy_Calls_P2P: String { return self._s[4059]! } public func CancelResetAccount_Success(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4060]!, self._r[4060]!, [_0]) + return formatWithArgumentRanges(self._s[4061]!, self._r[4061]!, [_0]) } - public var SocksProxySetup_UseForCallsHelp: String { return self._s[4061]! } + public var SocksProxySetup_UseForCallsHelp: String { return self._s[4062]! } public func PUSH_CHAT_ALBUM(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4062]!, self._r[4062]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4063]!, self._r[4063]!, [_1, _2]) } - public var Stickers_ClearRecent: String { return self._s[4063]! } - public var EnterPasscode_ChangeTitle: String { return self._s[4064]! } - public var TwoFactorSetup_Email_Title: String { return self._s[4065]! } - public var Passport_InfoText: String { return self._s[4066]! } - public var Checkout_NewCard_SaveInfoEnableHelp: String { return self._s[4067]! } + public var Stickers_ClearRecent: String { return self._s[4064]! } + public var EnterPasscode_ChangeTitle: String { return self._s[4065]! } + public var TwoFactorSetup_Email_Title: String { return self._s[4066]! } + public var Passport_InfoText: String { return self._s[4067]! } + public var Checkout_NewCard_SaveInfoEnableHelp: String { return self._s[4068]! } public func Login_InvalidPhoneEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4068]!, self._r[4068]!, [_0]) + return formatWithArgumentRanges(self._s[4069]!, self._r[4069]!, [_0]) } public func Time_PreciseDate_m3(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4069]!, self._r[4069]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4070]!, self._r[4070]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChannels: String { return self._s[4070]! } - public var ScheduledMessages_PollUnavailable: String { return self._s[4071]! } - public var VoiceOver_Navigation_Compose: String { return self._s[4072]! } - public var Passport_Identity_EditDriversLicense: String { return self._s[4073]! } - public var Conversation_TapAndHoldToRecord: String { return self._s[4075]! } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChats: String { return self._s[4076]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChannels: String { return self._s[4071]! } + public var ScheduledMessages_PollUnavailable: String { return self._s[4072]! } + public var VoiceOver_Navigation_Compose: String { return self._s[4073]! } + public var Passport_Identity_EditDriversLicense: String { return self._s[4074]! } + public var Conversation_TapAndHoldToRecord: String { return self._s[4076]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChats: String { return self._s[4077]! } public func Notification_CallTimeFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4077]!, self._r[4077]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4078]!, self._r[4078]!, [_1, _2]) } - public var Channel_EditAdmin_PermissionInviteViaLink: String { return self._s[4079]! } - public var ChatSettings_OpenLinksIn: String { return self._s[4080]! } - public var Map_HomeAndWorkTitle: String { return self._s[4081]! } + public var Channel_EditAdmin_PermissionInviteViaLink: String { return self._s[4080]! } + public var ChatSettings_OpenLinksIn: String { return self._s[4081]! } + public var Map_HomeAndWorkTitle: String { return self._s[4082]! } public func Generic_OpenHiddenLinkAlert(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4083]!, self._r[4083]!, [_0]) + return formatWithArgumentRanges(self._s[4084]!, self._r[4084]!, [_0]) } - public var DialogList_Unread: String { return self._s[4084]! } + public var DialogList_Unread: String { return self._s[4085]! } public func PUSH_CHAT_MESSAGE_GIF(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4085]!, self._r[4085]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4086]!, self._r[4086]!, [_1, _2]) } - public var User_DeletedAccount: String { return self._s[4086]! } - public var OwnershipTransfer_SetupTwoStepAuth: String { return self._s[4087]! } + public var User_DeletedAccount: String { return self._s[4087]! } + public var OwnershipTransfer_SetupTwoStepAuth: String { return self._s[4088]! } public func Watch_Time_ShortYesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4088]!, self._r[4088]!, [_0]) + return formatWithArgumentRanges(self._s[4089]!, self._r[4089]!, [_0]) } - public var UserInfo_NotificationsDefault: String { return self._s[4089]! } - public var SharedMedia_CategoryMedia: String { return self._s[4090]! } - public var SocksProxySetup_ProxyStatusUnavailable: String { return self._s[4091]! } - public var Channel_AdminLog_MessageRestrictedForever: String { return self._s[4092]! } - public var Watch_ChatList_Compose: String { return self._s[4093]! } - public var Notifications_MessageNotificationsExceptionsHelp: String { return self._s[4094]! } - public var AutoDownloadSettings_Delimeter: String { return self._s[4095]! } - public var Watch_Microphone_Access: String { return self._s[4096]! } - public var Group_Setup_HistoryHeader: String { return self._s[4097]! } - public var Map_SetThisLocation: String { return self._s[4098]! } - public var Appearance_ThemePreview_Chat_2_ReplyName: String { return self._s[4099]! } - public var Activity_UploadingPhoto: String { return self._s[4100]! } - public var Conversation_Edit: String { return self._s[4102]! } - public var Group_ErrorSendRestrictedMedia: String { return self._s[4103]! } - public var Login_TermsOfServiceDecline: String { return self._s[4104]! } - public var Message_PinnedContactMessage: String { return self._s[4105]! } + public var UserInfo_NotificationsDefault: String { return self._s[4090]! } + public var SharedMedia_CategoryMedia: String { return self._s[4091]! } + public var SocksProxySetup_ProxyStatusUnavailable: String { return self._s[4092]! } + public var Channel_AdminLog_MessageRestrictedForever: String { return self._s[4093]! } + public var Watch_ChatList_Compose: String { return self._s[4094]! } + public var Notifications_MessageNotificationsExceptionsHelp: String { return self._s[4095]! } + public var AutoDownloadSettings_Delimeter: String { return self._s[4096]! } + public var Watch_Microphone_Access: String { return self._s[4097]! } + public var Group_Setup_HistoryHeader: String { return self._s[4098]! } + public var Map_SetThisLocation: String { return self._s[4099]! } + public var Appearance_ThemePreview_Chat_2_ReplyName: String { return self._s[4100]! } + public var Activity_UploadingPhoto: String { return self._s[4101]! } + public var Conversation_Edit: String { return self._s[4103]! } + public var Group_ErrorSendRestrictedMedia: String { return self._s[4104]! } + public var Login_TermsOfServiceDecline: String { return self._s[4105]! } + public var Message_PinnedContactMessage: String { return self._s[4106]! } public func Channel_AdminLog_MessageRestrictedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4106]!, self._r[4106]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4107]!, self._r[4107]!, [_1, _2]) } public func Login_PhoneBannedEmailBody(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4107]!, self._r[4107]!, [_1, _2, _3, _4, _5]) + return formatWithArgumentRanges(self._s[4108]!, self._r[4108]!, [_1, _2, _3, _4, _5]) } - public var Appearance_LargeEmoji: String { return self._s[4108]! } - public var TwoStepAuth_AdditionalPassword: String { return self._s[4110]! } - public var EditTheme_Edit_Preview_IncomingReplyText: String { return self._s[4111]! } + public var Appearance_LargeEmoji: String { return self._s[4109]! } + public var TwoStepAuth_AdditionalPassword: String { return self._s[4111]! } + public var EditTheme_Edit_Preview_IncomingReplyText: String { return self._s[4112]! } public func PUSH_CHAT_DELETE_YOU(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4112]!, self._r[4112]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4113]!, self._r[4113]!, [_1, _2]) } - public var Passport_Phone_EnterOtherNumber: String { return self._s[4113]! } - public var Message_PinnedPhotoMessage: String { return self._s[4114]! } - public var Passport_FieldPhone: String { return self._s[4115]! } - public var TwoStepAuth_RecoveryEmailAddDescription: String { return self._s[4116]! } - public var ChatSettings_AutoPlayGifs: String { return self._s[4117]! } - public var InfoPlist_NSCameraUsageDescription: String { return self._s[4119]! } - public var Conversation_Call: String { return self._s[4120]! } - public var Common_TakePhoto: String { return self._s[4122]! } - public var Group_EditAdmin_RankTitle: String { return self._s[4123]! } - public var Wallet_Receive_CommentHeader: String { return self._s[4124]! } - public var Channel_NotificationLoading: String { return self._s[4125]! } + public var Passport_Phone_EnterOtherNumber: String { return self._s[4114]! } + public var Message_PinnedPhotoMessage: String { return self._s[4115]! } + public var Passport_FieldPhone: String { return self._s[4116]! } + public var TwoStepAuth_RecoveryEmailAddDescription: String { return self._s[4117]! } + public var ChatSettings_AutoPlayGifs: String { return self._s[4118]! } + public var InfoPlist_NSCameraUsageDescription: String { return self._s[4120]! } + public var Conversation_Call: String { return self._s[4121]! } + public var Common_TakePhoto: String { return self._s[4123]! } + public var Group_EditAdmin_RankTitle: String { return self._s[4124]! } + public var Wallet_Receive_CommentHeader: String { return self._s[4125]! } + public var Channel_NotificationLoading: String { return self._s[4126]! } public func Notification_Exceptions_Sound(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4126]!, self._r[4126]!, [_0]) - } - public func ScheduledMessages_ScheduledDate(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[4127]!, self._r[4127]!, [_0]) } + public func ScheduledMessages_ScheduledDate(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[4128]!, self._r[4128]!, [_0]) + } public func PUSH_CHANNEL_MESSAGE_VIDEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4128]!, self._r[4128]!, [_1]) + return formatWithArgumentRanges(self._s[4129]!, self._r[4129]!, [_1]) } - public var Permissions_SiriTitle_v0: String { return self._s[4129]! } + public var Permissions_SiriTitle_v0: String { return self._s[4130]! } public func VoiceOver_Chat_VoiceMessageFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4130]!, self._r[4130]!, [_0]) - } - public func Login_ResetAccountProtected_Text(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[4131]!, self._r[4131]!, [_0]) } - public var Channel_MessagePhotoRemoved: String { return self._s[4132]! } - public var Wallet_Info_ReceiveGrams: String { return self._s[4133]! } - public var ClearCache_FreeSpace: String { return self._s[4134]! } - public var Common_edit: String { return self._s[4135]! } - public var PrivacySettings_AuthSessions: String { return self._s[4136]! } - public var Month_ShortJune: String { return self._s[4137]! } - public var PrivacyLastSeenSettings_AlwaysShareWith_Placeholder: String { return self._s[4138]! } - public var Call_ReportSend: String { return self._s[4139]! } - public var Watch_LastSeen_JustNow: String { return self._s[4140]! } - public var Notifications_MessageNotifications: String { return self._s[4141]! } - public var WallpaperSearch_ColorGreen: String { return self._s[4142]! } - public var BroadcastListInfo_AddRecipient: String { return self._s[4144]! } - public var Group_Status: String { return self._s[4145]! } + public func Login_ResetAccountProtected_Text(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[4132]!, self._r[4132]!, [_0]) + } + public var Channel_MessagePhotoRemoved: String { return self._s[4133]! } + public var Wallet_Info_ReceiveGrams: String { return self._s[4134]! } + public var ClearCache_FreeSpace: String { return self._s[4135]! } + public var Common_edit: String { return self._s[4136]! } + public var PrivacySettings_AuthSessions: String { return self._s[4137]! } + public var Month_ShortJune: String { return self._s[4138]! } + public var PrivacyLastSeenSettings_AlwaysShareWith_Placeholder: String { return self._s[4139]! } + public var Call_ReportSend: String { return self._s[4140]! } + public var Watch_LastSeen_JustNow: String { return self._s[4141]! } + public var Notifications_MessageNotifications: String { return self._s[4142]! } + public var WallpaperSearch_ColorGreen: String { return self._s[4143]! } + public var BroadcastListInfo_AddRecipient: String { return self._s[4145]! } + public var Group_Status: String { return self._s[4146]! } public func AutoNightTheme_LocationHelp(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4146]!, self._r[4146]!, [_0, _1]) + return formatWithArgumentRanges(self._s[4147]!, self._r[4147]!, [_0, _1]) } - public var TextFormat_AddLinkTitle: String { return self._s[4147]! } - public var ShareMenu_ShareTo: String { return self._s[4148]! } - public var Conversation_Moderate_Ban: String { return self._s[4149]! } + public var TextFormat_AddLinkTitle: String { return self._s[4148]! } + public var ShareMenu_ShareTo: String { return self._s[4149]! } + public var Conversation_Moderate_Ban: String { return self._s[4150]! } public func Conversation_DeleteMessagesFor(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4150]!, self._r[4150]!, [_0]) + return formatWithArgumentRanges(self._s[4151]!, self._r[4151]!, [_0]) } - public var SharedMedia_ViewInChat: String { return self._s[4151]! } - public var Map_LiveLocationFor8Hours: String { return self._s[4152]! } + public var SharedMedia_ViewInChat: String { return self._s[4152]! } + public var Map_LiveLocationFor8Hours: String { return self._s[4153]! } public func PUSH_PINNED_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4153]!, self._r[4153]!, [_1]) + return formatWithArgumentRanges(self._s[4154]!, self._r[4154]!, [_1]) } public func PUSH_PINNED_POLL(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4154]!, self._r[4154]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4155]!, self._r[4155]!, [_1, _2]) } public func Map_AccurateTo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4156]!, self._r[4156]!, [_0]) + return formatWithArgumentRanges(self._s[4157]!, self._r[4157]!, [_0]) } - public var Map_OpenInHereMaps: String { return self._s[4157]! } - public var Appearance_ReduceMotion: String { return self._s[4158]! } + public var Map_OpenInHereMaps: String { return self._s[4158]! } + public var Appearance_ReduceMotion: String { return self._s[4159]! } public func PUSH_MESSAGE_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4159]!, self._r[4159]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4160]!, self._r[4160]!, [_1, _2]) } - public var Channel_Setup_TypePublicHelp: String { return self._s[4160]! } - public var Passport_Identity_EditInternalPassport: String { return self._s[4161]! } - public var PhotoEditor_Skip: String { return self._s[4162]! } - public func MuteExpires_Minutes(_ value: Int32) -> String { + public var Channel_Setup_TypePublicHelp: String { return self._s[4161]! } + public var Passport_Identity_EditInternalPassport: String { return self._s[4162]! } + public var PhotoEditor_Skip: String { return self._s[4163]! } + public func CreatePoll_AddMoreOptions(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue) } - public func StickerPack_RemoveStickerCount(_ value: Int32) -> String { + public func GroupInfo_ShowMoreMembers(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue) } - public func ChatList_SelectedChats(_ value: Int32) -> String { + public func Call_Minutes(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[2 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessageTimer_ShortDays(_ value: Int32) -> String { + public func MessageTimer_ShortWeeks(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[3 * 6 + Int(form.rawValue)]!, stringValue) } - public func ChatList_DeleteConfirmation(_ value: Int32) -> String { + public func LastSeen_MinutesAgo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[4 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessageTimer_ShortSeconds(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[5 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_PollVotes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[6 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notification_GameScoreExtended(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[7 * 6 + Int(form.rawValue)]!, stringValue) - } - public func CreatePoll_AddMoreOptions(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[8 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notification_GameScoreSelfSimple(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[9 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_ExceptionMuteExpires_Days(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[10 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Minutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[11 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedGifs(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[12 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedPolls(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[13 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_RemoveMaskCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[14 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessagePoll_VotedCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[15 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Media_SharePhoto(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[16 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PasscodeSettings_FailedAttempts(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[17 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteExpires_Days(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[18 * 6 + Int(form.rawValue)]!, stringValue) + public func PUSH_CHAT_MESSAGE_VIDEOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[5 * 6 + Int(form.rawValue)]!, _2, _1, _3) } public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[19 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteExpires_Hours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[20 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Chat_DeleteMessagesConfirmation(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[21 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[22 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func MuteFor_Hours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[23 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedMessages(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[24 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedPhotos(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[25 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_Minutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[26 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Conversation_LiveLocationMembersCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[27 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Contacts_ImportersCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[28 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_DeleteItemsConfirmation(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[29 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedContacts(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[30 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Wallet_Updated_HoursAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[31 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Wallpaper_DeleteConfirmation(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[32 * 6 + Int(form.rawValue)]!, stringValue) - } - public func LiveLocationUpdated_MinutesAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[33 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_ShortMinutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[34 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreSelfExtended(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[35 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_PollOptionCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[36 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[37 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func Conversation_StatusOnline(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[38 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Watch_UserInfo_Mute(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[39 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGE_FWDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[40 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func InviteText_ContactsCountText(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[41 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessagePoll_QuizCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[42 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_Video(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[43 * 6 + Int(form.rawValue)]!, stringValue) - } - public func AttachmentMenu_SendPhoto(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[44 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Passport_Scans(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[45 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortWeeks(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[46 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_Exceptions(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[47 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGE_PHOTOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[48 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func PUSH_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[49 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func MessageTimer_Weeks(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[50 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_ExceptionMuteExpires_Hours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[51 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortMinutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[52 * 6 + Int(form.rawValue)]!, stringValue) - } - public func DialogList_LiveLocationChatsCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[53 * 6 + Int(form.rawValue)]!, stringValue) - } - public func OldChannels_InactiveWeek(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[54 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Conversation_StatusSubscribers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[55 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Forward_ConfirmMultipleFiles(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[56 * 6 + Int(form.rawValue)]!, stringValue) - } - public func AttachmentMenu_SendVideo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[57 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Watch_LastSeen_HoursAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[58 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Media_ShareVideo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[59 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_File(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[60 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Watch_LastSeen_MinutesAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[61 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PrivacyLastSeenSettings_AddUsers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[62 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_Generic(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[63 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_ContactEmailCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[64 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[65 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func PUSH_CHANNEL_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[66 * 6 + Int(form.rawValue)]!, _1, _2) + return String(format: self._ps[6 * 6 + Int(form.rawValue)]!, stringValue) } public func ForwardedStickers(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[67 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[7 * 6 + Int(form.rawValue)]!, stringValue) } - public func GroupInfo_ShowMoreMembers(_ value: Int32) -> String { + public func ForwardedPhotos(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[68 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ChatList_DeletedChats(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[69 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Conversation_SelectedMessages(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[70 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notification_GameScoreSelfExtended(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[71 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[72 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func LiveLocation_MenuChatsCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[73 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Years(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[74 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notification_GameScoreSimple(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[75 * 6 + Int(form.rawValue)]!, stringValue) - } - public func OldChannels_Leave(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[76 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreSelfSimple(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[77 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PollResults_ShowMore(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[78 * 6 + Int(form.rawValue)]!, stringValue) - } - public func OldChannels_InactiveMonth(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[79 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[80 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func SharedMedia_Link(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[81 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGES(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[82 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func ServiceMessage_GameScoreExtended(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[83 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[84 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func MessageTimer_Seconds(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[85 * 6 + Int(form.rawValue)]!, stringValue) - } - public func UserCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[86 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Map_ETAHours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[87 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_ExceptionMuteExpires_Minutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[88 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGE_ROUNDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[89 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func MessageTimer_ShortHours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[90 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_AddMaskCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[91 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_Seconds(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[92 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedVideos(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[93 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Conversation_StatusMembers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[94 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_AddStickerCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[95 * 6 + Int(form.rawValue)]!, stringValue) - } - public func OldChannels_InactiveYear(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[96 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedVideoMessages(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[97 * 6 + Int(form.rawValue)]!, stringValue) - } - public func AttachmentMenu_SendItem(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[98 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedAuthorsOthers(_ selector: Int32, _ _0: String, _ _1: String) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[99 * 6 + Int(form.rawValue)]!, _0, _1) - } - public func ForwardedFiles(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[100 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Contacts_InviteContacts(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[101 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Invitation_Members(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[102 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Theme_UsersCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[103 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGE_VIDEOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[104 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func ServiceMessage_GameScoreSimple(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[105 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_ShortSeconds(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[106 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Months(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[107 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[108 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func Map_ETAMinutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[109 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Days(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[110 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[8 * 6 + Int(form.rawValue)]!, stringValue) } public func QuickSend_Photos(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[111 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[9 * 6 + Int(form.rawValue)]!, stringValue) } - public func LastSeen_MinutesAgo(_ value: Int32) -> String { + public func MessageTimer_Minutes(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[112 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[10 * 6 + Int(form.rawValue)]!, stringValue) } - public func VoiceOver_Chat_ContactPhoneNumberCount(_ value: Int32) -> String { + public func Notifications_ExceptionMuteExpires_Days(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[113 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[11 * 6 + Int(form.rawValue)]!, stringValue) } - public func ForwardedAudios(_ value: Int32) -> String { + public func LiveLocationUpdated_MinutesAgo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[114 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[12 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessageTimer_Hours(_ value: Int32) -> String { + public func Map_ETAMinutes(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[115 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[13 * 6 + Int(form.rawValue)]!, stringValue) } public func MuteFor_Days(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[116 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[14 * 6 + Int(form.rawValue)]!, stringValue) } - public func LastSeen_HoursAgo(_ value: Int32) -> String { + public func ChatList_DeleteConfirmation(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[117 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[15 * 6 + Int(form.rawValue)]!, stringValue) } - public func AttachmentMenu_SendGif(_ value: Int32) -> String { + public func Forward_ConfirmMultipleFiles(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[118 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[16 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortHours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[17 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_Generic(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[18 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedMessages(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[19 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_DeleteItemsConfirmation(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[20 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHAT_MESSAGE_PHOTOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[21 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func Wallpaper_DeleteConfirmation(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[22 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_RemoveStickerCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[23 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Contacts_InviteContacts(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[24 * 6 + Int(form.rawValue)]!, stringValue) } public func GroupInfo_ParticipantCount(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[119 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[25 * 6 + Int(form.rawValue)]!, stringValue) + } + public func DialogList_LiveLocationChatsCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[26 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Watch_LastSeen_MinutesAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[27 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PollResults_ShowMore(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[28 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreSelfSimple(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[29 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PasscodeSettings_FailedAttempts(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[30 * 6 + Int(form.rawValue)]!, stringValue) } public func PUSH_CHANNEL_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[120 * 6 + Int(form.rawValue)]!, _1, _2) + return String(format: self._ps[31 * 6 + Int(form.rawValue)]!, _1, _2) } - public func StickerPack_StickerCount(_ value: Int32) -> String { + public func MessageTimer_Months(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[121 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[32 * 6 + Int(form.rawValue)]!, stringValue) } - public func OldChannels_GroupFormat(_ value: Int32) -> String { + public func PUSH_CHANNEL_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[33 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func InviteText_ContactsCountText(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[122 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[34 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_ShortMinutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[35 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Media_ShareVideo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[36 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_SelectedMessages(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[37 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Years(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[38 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Passport_Scans(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[39 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedAuthorsOthers(_ selector: Int32, _ _0: String, _ _1: String) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[40 * 6 + Int(form.rawValue)]!, _0, _1) + } + public func PUSH_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[41 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func AttachmentMenu_SendPhoto(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[42 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessagePoll_QuizCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[43 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[44 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func PUSH_CHANNEL_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[45 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func SharedMedia_Video(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[46 * 6 + Int(form.rawValue)]!, stringValue) + } + public func OldChannels_InactiveYear(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[47 * 6 + Int(form.rawValue)]!, stringValue) + } + public func OldChannels_InactiveWeek(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[48 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_PollVotes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[49 * 6 + Int(form.rawValue)]!, stringValue) + } + public func UserCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[50 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_ShortSeconds(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[51 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Weeks(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[52 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteExpires_Hours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[53 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Theme_UsersCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[54 * 6 + Int(form.rawValue)]!, stringValue) + } + public func AttachmentMenu_SendItem(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[55 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notifications_Exceptions(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[56 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortDays(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[57 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedFiles(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[58 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Watch_LastSeen_HoursAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[59 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Contacts_ImportersCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[60 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedVideoMessages(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[61 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Wallet_Updated_HoursAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[62 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Chat_DeleteMessagesConfirmation(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[63 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ChatList_SelectedChats(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[64 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Media_SharePhoto(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[65 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedGifs(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[66 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedVideos(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[67 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_PollOptionCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[68 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PrivacyLastSeenSettings_AddUsers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[69 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_AddStickerCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[70 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ChatList_DeletedChats(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[71 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreSelfExtended(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[72 * 6 + Int(form.rawValue)]!, stringValue) + } + public func AttachmentMenu_SendGif(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[73 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notifications_ExceptionMuteExpires_Minutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[74 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreSelfSimple(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[75 * 6 + Int(form.rawValue)]!, stringValue) } public func Media_ShareItem(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[123 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[76 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notifications_ExceptionMuteExpires_Hours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[77 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Seconds(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[78 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteExpires_Days(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[79 * 6 + Int(form.rawValue)]!, stringValue) + } + public func OldChannels_InactiveMonth(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[80 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_AddMaskCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[81 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessagePoll_VotedCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[82 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_ContactPhoneNumberCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[83 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_File(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[84 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Watch_UserInfo_Mute(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[85 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[86 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func Notification_GameScoreExtended(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[87 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_StickerCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[88 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_RemoveMaskCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[89 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteExpires_Minutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[90 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_ContactEmailCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[91 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_StatusOnline(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[92 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_Seconds(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[93 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[94 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func Notification_GameScoreSelfExtended(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[95 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_StatusMembers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[96 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedLocations(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[97 * 6 + Int(form.rawValue)]!, stringValue) + } + public func OldChannels_GroupFormat(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[98 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHAT_MESSAGE_ROUNDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[99 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func ForwardedAudios(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[100 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreExtended(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[101 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Days(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[102 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Hours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[103 * 6 + Int(form.rawValue)]!, stringValue) + } + public func LastSeen_HoursAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[104 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortSeconds(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[105 * 6 + Int(form.rawValue)]!, stringValue) + } + public func LiveLocation_MenuChatsCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[106 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[107 * 6 + Int(form.rawValue)]!, _1, _2) } public func SharedMedia_Photo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[124 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[108 * 6 + Int(form.rawValue)]!, stringValue) } - public func ForwardedLocations(_ value: Int32) -> String { + public func OldChannels_Leave(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[109 * 6 + Int(form.rawValue)]!, stringValue) + } + public func AttachmentMenu_SendVideo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[110 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHAT_MESSAGE_FWDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[111 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func MessageTimer_ShortMinutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[112 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_StatusSubscribers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[113 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedPolls(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[114 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHAT_MESSAGES(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[115 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func PUSH_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[116 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func Map_ETAHours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[117 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteFor_Hours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[118 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreSimple(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[119 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedContacts(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[120 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreSimple(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[121 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_LiveLocationMembersCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[122 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_Link(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[123 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[124 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func Invitation_Members(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[125 * 6 + Int(form.rawValue)]!, stringValue) diff --git a/submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping b/submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping index 7adbe8a6e4e7f15e6e162ac5d7527016541fb600..0e740b4a155b225542e28dac2235e57e003820bf 100644 GIT binary patch delta 35643 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 Ze&i$wJNrMu*CRVKS;+Xqc)ChC{~u+SEO`I` delta 35728 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 B9ufcm From f436f10d4c29f554e70e8d0722c76600f954df01 Mon Sep 17 00:00:00 2001 From: overtake <> Date: Wed, 29 Jan 2020 12:01:30 +0400 Subject: [PATCH 02/30] fix forwarding messages --- submodules/TelegramCore/Sources/PendingMessageManager.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/submodules/TelegramCore/Sources/PendingMessageManager.swift b/submodules/TelegramCore/Sources/PendingMessageManager.swift index cb35a4dccd..9cb6459e60 100644 --- a/submodules/TelegramCore/Sources/PendingMessageManager.swift +++ b/submodules/TelegramCore/Sources/PendingMessageManager.swift @@ -675,7 +675,9 @@ public final class PendingMessageManager { let sendMessageRequest: Signal if isForward { - flags |= (1 << 9) + if !messages.contains(where: { $0.0.groupingKey == nil }) { + flags |= (1 << 9) + } var forwardIds: [(MessageId, Int64)] = [] for (message, content) in messages { From 8afd80c31d1103ca0fd42464fc1be0964f6e58b2 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Sat, 1 Feb 2020 00:15:18 +0400 Subject: [PATCH 03/30] Basic implementation of the redesigned profiles --- .../AvatarNode/Sources/PeerAvatar.swift | 12 +- .../ContainedViewLayoutTransition.swift | 18 + submodules/Display/Display/ListView.swift | 2 +- .../Display/Display/ListViewScroller.swift | 16 +- .../Sources/PeerInfoController.swift | 14 - .../ButtonMessage.imageset/Contents.json | 20 + .../TelegramUI/PeerInfoFilesPane.swift | 174 ++ .../TelegramUI/PeerInfoScreen.swift | 1618 +++++++++++++++++ .../PeerInfoScreenLabeledValueItem.swift | 123 ++ ...erInfoScreenSelectableBackgroundNode.swift | 55 + .../TelegramUI/PeerInfoVisualMediaPane.swift | 458 +++++ .../TelegramUI/SharedAccountContext.swift | 17 + 12 files changed, 2500 insertions(+), 27 deletions(-) create mode 100644 submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMessage.imageset/Contents.json create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfoFilesPane.swift create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfoScreenLabeledValueItem.swift create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfoScreenSelectableBackgroundNode.swift create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfoVisualMediaPane.swift diff --git a/submodules/AvatarNode/Sources/PeerAvatar.swift b/submodules/AvatarNode/Sources/PeerAvatar.swift index 183a06137a..f9dee458bd 100644 --- a/submodules/AvatarNode/Sources/PeerAvatar.swift +++ b/submodules/AvatarNode/Sources/PeerAvatar.swift @@ -77,10 +77,18 @@ public func peerAvatarImage(account: Account, peerReference: PeerReference?, aut if let imageSource = CGImageSourceCreateWithData(data as CFData, nil), let dataImage = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) { context.clear(CGRect(origin: CGPoint(), size: displayDimensions)) context.setBlendMode(.copy) + + if round && displayDimensions.width != 60.0 { + context.addEllipse(in: CGRect(origin: CGPoint(), size: displayDimensions).insetBy(dx: inset, dy: inset)) + context.clip() + } + context.draw(dataImage, in: CGRect(origin: CGPoint(), size: displayDimensions).insetBy(dx: inset, dy: inset)) if round { - context.setBlendMode(.destinationOut) - context.draw(roundCorners.cgImage!, in: CGRect(origin: CGPoint(), size: displayDimensions).insetBy(dx: inset, dy: inset)) + if displayDimensions.width == 60.0 { + context.setBlendMode(.destinationOut) + context.draw(roundCorners.cgImage!, in: CGRect(origin: CGPoint(), size: displayDimensions).insetBy(dx: inset, dy: inset)) + } } } else { if let emptyColor = emptyColor { diff --git a/submodules/Display/Display/ContainedViewLayoutTransition.swift b/submodules/Display/Display/ContainedViewLayoutTransition.swift index 45510880e9..3df59e854a 100644 --- a/submodules/Display/Display/ContainedViewLayoutTransition.swift +++ b/submodules/Display/Display/ContainedViewLayoutTransition.swift @@ -141,6 +141,24 @@ public extension ContainedViewLayoutTransition { } } + func updateFrameAdditiveToCenter(node: ASDisplayNode, frame: CGRect, force: Bool = false, completion: ((Bool) -> Void)? = nil) { + if node.frame.equalTo(frame) && !force { + completion?(true) + } else { + switch self { + case .immediate: + node.frame = frame + if let completion = completion { + completion(true) + } + case .animated: + let previousFrame = node.frame + node.frame = frame + self.animatePositionAdditive(node: node, offset: CGPoint(x: previousFrame.midX - frame.midX, y: previousFrame.midY - frame.midY)) + } + } + } + func updateBounds(node: ASDisplayNode, bounds: CGRect, force: Bool = false, completion: ((Bool) -> Void)? = nil) { if node.bounds.equalTo(bounds) && !force { completion?(true) diff --git a/submodules/Display/Display/ListView.swift b/submodules/Display/Display/ListView.swift index 59fc67d902..7a65d3b39e 100644 --- a/submodules/Display/Display/ListView.swift +++ b/submodules/Display/Display/ListView.swift @@ -125,7 +125,7 @@ public enum GeneralScrollDirection { } open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGestureRecognizerDelegate { - final let scroller: ListViewScroller + public final let scroller: ListViewScroller private final var visibleSize: CGSize = CGSize() public private(set) final var insets = UIEdgeInsets() public final var visualInsets: UIEdgeInsets? diff --git a/submodules/Display/Display/ListViewScroller.swift b/submodules/Display/Display/ListViewScroller.swift index 7e8921f718..c77b2207cb 100644 --- a/submodules/Display/Display/ListViewScroller.swift +++ b/submodules/Display/Display/ListViewScroller.swift @@ -1,29 +1,27 @@ import UIKit -class ListViewScroller: UIScrollView, UIGestureRecognizerDelegate { - override init(frame: CGRect) { +public final class ListViewScroller: UIScrollView, UIGestureRecognizerDelegate { + override public init(frame: CGRect) { super.init(frame: frame) - #if os(iOS) self.scrollsToTop = false if #available(iOSApplicationExtension 11.0, iOS 11.0, *) { self.contentInsetAdjustmentBehavior = .never } - #endif } - required init?(coder aDecoder: NSCoder) { + required public init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } - @objc func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { + public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { if otherGestureRecognizer is ListViewTapGestureRecognizer { return true } return false } - override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + override public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { if gestureRecognizer is UIPanGestureRecognizer, let gestureRecognizers = gestureRecognizer.view?.gestureRecognizers { for otherGestureRecognizer in gestureRecognizers { if otherGestureRecognizer !== gestureRecognizer, let panGestureRecognizer = otherGestureRecognizer as? UIPanGestureRecognizer, panGestureRecognizer.minimumNumberOfTouches == 2 { @@ -36,9 +34,7 @@ class ListViewScroller: UIScrollView, UIGestureRecognizerDelegate { } } - #if os(iOS) - override func touchesShouldCancel(in view: UIView) -> Bool { + override public func touchesShouldCancel(in view: UIView) -> Bool { return true } - #endif } diff --git a/submodules/PeerInfoUI/Sources/PeerInfoController.swift b/submodules/PeerInfoUI/Sources/PeerInfoController.swift index f34ef9a845..62e5703def 100644 --- a/submodules/PeerInfoUI/Sources/PeerInfoController.swift +++ b/submodules/PeerInfoUI/Sources/PeerInfoController.swift @@ -7,17 +7,3 @@ import TelegramCore import SyncCore import AccountContext -public func peerInfoControllerImpl(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode) -> ViewController? { - if let _ = peer as? TelegramGroup { - return groupInfoController(context: context, peerId: peer.id) - } else if let channel = peer as? TelegramChannel { - if case .group = channel.info { - return groupInfoController(context: context, peerId: peer.id) - } else { - return channelInfoController(context: context, peerId: peer.id) - } - } else if peer is TelegramUser || peer is TelegramSecretChat { - return userInfoController(context: context, peerId: peer.id, mode: mode) - } - return nil -} diff --git a/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMessage.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMessage.imageset/Contents.json new file mode 100644 index 0000000000..f8f827e40b --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMessage.imageset/Contents.json @@ -0,0 +1,20 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoFilesPane.swift b/submodules/TelegramUI/TelegramUI/PeerInfoFilesPane.swift new file mode 100644 index 0000000000..112682fe33 --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/PeerInfoFilesPane.swift @@ -0,0 +1,174 @@ +import AsyncDisplayKit +import Display +import TelegramCore +import SyncCore +import SwiftSignalKit +import Postbox +import TelegramPresentationData +import AccountContext +import ContextUI +import PhotoResources +import TelegramUIPreferences + +final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode { + private let context: AccountContext + private let peerId: PeerId + + private let listNode: ChatHistoryListNode + + private var currentParams: (size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData)? + + private let ready = Promise() + private var didSetReady: Bool = false + var isReady: Signal { + return self.ready.get() + } + + private var hiddenMediaDisposable: Disposable? + + init(context: AccountContext, openMessage: @escaping (MessageId) -> Bool, peerId: PeerId, tagMask: MessageTags) { + self.context = context + self.peerId = peerId + + var openMessageImpl: ((MessageId) -> Bool)? + let controllerInteraction = ChatControllerInteraction(openMessage: { message, _ in + return openMessageImpl?(message.id) ?? false + }, openPeer: { _, _, _ in + }, openPeerMention: { _ in + }, openMessageContextMenu: { _, _, _, _, _ in + }, openMessageContextActions: { _, _, _, _ in + }, navigateToMessage: { _, _ in + }, tapMessage: nil, clickThroughMessage: { + }, toggleMessagesSelection: { _, _ in + }, sendCurrentMessage: { _ in + }, sendMessage: { _ in + }, sendSticker: { _, _, _, _ in + return false + }, sendGif: { _, _, _ in + return false + }, requestMessageActionCallback: { _, _, _ in + }, requestMessageActionUrlAuth: { _, _, _ in + }, activateSwitchInline: { _, _ in + }, openUrl: { _, _, _, _ in + }, shareCurrentLocation: { + }, shareAccountContact: { + }, sendBotCommand: { _, _ in + }, openInstantPage: { _, _ in + }, openWallpaper: { _ in + }, openTheme: {_ in + }, openHashtag: { _, _ in + }, updateInputState: { _ in + }, updateInputMode: { _ in + }, openMessageShareMenu: { _ in + }, presentController: { _, _ in + }, navigationController: { + return nil + }, chatControllerNode: { + return nil + }, reactionContainerNode: { + return nil + }, presentGlobalOverlayController: { _, _ in + }, callPeer: { _ in + }, longTap: { _, _ in + }, openCheckoutOrReceipt: { _ in + }, openSearch: { + }, setupReply: { _ in + }, canSetupReply: { _ in + return false + }, navigateToFirstDateMessage: { _ in + }, requestRedeliveryOfFailedMessages: { _ in + }, addContact: { _ in + }, rateCall: { _, _ in + }, requestSelectMessagePollOptions: { _, _ in + }, requestOpenMessagePollResults: { _, _ in + }, openAppStorePage: { + }, displayMessageTooltip: { _, _, _, _ in + }, seekToTimecode: { _, _, _ in + }, scheduleCurrentMessage: { + }, sendScheduledMessagesNow: { _ in + }, editScheduledMessagesTime: { _ in + }, performTextSelectionAction: { _, _, _ in + }, updateMessageReaction: { _, _ in + }, openMessageReactions: { _ in + }, displaySwipeToReplyHint: { + }, dismissReplyMarkupMessage: { _ in + }, openMessagePollResults: { _, _ in + }, openPollCreation: { _ in + }, requestMessageUpdate: { _ in + }, cancelInteractiveKeyboardGestures: { + }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false)) + + self.listNode = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), tagMask: tagMask, subject: nil, controllerInteraction: controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: false)) + + super.init() + + openMessageImpl = { id in + return openMessage(id) + } + + self.hiddenMediaDisposable = context.sharedContext.mediaManager.galleryHiddenMediaManager.hiddenIds().start(next: { [weak self] ids in + guard let strongSelf = self else { + return + } + var hiddenMedia: [MessageId: [Media]] = [:] + for id in ids { + if case let .chat(accountId, messageId, media) = id, accountId == strongSelf.context.account.id { + hiddenMedia[messageId] = [media] + } + } + controllerInteraction.hiddenMedia = hiddenMedia + strongSelf.listNode.forEachItemNode { itemNode in + if let itemNode = itemNode as? ListMessageNode { + itemNode.updateHiddenMedia() + } + } + }) + + self.listNode.preloadPages = true + self.addSubnode(self.listNode) + + self.ready.set(self.listNode.historyState.get() + |> take(1) + |> map { _ -> Bool in true }) + } + + deinit { + self.hiddenMediaDisposable?.dispose() + } + + func scrollToTop() -> Bool { + let offset = self.listNode.visibleContentOffset() + switch offset { + case let .known(value) where value <= CGFloat.ulpOfOne: + return false + default: + self.listNode.scrollToEndOfHistory() + return true + } + } + + func update(size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { + self.currentParams = (size, isScrollingLockedAtTop, presentationData) + + transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(), size: size)) + let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition) + self.listNode.updateLayout(transition: transition, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: size, insets: UIEdgeInsets(), duration: duration, curve: curve)) + self.listNode.scrollEnabled = !isScrollingLockedAtTop + } + + func findLoadedMessage(id: MessageId) -> Message? { + self.listNode.messageInCurrentHistoryView(id) + } + + func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { + var transitionNode: (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? + self.listNode.forEachItemNode { itemNode in + if let itemNode = itemNode as? ListMessageNode { + if let result = itemNode.transitionNode(id: messageId, media: media) { + transitionNode = result + } + } + } + return transitionNode + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift b/submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift new file mode 100644 index 0000000000..e1f5116a47 --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift @@ -0,0 +1,1618 @@ +import Foundation +import UIKit +import Display +import AsyncDisplayKit +import Postbox +import TelegramCore +import SyncCore +import SwiftSignalKit +import AccountContext +import TelegramPresentationData +import TelegramUIPreferences +import AvatarNode +import TelegramStringFormatting +import PhoneNumberFormat +import AppBundle +import PresentationDataUtils +import NotificationMuteSettingsUI +import NotificationSoundSelectionUI +import OverlayStatusController +import ShareController + +private let avatarFont = avatarPlaceholderFont(size: 28.0) + +private enum PeerInfoHeaderButtonKey: Hashable { + case message + case call + case mute + case more +} + +private enum PeerInfoHeaderButtonIcon { + case message + case call + case mute + case unmute + case more +} + +private final class PeerInfoHeaderButtonNode: HighlightableButtonNode { + let key: PeerInfoHeaderButtonKey + private let action: (PeerInfoHeaderButtonNode) -> Void + private let backgroundNode: ASImageNode + private let textNode: ImmediateTextNode + + private var theme: PresentationTheme? + private var icon: PeerInfoHeaderButtonIcon? + + init(key: PeerInfoHeaderButtonKey, action: @escaping (PeerInfoHeaderButtonNode) -> Void) { + self.key = key + self.action = action + + self.backgroundNode = ASImageNode() + self.backgroundNode.displaysAsynchronously = false + self.backgroundNode.displayWithoutProcessing = true + + self.textNode = ImmediateTextNode() + self.textNode.displaysAsynchronously = false + + super.init() + + self.addSubnode(self.backgroundNode) + self.addSubnode(self.textNode) + + self.highligthedChanged = { [weak self] highlighted in + if let strongSelf = self { + if highlighted { + strongSelf.layer.removeAnimation(forKey: "opacity") + strongSelf.alpha = 0.4 + } else { + strongSelf.alpha = 1.0 + strongSelf.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) + } + } + } + + self.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside) + } + + @objc private func buttonPressed() { + self.action(self) + } + + func update(size: CGSize, text: String, icon: PeerInfoHeaderButtonIcon, isExpanded: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) { + if self.theme != presentationData.theme || self.icon != icon { + self.theme = presentationData.theme + self.icon = icon + self.backgroundNode.image = generateImage(CGSize(width: 40.0, height: 40.0), contextGenerator: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + context.setFillColor(presentationData.theme.list.itemAccentColor.cgColor) + context.fillEllipse(in: CGRect(origin: CGPoint(), size: size)) + context.setBlendMode(.copy) + context.setFillColor(UIColor.clear.cgColor) + let imageName: String + switch icon { + case .message: + imageName = "Chat/Context Menu/Message" + case .call: + imageName = "Chat/Context Menu/Call" + case .mute: + imageName = "Chat/Context Menu/Muted" + case .unmute: + imageName = "Chat/Context Menu/Unmute" + case .more: + imageName = "Chat/Context Menu/More" + } + if let image = UIImage(bundleImageName: imageName) { + let imageRect = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size) + context.clip(to: imageRect, mask: image.cgImage!) + context.fill(imageRect) + } + }) + } + + self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(12.0), textColor: presentationData.theme.list.itemAccentColor) + let titleSize = self.textNode.updateLayout(CGSize(width: 120.0, height: .greatestFiniteMagnitude)) + + transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size)) + transition.updateFrameAdditiveToCenter(node: self.textNode, frame: CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: size.height + 6.0), size: titleSize)) + } +} + +private final class PeerInfoHeaderNode: ASDisplayNode { + private var context: AccountContext + private var presentationData: PresentationData? + + private let avatarNode: AvatarNode + private let titleNode: ImmediateTextNode + private let subtitleNode: ImmediateTextNode + private var buttonNodes: [PeerInfoHeaderButtonKey: PeerInfoHeaderButtonNode] = [:] + private let backgroundNode: ASDisplayNode + private let separatorNode: ASDisplayNode + + var performButtonAction: ((PeerInfoHeaderButtonKey) -> Void)? + + init(context: AccountContext) { + self.context = context + + self.avatarNode = AvatarNode(font: avatarFont) + + self.titleNode = ImmediateTextNode() + self.titleNode.displaysAsynchronously = false + + self.subtitleNode = ImmediateTextNode() + self.subtitleNode.displaysAsynchronously = false + + self.backgroundNode = ASDisplayNode() + self.backgroundNode.isLayerBacked = true + + self.separatorNode = ASDisplayNode() + self.separatorNode.isLayerBacked = true + + super.init() + + self.addSubnode(self.backgroundNode) + self.addSubnode(self.separatorNode) + self.addSubnode(self.avatarNode) + self.addSubnode(self.titleNode) + self.addSubnode(self.subtitleNode) + } + + func update(width: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, notificationSettings: TelegramPeerNotificationSettings?, presence: TelegramUserPresence?, transition: ContainedViewLayoutTransition) -> CGFloat { + self.presentationData = presentationData + + self.backgroundNode.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor + self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + + let avatarSize: CGFloat = 100.0 + let defaultButtonSize: CGFloat = 40.0 + let defaultMaxButtonSpacing: CGFloat = 40.0 + + var buttonKeys: [PeerInfoHeaderButtonKey] = [] + + if let peer = peer { + buttonKeys.append(.message) + buttonKeys.append(.call) + buttonKeys.append(.mute) + buttonKeys.append(.more) + + self.avatarNode.setPeer(context: self.context, theme: presentationData.theme, peer: peer, displayDimensions: CGSize(width: avatarSize, height: avatarSize)) + + self.titleNode.attributedText = NSAttributedString(string: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.medium(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor) + + let presence = presence ?? TelegramUserPresence(status: .none, lastActivity: 0) + let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + let (subtitleString, activity) = stringAndActivityForUserPresence(strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, presence: presence, relativeTo: Int32(timestamp), expanded: true) + let subtitleColor: UIColor + if activity { + subtitleColor = presentationData.theme.list.itemAccentColor + } else { + subtitleColor = presentationData.theme.list.itemSecondaryTextColor + } + self.subtitleNode.attributedText = NSAttributedString(string: subtitleString, font: Font.regular(15.0), textColor: subtitleColor) + } + + let textSideInset: CGFloat = 16.0 + + var height: CGFloat = navigationHeight + height += 212.0 + + let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 10.0), size: CGSize(width: avatarSize, height: avatarSize)) + transition.updateFrame(node: self.avatarNode, frame: avatarFrame) + + let titleSize = self.titleNode.updateLayout(CGSize(width: width - textSideInset * 2.0, height: .greatestFiniteMagnitude)) + let subtitleSize = self.subtitleNode.updateLayout(CGSize(width: width - textSideInset * 2.0, height: .greatestFiniteMagnitude)) + + let titleFrame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: avatarFrame.maxY + 10.0), size: titleSize) + let subtitleFrame = CGRect(origin: CGPoint(x: floor((width - subtitleSize.width) / 2.0), y: titleFrame.maxY + 1.0), size: subtitleSize) + transition.updateFrameAdditiveToCenter(node: self.titleNode, frame: titleFrame) + transition.updateFrameAdditiveToCenter(node: self.subtitleNode, frame: subtitleFrame) + + let buttonSpacing: CGFloat = min(defaultMaxButtonSpacing, width - floor(CGFloat(buttonKeys.count) * defaultButtonSize / CGFloat(buttonKeys.count + 1))) + let buttonsWidth = buttonSpacing * CGFloat(buttonKeys.count - 1) + CGFloat(buttonKeys.count) * defaultButtonSize + var buttonRightOrigin = CGPoint(x: floor((width - buttonsWidth) / 2.0) + buttonsWidth, y: height - 74.0) + for buttonKey in buttonKeys.reversed() { + let buttonNode: PeerInfoHeaderButtonNode + var wasAdded = false + if let current = self.buttonNodes[buttonKey] { + buttonNode = current + } else { + wasAdded = true + buttonNode = PeerInfoHeaderButtonNode(key: buttonKey, action: { [weak self] buttonNode in + self?.buttonPressed(buttonNode) + }) + self.buttonNodes[buttonKey] = buttonNode + self.addSubnode(buttonNode) + } + + let buttonFrame = CGRect(origin: CGPoint(x: buttonRightOrigin.x - defaultButtonSize, y: buttonRightOrigin.y), size: CGSize(width: defaultButtonSize, height: defaultButtonSize)) + buttonRightOrigin.x -= defaultButtonSize + buttonSpacing + let buttonTransition: ContainedViewLayoutTransition = wasAdded ? .immediate : transition + buttonTransition.updateFrame(node: buttonNode, frame: buttonFrame) + let buttonText: String + let buttonIcon: PeerInfoHeaderButtonIcon + switch buttonKey { + case .message: + buttonText = "Message" + buttonIcon = .message + case .call: + buttonText = "Call" + buttonIcon = .call + case .mute: + if let notificationSettings = notificationSettings, case .muted = notificationSettings.muteState { + buttonText = "Unmute" + buttonIcon = .unmute + } else { + buttonText = "Mute" + buttonIcon = .mute + } + case .more: + buttonText = "More" + buttonIcon = .more + } + buttonNode.update(size: buttonFrame.size, text: buttonText, icon: buttonIcon, isExpanded: false, presentationData: presentationData, transition: buttonTransition) + } + + for key in self.buttonNodes.keys { + if !buttonKeys.contains(key) { + if let buttonNode = self.buttonNodes[key] { + self.buttonNodes.removeValue(forKey: key) + buttonNode.removeFromSupernode() + } + } + } + + transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -1000.0), size: CGSize(width: width, height: 1000.0 + height))) + transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: height), size: CGSize(width: width, height: UIScreenPixel))) + + return height + } + + private func buttonPressed(_ buttonNode: PeerInfoHeaderButtonNode) { + self.performButtonAction?(buttonNode.key) + } +} + +protocol PeerInfoPaneNode: ASDisplayNode { + var isReady: Signal { get } + + func update(size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) + func scrollToTop() -> Bool + func findLoadedMessage(id: MessageId) -> Message? + func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? +} + +private final class PeerInfoPaneWrapper { + let key: PeerInfoPaneKey + let node: PeerInfoPaneNode + private var appliedParams: (CGSize, Bool, PresentationData)? + + init(key: PeerInfoPaneKey, node: PeerInfoPaneNode) { + self.key = key + self.node = node + } + + func update(size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { + if let (currentSize, currentIsScrollingLockedAtTop, currentPresentationData) = self.appliedParams { + if currentSize == size && currentIsScrollingLockedAtTop == isScrollingLockedAtTop && currentPresentationData === presentationData { + return + } + } + self.appliedParams = (size, isScrollingLockedAtTop, presentationData) + self.node.update(size: size, isScrollingLockedAtTop: isScrollingLockedAtTop, presentationData: presentationData, synchronous: synchronous, transition: transition) + } +} + +private enum PeerInfoPaneKey { + case media + case files + case links + case music +} + +private final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode { + private let pressed: () -> Void + + private let titleNode: ImmediateTextNode + private let buttonNode: HighlightTrackingButtonNode + + init(pressed: @escaping () -> Void) { + self.pressed = pressed + + self.titleNode = ImmediateTextNode() + self.titleNode.displaysAsynchronously = false + + self.buttonNode = HighlightTrackingButtonNode() + + super.init() + + self.addSubnode(self.titleNode) + self.addSubnode(self.buttonNode) + + self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside) + self.buttonNode.highligthedChanged = { [weak self] highlighted in + if let strongSelf = self { + if highlighted { + strongSelf.titleNode.layer.removeAnimation(forKey: "opacity") + strongSelf.titleNode.alpha = 0.4 + } else { + strongSelf.titleNode.alpha = 1.0 + strongSelf.titleNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) + } + } + } + } + + @objc private func buttonPressed() { + self.pressed() + } + + func updateText(_ title: String, isSelected: Bool, presentationData: PresentationData) { + self.titleNode.attributedText = NSAttributedString(string: title, font: Font.medium(14.0), textColor: isSelected ? presentationData.theme.list.itemAccentColor : presentationData.theme.list.itemSecondaryTextColor) + } + + func updateLayout(height: CGFloat) -> CGFloat { + let titleSize = self.titleNode.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude)) + self.titleNode.frame = CGRect(origin: CGPoint(x: 0.0, y: floor((height - titleSize.height) / 2.0)), size: titleSize) + return titleSize.width + } + + func updateArea(size: CGSize, sideInset: CGFloat) { + self.buttonNode.frame = CGRect(origin: CGPoint(x: -sideInset, y: 0.0), size: CGSize(width: size.width + sideInset * 2.0, height: size.height)) + } +} + +private struct PeerInfoPaneSpecifier: Equatable { + var key: PeerInfoPaneKey + var title: String +} + +private final class PeerInfoPaneTabsContainerNode: ASDisplayNode { + private let scrollNode: ASScrollNode + private var paneNodes: [PeerInfoPaneKey: PeerInfoPaneTabsContainerPaneNode] = [:] + private let selectedLineNode: ASImageNode + + private var currentParams: ([PeerInfoPaneSpecifier], PeerInfoPaneKey?, PresentationData)? + + var requestSelectPane: ((PeerInfoPaneKey) -> Void)? + + override init() { + self.scrollNode = ASScrollNode() + + self.selectedLineNode = ASImageNode() + self.selectedLineNode.displaysAsynchronously = false + self.selectedLineNode.displayWithoutProcessing = true + + super.init() + + self.scrollNode.view.showsHorizontalScrollIndicator = false + self.scrollNode.view.scrollsToTop = false + if #available(iOS 11.0, *) { + self.scrollNode.view.contentInsetAdjustmentBehavior = .never + } + + self.addSubnode(self.scrollNode) + self.scrollNode.addSubnode(self.selectedLineNode) + } + + func update(size: CGSize, presentationData: PresentationData, paneList: [PeerInfoPaneSpecifier], selectedPane: PeerInfoPaneKey?, transition: ContainedViewLayoutTransition) { + transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: size)) + + if self.currentParams?.2.theme !== presentationData.theme { + self.selectedLineNode.image = generateImage(CGSize(width: 7.0, height: 4.0), rotatedContext: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + context.setFillColor(presentationData.theme.list.itemAccentColor.cgColor) + context.fillEllipse(in: CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.width))) + })?.stretchableImage(withLeftCapWidth: 4, topCapHeight: 1) + } + + if self.currentParams?.0 != paneList || self.currentParams?.1 != selectedPane || self.currentParams?.2 !== presentationData { + self.currentParams = (paneList, selectedPane, presentationData) + for specifier in paneList { + let paneNode: PeerInfoPaneTabsContainerPaneNode + var wasAdded = false + if let current = self.paneNodes[specifier.key] { + paneNode = current + } else { + wasAdded = true + paneNode = PeerInfoPaneTabsContainerPaneNode(pressed: { [weak self] in + self?.paneSelected(specifier.key) + }) + self.paneNodes[specifier.key] = paneNode + self.scrollNode.addSubnode(paneNode) + } + paneNode.updateText(specifier.title, isSelected: selectedPane == specifier.key, presentationData: presentationData) + } + var removeKeys: [PeerInfoPaneKey] = [] + for (key, _) in self.paneNodes { + if !paneList.contains(where: { $0.key == key }) { + removeKeys.append(key) + } + } + for key in removeKeys { + if let paneNode = self.paneNodes.removeValue(forKey: key) { + paneNode.removeFromSupernode() + } + } + } + + var tabSizes: [(CGSize, PeerInfoPaneTabsContainerPaneNode)] = [] + var totalRawTabSize: CGFloat = 0.0 + + var selectedFrame: CGRect? + for specifier in paneList { + guard let paneNode = self.paneNodes[specifier.key] else { + continue + } + let paneNodeWidth = paneNode.updateLayout(height: size.height) + let paneNodeSize = CGSize(width: paneNodeWidth, height: size.height) + tabSizes.append((paneNodeSize, paneNode)) + totalRawTabSize += paneNodeSize.width + } + + let spacing: CGFloat = 32.0 + if totalRawTabSize + CGFloat(tabSizes.count + 1) * spacing <= size.width { + let singleTabSpace = floor((size.width - spacing * 2.0) / CGFloat(tabSizes.count)) + + for i in 0 ..< tabSizes.count { + let (paneNodeSize, paneNode) = tabSizes[i] + let leftOffset = spacing + CGFloat(i) * singleTabSpace + floor((singleTabSpace - paneNodeSize.width) / 2.0) + + let paneFrame = CGRect(origin: CGPoint(x: leftOffset, y: floor((size.height - paneNodeSize.height) / 2.0)), size: paneNodeSize) + paneNode.frame = paneFrame + let areaSideInset = floor((singleTabSpace - paneFrame.size.width) / 2.0) + paneNode.updateArea(size: paneFrame.size, sideInset: areaSideInset) + paneNode.hitTestSlop = UIEdgeInsets(top: 0.0, left: -areaSideInset, bottom: 0.0, right: -areaSideInset) + + if paneList[i].key == selectedPane { + selectedFrame = paneFrame + } + } + self.scrollNode.view.contentSize = CGSize(width: size.width, height: size.height) + } else { + let sideInset: CGFloat = 16.0 + var leftOffset: CGFloat = sideInset + for i in 0 ..< tabSizes.count { + let (paneNodeSize, paneNode) = tabSizes[i] + let paneFrame = CGRect(origin: CGPoint(x: leftOffset, y: floor((size.height - paneNodeSize.height) / 2.0)), size: paneNodeSize) + paneNode.frame = paneFrame + paneNode.updateArea(size: paneFrame.size, sideInset: spacing) + paneNode.hitTestSlop = UIEdgeInsets(top: 0.0, left: -spacing, bottom: 0.0, right: -spacing) + if paneList[i].key == selectedPane { + selectedFrame = paneFrame + } + leftOffset += paneNodeSize.width + spacing + } + self.scrollNode.view.contentSize = CGSize(width: leftOffset + sideInset, height: size.height) + } + + if let selectedFrame = selectedFrame { + self.selectedLineNode.isHidden = false + transition.updateFrame(node: self.selectedLineNode, frame: CGRect(origin: CGPoint(x: selectedFrame.minX, y: size.height - 4.0), size: CGSize(width: selectedFrame.width, height: 4.0))) + } else { + self.selectedLineNode.isHidden = true + } + } + + private func paneSelected(_ key: PeerInfoPaneKey) { + self.requestSelectPane?(key) + } +} + +private final class PeerInfoPaneContainerNode: ASDisplayNode { + private let context: AccountContext + private let peerId: PeerId + + private let coveringBackgroundNode: ASDisplayNode + private let separatorNode: ASDisplayNode + private let tabsContainerNode: PeerInfoPaneTabsContainerNode + private let tapsSeparatorNode: ASDisplayNode + + let isReady = Promise() + var didSetIsReady = false + + private var currentParams: (size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData)? + + private var availablePanes: [PeerInfoPaneKey] = [] + private var currentPaneKey: PeerInfoPaneKey? + private var currentPane: PeerInfoPaneWrapper? + + private var candidatePane: (PeerInfoPaneWrapper, Disposable)? + + var openMessage: ((MessageId) -> Bool)? + + init(context: AccountContext, peerId: PeerId) { + self.context = context + self.peerId = peerId + + self.separatorNode = ASDisplayNode() + self.separatorNode.isLayerBacked = true + + self.coveringBackgroundNode = ASDisplayNode() + self.coveringBackgroundNode.isLayerBacked = true + + self.tabsContainerNode = PeerInfoPaneTabsContainerNode() + + self.tapsSeparatorNode = ASDisplayNode() + self.tapsSeparatorNode.isLayerBacked = true + + super.init() + + self.addSubnode(self.separatorNode) + self.addSubnode(self.coveringBackgroundNode) + self.addSubnode(self.tabsContainerNode) + self.addSubnode(self.tapsSeparatorNode) + + self.availablePanes = [.media, .files, .links, .music] + self.currentPaneKey = .media + + self.tabsContainerNode.requestSelectPane = { [weak self] key in + guard let strongSelf = self else { + return + } + if strongSelf.currentPaneKey == key { + return + } + + let paneNode: PeerInfoPaneNode + switch key { + case .media: + paneNode = PeerInfoVisualMediaPaneNode(context: strongSelf.context, openMessage: { id in + return self?.openMessage?(id) ?? false + }, peerId: strongSelf.peerId) + case .files: + paneNode = PeerInfoListPaneNode(context: strongSelf.context, openMessage: { id in + return self?.openMessage?(id) ?? false + }, peerId: strongSelf.peerId, tagMask: .file) + case .links: + paneNode = PeerInfoListPaneNode(context: strongSelf.context, openMessage: { id in + return self?.openMessage?(id) ?? false + }, peerId: strongSelf.peerId, tagMask: .webPage) + case .music: + paneNode = PeerInfoListPaneNode(context: strongSelf.context, openMessage: { id in + return self?.openMessage?(id) ?? false + }, peerId: strongSelf.peerId, tagMask: .music) + } + + if let (_, disposable) = strongSelf.candidatePane { + disposable.dispose() + } + + let disposable = MetaDisposable() + strongSelf.candidatePane = (PeerInfoPaneWrapper(key: key, node: paneNode), disposable) + + if let (size, isScrollingLockedAtTop, presentationData) = strongSelf.currentParams { + strongSelf.update(size: size, isScrollingLockedAtTop: isScrollingLockedAtTop, presentationData: presentationData, transition: .immediate) + } + + disposable.set((paneNode.isReady + |> take(1) + |> deliverOnMainQueue).start(next: { _ in + guard let strongSelf = self else { + return + } + if let (candidatePane, _) = strongSelf.candidatePane { + let previousPane = strongSelf.currentPane + strongSelf.candidatePane = nil + strongSelf.currentPaneKey = candidatePane.key + strongSelf.currentPane = candidatePane + + if let (size, isScrollingLockedAtTop, presentationData) = strongSelf.currentParams { + strongSelf.update(size: size, isScrollingLockedAtTop: isScrollingLockedAtTop, presentationData: presentationData, transition: .animated(duration: 0.35, curve: .spring)) + + if let previousPane = previousPane { + let directionToRight: Bool + if let previousIndex = strongSelf.availablePanes.index(of: previousPane.key), let updatedIndex = strongSelf.availablePanes.index(of: candidatePane.key) { + directionToRight = previousIndex < updatedIndex + } else { + directionToRight = false + } + + let offset: CGFloat = directionToRight ? previousPane.node.bounds.width : -previousPane.node.bounds.width + candidatePane.node.layer.animatePosition(from: CGPoint(x: offset, y: 0.0), to: CGPoint(), duration: 0.35, timingFunction: kCAMediaTimingFunctionSpring, additive: true) + let previousNode = previousPane.node + previousNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: -offset, y: 0.0), duration: 0.35, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true, completion: { [weak previousNode] _ in + previousNode?.removeFromSupernode() + }) + } + } else { + if let previousPane = previousPane { + previousPane.node.removeFromSupernode() + } + } + } + })) + } + } + + func scrollToTop() -> Bool { + if let currentPane = self.currentPane { + return currentPane.node.scrollToTop() + } else { + return false + } + } + + func findLoadedMessage(id: MessageId) -> Message? { + return self.currentPane?.node.findLoadedMessage(id: id) + } + + func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { + return self.currentPane?.node.transitionNodeForGallery(messageId: messageId, media: media) + } + + func update(size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) { + self.currentParams = (size, isScrollingLockedAtTop, presentationData) + + transition.updateAlpha(node: self.coveringBackgroundNode, alpha: isScrollingLockedAtTop ? 0.0 : 1.0) + + self.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor + self.coveringBackgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.backgroundColor + self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + self.tapsSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + + let tabsHeight: CGFloat = 48.0 + + transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: size.width, height: UIScreenPixel))) + transition.updateFrame(node: self.coveringBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: tabsHeight))) + + transition.updateFrame(node: self.tapsSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: tabsHeight - UIScreenPixel), size: CGSize(width: size.width, height: UIScreenPixel))) + + transition.updateFrame(node: self.tabsContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: tabsHeight))) + self.tabsContainerNode.update(size: CGSize(width: size.width, height: tabsHeight), presentationData: presentationData, paneList: self.availablePanes.map { key in + let title: String + switch key { + case .media: + title = "Media" + case .files: + title = "Files" + case .links: + title = "Links" + case .music: + title = "Audio" + } + return PeerInfoPaneSpecifier(key: key, title: title) + }, selectedPane: self.currentPaneKey, transition: transition) + + let paneFrame = CGRect(origin: CGPoint(x: 0.0, y: tabsHeight), size: CGSize(width: size.width, height: size.height - tabsHeight)) + + if self.currentPane?.key != self.currentPaneKey { + if let currentPane = self.currentPane { + currentPane.node.removeFromSupernode() + self.currentPane = nil + } + + if let currentPaneKey = self.currentPaneKey { + let paneNode: PeerInfoPaneNode + switch currentPaneKey { + case .media: + paneNode = PeerInfoVisualMediaPaneNode(context: self.context, openMessage: { [weak self] id in + return self?.openMessage?(id) ?? false + }, peerId: self.peerId) + case .files: + paneNode = PeerInfoListPaneNode(context: self.context, openMessage: { [weak self] id in + return self?.openMessage?(id) ?? false + }, peerId: self.peerId, tagMask: .file) + case .links: + paneNode = PeerInfoListPaneNode(context: self.context, openMessage: { [weak self] id in + return self?.openMessage?(id) ?? false + }, peerId: self.peerId, tagMask: .webPage) + case .music: + paneNode = PeerInfoListPaneNode(context: self.context, openMessage: { [weak self] id in + return self?.openMessage?(id) ?? false + }, peerId: self.peerId, tagMask: .music) + } + self.currentPane = PeerInfoPaneWrapper(key: currentPaneKey, node: paneNode) + } + } + + if let currentPane = self.currentPane { + let paneWasAdded = currentPane.node.supernode == nil + if paneWasAdded { + self.addSubnode(currentPane.node) + } + + let paneTransition: ContainedViewLayoutTransition = paneWasAdded ? .immediate : transition + paneTransition.updateFrame(node: currentPane.node, frame: paneFrame) + currentPane.update(size: paneFrame.size, isScrollingLockedAtTop: isScrollingLockedAtTop, presentationData: presentationData, synchronous: paneWasAdded, transition: paneTransition) + } + if let (candidatePane, _) = self.candidatePane { + let paneTransition: ContainedViewLayoutTransition = .immediate + paneTransition.updateFrame(node: candidatePane.node, frame: paneFrame) + candidatePane.update(size: paneFrame.size, isScrollingLockedAtTop: isScrollingLockedAtTop, presentationData: presentationData, synchronous: true, transition: paneTransition) + } + if !self.didSetIsReady { + self.didSetIsReady = true + if let currentPane = self.currentPane { + self.isReady.set(currentPane.node.isReady) + } else { + self.isReady.set(.single(true)) + } + } + } +} + +protocol PeerInfoScreenItem: class { + var id: AnyHashable { get } + func node() -> PeerInfoScreenItemNode +} + +class PeerInfoScreenItemNode: ASDisplayNode { + var bringToFrontForHighlight: (() -> Void)? + + func update(width: CGFloat, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + preconditionFailure() + } +} + +private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { + let id: AnyHashable + + private let backgroundNode: ASDisplayNode + private let topSeparatorNode: ASDisplayNode + private let bottomSeparatorNode: ASDisplayNode + + private var currentItems: [PeerInfoScreenItem] = [] + private var itemNodes: [AnyHashable: PeerInfoScreenItemNode] = [:] + + init(id: AnyHashable) { + self.id = id + + self.backgroundNode = ASDisplayNode() + self.backgroundNode.isLayerBacked = true + + self.topSeparatorNode = ASDisplayNode() + self.topSeparatorNode.isLayerBacked = true + + self.bottomSeparatorNode = ASDisplayNode() + self.bottomSeparatorNode.isLayerBacked = true + + super.init() + + self.addSubnode(self.backgroundNode) + self.addSubnode(self.topSeparatorNode) + self.addSubnode(self.bottomSeparatorNode) + } + + func update(width: CGFloat, presentationData: PresentationData, items: [PeerInfoScreenItem], transition: ContainedViewLayoutTransition) -> CGFloat { + self.backgroundNode.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor + self.topSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + + var contentHeight: CGFloat = 0.0 + + for i in 0 ..< items.count { + let item = items[i] + + let itemNode: PeerInfoScreenItemNode + var wasAdded = false + if let current = self.itemNodes[item.id] { + itemNode = current + } else { + wasAdded = true + itemNode = item.node() + self.itemNodes[item.id] = itemNode + self.addSubnode(itemNode) + itemNode.bringToFrontForHighlight = { [weak self, weak itemNode] in + guard let strongSelf = self, let itemNode = itemNode else { + return + } + strongSelf.view.bringSubviewToFront(itemNode.view) + } + } + + let itemTransition: ContainedViewLayoutTransition = wasAdded ? .immediate : transition + + let itemHeight = itemNode.update(width: width, presentationData: presentationData, item: item, topItem: i == 0 ? nil : items[i - 1], bottomItem: (i == items.count - 1) ? nil : items[i + 1], transition: itemTransition) + let itemFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: itemHeight)) + itemTransition.updateFrame(node: itemNode, frame: itemFrame) + if wasAdded { + itemNode.alpha = 0.0 + transition.updateAlpha(node: itemNode, alpha: 1.0) + } + contentHeight += itemHeight + } + + var removeIds: [AnyHashable] = [] + for (id, _) in self.itemNodes { + if !items.contains(where: { $0.id == id }) { + removeIds.append(id) + } + } + for id in removeIds { + if let itemNode = self.itemNodes[id] { + transition.updateAlpha(node: itemNode, alpha: 0.0, completion: { [weak itemNode] _ in + itemNode?.removeFromSupernode() + }) + } + } + + transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: contentHeight))) + transition.updateFrame(node: self.topSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel))) + transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: UIScreenPixel))) + + return contentHeight + } +} + +private final class PeerInfoScreenData { + let peer: Peer? + let cachedData: CachedPeerData? + let presence: TelegramUserPresence? + let notificationSettings: TelegramPeerNotificationSettings? + + init( + peer: Peer?, + cachedData: CachedPeerData?, + presence: TelegramUserPresence?, + notificationSettings: TelegramPeerNotificationSettings? + ) { + self.peer = peer + self.cachedData = cachedData + self.presence = presence + self.notificationSettings = notificationSettings + } +} + +private enum PeerInfoScreenInputData: Equatable { + case none + case user +} + +private func peerInfoScreenData(context: AccountContext, peerId: PeerId) -> Signal { + return context.account.postbox.combinedView(keys: [.basicPeer(peerId)]) + |> map { view -> PeerInfoScreenInputData in + guard let peer = (view.views[.basicPeer(peerId)] as? BasicPeerView)?.peer else { + return .none + } + if let _ = peer as? TelegramUser { + return .user + } else { + preconditionFailure() + } + } + |> distinctUntilChanged + |> mapToSignal { inputData -> Signal in + switch inputData { + case .none: + return .single(PeerInfoScreenData( + peer: nil, + cachedData: nil, + presence: nil, + notificationSettings: nil + )) + case .user: + return context.account.viewTracker.peerView(peerId, updateData: true) + |> map { view -> PeerInfoScreenData in + return PeerInfoScreenData( + peer: view.peers[peerId], + cachedData: view.cachedData, + presence: view.peerPresences[peerId] as? TelegramUserPresence, + notificationSettings: view.notificationSettings as? TelegramPeerNotificationSettings + ) + } + } + } +} + +private final class PeerInfoInteraction { + let openUsername: (String) -> Void + let openPhone: (String) -> Void + + init( + openUsername: @escaping (String) -> Void, + openPhone: @escaping (String) -> Void + ) { + self.openUsername = openUsername + self.openPhone = openPhone + } +} + +private func peerInfoSectionItems(data: PeerInfoScreenData?, presentationData: PresentationData, interaction: PeerInfoInteraction) -> [PeerInfoScreenItem] { + var items: [PeerInfoScreenItem] = [] + if let user = data?.peer as? TelegramUser { + if let cachedData = data?.cachedData as? CachedUserData { + if let about = cachedData.about { + items.append(PeerInfoScreenLabeledValueItem(id: 0, label: "bio", text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) + } + } + if let username = user.username { + items.append(PeerInfoScreenLabeledValueItem(id: 1, label: "username", text: "@\(username)", textColor: .accent, action: { + interaction.openUsername(username) + })) + } + if let phone = user.phone { + items.append(PeerInfoScreenLabeledValueItem(id: 2, label: "mobile", text: "\(formatPhoneNumber(phone))", textColor: .accent, action: { + interaction.openPhone(phone) + })) + } + } + return items +} + +private final class PeerInfoNavigationNode: ASDisplayNode { + private let backgroundNode: ASDisplayNode + private let separatorContainerNode: ASDisplayNode + private let separatorCoveringNode: ASDisplayNode + private let separatorNode: ASDisplayNode + private let titleNode: ImmediateTextNode + + private var currentParams: (PresentationData, Peer?)? + + override init() { + self.backgroundNode = ASDisplayNode() + self.backgroundNode.isLayerBacked = true + + self.separatorContainerNode = ASDisplayNode() + self.separatorContainerNode.isLayerBacked = true + self.separatorContainerNode.clipsToBounds = true + + self.separatorCoveringNode = ASDisplayNode() + self.separatorCoveringNode.isLayerBacked = true + + self.separatorNode = ASDisplayNode() + self.separatorNode.isLayerBacked = true + + self.titleNode = ImmediateTextNode() + + super.init() + + self.addSubnode(self.backgroundNode) + + self.separatorContainerNode.addSubnode(self.separatorNode) + self.separatorContainerNode.addSubnode(self.separatorCoveringNode) + self.addSubnode(self.separatorContainerNode) + + self.addSubnode(self.titleNode) + } + + func update(size: CGSize, statusBarHeight: CGFloat, navigationHeight: CGFloat, offset: CGFloat, paneContainerOffset: CGFloat, presentationData: PresentationData, peer: Peer?, transition: ContainedViewLayoutTransition) { + if let (currentPresentationData, currentPeer) = self.currentParams { + if currentPresentationData !== presentationData || currentPeer !== peer { + if let peer = peer { + self.titleNode.attributedText = NSAttributedString(string: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.semibold(17.0), textColor: presentationData.theme.rootController.navigationBar.primaryTextColor) + } + } + } + + if self.currentParams?.0.theme !== presentationData.theme { + self.backgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.backgroundColor + self.separatorNode.backgroundColor = presentationData.theme.rootController.navigationBar.separatorColor + self.separatorCoveringNode.backgroundColor = presentationData.theme.rootController.navigationBar.backgroundColor + } + + self.currentParams = (presentationData, peer) + + let titleSize = self.titleNode.updateLayout(CGSize(width: size.width - 100.0, height: .greatestFiniteMagnitude)) + let titleFrame = CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: statusBarHeight + floor((navigationHeight - statusBarHeight - titleSize.height) / 2.0)), size: titleSize) + transition.updateFrameAdditiveToCenter(node: self.titleNode, frame: titleFrame) + + transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size)) + transition.updateFrame(node: self.separatorContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: size.height), size: CGSize(width: size.width, height: UIScreenPixel))) + transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: UIScreenPixel))) + transition.updateFrame(node: self.separatorCoveringNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -offset + paneContainerOffset - size.height), size: CGSize(width: size.width, height: 10.0 + UIScreenPixel))) + + let revealOffset: CGFloat = 100.0 + let progress: CGFloat = max(0.0, min(1.0, offset / revealOffset)) + + transition.updateAlpha(node: self.backgroundNode, alpha: progress) + transition.updateAlpha(node: self.separatorNode, alpha: progress) + transition.updateAlpha(node: self.titleNode, alpha: progress) + } +} + +private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate { + private weak var controller: PeerInfoScreen? + + private let context: AccountContext + private let peerId: PeerId + private var presentationData: PresentationData + private let scrollNode: ASScrollNode + + private let navigationNode: PeerInfoNavigationNode + private let headerNode: PeerInfoHeaderNode + private let infoSection: PeerInfoScreenItemSectionContainerNode + private let paneContainerNode: PeerInfoPaneContainerNode + private var isPaneAreaExpanded: Bool = false + private var ignoreScrolling: Bool = false + + private var _interaction: PeerInfoInteraction? + private var interaction: PeerInfoInteraction { + return self._interaction! + } + + private var validLayout: (ContainerViewLayout, CGFloat)? + private var data: PeerInfoScreenData? + private var dataDisposable: Disposable? + + private let _ready = Promise() + var ready: Promise { + return self._ready + } + private var didSetReady = false + + init(controller: PeerInfoScreen, context: AccountContext, peerId: PeerId) { + self.controller = controller + self.context = context + self.peerId = peerId + self.presentationData = context.sharedContext.currentPresentationData.with { $0 } + + self.scrollNode = ASScrollNode() + + self.navigationNode = PeerInfoNavigationNode() + self.headerNode = PeerInfoHeaderNode(context: context) + self.infoSection = PeerInfoScreenItemSectionContainerNode(id: 0) + self.paneContainerNode = PeerInfoPaneContainerNode(context: context, peerId: peerId) + + super.init() + + self._interaction = PeerInfoInteraction( + openUsername: { [weak self] value in + self?.openUsername(value: value) + }, + openPhone: { [weak self] value in + self?.openPhone(value: value) + } + ) + + self.backgroundColor = self.presentationData.theme.list.blocksBackgroundColor + + self.scrollNode.view.showsVerticalScrollIndicator = false + if #available(iOS 11.0, *) { + self.scrollNode.view.contentInsetAdjustmentBehavior = .never + } + self.scrollNode.view.scrollsToTop = false + self.scrollNode.view.delegate = self + self.addSubnode(self.scrollNode) + self.addSubnode(self.navigationNode) + + self.scrollNode.addSubnode(self.headerNode) + self.scrollNode.addSubnode(self.infoSection) + self.scrollNode.addSubnode(self.paneContainerNode) + + self.paneContainerNode.openMessage = { [weak self] id in + return self?.openMessage(id: id) ?? false + } + + self.headerNode.performButtonAction = { [weak self] key in + self?.performButtonAction(key: key) + } + + self.dataDisposable = (peerInfoScreenData(context: context, peerId: peerId) + |> deliverOnMainQueue).start(next: { [weak self] data in + guard let strongSelf = self else { + return + } + strongSelf.updateData(data) + }) + } + + deinit { + self.dataDisposable?.dispose() + } + + override func didLoad() { + super.didLoad() + } + + private func updateData(_ data: PeerInfoScreenData) { + self.data = data + if let (layout, navigationHeight) = self.validLayout { + self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate) + } + } + + func scrollToTop() { + if self.isPaneAreaExpanded { + if !self.paneContainerNode.scrollToTop() { + + } + } else { + self.scrollNode.view.setContentOffset(CGPoint(), animated: true) + } + } + + private func openMessage(id: MessageId) -> Bool { + guard let galleryMessage = self.paneContainerNode.findLoadedMessage(id: id), let controller = self.controller, let navigationController = controller.navigationController as? NavigationController else { + return false + } + self.view.endEditing(true) + + return self.context.sharedContext.openChatMessage(OpenChatMessageParams(context: self.context, message: galleryMessage, standalone: false, reverseMessageGalleryOrder: true, navigationController: navigationController, dismissInput: { [weak self] in + self?.view.endEditing(true) + }, present: { [weak self] c, a in + self?.controller?.present(c, in: .window(.root), with: a, blockInteraction: true) + }, transitionNode: { [weak self] messageId, media in + guard let strongSelf = self else { + return nil + } + return strongSelf.paneContainerNode.transitionNodeForGallery(messageId: messageId, media: media) + }, addToTransitionSurface: { [weak self] view in + guard let strongSelf = self else { + return + } + strongSelf.view.addSubview(view) + }, openUrl: { url in + //self?.openUrl(url) + }, openPeer: { peer, navigation in + //self?.controllerInteraction?.openPeer(peer.id, navigation, nil) + }, callPeer: { peerId in + //self?.controllerInteraction?.callPeer(peerId) + }, enqueueMessage: { _ in + }, sendSticker: nil, setupTemporaryHiddenMedia: { _, _, _ in }, chatAvatarHiddenMedia: { _, _ in })) + } + + private func performButtonAction(key: PeerInfoHeaderButtonKey) { + guard let controller = self.controller else { + return + } + switch key { + case .message: + if let navigationController = controller.navigationController as? NavigationController { + context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(self.peerId))) + } + case .call: + self.requestCall() + case .mute: + let peerId = self.peerId + let _ = (self.context.account.postbox.transaction { transaction -> (TelegramPeerNotificationSettings, GlobalNotificationSettings) in + let peerSettings: TelegramPeerNotificationSettings = (transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings) ?? TelegramPeerNotificationSettings.defaultSettings + let globalSettings: GlobalNotificationSettings = (transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications) as? GlobalNotificationSettings) ?? GlobalNotificationSettings.defaultSettings + return (peerSettings, globalSettings) + } + |> deliverOnMainQueue).start(next: { [weak self] peerSettings, globalSettings in + guard let strongSelf = self else { + return + } + let soundSettings: NotificationSoundSettings? + if case .default = peerSettings.messageSound { + soundSettings = NotificationSoundSettings(value: nil) + } else { + soundSettings = NotificationSoundSettings(value: peerSettings.messageSound) + } + let muteSettingsController = notificationMuteSettingsController(presentationData: strongSelf.presentationData, notificationSettings: globalSettings.effective.groupChats, soundSettings: soundSettings, openSoundSettings: { + guard let strongSelf = self else { + return + } + let soundController = notificationSoundSelectionController(context: strongSelf.context, isModal: true, currentSound: peerSettings.messageSound, defaultSound: globalSettings.effective.groupChats.sound, completion: { sound in + guard let strongSelf = self else { + return + } + let _ = updatePeerNotificationSoundInteractive(account: strongSelf.context.account, peerId: strongSelf.peerId, sound: sound).start() + }) + strongSelf.controller?.present(soundController, in: .window(.root)) + }, updateSettings: { value in + guard let strongSelf = self else { + return + } + let _ = updatePeerMuteSetting(account: strongSelf.context.account, peerId: strongSelf.peerId, muteInterval: value).start() + }) + strongSelf.controller?.present(muteSettingsController, in: .window(.root)) + }) + case .more: + let actionSheet = ActionSheetController(presentationData: self.presentationData) + let dismissAction: () -> Void = { [weak actionSheet] in + actionSheet?.dismissAnimated() + } + var reportSpam = false + var deleteChat = false + actionSheet.setItemGroups([ + ActionSheetItemGroup(items: [ + ActionSheetButtonItem(title: presentationData.strings.UserInfo_StartSecretChat, color: .accent, action: { [weak self] in + dismissAction() + self?.openStartSecretChat() + }) + ]), + ActionSheetItemGroup(items: [ActionSheetButtonItem(title: self.presentationData.strings.Common_Cancel, action: { dismissAction() })]) + ]) + controller.present(actionSheet, in: .window(.root)) + } + } + + private func openStartSecretChat() { + let peerId = self.peerId + let _ = (self.context.account.postbox.transaction { transaction -> (Peer?, PeerId?) in + let peer = transaction.getPeer(peerId) + let filteredPeerIds = Array(transaction.getAssociatedPeerIds(peerId)).filter { $0.namespace == Namespaces.Peer.SecretChat } + var activeIndices: [ChatListIndex] = [] + for associatedId in filteredPeerIds { + if let state = (transaction.getPeer(associatedId) as? TelegramSecretChat)?.embeddedState { + switch state { + case .active, .handshake: + if let (_, index) = transaction.getPeerChatListIndex(associatedId) { + activeIndices.append(index) + } + default: + break + } + } + } + activeIndices.sort() + if let index = activeIndices.last { + return (peer, index.messageIndex.id.peerId) + } else { + return (peer, nil) + } + } + |> deliverOnMainQueue).start(next: { [weak self] peer, currentPeerId in + guard let strongSelf = self else { + return + } + if let currentPeerId = currentPeerId { + if let navigationController = (strongSelf.controller?.navigationController as? NavigationController) { + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(currentPeerId))) + } + } else if let controller = strongSelf.controller { + let displayTitle = peer?.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder) ?? "" + controller.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.UserInfo_StartSecretChatConfirmation(displayTitle).0, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.UserInfo_StartSecretChatStart, action: { + guard let strongSelf = self else { + return + } + var createSignal = createSecretChat(account: strongSelf.context.account, peerId: peerId) + var cancelImpl: (() -> Void)? + let progressSignal = Signal { subscriber in + if let strongSelf = self { + let statusController = OverlayStatusController(theme: strongSelf.presentationData.theme, type: .loading(cancelled: { + cancelImpl?() + })) + strongSelf.controller?.present(statusController, in: .window(.root)) + return ActionDisposable { [weak controller] in + Queue.mainQueue().async() { + controller?.dismiss() + } + } + } else { + return EmptyDisposable + } + } + |> runOn(Queue.mainQueue()) + |> delay(0.15, queue: Queue.mainQueue()) + let progressDisposable = progressSignal.start() + + createSignal = createSignal + |> afterDisposed { + Queue.mainQueue().async { + progressDisposable.dispose() + } + } + let createSecretChatDisposable = MetaDisposable() + cancelImpl = { + createSecretChatDisposable.set(nil) + } + + createSecretChatDisposable.set((createSignal + |> deliverOnMainQueue).start(next: { peerId in + guard let strongSelf = self else { + return + } + if let navigationController = (strongSelf.controller?.navigationController as? NavigationController) { + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(strongSelf.peerId))) + } + }, error: { _ in + guard let strongSelf = self else { + return + } + strongSelf.controller?.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + })) + })]), in: .window(.root)) + } + }) + } + + private func openUsername(value: String) { + let shareController = ShareController(context: context, subject: .url("\(value)")) + self.controller?.present(shareController, in: .window(.root)) + } + + private func requestCall() { + guard let peer = self.data?.peer as? TelegramUser, let cachedUserData = self.data?.cachedData as? CachedUserData else { + return + } + if cachedUserData.callsPrivate { + self.controller?.present(textAlertController(context: self.context, title: self.presentationData.strings.Call_ConnectionErrorTitle, text: self.presentationData.strings.Call_PrivacyErrorMessage(peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + return + } + + let callResult = self.context.sharedContext.callManager?.requestCall(account: self.context.account, peerId: peer.id, endCurrentIfAny: false) + if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult { + if currentPeerId == peer.id { + self.context.sharedContext.navigateToCurrentCall() + } else { + let _ = (self.context.account.postbox.transaction { transaction -> (Peer?, Peer?) in + return (transaction.getPeer(peer.id), transaction.getPeer(currentPeerId)) + } + |> deliverOnMainQueue).start(next: { [weak self] peer, current in + guard let strongSelf = self else { + return + } + if let peer = peer, let current = current { + strongSelf.controller?.present(textAlertController(context: strongSelf.context, title: strongSelf.presentationData.strings.Call_CallInProgressTitle, text: strongSelf.presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_OK, action: { + guard let strongSelf = self else { + return + } + let _ = strongSelf.context.sharedContext.callManager?.requestCall(account: strongSelf.context.account, peerId: peer.id, endCurrentIfAny: true) + })]), in: .window(.root)) + } + }) + } + } + } + + private func openPhone(value: String) { + let _ = (getUserPeer(postbox: self.context.account.postbox, peerId: peerId) + |> deliverOnMainQueue).start(next: { [weak self] peer, _ in + guard let strongSelf = self else { + return + } + if let peer = peer as? TelegramUser, let peerPhoneNumber = peer.phone, formatPhoneNumber(value) == formatPhoneNumber(peerPhoneNumber) { + let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData) + let dismissAction: () -> Void = { [weak actionSheet] in + actionSheet?.dismissAnimated() + } + actionSheet.setItemGroups([ + ActionSheetItemGroup(items: [ + ActionSheetButtonItem(title: strongSelf.presentationData.strings.UserInfo_TelegramCall, action: { + dismissAction() + self?.requestCall() + }), + ActionSheetButtonItem(title: strongSelf.presentationData.strings.UserInfo_PhoneCall, action: { + dismissAction() + + guard let strongSelf = self else { + return + } + strongSelf.context.sharedContext.applicationBindings.openUrl("tel:\(formatPhoneNumber(value).replacingOccurrences(of: " ", with: ""))") + }), + ]), + ActionSheetItemGroup(items: [ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, action: { dismissAction() })]) + ]) + strongSelf.controller?.present(actionSheet, in: .window(.root)) + } else { + strongSelf.context.sharedContext.applicationBindings.openUrl("tel:\(formatPhoneNumber(value).replacingOccurrences(of: " ", with: ""))") + } + }) + } + + func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition) { + self.validLayout = (layout, navigationHeight) + + self.ignoreScrolling = true + + transition.updateFrame(node: self.navigationNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: navigationHeight))) + transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: layout.size)) + + let sectionSpacing: CGFloat = 24.0 + + var contentHeight: CGFloat = 0.0 + + let headerHeight = self.headerNode.update(width: layout.size.width, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, presence: self.data?.presence, transition: transition) + transition.updateFrame(node: self.headerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: headerHeight))) + contentHeight += headerHeight + contentHeight += sectionSpacing + + let infoSectionHeight = self.infoSection.update(width: layout.size.width, presentationData: self.presentationData, items: peerInfoSectionItems(data: self.data, presentationData: self.presentationData, interaction: self.interaction), transition: transition) + let infoSectionFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: infoSectionHeight)) + transition.updateFrame(node: self.infoSection, frame: infoSectionFrame) + contentHeight += infoSectionHeight + contentHeight += sectionSpacing + + let paneContainerSize = CGSize(width: layout.size.width, height: layout.size.height - navigationHeight) + self.paneContainerNode.update(size: paneContainerSize, isScrollingLockedAtTop: !self.isPaneAreaExpanded, presentationData: self.presentationData, transition: transition) + transition.updateFrame(node: self.paneContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: paneContainerSize)) + contentHeight += layout.size.height - navigationHeight + + self.scrollNode.view.contentSize = CGSize(width: layout.size.width, height: contentHeight) + + if self.isPaneAreaExpanded { + transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: 0.0, y: contentHeight - self.scrollNode.bounds.height), size: self.scrollNode.bounds.size)) + } else { + let maxOffsetY = max(0.0, contentHeight - floor(self.scrollNode.bounds.height * 1.5)) + if self.scrollNode.view.contentOffset.y > maxOffsetY { + //transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: 0.0, y: maxOffsetY), size: self.scrollNode.bounds.size)) + } + } + + self.ignoreScrolling = false + self.updateNavigation(transition: transition) + + if !self.didSetReady && self.data != nil { + self.didSetReady = true + self._ready.set(self.paneContainerNode.isReady.get()) + } + } + + private func updateNavigation(transition: ContainedViewLayoutTransition) { + let offsetY = self.scrollNode.view.contentOffset.y + + if offsetY <= 1.0 { + self.scrollNode.view.bounces = true + } else { + self.scrollNode.view.bounces = false + } + + if let (layout, navigationHeight) = self.validLayout { + self.navigationNode.update(size: CGSize(width: layout.size.width, height: navigationHeight), statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, offset: offsetY, paneContainerOffset: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, transition: transition) + } + } + + func scrollViewDidScroll(_ scrollView: UIScrollView) { + if self.ignoreScrolling { + return + } + self.updateNavigation(transition: .immediate) + } + + func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { + guard let (_, navigationHeight) = self.validLayout else { + return + } + let snapDurationFactor = max(0.5, min(1.5, abs(velocity.y) * 0.8)) + + var snapToOffset: CGFloat? + let offset = targetContentOffset.pointee.y + + let headerMaxOffset = self.headerNode.bounds.height - navigationHeight + let collapsedPanesOffset = max(0.0, scrollView.contentSize.height - floor(scrollNode.bounds.height * 1.5)) + let expandedPanesOffset = scrollView.contentSize.height - self.scrollNode.bounds.height + + if offset > collapsedPanesOffset { + if velocity.y < 0.0 { + var targetOffset = collapsedPanesOffset + if targetOffset < headerMaxOffset { + targetOffset = 0.0 + } + snapToOffset = targetOffset + } else { + snapToOffset = expandedPanesOffset + } + } else if offset < headerMaxOffset && offset > 0.0 { + let directionIsDown: Bool + if abs(velocity.y) > 0.2 { + directionIsDown = velocity.y >= 0.0 + } else { + directionIsDown = offset >= headerMaxOffset / 2.0 + } + + if directionIsDown { + snapToOffset = headerMaxOffset + } else { + snapToOffset = 0.0 + } + } else if self.isPaneAreaExpanded && offset < expandedPanesOffset { + let directionIsDown: Bool + if abs(velocity.y) > 0.2 { + directionIsDown = velocity.y >= 0.0 + } else { + directionIsDown = offset >= headerMaxOffset / 2.0 + } + + if directionIsDown { + snapToOffset = headerMaxOffset + } else { + snapToOffset = 0.0 + } + } + + if let snapToOffset = snapToOffset { + targetContentOffset.pointee = scrollView.contentOffset + DispatchQueue.main.async { + let isPaneAreaExpanded = abs(snapToOffset - expandedPanesOffset) < CGFloat.ulpOfOne ? true : false + self.isPaneAreaExpanded = isPaneAreaExpanded + let currentOffset = scrollView.contentOffset + let transition: ContainedViewLayoutTransition = .animated(duration: 0.3 * Double(1.0 / snapDurationFactor), curve: .spring) + self.ignoreScrolling = true + transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: 0.0, y: snapToOffset), size: self.scrollNode.bounds.size)) + self.ignoreScrolling = false + if let (layout, navigationHeight) = self.validLayout { + self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: transition) + } + } + } + } + + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + guard let result = super.hitTest(point, with: event) else { + return nil + } + var currentParent: UIView? = result + var enableScrolling = true + while true { + if currentParent == nil || currentParent === self.view { + break + } + if let scrollView = currentParent as? UIScrollView { + if scrollView === self.scrollNode.view { + break + } + if scrollView.isDecelerating && scrollView.contentOffset.y < -scrollView.contentInset.top { + return self.scrollNode.view + } + } else if let listView = currentParent as? ListViewBackingView, let listNode = listView.target { + if listNode.scroller.isDecelerating && listNode.scroller.contentOffset.y < listNode.scroller.contentInset.top { + return self.scrollNode.view + } + } + currentParent = currentParent?.superview + } + return result + } +} + +public final class PeerInfoScreen: ViewController { + private let context: AccountContext + private let peerId: PeerId + + private var presentationData: PresentationData + + private var controllerNode: PeerInfoScreenNode { + return self.displayNode as! PeerInfoScreenNode + } + + private let _ready = Promise() + override public var ready: Promise { + return self._ready + } + + public init(context: AccountContext, peerId: PeerId) { + self.context = context + self.peerId = peerId + + self.presentationData = context.sharedContext.currentPresentationData.with { $0 } + + let baseNavigationBarPresentationData = NavigationBarPresentationData(presentationData: self.presentationData) + super.init(navigationBarPresentationData: NavigationBarPresentationData( + theme: NavigationBarTheme( + buttonColor: baseNavigationBarPresentationData.theme.buttonColor, + disabledButtonColor: baseNavigationBarPresentationData.theme.disabledButtonColor, + primaryTextColor: baseNavigationBarPresentationData.theme.primaryTextColor, + backgroundColor: .clear, + separatorColor: .clear, + badgeBackgroundColor: baseNavigationBarPresentationData.theme.badgeBackgroundColor, + badgeStrokeColor: baseNavigationBarPresentationData.theme.badgeStrokeColor, + badgeTextColor: baseNavigationBarPresentationData.theme.badgeTextColor + ), strings: baseNavigationBarPresentationData.strings)) + + self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style + + self.scrollToTop = { [weak self] in + self?.controllerNode.scrollToTop() + } + } + + required init(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override public func loadDisplayNode() { + self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId) + + self._ready.set(self.controllerNode.ready.get()) + + super.displayNodeDidLoad() + } + + override public func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + } + + override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { + super.containerLayoutUpdated(layout, transition: transition) + + self.controllerNode.containerLayoutUpdated(layout: layout, navigationHeight: self.navigationHeight, transition: transition) + } +} + +private func getUserPeer(postbox: Postbox, peerId: PeerId) -> Signal<(Peer?, CachedPeerData?), NoError> { + return postbox.transaction { transaction -> (Peer?, CachedPeerData?) in + guard let peer = transaction.getPeer(peerId) else { + return (nil, nil) + } + var resultPeer: Peer? + if let peer = peer as? TelegramSecretChat { + resultPeer = transaction.getPeer(peer.regularPeerId) + } else { + resultPeer = peer + } + return (resultPeer, resultPeer.flatMap({ transaction.getPeerCachedData(peerId: $0.id) })) + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoScreenLabeledValueItem.swift b/submodules/TelegramUI/TelegramUI/PeerInfoScreenLabeledValueItem.swift new file mode 100644 index 0000000000..d7f382389f --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/PeerInfoScreenLabeledValueItem.swift @@ -0,0 +1,123 @@ +import AsyncDisplayKit +import Display +import TelegramPresentationData + +enum PeerInfoScreenLabeledValueTextColor { + case primary + case accent +} + +enum PeerInfoScreenLabeledValueTextBehavior: Equatable { + case singleLine + case multiLine(maxLines: Int) +} + +final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem { + let id: AnyHashable + let label: String + let text: String + let textColor: PeerInfoScreenLabeledValueTextColor + let textBehavior: PeerInfoScreenLabeledValueTextBehavior + let action: (() -> Void)? + + init(id: AnyHashable, label: String, text: String, textColor: PeerInfoScreenLabeledValueTextColor = .primary, textBehavior: PeerInfoScreenLabeledValueTextBehavior = .singleLine, action: (() -> Void)?) { + self.id = id + self.label = label + self.text = text + self.textColor = textColor + self.textBehavior = textBehavior + self.action = action + } + + func node() -> PeerInfoScreenItemNode { + return PeerInfoScreenLabeledValueItemNode() + } +} + +private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode { + private let selectionNode: PeerInfoScreenSelectableBackgroundNode + private let labelNode: ImmediateTextNode + private let textNode: ImmediateTextNode + private let bottomSeparatorNode: ASDisplayNode + + private var item: PeerInfoScreenLabeledValueItem? + + override init() { + var bringToFrontForHighlightImpl: (() -> Void)? + self.selectionNode = PeerInfoScreenSelectableBackgroundNode(bringToFrontForHighlight: { bringToFrontForHighlightImpl?() }) + + self.labelNode = ImmediateTextNode() + self.labelNode.displaysAsynchronously = false + self.labelNode.isUserInteractionEnabled = false + + self.textNode = ImmediateTextNode() + self.textNode.displaysAsynchronously = false + self.textNode.isUserInteractionEnabled = false + + self.bottomSeparatorNode = ASDisplayNode() + self.bottomSeparatorNode.isLayerBacked = true + + super.init() + + bringToFrontForHighlightImpl = { [weak self] in + self?.bringToFrontForHighlight?() + } + + self.addSubnode(self.bottomSeparatorNode) + self.addSubnode(self.selectionNode) + self.addSubnode(self.labelNode) + self.addSubnode(self.textNode) + } + + override func update(width: CGFloat, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + guard let item = item as? PeerInfoScreenLabeledValueItem else { + return 10.0 + } + + self.item = item + + self.selectionNode.pressed = item.action + + let sideInset: CGFloat = 16.0 + + self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + + let textColorValue: UIColor + switch item.textColor { + case .primary: + textColorValue = presentationData.theme.list.itemPrimaryTextColor + case .accent: + textColorValue = presentationData.theme.list.itemAccentColor + } + + self.labelNode.attributedText = NSAttributedString(string: item.label, font: Font.regular(14.0), textColor: presentationData.theme.list.itemPrimaryTextColor) + + switch item.textBehavior { + case .singleLine: + self.textNode.maximumNumberOfLines = 1 + case let .multiLine(maxLines): + self.textNode.maximumNumberOfLines = maxLines + } + self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(17.0), textColor: textColorValue) + + let labelSize = self.labelNode.updateLayout(CGSize(width: width - sideInset * 2.0, height: .greatestFiniteMagnitude)) + let textSize = self.textNode.updateLayout(CGSize(width: width - sideInset * 2.0, height: .greatestFiniteMagnitude)) + + let labelFrame = CGRect(origin: CGPoint(x: sideInset, y: 11.0), size: labelSize) + let textFrame = CGRect(origin: CGPoint(x: sideInset, y: labelFrame.maxY + 3.0), size: textSize) + + transition.updateFrame(node: self.labelNode, frame: labelFrame) + transition.updateFrame(node: self.textNode, frame: textFrame) + + let height = labelSize.height + 3.0 + textSize.height + 22.0 + + let highlightNodeOffset: CGFloat = topItem == nil ? 0.0 : UIScreenPixel + self.selectionNode.update(size: CGSize(width: width, height: height + highlightNodeOffset), theme: presentationData.theme, transition: transition) + transition.updateFrame(node: self.selectionNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -highlightNodeOffset), size: CGSize(width: width, height: height + highlightNodeOffset))) + + transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: sideInset, y: height - UIScreenPixel), size: CGSize(width: width - sideInset, height: UIScreenPixel))) + transition.updateAlpha(node: self.bottomSeparatorNode, alpha: bottomItem == nil ? 0.0 : 1.0) + + return height + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoScreenSelectableBackgroundNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfoScreenSelectableBackgroundNode.swift new file mode 100644 index 0000000000..08b0c6e17a --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/PeerInfoScreenSelectableBackgroundNode.swift @@ -0,0 +1,55 @@ +import AsyncDisplayKit +import Display +import TelegramPresentationData + +final class PeerInfoScreenSelectableBackgroundNode: ASDisplayNode { + private let backgroundNode: ASDisplayNode + private let buttonNode: HighlightTrackingButtonNode + + let bringToFrontForHighlight: () -> Void + + var pressed: (() -> Void)? { + didSet { + self.buttonNode.isUserInteractionEnabled = self.pressed != nil + } + } + + init(bringToFrontForHighlight: @escaping () -> Void) { + self.bringToFrontForHighlight = bringToFrontForHighlight + + self.backgroundNode = ASDisplayNode() + self.backgroundNode.isLayerBacked = true + self.backgroundNode.alpha = 0.0 + + self.buttonNode = HighlightTrackingButtonNode() + + super.init() + + self.addSubnode(self.backgroundNode) + self.addSubnode(self.buttonNode) + + self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside) + self.buttonNode.highligthedChanged = { [weak self] highlighted in + if let strongSelf = self { + if highlighted { + strongSelf.bringToFrontForHighlight() + strongSelf.backgroundNode.layer.removeAnimation(forKey: "opacity") + strongSelf.backgroundNode.alpha = 1.0 + } else { + strongSelf.backgroundNode.alpha = 0.0 + strongSelf.backgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25) + } + } + } + } + + @objc private func buttonPressed() { + self.pressed?() + } + + func update(size: CGSize, theme: PresentationTheme, transition: ContainedViewLayoutTransition) { + self.backgroundNode.backgroundColor = theme.list.itemHighlightedBackgroundColor + transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size)) + transition.updateFrame(node: self.buttonNode, frame: CGRect(origin: CGPoint(), size: size)) + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoVisualMediaPane.swift b/submodules/TelegramUI/TelegramUI/PeerInfoVisualMediaPane.swift new file mode 100644 index 0000000000..f49d9978e6 --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/PeerInfoVisualMediaPane.swift @@ -0,0 +1,458 @@ +import AsyncDisplayKit +import Display +import TelegramCore +import SyncCore +import SwiftSignalKit +import Postbox +import TelegramPresentationData +import AccountContext +import ContextUI +import PhotoResources + +private final class VisualMediaItemInteraction { + let openMessage: (MessageId) -> Void + var hiddenMedia: [MessageId: [Media]] = [:] + + init(openMessage: @escaping (MessageId) -> Void) { + self.openMessage = openMessage + } +} + +private final class VisualMediaItemNode: ASDisplayNode { + private let context: AccountContext + private let interaction: VisualMediaItemInteraction + + private let containerNode: ContextControllerSourceNode + private let imageNode: TransformImageNode + + private let fetchStatusDisposable = MetaDisposable() + private let fetchDisposable = MetaDisposable() + private var resourceStatus: MediaResourceStatus? + + private var item: (VisualMediaItem, Media?, CGSize, CGSize?)? + + init(context: AccountContext, interaction: VisualMediaItemInteraction) { + self.context = context + self.interaction = interaction + + self.containerNode = ContextControllerSourceNode() + self.imageNode = TransformImageNode() + + super.init() + + self.addSubnode(self.containerNode) + self.containerNode.addSubnode(self.imageNode) + + self.containerNode.isGestureEnabled = false + } + + deinit { + self.fetchStatusDisposable.dispose() + self.fetchDisposable.dispose() + } + + override func didLoad() { + super.didLoad() + + self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))) + } + + @objc func tapGesture(_ recognizer: UITapGestureRecognizer) { + if case .ended = recognizer.state { + if let (item, _, _, _) = self.item { + self.interaction.openMessage(item.message.id) + } + } + } + + func update(size: CGSize, item: VisualMediaItem, theme: PresentationTheme, synchronousLoad: Bool) { + if item === self.item?.0 && size == self.item?.2 { + return + } + var media: Media? + for value in item.message.media { + if let image = value as? TelegramMediaImage { + media = image + break + } else if let file = value as? TelegramMediaFile { + media = file + break + } + } + + if let media = media, (self.item?.1 == nil || !media.isEqual(to: self.item!.1!)) { + var mediaDimensions: CGSize? + if let image = media as? TelegramMediaImage, let largestSize = largestImageRepresentation(image.representations)?.dimensions { + mediaDimensions = largestSize.cgSize + + self.imageNode.setSignal(mediaGridMessagePhoto(account: context.account, photoReference: .message(message: MessageReference(item.message), media: image), fullRepresentationSize: CGSize(width: 300.0, height: 300.0), synchronousLoad: synchronousLoad), attemptSynchronously: synchronousLoad, dispatchOnDisplayLink: true) + + self.fetchStatusDisposable.set(nil) + /*self.statusNode.transitionToState(.none, completion: { [weak self] in + self?.statusNode.isHidden = true + })*/ + //self.mediaBadgeNode.isHidden = true + self.resourceStatus = nil + } else if let file = media as? TelegramMediaFile, file.isVideo { + mediaDimensions = file.dimensions?.cgSize + self.imageNode.setSignal(mediaGridMessageVideo(postbox: context.account.postbox, videoReference: .message(message: MessageReference(item.message), media: file), synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: true), attemptSynchronously: synchronousLoad) + + /*self.mediaBadgeNode.isHidden = false + + self.resourceStatus = nil + self.fetchStatusDisposable.set((messageMediaFileStatus(context: context, messageId: messageId, file: file) |> deliverOnMainQueue).start(next: { [weak self] status in + if let strongSelf = self, let item = strongSelf.item { + strongSelf.resourceStatus = status + + let isStreamable = isMediaStreamable(message: item.message, media: file) + + let statusState: RadialStatusNodeState + if isStreamable { + statusState = .none + } else { + switch status { + case let .Fetching(_, progress): + let adjustedProgress = max(progress, 0.027) + statusState = .progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true) + case .Local: + statusState = .none + case .Remote: + statusState = .download(.white) + } + } + + switch statusState { + case .none: + break + default: + strongSelf.statusNode.isHidden = false + } + + strongSelf.statusNode.transitionToState(statusState, animated: true, completion: { + if let strongSelf = self { + if case .none = statusState { + strongSelf.statusNode.isHidden = true + } + } + }) + + if let duration = file.duration { + let durationString = stringForDuration(duration) + + var badgeContent: ChatMessageInteractiveMediaBadgeContent? + var mediaDownloadState: ChatMessageInteractiveMediaDownloadState? + + if isStreamable { + switch status { + case let .Fetching(_, progress): + let progressString = String(format: "%d%%", Int(progress * 100.0)) + badgeContent = .text(inset: 12.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: progressString)) + mediaDownloadState = .compactFetching(progress: 0.0) + case .Local: + badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString)) + case .Remote: + badgeContent = .text(inset: 12.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString)) + mediaDownloadState = .compactRemote + } + } else { + badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString)) + } + + strongSelf.mediaBadgeNode.update(theme: item.theme, content: badgeContent, mediaDownloadState: mediaDownloadState, alignment: .right, animated: false, badgeAnimated: false) + } + } + })) + if self.statusNode.supernode == nil { + self.imageNode.addSubnode(self.statusNode) + }*/ + } else { + //self.mediaBadgeNode.isHidden = true + } + self.item = (item, media, size, mediaDimensions) + + self.updateHiddenMedia() + } + + if let (item, media, _, mediaDimensions) = self.item { + self.item = (item, media, size, mediaDimensions) + + let imageFrame = CGRect(origin: CGPoint(), size: size) + + self.containerNode.frame = imageFrame + self.imageNode.frame = imageFrame + + if let mediaDimensions = mediaDimensions { + let imageSize = mediaDimensions.aspectFilled(imageFrame.size) + self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageFrame.size, intrinsicInsets: UIEdgeInsets(), emptyColor: theme.list.mediaPlaceholderColor))() + } + } + } + + func transitionNode() -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { + let imageNode = self.imageNode + return (self.imageNode, self.imageNode.bounds, { [weak self, weak imageNode] in + var statusNodeHidden = false + var accessoryHidden = false + if let strongSelf = self { + //statusNodeHidden = strongSelf.statusNode.isHidden + //accessoryHidden = strongSelf.mediaBadgeNode.isHidden + //strongSelf.statusNode.isHidden = true + //strongSelf.mediaBadgeNode.isHidden = true + } + let view = imageNode?.view.snapshotContentTree(unhide: true) + if let strongSelf = self { + //strongSelf.statusNode.isHidden = statusNodeHidden + //strongSelf.mediaBadgeNode.isHidden = accessoryHidden + } + return (view, nil) + }) + } + + func updateHiddenMedia() { + if let (item, _, _, _) = self.item { + if let _ = self.interaction.hiddenMedia[item.message.id] { + self.isHidden = true + } else { + self.isHidden = false + } + } else { + self.isHidden = false + } + } +} + +private final class VisualMediaItem { + let message: Message + + init(message: Message) { + self.message = message + } +} + +final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScrollViewDelegate { + private let context: AccountContext + private let peerId: PeerId + private let scrollNode: ASScrollNode + + private var _itemInteraction: VisualMediaItemInteraction? + private var itemInteraction: VisualMediaItemInteraction { + return self._itemInteraction! + } + + private var currentParams: (size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData)? + + private let ready = Promise() + private var didSetReady: Bool = false + var isReady: Signal { + return self.ready.get() + } + + private let listDisposable = MetaDisposable() + private var hiddenMediaDisposable: Disposable? + private var mediaItems: [VisualMediaItem] = [] + private var visibleMediaItems: [UInt32: VisualMediaItemNode] = [:] + + private var numberOfItemsToRequest: Int = 50 + private var currentView: MessageHistoryView? + private var isRequestingView: Bool = false + private var isFirstHistoryView: Bool = true + + init(context: AccountContext, openMessage: @escaping (MessageId) -> Bool, peerId: PeerId) { + self.context = context + self.peerId = peerId + + self.scrollNode = ASScrollNode() + + super.init() + + self._itemInteraction = VisualMediaItemInteraction(openMessage: { id in + openMessage(id) + }) + + self.scrollNode.view.showsVerticalScrollIndicator = false + if #available(iOS 11.0, *) { + self.scrollNode.view.contentInsetAdjustmentBehavior = .never + } + self.scrollNode.view.scrollsToTop = false + self.scrollNode.view.delegate = self + + self.addSubnode(self.scrollNode) + + self.requestHistoryAroundVisiblePosition() + + self.hiddenMediaDisposable = context.sharedContext.mediaManager.galleryHiddenMediaManager.hiddenIds().start(next: { [weak self] ids in + guard let strongSelf = self else { + return + } + var hiddenMedia: [MessageId: [Media]] = [:] + for id in ids { + if case let .chat(accountId, messageId, media) = id, accountId == strongSelf.context.account.id { + hiddenMedia[messageId] = [media] + } + } + strongSelf.itemInteraction.hiddenMedia = hiddenMedia + for (_, itemNode) in strongSelf.visibleMediaItems { + itemNode.updateHiddenMedia() + } + }) + } + + deinit { + self.listDisposable.dispose() + self.hiddenMediaDisposable?.dispose() + } + + private func requestHistoryAroundVisiblePosition() { + if self.isRequestingView { + return + } + self.isRequestingView = true + self.listDisposable.set((self.context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(self.peerId), index: .upperBound, anchorIndex: .upperBound, count: self.numberOfItemsToRequest, fixedCombinedReadStates: nil, tagMask: .photoOrVideo) + |> deliverOnMainQueue).start(next: { [weak self] (view, updateType, _) in + guard let strongSelf = self else { + return + } + strongSelf.updateHistory(view: view, updateType: updateType) + strongSelf.isRequestingView = false + })) + } + + private func updateHistory(view: MessageHistoryView, updateType: ViewUpdateType) { + self.currentView = view + + self.mediaItems.removeAll() + switch updateType { + case .FillHole: + self.requestHistoryAroundVisiblePosition() + default: + for entry in view.entries.reversed() { + self.mediaItems.append(VisualMediaItem(message: entry.message)) + } + + let wasFirstHistoryView = self.isFirstHistoryView + self.isFirstHistoryView = false + + if let (size, isScrollingLockedAtTop, presentationData) = self.currentParams { + self.update(size: size, isScrollingLockedAtTop: isScrollingLockedAtTop, presentationData: presentationData, synchronous: wasFirstHistoryView, transition: .immediate) + if !self.didSetReady { + self.didSetReady = true + self.ready.set(.single(true)) + } + } + } + } + + func scrollToTop() -> Bool { + if self.scrollNode.view.contentOffset.y > 0.0 { + self.scrollNode.view.setContentOffset(CGPoint(), animated: true) + return true + } else { + return false + } + } + + func findLoadedMessage(id: MessageId) -> Message? { + for item in self.mediaItems { + if item.message.id == id { + return item.message + } + } + return nil + } + + func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { + for item in self.mediaItems { + if item.message.id == messageId { + if let itemNode = self.visibleMediaItems[item.message.stableId] { + return itemNode.transitionNode() + } + break + } + } + return nil + } + + func update(size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { + self.currentParams = (size, isScrollingLockedAtTop, presentationData) + + transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: size)) + + let itemSpacing: CGFloat = 1.0 + let itemsInRow: Int = max(3, min(6, Int(size.width / 100.0))) + let itemSize: CGFloat = floor(size.width / CGFloat(itemsInRow)) + + let rowCount: Int = self.mediaItems.count / itemsInRow + (self.mediaItems.count % itemsInRow == 0 ? 0 : 1) + let contentHeight = CGFloat(rowCount + 1) * itemSpacing + CGFloat(rowCount) * itemSize + + self.scrollNode.view.contentSize = CGSize(width: size.width, height: contentHeight) + self.updateVisibleItems(size: size, theme: presentationData.theme, synchronousLoad: synchronous) + + if isScrollingLockedAtTop { + transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(), size: self.scrollNode.bounds.size)) + } + self.scrollNode.view.isScrollEnabled = !isScrollingLockedAtTop + } + + func scrollViewDidScroll(_ scrollView: UIScrollView) { + if let (size, _, presentationData) = self.currentParams { + self.updateVisibleItems(size: size, theme: presentationData.theme, synchronousLoad: false) + + if scrollView.contentOffset.y >= scrollView.contentSize.height - scrollView.bounds.height * 2.0, let currentView = self.currentView, currentView.earlierId != nil { + if !self.isRequestingView { + self.numberOfItemsToRequest += 50 + self.requestHistoryAroundVisiblePosition() + } + } + } + } + + private func updateVisibleItems(size: CGSize, theme: PresentationTheme, synchronousLoad: Bool) { + let itemSpacing: CGFloat = 1.0 + let itemsInRow: Int = max(3, min(6, Int(size.width / 100.0))) + let itemSize: CGFloat = floor(size.width / CGFloat(itemsInRow)) + + let rowCount: Int = self.mediaItems.count / itemsInRow + (self.mediaItems.count % itemsInRow == 0 ? 0 : 1) + + let visibleRect = self.scrollNode.view.bounds + var minVisibleRow = Int(floor((visibleRect.minY - itemSpacing) / (itemSize + itemSpacing))) + minVisibleRow = max(0, minVisibleRow) + var maxVisibleRow = Int(ceil((visibleRect.maxY - itemSpacing) / (itemSize + itemSpacing))) + maxVisibleRow = min(rowCount - 1, maxVisibleRow) + + let minVisibleIndex = minVisibleRow * itemsInRow + let maxVisibleIndex = min(self.mediaItems.count - 1, maxVisibleRow * itemsInRow - 1) + + var validIds = Set() + if minVisibleIndex < maxVisibleIndex { + for i in minVisibleIndex ... maxVisibleIndex { + let stableId = self.mediaItems[i].message.stableId + validIds.insert(stableId) + let rowIndex = i / Int(itemsInRow) + let columnIndex = i % Int(itemsInRow) + let itemOrigin = CGPoint(x: CGFloat(columnIndex) * (itemSize + itemSpacing), y: itemSpacing + CGFloat(rowIndex) * (itemSize + itemSpacing)) + let itemFrame = CGRect(origin: itemOrigin, size: CGSize(width: columnIndex == itemsInRow ? (size.width - itemOrigin.x) : itemSize, height: itemSize)) + let itemNode: VisualMediaItemNode + if let current = self.visibleMediaItems[stableId] { + itemNode = current + } else { + itemNode = VisualMediaItemNode(context: self.context, interaction: self.itemInteraction) + self.visibleMediaItems[stableId] = itemNode + self.scrollNode.addSubnode(itemNode) + } + itemNode.frame = itemFrame + itemNode.update(size: itemFrame.size, item: self.mediaItems[i], theme: theme, synchronousLoad: synchronousLoad) + } + } + var removeKeys: [UInt32] = [] + for (id, _) in self.visibleMediaItems { + if !validIds.contains(id) { + removeKeys.append(id) + } + } + for id in removeKeys { + if let itemNode = self.visibleMediaItems.removeValue(forKey: id) { + itemNode.removeFromSupernode() + } + } + } +} diff --git a/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift b/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift index f6fa41cde3..160fa6cfcc 100644 --- a/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift +++ b/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift @@ -1244,3 +1244,20 @@ public final class SharedAccountContextImpl: SharedAccountContext { } private let defaultChatControllerInteraction = ChatControllerInteraction.default + +private func peerInfoControllerImpl(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode) -> ViewController? { + if let _ = peer as? TelegramGroup { + return groupInfoController(context: context, peerId: peer.id) + } else if let channel = peer as? TelegramChannel { + if case .group = channel.info { + return groupInfoController(context: context, peerId: peer.id) + } else { + return channelInfoController(context: context, peerId: peer.id) + } + } else if peer is TelegramUser { + return PeerInfoScreen(context: context, peerId: peer.id) + } else if peer is TelegramSecretChat { + return userInfoController(context: context, peerId: peer.id, mode: mode) + } + return nil +} From 6758002adef00d3a93d41a21117ffbf8dcec0c2a Mon Sep 17 00:00:00 2001 From: Ali <> Date: Wed, 5 Feb 2020 01:38:55 +0000 Subject: [PATCH 04/30] User info screen design update --- .../Sources/AccountContext.swift | 2 +- .../Sources/CallListController.swift | 2 +- .../ChatTitleActivityContentNode.swift | 9 + .../Sources/ChatTitleActivityNode.swift | 9 + .../Sources/ContactsController.swift | 2 +- .../ContainedViewLayoutTransition.swift | 47 +- .../Display/Display/ImmediateTextNode.swift | 7 + .../Display/Display/NavigationBar.swift | 71 +- .../Display/Display/NavigationBarBadge.swift | 6 +- .../Display/NavigationButtonNode.swift | 64 +- .../NavigationTransitionCoordinator.swift | 77 +- submodules/Display/Display/TextNode.swift | 2 +- .../Sources/InstantPageControllerNode.swift | 2 +- .../Sources/SecureIdAuthController.swift | 2 +- .../Sources/AvatarGalleryController.swift | 40 +- .../Sources/ChannelBlacklistController.swift | 2 +- .../Sources/ChannelMembersController.swift | 4 +- .../ChannelPermissionsController.swift | 2 +- .../Sources/GroupInfoController.swift | 4 +- .../BlockedPeersController.swift | 2 +- .../Recent Sessions/ItemListWebsiteItem.swift | 2 +- ...ectivePrivacySettingsPeersController.swift | 2 +- .../Resources/PresentationResourceKey.swift | 1 + .../PresentationResourcesRootController.swift | 13 + .../ButtonAddMember.imageset/Contents.json | 12 + .../ic_pf_addmember.pdf | Bin 0 -> 4256 bytes .../ButtonCall.imageset/Contents.json | 12 + .../ButtonCall.imageset/ic_pf_call.pdf | Bin 0 -> 4226 bytes .../ButtonMessage.imageset/Contents.json | 10 +- .../ButtonMessage.imageset/ic_pf_message.pdf | Bin 0 -> 3918 bytes .../ButtonMore.imageset/Contents.json | 12 + .../ButtonMore.imageset/ic_pf_more.pdf | Bin 0 -> 3933 bytes .../ButtonMute.imageset/Contents.json | 12 + .../ButtonMute.imageset/ic_pf_mute.pdf | Bin 0 -> 4295 bytes .../ButtonUnmute.imageset/Contents.json | 12 + .../ButtonUnmute.imageset/ic_pf_unmute.pdf | Bin 0 -> 4154 bytes .../TelegramUI/ChatAvatarNavigationNode.swift | 17 +- .../TelegramUI/ChatController.swift | 150 +- .../ChatInterfaceStateNavigationButtons.swift | 5 +- .../ChatRecentActionsControllerNode.swift | 4 +- .../TelegramUI/TelegramUI/ChatTitleView.swift | 65 +- .../TelegramUI/OpenAddContact.swift | 2 +- .../TelegramUI/TelegramUI/OpenUrl.swift | 4 +- .../TelegramUI/PeerInfoScreen.swift | 1275 ++++++++++++++--- .../PeerMediaCollectionController.swift | 2 +- .../TelegramUI/PollResultsController.swift | 2 +- .../TelegramUI/SharedAccountContext.swift | 8 +- .../TelegramUI/SharedWakeupManager.swift | 2 +- .../TelegramUI/TextLinkHandling.swift | 2 +- 49 files changed, 1543 insertions(+), 439 deletions(-) create mode 100644 submodules/TelegramUI/Images.xcassets/Peer Info/ButtonAddMember.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Peer Info/ButtonAddMember.imageset/ic_pf_addmember.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Peer Info/ButtonCall.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Peer Info/ButtonCall.imageset/ic_pf_call.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMessage.imageset/ic_pf_message.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMore.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMore.imageset/ic_pf_more.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMute.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMute.imageset/ic_pf_mute.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Peer Info/ButtonUnmute.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Peer Info/ButtonUnmute.imageset/ic_pf_unmute.pdf diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 620bf03962..966bb8418a 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -440,7 +440,7 @@ public protocol SharedAccountContext: class { func openChatMessage(_ params: OpenChatMessageParams) -> Bool func messageFromPreloadedChatHistoryViewForLocation(id: MessageId, location: ChatHistoryLocationInput, account: Account, chatLocation: ChatLocation, tagMask: MessageTags?) -> Signal<(MessageIndex?, Bool), NoError> func makeOverlayAudioPlayerController(context: AccountContext, peerId: PeerId, type: MediaManagerPlayerType, initialMessageId: MessageId, initialOrder: MusicPlaybackSettingsOrder, parentNavigationController: NavigationController?) -> ViewController & OverlayAudioPlayerController - func makePeerInfoController(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode) -> ViewController? + func makePeerInfoController(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool) -> ViewController? func makeDeviceContactInfoController(context: AccountContext, subject: DeviceContactInfoSubject, completed: (() -> Void)?, cancelled: (() -> Void)?) -> ViewController func makePeersNearbyController(context: AccountContext) -> ViewController func makeComposeController(context: AccountContext) -> ViewController diff --git a/submodules/CallListUI/Sources/CallListController.swift b/submodules/CallListUI/Sources/CallListController.swift index 8de824eba8..1b87df0834 100644 --- a/submodules/CallListUI/Sources/CallListController.swift +++ b/submodules/CallListUI/Sources/CallListController.swift @@ -149,7 +149,7 @@ public final class CallListController: ViewController { let _ = (strongSelf.context.account.postbox.loadedPeerWithId(peerId) |> take(1) |> deliverOnMainQueue).start(next: { peer in - if let strongSelf = self, let controller = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .calls(messages: messages)) { + if let strongSelf = self, let controller = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .calls(messages: messages), avatarInitiallyExpanded: false) { (strongSelf.navigationController as? NavigationController)?.pushViewController(controller) } }) diff --git a/submodules/ChatTitleActivityNode/Sources/ChatTitleActivityContentNode.swift b/submodules/ChatTitleActivityNode/Sources/ChatTitleActivityContentNode.swift index 27c2014190..3578b12212 100644 --- a/submodules/ChatTitleActivityNode/Sources/ChatTitleActivityContentNode.swift +++ b/submodules/ChatTitleActivityNode/Sources/ChatTitleActivityContentNode.swift @@ -95,6 +95,15 @@ public class ChatTitleActivityContentNode: ASDisplayNode { self.textNode.attributedText = text } + func makeCopy() -> ASDisplayNode { + let node = ASDisplayNode() + let textNode = self.textNode.makeCopy() + textNode.frame = self.textNode.frame + node.addSubnode(textNode) + node.frame = self.frame + return node + } + public func animateOut(to: ChatTitleActivityNodeState, style: ChatTitleActivityAnimationStyle, completion: @escaping () -> Void) { self.layer.animateAlpha(from: 1.0, to: 0.0, duration: transitionDuration, removeOnCompletion: false, completion: { _ in completion() diff --git a/submodules/ChatTitleActivityNode/Sources/ChatTitleActivityNode.swift b/submodules/ChatTitleActivityNode/Sources/ChatTitleActivityNode.swift index c345f428bb..2ccf9a29f5 100644 --- a/submodules/ChatTitleActivityNode/Sources/ChatTitleActivityNode.swift +++ b/submodules/ChatTitleActivityNode/Sources/ChatTitleActivityNode.swift @@ -61,6 +61,15 @@ public class ChatTitleActivityNode: ASDisplayNode { super.init() } + public func makeCopy() -> ASDisplayNode { + let node = ASDisplayNode() + if let contentNode = self.contentNode { + node.addSubnode(contentNode.makeCopy()) + } + node.frame = self.frame + return node + } + public func transitionToState(_ state: ChatTitleActivityNodeState, animation: ChatTitleActivityAnimationStyle = .crossfade, completion: @escaping () -> Void = {}) -> Bool { if self.state != state { let currentState = self.state diff --git a/submodules/ContactListUI/Sources/ContactsController.swift b/submodules/ContactListUI/Sources/ContactsController.swift index 7dcfc4b716..087fdfa678 100644 --- a/submodules/ContactListUI/Sources/ContactsController.swift +++ b/submodules/ContactListUI/Sources/ContactsController.swift @@ -530,7 +530,7 @@ public class ContactsController: ViewController { return } if let peer = peer { - if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic) { + if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { (strongSelf.navigationController as? NavigationController)?.pushViewController(infoController) } } else { diff --git a/submodules/Display/Display/ContainedViewLayoutTransition.swift b/submodules/Display/Display/ContainedViewLayoutTransition.swift index 3df59e854a..286e3070e1 100644 --- a/submodules/Display/Display/ContainedViewLayoutTransition.swift +++ b/submodules/Display/Display/ContainedViewLayoutTransition.swift @@ -147,14 +147,17 @@ public extension ContainedViewLayoutTransition { } else { switch self { case .immediate: - node.frame = frame + node.position = frame.center + node.bounds = CGRect(origin: node.bounds.origin, size: frame.size) if let completion = completion { completion(true) } - case .animated: - let previousFrame = node.frame - node.frame = frame - self.animatePositionAdditive(node: node, offset: CGPoint(x: previousFrame.midX - frame.midX, y: previousFrame.midY - frame.midY)) + case let .animated(duration, curve): + let previousBounds = node.bounds + let previousCenter = node.frame.center + node.position = frame.center + node.bounds = CGRect(origin: node.bounds.origin, size: frame.size) + self.animatePositionAdditive(node: node, offset: CGPoint(x: previousCenter.x - frame.midX, y: previousCenter.y - frame.midY)) } } } @@ -655,6 +658,40 @@ public extension ContainedViewLayoutTransition { } } + func updateSublayerTransformScaleAdditive(node: ASDisplayNode, scale: CGFloat, completion: ((Bool) -> Void)? = nil) { + if !node.isNodeLoaded { + node.subnodeTransform = CATransform3DMakeScale(scale, scale, 1.0) + completion?(true) + return + } + let t = node.layer.sublayerTransform + let currentScale = sqrt((t.m11 * t.m11) + (t.m12 * t.m12) + (t.m13 * t.m13)) + if currentScale.isEqual(to: scale) { + if let completion = completion { + completion(true) + } + return + } + + switch self { + case .immediate: + node.layer.sublayerTransform = CATransform3DMakeScale(scale, scale, 1.0) + if let completion = completion { + completion(true) + } + case let .animated(duration, curve): + let t = node.layer.sublayerTransform + let currentScale = sqrt((t.m11 * t.m11) + (t.m12 * t.m12) + (t.m13 * t.m13)) + node.layer.sublayerTransform = CATransform3DMakeScale(scale, scale, 1.0) + node.layer.animate(from: -(scale - currentScale) as NSNumber, to: 0.0 as NSNumber, keyPath: "sublayerTransform.scale", timingFunction: curve.timingFunction, duration: duration, delay: 0.0, mediaTimingFunction: curve.mediaTimingFunction, removeOnCompletion: true, additive: true, completion: { + result in + if let completion = completion { + completion(result) + } + }) + } + } + func updateSublayerTransformScaleAndOffset(node: ASDisplayNode, scale: CGFloat, offset: CGPoint, beginWithCurrentState: Bool = false, completion: ((Bool) -> Void)? = nil) { if !node.isNodeLoaded { node.subnodeTransform = CATransform3DMakeScale(scale, scale, 1.0) diff --git a/submodules/Display/Display/ImmediateTextNode.swift b/submodules/Display/Display/ImmediateTextNode.swift index c8c70cc94f..38488ecda3 100644 --- a/submodules/Display/Display/ImmediateTextNode.swift +++ b/submodules/Display/Display/ImmediateTextNode.swift @@ -34,6 +34,13 @@ public class ImmediateTextNode: TextNode { public var tapAttributeAction: (([NSAttributedString.Key: Any]) -> Void)? public var longTapAttributeAction: (([NSAttributedString.Key: Any]) -> Void)? + public func makeCopy() -> TextNode { + let node = TextNode() + node.cachedLayout = self.cachedLayout + node.frame = self.frame + return node + } + public func updateLayout(_ constrainedSize: CGSize) -> CGSize { let makeLayout = TextNode.asyncLayout(self) let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, lineSpacing: self.lineSpacing, cutout: nil, insets: self.insets, textShadowColor: self.textShadowColor, textStroke: self.textStroke)) diff --git a/submodules/Display/Display/NavigationBar.swift b/submodules/Display/Display/NavigationBar.swift index e26a082850..6fc314f111 100644 --- a/submodules/Display/Display/NavigationBar.swift +++ b/submodules/Display/Display/NavigationBar.swift @@ -111,6 +111,9 @@ open class NavigationBar: ASDisplayNode { public var backPressed: () -> () = { } + public var userInfo: Any? + public var makeCustomTransitionNode: ((NavigationBar) -> CustomNavigationTransitionNode?)? + private var collapsed: Bool { get { return self.frame.size.height.isLess(than: 44.0) @@ -243,6 +246,8 @@ open class NavigationBar: ASDisplayNode { } } + public var customBackButtonText: String? + private var title: String? { didSet { if let title = self.title { @@ -261,7 +266,7 @@ open class NavigationBar: ASDisplayNode { } } - private var titleView: UIView? { + public private(set) var titleView: UIView? { didSet { if let oldValue = oldValue { oldValue.removeFromSuperview() @@ -377,7 +382,9 @@ open class NavigationBar: ASDisplayNode { case let .item(itemValue): self.previousItemListenerKey = itemValue.addSetTitleListener { [weak self] _, _ in if let strongSelf = self, let previousItem = strongSelf.previousItem, case let .item(itemValue) = previousItem { - if let backBarButtonItem = itemValue.backBarButtonItem { + if let customBackButtonText = strongSelf.customBackButtonText { + strongSelf.backButtonNode.updateManualText(customBackButtonText) + } else if let backBarButtonItem = itemValue.backBarButtonItem { strongSelf.backButtonNode.updateManualText(backBarButtonItem.title ?? "") } else { strongSelf.backButtonNode.updateManualText(itemValue.title ?? "") @@ -389,7 +396,9 @@ open class NavigationBar: ASDisplayNode { self.previousItemBackListenerKey = itemValue.addSetBackBarButtonItemListener { [weak self] _, _, _ in if let strongSelf = self, let previousItem = strongSelf.previousItem, case let .item(itemValue) = previousItem { - if let backBarButtonItem = itemValue.backBarButtonItem { + if let customBackButtonText = strongSelf.customBackButtonText { + strongSelf.backButtonNode.updateManualText(customBackButtonText) + } else if let backBarButtonItem = itemValue.backBarButtonItem { strongSelf.backButtonNode.updateManualText(backBarButtonItem.title ?? "") } else { strongSelf.backButtonNode.updateManualText(itemValue.title ?? "") @@ -505,7 +514,9 @@ open class NavigationBar: ASDisplayNode { self.leftButtonNode.removeFromSupernode() var backTitle: String? - if let leftBarButtonItem = item.leftBarButtonItem, leftBarButtonItem.backButtonAppearance { + if let customBackButtonText = self.customBackButtonText { + backTitle = customBackButtonText + } else if let leftBarButtonItem = item.leftBarButtonItem, leftBarButtonItem.backButtonAppearance { backTitle = leftBarButtonItem.title } else if let previousItem = self.previousItem { switch previousItem { @@ -589,12 +600,11 @@ open class NavigationBar: ASDisplayNode { self.updateAccessibilityElements() } - private let backButtonNode: NavigationButtonNode - private let badgeNode: NavigationBarBadgeNode - private let backButtonArrow: ASImageNode - private let leftButtonNode: NavigationButtonNode - private let rightButtonNode: NavigationButtonNode - + public let backButtonNode: NavigationButtonNode + public let badgeNode: NavigationBarBadgeNode + public let backButtonArrow: ASImageNode + public let leftButtonNode: NavigationButtonNode + public let rightButtonNode: NavigationButtonNode private var _transitionState: NavigationBarTransitionState? var transitionState: NavigationBarTransitionState? { @@ -694,6 +704,7 @@ open class NavigationBar: ASDisplayNode { self.leftButtonNode.disabledColor = self.presentationData.theme.disabledButtonColor self.rightButtonNode.color = self.presentationData.theme.buttonColor self.rightButtonNode.disabledColor = self.presentationData.theme.disabledButtonColor + self.rightButtonNode.rippleColor = self.presentationData.theme.primaryTextColor.withAlphaComponent(0.05) self.backButtonArrow.image = backArrowImage(color: self.presentationData.theme.buttonColor) if let title = self.title { self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(17.0), textColor: self.presentationData.theme.primaryTextColor) @@ -768,6 +779,7 @@ open class NavigationBar: ASDisplayNode { self.leftButtonNode.disabledColor = self.presentationData.theme.disabledButtonColor self.rightButtonNode.color = self.presentationData.theme.buttonColor self.rightButtonNode.disabledColor = self.presentationData.theme.disabledButtonColor + self.rightButtonNode.rippleColor = self.presentationData.theme.primaryTextColor.withAlphaComponent(0.05) self.backButtonArrow.image = backArrowImage(color: self.presentationData.theme.buttonColor) if let title = self.title { self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(17.0), textColor: self.presentationData.theme.primaryTextColor) @@ -821,7 +833,7 @@ open class NavigationBar: ASDisplayNode { transition.updateFrame(node: self.stripeNode, frame: CGRect(x: 0.0, y: size.height, width: size.width, height: UIScreenPixel)) - let nominalHeight: CGFloat = self.collapsed ? 32.0 : defaultHeight + let nominalHeight: CGFloat = defaultHeight let contentVerticalOrigin = size.height - nominalHeight - expansionHeight var leftTitleInset: CGFloat = leftInset + 1.0 @@ -958,7 +970,7 @@ open class NavigationBar: ASDisplayNode { if let titleView = self.titleView { let titleSize = CGSize(width: max(1.0, size.width - max(leftTitleInset, rightTitleInset) * 2.0), height: nominalHeight) - let titleFrame = CGRect(origin: CGPoint(x: leftTitleInset, y: contentVerticalOrigin), size: titleSize) + let titleFrame = CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: contentVerticalOrigin + floorToScreenPixels((nominalHeight - titleSize.height) / 2.0)), size: titleSize) titleView.frame = titleFrame if let titleView = titleView as? NavigationBarTitleView { @@ -996,7 +1008,7 @@ open class NavigationBar: ASDisplayNode { } } titleView.alpha = 1.0 - titleView.frame = CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: contentVerticalOrigin + floorToScreenPixels((nominalHeight - titleSize.height) / 2.0)), size: titleSize) + titleView.frame = titleFrame } } } @@ -1017,18 +1029,45 @@ open class NavigationBar: ASDisplayNode { } } - private func makeTransitionBackButtonNode(accentColor: UIColor) -> NavigationButtonNode? { + public func makeTransitionBackButtonNode(accentColor: UIColor) -> NavigationButtonNode? { if self.backButtonNode.supernode != nil { let node = NavigationButtonNode() node.updateManualText(self.backButtonNode.manualText) node.color = accentColor + if let (size, defaultHeight, _, _) = self.validLayout { + node.updateLayout(constrainedSize: CGSize(width: size.width, height: defaultHeight)) + node.frame = self.backButtonNode.frame + } return node } else { return nil } } - private func makeTransitionBackArrowNode(accentColor: UIColor) -> ASDisplayNode? { + public func makeTransitionRightButtonNode(accentColor: UIColor) -> NavigationButtonNode? { + if self.rightButtonNode.supernode != nil { + let node = NavigationButtonNode() + var items: [UIBarButtonItem] = [] + if let item = self.item { + if let rightBarButtonItems = item.rightBarButtonItems, !rightBarButtonItems.isEmpty { + items = rightBarButtonItems + } else if let rightBarButtonItem = item.rightBarButtonItem { + items = [rightBarButtonItem] + } + } + node.updateItems(items) + node.color = accentColor + if let (size, defaultHeight, _, _) = self.validLayout { + node.updateLayout(constrainedSize: CGSize(width: size.width, height: defaultHeight)) + node.frame = self.backButtonNode.frame + } + return node + } else { + return nil + } + } + + public func makeTransitionBackArrowNode(accentColor: UIColor) -> ASDisplayNode? { if self.backButtonArrow.supernode != nil { let node = ASImageNode() node.image = backArrowImage(color: accentColor) @@ -1041,7 +1080,7 @@ open class NavigationBar: ASDisplayNode { } } - private func makeTransitionBadgeNode() -> ASDisplayNode? { + public func makeTransitionBadgeNode() -> ASDisplayNode? { if self.badgeNode.supernode != nil && !self.badgeNode.isHidden { let node = NavigationBarBadgeNode(fillColor: self.presentationData.theme.badgeBackgroundColor, strokeColor: self.presentationData.theme.badgeStrokeColor, textColor: self.presentationData.theme.badgeTextColor) node.text = self.badgeNode.text diff --git a/submodules/Display/Display/NavigationBarBadge.swift b/submodules/Display/Display/NavigationBarBadge.swift index 089b88b0e3..348ff085c5 100644 --- a/submodules/Display/Display/NavigationBarBadge.swift +++ b/submodules/Display/Display/NavigationBarBadge.swift @@ -2,7 +2,7 @@ import Foundation import UIKit import AsyncDisplayKit -final class NavigationBarBadgeNode: ASDisplayNode { +public final class NavigationBarBadgeNode: ASDisplayNode { private var fillColor: UIColor private var strokeColor: UIColor private var textColor: UIColor @@ -19,7 +19,7 @@ final class NavigationBarBadgeNode: ASDisplayNode { } } - init(fillColor: UIColor, strokeColor: UIColor, textColor: UIColor) { + public init(fillColor: UIColor, strokeColor: UIColor, textColor: UIColor) { self.fillColor = fillColor self.strokeColor = strokeColor self.textColor = textColor @@ -48,7 +48,7 @@ final class NavigationBarBadgeNode: ASDisplayNode { self.textNode.attributedText = NSAttributedString(string: self.text, font: self.font, textColor: self.textColor) } - override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { + override public func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { let badgeSize = self.textNode.measure(constrainedSize) let backgroundSize = CGSize(width: max(18.0, badgeSize.width + 10.0 + 1.0), height: 18.0) let backgroundFrame = CGRect(origin: CGPoint(), size: backgroundSize) diff --git a/submodules/Display/Display/NavigationButtonNode.swift b/submodules/Display/Display/NavigationButtonNode.swift index d246df1c1f..29a6d37f0e 100644 --- a/submodules/Display/Display/NavigationButtonNode.swift +++ b/submodules/Display/Display/NavigationButtonNode.swift @@ -53,6 +53,7 @@ private final class NavigationButtonItemNode: ASTextNode { } private var imageNode: ASImageNode? + private let imageRippleNode: ASImageNode private var _image: UIImage? public var image: UIImage? { @@ -61,18 +62,34 @@ private final class NavigationButtonItemNode: ASTextNode { } set(value) { _image = value - if let _ = value { + if let value = value { if self.imageNode == nil { let imageNode = ASImageNode() imageNode.displayWithoutProcessing = true imageNode.displaysAsynchronously = false self.imageNode = imageNode + if value.size == CGSize(width: 30.0, height: 30.0) { + if self.imageRippleNode.supernode == nil { + self.addSubnode(self.imageRippleNode) + self.imageRippleNode.image = generateFilledCircleImage(diameter: 30.0, color: self.rippleColor) + } + } else { + if self.imageRippleNode.supernode != nil { + self.imageRippleNode.image = nil + self.imageRippleNode.removeFromSupernode() + } + } + self.addSubnode(imageNode) } self.imageNode?.image = image } else if let imageNode = self.imageNode { imageNode.removeFromSupernode() self.imageNode = nil + if self.imageRippleNode.supernode != nil { + self.imageRippleNode.image = nil + self.imageRippleNode.removeFromSupernode() + } } self.invalidateCalculatedLayout() @@ -101,6 +118,14 @@ private final class NavigationButtonItemNode: ASTextNode { } } + public var rippleColor: UIColor = UIColor(rgb: 0x000000, alpha: 0.05) { + didSet { + if self.imageRippleNode.image != nil { + self.imageRippleNode.image = generateFilledCircleImage(diameter: 30.0, color: self.rippleColor) + } + } + } + public var disabledColor: UIColor = UIColor(rgb: 0xd0d0d0) { didSet { if let text = self._text { @@ -160,6 +185,11 @@ private final class NavigationButtonItemNode: ASTextNode { } override public init() { + self.imageRippleNode = ASImageNode() + self.imageRippleNode.displaysAsynchronously = false + self.imageRippleNode.displayWithoutProcessing = true + self.imageRippleNode.alpha = 0.0 + super.init() self.isAccessibilityElement = true @@ -183,7 +213,9 @@ private final class NavigationButtonItemNode: ASTextNode { } else if let imageNode = self.imageNode { let nodeSize = imageNode.image?.size ?? CGSize() let size = CGSize(width: max(nodeSize.width, superSize.width), height: max(nodeSize.height, superSize.height)) - imageNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - nodeSize.width) / 2.0) + 5.0, y: floorToScreenPixels((size.height - nodeSize.height) / 2.0)), size: nodeSize) + let imageFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - nodeSize.width) / 2.0) + 5.0, y: floorToScreenPixels((size.height - nodeSize.height) / 2.0)), size: nodeSize) + imageNode.frame = imageFrame + self.imageRippleNode.frame = imageFrame return size } return superSize @@ -242,7 +274,15 @@ private final class NavigationButtonItemNode: ASTextNode { } if shouldChangeHighlight { - self.alpha = !self.isEnabled ? 1.0 : (highlighted ? 0.4 : 1.0) + if let imageNode = self.imageNode { + let previousAlpha = self.imageRippleNode.alpha + self.imageRippleNode.alpha = highlighted ? 1.0 : 0.0 + if !highlighted { + self.imageRippleNode.layer.animateAlpha(from: previousAlpha, to: self.imageRippleNode.alpha, duration: 0.25) + } + } else { + self.alpha = !self.isEnabled ? 1.0 : (highlighted ? 0.4 : 1.0) + } self.highlightChanged(highlighted) } } @@ -263,7 +303,7 @@ private final class NavigationButtonItemNode: ASTextNode { } -final class NavigationButtonNode: ASDisplayNode { +public final class NavigationButtonNode: ASDisplayNode { private var nodes: [NavigationButtonItemNode] = [] public var pressed: (Int) -> () = { _ in } @@ -279,6 +319,16 @@ final class NavigationButtonNode: ASDisplayNode { } } + public var rippleColor: UIColor = UIColor(rgb: 0x000000, alpha: 0.05) { + didSet { + if !self.rippleColor.isEqual(oldValue) { + for node in self.nodes { + node.rippleColor = self.rippleColor + } + } + } + } + public var disabledColor: UIColor = UIColor(rgb: 0xd0d0d0) { didSet { if !self.disabledColor.isEqual(oldValue) { @@ -296,7 +346,7 @@ final class NavigationButtonNode: ASDisplayNode { } } - override init() { + override public init() { super.init() self.isAccessibilityElement = false @@ -313,6 +363,7 @@ final class NavigationButtonNode: ASDisplayNode { } else { node = NavigationButtonItemNode() node.color = self.color + node.rippleColor = self.rippleColor node.highlightChanged = { [weak node, weak self] value in if let strongSelf = self, let node = node { if let index = strongSelf.nodes.firstIndex(where: { $0 === node }) { @@ -353,6 +404,7 @@ final class NavigationButtonNode: ASDisplayNode { } else { node = NavigationButtonItemNode() node.color = self.color + node.rippleColor = self.rippleColor node.highlightChanged = { [weak node, weak self] value in if let strongSelf = self, let node = node { if let index = strongSelf.nodes.firstIndex(where: { $0 === node }) { @@ -385,7 +437,7 @@ final class NavigationButtonNode: ASDisplayNode { } } - func updateLayout(constrainedSize: CGSize) -> CGSize { + public func updateLayout(constrainedSize: CGSize) -> CGSize { var nodeOrigin = CGPoint() var totalSize = CGSize() for node in self.nodes { diff --git a/submodules/Display/Display/NavigationTransitionCoordinator.swift b/submodules/Display/Display/NavigationTransitionCoordinator.swift index a3ea0997c5..f439a5bc64 100644 --- a/submodules/Display/Display/NavigationTransitionCoordinator.swift +++ b/submodules/Display/Display/NavigationTransitionCoordinator.swift @@ -15,12 +15,17 @@ private func generateShadow() -> UIImage? { context.setShadow(offset: CGSize(), blur: 16.0, color: UIColor(white: 0.0, alpha: 0.5).cgColor) context.fill(CGRect(origin: CGPoint(x: size.width, y: 0.0), size: CGSize(width: 16.0, height: 1.0))) }) - //return UIImage(named: "NavigationShadow", in: getAppBundle(), compatibleWith: nil)?.precomposed().resizableImage(withCapInsets: UIEdgeInsets(), resizingMode: .tile) } private let shadowImage = generateShadow() -class NavigationTransitionCoordinator { +public protocol CustomNavigationTransitionNode: ASDisplayNode { + func setup(topNavigationBar: NavigationBar, bottomNavigationBar: NavigationBar) + func update(containerSize: CGSize, fraction: CGFloat, transition: ContainedViewLayoutTransition) + func restore() +} + +final class NavigationTransitionCoordinator { private var _progress: CGFloat = 0.0 var progress: CGFloat { get { @@ -36,6 +41,7 @@ class NavigationTransitionCoordinator { private let bottomNavigationBar: NavigationBar? private let dimNode: ASDisplayNode private let shadowNode: ASImageNode + private let customTransitionNode: CustomNavigationTransitionNode? private let inlineNavigationBarTransition: Bool @@ -58,25 +64,43 @@ class NavigationTransitionCoordinator { self.shadowNode.displayWithoutProcessing = true self.shadowNode.image = shadowImage - if let topNavigationBar = topNavigationBar, let bottomNavigationBar = bottomNavigationBar, !topNavigationBar.isHidden, !bottomNavigationBar.isHidden, topNavigationBar.canTransitionInline, bottomNavigationBar.canTransitionInline, topNavigationBar.item?.leftBarButtonItem == nil { - var topFrame = topNavigationBar.view.convert(topNavigationBar.bounds, to: container.view) - var bottomFrame = bottomNavigationBar.view.convert(bottomNavigationBar.bounds, to: container.view) - topFrame.origin.x = 0.0 - bottomFrame.origin.x = 0.0 - self.inlineNavigationBarTransition = true// topFrame.equalTo(bottomFrame) + if let topNavigationBar = topNavigationBar, let bottomNavigationBar = bottomNavigationBar { + if let customTransitionNode = topNavigationBar.makeCustomTransitionNode?(bottomNavigationBar) { + self.inlineNavigationBarTransition = false + customTransitionNode.setup(topNavigationBar: topNavigationBar, bottomNavigationBar: bottomNavigationBar) + self.customTransitionNode = customTransitionNode + } else if let customTransitionNode = bottomNavigationBar.makeCustomTransitionNode?(topNavigationBar) { + self.inlineNavigationBarTransition = false + customTransitionNode.setup(topNavigationBar: topNavigationBar, bottomNavigationBar: bottomNavigationBar) + self.customTransitionNode = customTransitionNode + } else if !topNavigationBar.isHidden, !bottomNavigationBar.isHidden, topNavigationBar.canTransitionInline, bottomNavigationBar.canTransitionInline, topNavigationBar.item?.leftBarButtonItem == nil { + var topFrame = topNavigationBar.view.convert(topNavigationBar.bounds, to: container.view) + var bottomFrame = bottomNavigationBar.view.convert(bottomNavigationBar.bounds, to: container.view) + topFrame.origin.x = 0.0 + bottomFrame.origin.x = 0.0 + self.inlineNavigationBarTransition = true + self.customTransitionNode = nil + } else { + self.inlineNavigationBarTransition = false + self.customTransitionNode = nil + } } else { self.inlineNavigationBarTransition = false + self.customTransitionNode = nil } switch transition { - case .Push: - self.container.addSubnode(topNode) - case .Pop: - self.container.insertSubnode(bottomNode, belowSubnode: topNode) + case .Push: + self.container.addSubnode(topNode) + case .Pop: + self.container.insertSubnode(bottomNode, belowSubnode: topNode) } self.container.insertSubnode(self.dimNode, belowSubnode: topNode) - self.container.insertSubnode(self.shadowNode, belowSubnode: dimNode) + self.container.insertSubnode(self.shadowNode, belowSubnode: self.dimNode) + if let customTransitionNode = self.customTransitionNode { + self.container.addSubnode(customTransitionNode) + } self.maybeCreateNavigationBarTransition() self.updateProgress(0.0, transition: .immediate, completion: {}) @@ -91,10 +115,10 @@ class NavigationTransitionCoordinator { let position: CGFloat switch self.transition { - case .Push: - position = 1.0 - progress - case .Pop: - position = progress + case .Push: + position = 1.0 - progress + case .Pop: + position = progress } var dimInset: CGFloat = 0.0 @@ -119,10 +143,15 @@ class NavigationTransitionCoordinator { self.updateNavigationBarTransition(transition: transition) + if let customTransitionNode = self.customTransitionNode { + customTransitionNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: containerSize.width, height: containerSize.height)) + customTransitionNode.update(containerSize: containerSize, fraction: position, transition: transition) + } + self.didUpdateProgress?(self.progress, transition, topFrame, bottomFrame) } - func updateNavigationBarTransition(transition: ContainedViewLayoutTransition) { + private func updateNavigationBarTransition(transition: ContainedViewLayoutTransition) { if let topNavigationBar = self.topNavigationBar, let bottomNavigationBar = self.bottomNavigationBar, self.inlineNavigationBarTransition { let position: CGFloat switch self.transition { @@ -178,6 +207,9 @@ class NavigationTransitionCoordinator { strongSelf.dimNode.removeFromSupernode() strongSelf.shadowNode.removeFromSupernode() + strongSelf.customTransitionNode?.restore() + strongSelf.customTransitionNode?.removeFromSupernode() + strongSelf.endNavigationBarTransition() if let currentCompletion = strongSelf.currentCompletion { @@ -195,6 +227,9 @@ class NavigationTransitionCoordinator { self.dimNode.removeFromSupernode() self.shadowNode.removeFromSupernode() + self.customTransitionNode?.restore() + self.customTransitionNode?.removeFromSupernode() + self.endNavigationBarTransition() if let currentCompletion = self.currentCompletion { @@ -209,6 +244,9 @@ class NavigationTransitionCoordinator { strongSelf.dimNode.removeFromSupernode() strongSelf.shadowNode.removeFromSupernode() + strongSelf.customTransitionNode?.restore() + strongSelf.customTransitionNode?.removeFromSupernode() + strongSelf.endNavigationBarTransition() if let currentCompletion = strongSelf.currentCompletion { @@ -228,6 +266,9 @@ class NavigationTransitionCoordinator { self.dimNode.removeFromSupernode() self.shadowNode.removeFromSupernode() + self.customTransitionNode?.restore() + self.customTransitionNode?.removeFromSupernode() + self.endNavigationBarTransition() if let currentCompletion = self.currentCompletion { diff --git a/submodules/Display/Display/TextNode.swift b/submodules/Display/Display/TextNode.swift index 4f8d2a301e..1e7268cdde 100644 --- a/submodules/Display/Display/TextNode.swift +++ b/submodules/Display/Display/TextNode.swift @@ -771,7 +771,7 @@ public final class TextAccessibilityOverlayNode: ASDisplayNode { } public class TextNode: ASDisplayNode { - public private(set) var cachedLayout: TextNodeLayout? + public internal(set) var cachedLayout: TextNodeLayout? override public init() { super.init() diff --git a/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift b/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift index c930ad926b..e15556a53a 100644 --- a/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift @@ -1180,7 +1180,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate { let _ = (strongSelf.context.account.postbox.loadedPeerWithId(peerId) |> deliverOnMainQueue).start(next: { peer in if let strongSelf = self { - if let controller = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic) { + if let controller = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { strongSelf.getNavigationController()?.pushViewController(controller) } } diff --git a/submodules/PassportUI/Sources/SecureIdAuthController.swift b/submodules/PassportUI/Sources/SecureIdAuthController.swift index a21449e859..66ca2894ea 100644 --- a/submodules/PassportUI/Sources/SecureIdAuthController.swift +++ b/submodules/PassportUI/Sources/SecureIdAuthController.swift @@ -330,7 +330,7 @@ public final class SecureIdAuthController: ViewController, StandalonePresentable guard let strongSelf = self else { return } - if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic) { + if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { (strongSelf.navigationController as? NavigationController)?.pushViewController(infoController) } }) diff --git a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift index 30c25a1b5b..0692fc4ad2 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift @@ -61,7 +61,7 @@ public final class AvatarGalleryControllerPresentationArguments { } } -private func initialAvatarGalleryEntries(peer: Peer) -> [AvatarGalleryEntry]{ +private func initialAvatarGalleryEntries(peer: Peer) -> [AvatarGalleryEntry] { var initialEntries: [AvatarGalleryEntry] = [] if !peer.profileImageRepresentations.isEmpty, let peerReference = PeerReference(peer) { initialEntries.append(.topImage(peer.profileImageRepresentations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatar(peer: peerReference, resource: $0.resource)) }), nil)) @@ -70,26 +70,30 @@ private func initialAvatarGalleryEntries(peer: Peer) -> [AvatarGalleryEntry]{ } public func fetchedAvatarGalleryEntries(account: Account, peer: Peer) -> Signal<[AvatarGalleryEntry], NoError> { - return requestPeerPhotos(account: account, peerId: peer.id) - |> map { photos -> [AvatarGalleryEntry] in - var result: [AvatarGalleryEntry] = [] - let initialEntries = initialAvatarGalleryEntries(peer: peer) - if photos.isEmpty { - result = initialEntries - } else { - var index: Int32 = 0 - for photo in photos { - let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photos.count)) - if result.isEmpty, let first = initialEntries.first { - result.append(.image(photo.image.reference, first.representations, peer, photo.date, indexData, photo.messageId)) - } else { - result.append(.image(photo.image.reference, photo.image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.standalone(resource: $0.resource)) }), peer, photo.date, indexData, photo.messageId)) + let initialEntries = initialAvatarGalleryEntries(peer: peer) + return Signal<[AvatarGalleryEntry], NoError>.single(initialEntries) + |> then( + requestPeerPhotos(account: account, peerId: peer.id) + |> map { photos -> [AvatarGalleryEntry] in + var result: [AvatarGalleryEntry] = [] + let initialEntries = initialAvatarGalleryEntries(peer: peer) + if photos.isEmpty { + result = initialEntries + } else { + var index: Int32 = 0 + for photo in photos { + let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photos.count)) + if result.isEmpty, let first = initialEntries.first { + result.append(.image(photo.image.reference, first.representations, peer, photo.date, indexData, photo.messageId)) + } else { + result.append(.image(photo.image.reference, photo.image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.standalone(resource: $0.resource)) }), peer, photo.date, indexData, photo.messageId)) + } + index += 1 } - index += 1 } + return result } - return result - } + ) } public class AvatarGalleryController: ViewController, StandalonePresentableController { diff --git a/submodules/PeerInfoUI/Sources/ChannelBlacklistController.swift b/submodules/PeerInfoUI/Sources/ChannelBlacklistController.swift index 59a2a57ad7..0750e10edc 100644 --- a/submodules/PeerInfoUI/Sources/ChannelBlacklistController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelBlacklistController.swift @@ -366,7 +366,7 @@ public func channelBlacklistController(context: AccountContext, peerId: PeerId) } items.append(ActionSheetButtonItem(title: presentationData.strings.GroupRemoved_ViewUserInfo, action: { [weak actionSheet] in actionSheet?.dismissAnimated() - if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: participant.peer, mode: .generic) { + if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: participant.peer, mode: .generic, avatarInitiallyExpanded: false) { pushControllerImpl?(infoController) } })) diff --git a/submodules/PeerInfoUI/Sources/ChannelMembersController.swift b/submodules/PeerInfoUI/Sources/ChannelMembersController.swift index 85c6dce8d6..dc6dc37ef0 100644 --- a/submodules/PeerInfoUI/Sources/ChannelMembersController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelMembersController.swift @@ -450,7 +450,7 @@ public func channelMembersController(context: AccountContext, peerId: PeerId) -> } })) }, openPeer: { peer in - if let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic) { + if let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { pushControllerImpl?(controller) } }, inviteViaLink: { @@ -502,7 +502,7 @@ public func channelMembersController(context: AccountContext, peerId: PeerId) -> return state.withUpdatedSearchingMembers(false) } }, openPeer: { peer, _ in - if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic) { + if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { pushControllerImpl?(infoController) } }, pushController: { c in diff --git a/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift b/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift index 7615d720b0..05e6b55824 100644 --- a/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift @@ -666,7 +666,7 @@ public func channelPermissionsController(context: AccountContext, peerId origina }), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) }) }, openPeerInfo: { peer in - if let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic) { + if let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { pushControllerImpl?(controller) } }, openKicked: { diff --git a/submodules/PeerInfoUI/Sources/GroupInfoController.swift b/submodules/PeerInfoUI/Sources/GroupInfoController.swift index c5c90866b8..8e3288a0aa 100644 --- a/submodules/PeerInfoUI/Sources/GroupInfoController.swift +++ b/submodules/PeerInfoUI/Sources/GroupInfoController.swift @@ -599,7 +599,7 @@ private enum GroupInfoEntry: ItemListNodeEntry { })) } return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer, presence: presence, text: .presence, label: label == nil ? .none : .text(label!, .standard), editing: editing, revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: enabled, selectable: selectable, sectionId: self.section, action: { - if let infoController = arguments.context.sharedContext.makePeerInfoController(context: arguments.context, peer: peer, mode: .generic), selectable { + if let infoController = arguments.context.sharedContext.makePeerInfoController(context: arguments.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false), selectable { arguments.pushController(infoController) } }, setPeerIdWithRevealedOptions: { peerId, fromPeerId in @@ -2342,7 +2342,7 @@ public func groupInfoController(context: AccountContext, peerId originalPeerId: return state.withUpdatedSearchingMembers(false) } }, openPeer: { peer, _ in - if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic) { + if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { arguments.pushController(infoController) } }, pushController: { c in diff --git a/submodules/SettingsUI/Sources/Privacy and Security/BlockedPeersController.swift b/submodules/SettingsUI/Sources/Privacy and Security/BlockedPeersController.swift index d81c161b2f..b59ad0429d 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/BlockedPeersController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/BlockedPeersController.swift @@ -259,7 +259,7 @@ public func blockedPeersController(context: AccountContext, blockedPeersContext: } })) }, openPeer: { peer in - if let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic) { + if let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { pushControllerImpl?(controller) } }) diff --git a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/ItemListWebsiteItem.swift b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/ItemListWebsiteItem.swift index d889d5aac4..802c7bac02 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/ItemListWebsiteItem.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/ItemListWebsiteItem.swift @@ -112,7 +112,7 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode { private var disabledOverlayNode: ASDisplayNode? private let maskNode: ASImageNode - private let avatarNode: AvatarNode + let avatarNode: AvatarNode private let titleNode: TextNode private let appNode: TextNode private let locationNode: TextNode diff --git a/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsPeersController.swift b/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsPeersController.swift index 627b6c3af5..130a649729 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsPeersController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsPeersController.swift @@ -341,7 +341,7 @@ public func selectivePrivacyPeersController(context: AccountContext, title: Stri return transaction.getPeer(peerId) } |> deliverOnMainQueue).start(next: { peer in - guard let peer = peer, let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic) else { + guard let peer = peer, let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) else { return } pushControllerImpl?(controller) diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift index 0c11f4342c..845a5b7daf 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift @@ -20,6 +20,7 @@ public enum PresentationResourceKey: Int32 { case navigationShareIcon case navigationSearchIcon case navigationCompactSearchIcon + case navigationMoreIcon case navigationAddIcon case navigationPlayerCloseButton diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesRootController.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesRootController.swift index b5982305bb..afc4cc9f0a 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesRootController.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesRootController.swift @@ -71,6 +71,19 @@ public struct PresentationResourcesRootController { }) } + public static func navigationMoreIcon(_ theme: PresentationTheme) -> UIImage? { + return theme.image(PresentationResourceKey.navigationMoreIcon.rawValue, { theme in + return generateImage(CGSize(width: 30.0, height: 30.0), rotatedContext: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + context.setFillColor(theme.rootController.navigationBar.accentTextColor.cgColor) + let dotSize: CGFloat = 4.0 + context.fillEllipse(in: CGRect(origin: CGPoint(x: 6.0, y: floor((size.height - dotSize) / 2.0)), size: CGSize(width: dotSize, height: dotSize))) + context.fillEllipse(in: CGRect(origin: CGPoint(x: 13.0, y: floor((size.height - dotSize) / 2.0)), size: CGSize(width: dotSize, height: dotSize))) + context.fillEllipse(in: CGRect(origin: CGPoint(x: 20.0, y: floor((size.height - dotSize) / 2.0)), size: CGSize(width: dotSize, height: dotSize))) + }) + }) + } + public static func navigationAddIcon(_ theme: PresentationTheme) -> UIImage? { return theme.image(PresentationResourceKey.navigationAddIcon.rawValue, { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat List/AddIcon"), color: theme.rootController.navigationBar.accentTextColor) diff --git a/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonAddMember.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonAddMember.imageset/Contents.json new file mode 100644 index 0000000000..196b36b491 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonAddMember.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_pf_addmember.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonAddMember.imageset/ic_pf_addmember.pdf b/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonAddMember.imageset/ic_pf_addmember.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ad2274b415c52c63ed481651d2e2e4bfeaf11c03 GIT binary patch literal 4256 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 C>`R0I literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMessage.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMessage.imageset/Contents.json index f8f827e40b..c1007d847a 100644 --- a/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMessage.imageset/Contents.json +++ b/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMessage.imageset/Contents.json @@ -2,15 +2,7 @@ "images" : [ { "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" + "filename" : "ic_pf_message.pdf" } ], "info" : { diff --git a/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMessage.imageset/ic_pf_message.pdf b/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMessage.imageset/ic_pf_message.pdf new file mode 100644 index 0000000000000000000000000000000000000000..64fe2bdbd1711e147dd0893688c4c74b5391ef0d GIT binary patch literal 3918 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 C$6J42aC!9M`gGiv*5&>mph?~1B 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 O(Q*)RaZNof$iD#q0JEY1 literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMute.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMute.imageset/Contents.json new file mode 100644 index 0000000000..61322e832d --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMute.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_pf_mute.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMute.imageset/ic_pf_mute.pdf b/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonMute.imageset/ic_pf_mute.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2cabbef68d7202673f0c93e4e5865267e3d7fad4 GIT binary patch literal 4295 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 b|F_Fe0r`>`x%{!wa3z=`SWHaESQq?nA8~9Z literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonUnmute.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonUnmute.imageset/Contents.json new file mode 100644 index 0000000000..29259c8539 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonUnmute.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_pf_unmute.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonUnmute.imageset/ic_pf_unmute.pdf b/submodules/TelegramUI/Images.xcassets/Peer Info/ButtonUnmute.imageset/ic_pf_unmute.pdf new file mode 100644 index 0000000000000000000000000000000000000000..617622f59ab7767dea94e224b007cedf9eaee1bc GIT binary patch literal 4154 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 Void)? + override init() { self.containerNode = ContextControllerSourceNode() self.avatarNode = AvatarNode(font: normalFont) @@ -67,6 +69,9 @@ final class ChatAvatarNavigationNode: ASDisplayNode { } strongSelf.contextAction?(strongSelf.containerNode, gesture) } + + self.containerNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 37.0, height: 37.0)) + self.avatarNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 37.0, height: 37.0)) } override func didLoad() { @@ -74,6 +79,14 @@ final class ChatAvatarNavigationNode: ASDisplayNode { self.view.isOpaque = false (self.view as? ChatAvatarNavigationNodeView)?.targetNode = self (self.view as? ChatAvatarNavigationNodeView)?.chatController = self.chatController + + self.avatarNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.avatarTapGesture(_:)))) + } + + @objc private func avatarTapGesture(_ recognizer: UITapGestureRecognizer) { + if case .ended = recognizer.state { + self.tapped?() + } } override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { @@ -85,7 +98,7 @@ final class ChatAvatarNavigationNode: ASDisplayNode { } func onLayout() { - let bounds = self.bounds + /*let bounds = self.bounds if self.bounds.size.height.isLessThanOrEqualTo(26.0) { if !self.avatarNode.bounds.size.equalTo(bounds.size) { self.avatarNode.font = smallFont @@ -98,6 +111,6 @@ final class ChatAvatarNavigationNode: ASDisplayNode { } self.containerNode.frame = bounds.offsetBy(dx: 10.0, dy: 1.0) self.avatarNode.frame = bounds - } + }*/ } } diff --git a/submodules/TelegramUI/TelegramUI/ChatController.swift b/submodules/TelegramUI/TelegramUI/ChatController.swift index 8e92f38297..ee1d46ff01 100644 --- a/submodules/TelegramUI/TelegramUI/ChatController.swift +++ b/submodules/TelegramUI/TelegramUI/ChatController.swift @@ -363,12 +363,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } super.init(context: context, navigationBarPresentationData: navigationBarPresentationData, mediaAccessoryPanelVisibility: mediaAccessoryPanelVisibility, locationBroadcastPanelSource: locationBroadcastPanelSource) - /*switch mode { - case .overlay: - self.navigationPresentation = .standaloneModal - default: - break - }*/ + self.navigationBar?.customBackButtonText = "" self.blocksBackgroundWhenInOverlay = true @@ -1871,67 +1866,43 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.controllerInteraction = controllerInteraction - self.chatTitleView = ChatTitleView(account: self.context.account, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder) - self.navigationItem.titleView = self.chatTitleView - self.chatTitleView?.pressed = { [weak self] in - if let strongSelf = self { - if strongSelf.chatLocation == .peer(strongSelf.context.account.peerId) { - strongSelf.effectiveNavigationController?.pushViewController(PeerMediaCollectionController(context: strongSelf.context, peerId: strongSelf.context.account.peerId)) - } else { - strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { - return $0.updatedTitlePanelContext { - if let index = $0.firstIndex(where: { - switch $0 { - case .chatInfo: - return true - default: - return false - } - }) { - var updatedContexts = $0 - updatedContexts.remove(at: index) - return updatedContexts - } else { - var updatedContexts = $0 - updatedContexts.append(.chatInfo) - return updatedContexts.sorted() - } - } - }) + var displayNavigationAvatar = false + if case let .peer(peerId) = chatLocation, peerId != context.account.peerId { + displayNavigationAvatar = true + self.navigationBar?.userInfo = PeerInfoNavigationSourceTag(peerId: peerId) + } + self.chatTitleView = ChatTitleView(account: self.context.account, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, displayAvatar: displayNavigationAvatar) + if let avatarNode = self.chatTitleView?.avatarNode { + avatarNode.chatController = self + avatarNode.contextAction = { [weak self] node, gesture in + guard let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer, peer.smallProfileImage != nil else { + return } + let galleryController = AvatarGalleryController(context: strongSelf.context, peer: peer, remoteEntries: nil, replaceRootController: { controller, ready in + }, synchronousLoad: true) + galleryController.setHintWillBePresentedInPreviewingContext(true) + + let items: [ContextMenuItem] = [ + .action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_LinkDialogOpen, icon: { _ in nil }, action: { _, f in + f(.dismissWithoutContent) + self?.navigationButtonAction(.openChatInfo(expandAvatar: false)) + })) + ] + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: galleryController, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture) + strongSelf.presentInGlobalOverlay(contextController) + } + avatarNode.tapped = { [weak self] in + self?.navigationButtonAction(.openChatInfo(expandAvatar: true)) } } - - let chatInfoButtonItem: UIBarButtonItem - switch chatLocation { - case .peer: - let avatarNode = ChatAvatarNavigationNode() - avatarNode.chatController = self - avatarNode.contextAction = { [weak self] node, gesture in - guard let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer, peer.smallProfileImage != nil else { - return - } - let galleryController = AvatarGalleryController(context: strongSelf.context, peer: peer, remoteEntries: nil, replaceRootController: { controller, ready in - }, synchronousLoad: true) - galleryController.setHintWillBePresentedInPreviewingContext(true) - - let items: [ContextMenuItem] = [ - .action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_LinkDialogOpen, icon: { _ in nil }, action: { _, f in - f(.dismissWithoutContent) - self?.navigationButtonAction(.openChatInfo) - })) - ] - let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: galleryController, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture) - strongSelf.presentInGlobalOverlay(contextController) - } - chatInfoButtonItem = UIBarButtonItem(customDisplayNode: avatarNode)! - /*case .group: - chatInfoButtonItem = UIBarButtonItem(customDisplayNode: ChatMultipleAvatarsNavigationNode())!*/ + self.navigationItem.titleView = self.chatTitleView + self.chatTitleView?.pressed = { [weak self] in + self?.navigationButtonAction(.openChatInfo(expandAvatar: false)) } - chatInfoButtonItem.target = self - chatInfoButtonItem.action = #selector(self.rightNavigationButtonAction) - chatInfoButtonItem.accessibilityLabel = self.presentationData.strings.Conversation_Info - self.chatInfoNavigationButton = ChatNavigationButton(action: .openChatInfo, buttonItem: chatInfoButtonItem) + + let buttonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationMoreIcon(presentationInterfaceState.theme), style: .plain, target: self, action: #selector(self.rightNavigationButtonAction)) + //buttonItem.accessibilityLabel = strings.Conversation_Search + chatInfoNavigationButton = ChatNavigationButton(action: .toggleInfoPanel, buttonItem: buttonItem) self.updateChatPresentationInterfaceState(animated: false, interactive: false, { state in if let botStart = botStart, case .interactive = botStart.behavior { @@ -2010,7 +1981,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if let strongSelf = self { if let peer = peerViewMainPeer(peerView) { strongSelf.chatTitleView?.titleContent = .peer(peerView: peerView, onlineMemberCount: onlineMemberCount, isScheduledMessages: isScheduledMessages) - (strongSelf.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.avatarNode.setPeer(context: strongSelf.context, theme: strongSelf.presentationData.theme, peer: peer, overrideImage: peer.isDeleted ? .deletedIcon : .none) + strongSelf.chatTitleView?.avatarNode?.avatarNode.setPeer(context: strongSelf.context, theme: strongSelf.presentationData.theme, peer: peer, overrideImage: peer.isDeleted ? .deletedIcon : .none) (strongSelf.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.contextActionIsEnabled = peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil } @@ -3545,7 +3516,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), subject: nil, keepStack: .always)) } }, openPeerInfo: { [weak self] in - self?.navigationButtonAction(.openChatInfo) + self?.navigationButtonAction(.openChatInfo(expandAvatar: false)) }, togglePeerNotifications: { [weak self] in if let strongSelf = self, case let .peer(peerId) = strongSelf.chatLocation { let _ = togglePeerMuted(account: strongSelf.context.account, peerId: peerId).start() @@ -5319,18 +5290,22 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.chatDisplayNode.dismissInput() self.present(actionSheet, in: .window(.root)) } - case .openChatInfo: + case let .openChatInfo(expandAvatar): switch self.chatLocationInfoData { - case let .peer(peerView): - self.navigationActionDisposable.set((peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { [weak self] peerView in - if let strongSelf = self, let peer = peerView.peers[peerView.peerId], peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil && !strongSelf.presentationInterfaceState.isNotAccessible { - if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic) { + case let .peer(peerView): + self.navigationActionDisposable.set((peerView.get() + |> take(1) + |> deliverOnMainQueue).start(next: { [weak self] peerView in + if let strongSelf = self, let peer = peerView.peers[peerView.peerId], peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil && !strongSelf.presentationInterfaceState.isNotAccessible { + if peer.id == strongSelf.context.account.peerId { + strongSelf.effectiveNavigationController?.pushViewController(PeerMediaCollectionController(context: strongSelf.context, peerId: strongSelf.context.account.peerId)) + } else { + if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: expandAvatar) { strongSelf.effectiveNavigationController?.pushViewController(infoController) } } - })) + } + })) } case .search: self.interfaceInteraction?.beginMessageSearch(.everything, "") @@ -5538,6 +5513,27 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G }) })) } + case .toggleInfoPanel: + self.updateChatPresentationInterfaceState(animated: true, interactive: true, { + return $0.updatedTitlePanelContext { + if let index = $0.firstIndex(where: { + switch $0 { + case .chatInfo: + return true + default: + return false + } + }) { + var updatedContexts = $0 + updatedContexts.remove(at: index) + return updatedContexts + } else { + var updatedContexts = $0 + updatedContexts.append(.chatInfo) + return updatedContexts.sorted() + } + } + }) } } @@ -7025,11 +7021,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.effectiveNavigationController?.pushViewController(controller) } - private func openPeer(peerId: PeerId?, navigation: ChatControllerInteractionNavigateToPeer, fromMessage: Message?) { + private func openPeer(peerId: PeerId?, navigation: ChatControllerInteractionNavigateToPeer, fromMessage: Message?, expandAvatar: Bool = false) { if case let .peer(currentPeerId) = self.chatLocation, peerId == currentPeerId { switch navigation { case .info: - self.navigationButtonAction(.openChatInfo) + self.navigationButtonAction(.openChatInfo(expandAvatar: expandAvatar)) case let .chat(textInputState, _): if let textInputState = textInputState { self.updateChatPresentationInterfaceState(animated: true, interactive: true, { @@ -7061,7 +7057,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } self.navigationActionDisposable.set((peerSignal |> take(1) |> deliverOnMainQueue).start(next: { [weak self] peer in if let strongSelf = self, let peer = peer { - if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic) { + if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: expandAvatar) { strongSelf.effectiveNavigationController?.pushViewController(infoController) } } @@ -7478,7 +7474,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G |> take(1) |> deliverOnMainQueue).start(next: { [weak self] peer in if let strongSelf = self, peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil { - if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic) { + if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { strongSelf.effectiveNavigationController?.pushViewController(infoController) } } diff --git a/submodules/TelegramUI/TelegramUI/ChatInterfaceStateNavigationButtons.swift b/submodules/TelegramUI/TelegramUI/ChatInterfaceStateNavigationButtons.swift index bf3eafbf57..3e0f9c33a0 100644 --- a/submodules/TelegramUI/TelegramUI/ChatInterfaceStateNavigationButtons.swift +++ b/submodules/TelegramUI/TelegramUI/ChatInterfaceStateNavigationButtons.swift @@ -6,13 +6,14 @@ import SyncCore import TelegramPresentationData import AccountContext -enum ChatNavigationButtonAction { - case openChatInfo +enum ChatNavigationButtonAction: Equatable { + case openChatInfo(expandAvatar: Bool) case clearHistory case clearCache case cancelMessageSelection case search case dismiss + case toggleInfoPanel } struct ChatNavigationButton: Equatable { diff --git a/submodules/TelegramUI/TelegramUI/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/TelegramUI/ChatRecentActionsControllerNode.swift index 271975abbe..c3b087ae3b 100644 --- a/submodules/TelegramUI/TelegramUI/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatRecentActionsControllerNode.swift @@ -659,7 +659,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { if peer is TelegramChannel, let navigationController = strongSelf.getNavigationController() { strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id), animated: true)) } else { - if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic) { + if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { strongSelf.pushController(infoController) } } @@ -681,7 +681,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { |> deliverOnMainQueue).start(next: { [weak self] peer in if let strongSelf = self { if let peer = peer { - if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic) { + if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { strongSelf.pushController(infoController) } } diff --git a/submodules/TelegramUI/TelegramUI/ChatTitleView.swift b/submodules/TelegramUI/TelegramUI/ChatTitleView.swift index 04ae85c66b..bc988e496b 100644 --- a/submodules/TelegramUI/TelegramUI/ChatTitleView.swift +++ b/submodules/TelegramUI/TelegramUI/ChatTitleView.swift @@ -15,6 +15,7 @@ import PeerPresenceStatusManager import ChatTitleActivityNode import LocalizedPeerData import PhoneNumberFormat +import ChatTitleActivityNode enum ChatTitleContent { case peer(peerView: PeerView, onlineMemberCount: Int32?, isScheduledMessages: Bool) @@ -92,14 +93,16 @@ final class ChatTitleView: UIView, NavigationBarTitleView { private var nameDisplayOrder: PresentationPersonNameOrder private let contentContainer: ASDisplayNode - private let titleNode: ImmediateTextNode - private let titleLeftIconNode: ASImageNode - private let titleRightIconNode: ASImageNode - private let titleCredibilityIconNode: ASImageNode - private let activityNode: ChatTitleActivityNode + let titleNode: ImmediateTextNode + let titleLeftIconNode: ASImageNode + let titleRightIconNode: ASImageNode + let titleCredibilityIconNode: ASImageNode + let activityNode: ChatTitleActivityNode private let button: HighlightTrackingButtonNode + let avatarNode: ChatAvatarNavigationNode? + private var validLayout: (CGSize, CGRect)? private var titleLeftIcon: ChatTitleIcon = .none @@ -136,7 +139,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { } else { statusNode = ChatTitleNetworkStatusNode(theme: self.theme) self.networkStatusNode = statusNode - self.insertSubview(statusNode.view, belowSubview: self.button.view) + self.insertSubview(statusNode.view, aboveSubview: self.contentContainer.view) } switch self.networkState { case .waitingForNetwork: @@ -451,7 +454,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { } } - init(account: Account, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder) { + init(account: Account, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, displayAvatar: Bool) { self.account = account self.theme = theme self.strings = strings @@ -482,6 +485,11 @@ final class ChatTitleView: UIView, NavigationBarTitleView { self.activityNode = ChatTitleActivityNode() self.button = HighlightTrackingButtonNode() + if displayAvatar { + self.avatarNode = ChatAvatarNavigationNode() + } else { + self.avatarNode = nil + } super.init(frame: CGRect()) @@ -492,12 +500,13 @@ final class ChatTitleView: UIView, NavigationBarTitleView { self.contentContainer.addSubnode(self.titleNode) self.contentContainer.addSubnode(self.activityNode) self.addSubnode(self.button) + self.avatarNode.flatMap(self.contentContainer.addSubnode) self.presenceManager = PeerPresenceStatusManager(update: { [weak self] in self?.updateStatus() }) - self.button.addTarget(self, action: #selector(buttonPressed), forControlEvents: [.touchUpInside]) + self.button.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: [.touchUpInside]) self.button.highligthedChanged = { [weak self] highlighted in if let strongSelf = self { if highlighted { @@ -558,7 +567,6 @@ final class ChatTitleView: UIView, NavigationBarTitleView { let transition: ContainedViewLayoutTransition = .immediate - self.button.frame = clearBounds self.contentContainer.frame = clearBounds var leftIconWidth: CGFloat = 0.0 @@ -592,35 +600,35 @@ final class ChatTitleView: UIView, NavigationBarTitleView { self.titleRightIconNode.removeFromSupernode() } + var leftInset: CGFloat = 12.0 + if let avatarNode = self.avatarNode { + let avatarSize = CGSize(width: 37.0, height: 37.0) + let avatarFrame = CGRect(origin: CGPoint(x: leftInset + 10.0, y: floor((size.height - avatarSize.height) / 2.0)), size: avatarSize) + avatarNode.frame = avatarFrame + leftInset += avatarSize.width + 10.0 + 8.0 + } + + self.button.frame = CGRect(origin: CGPoint(x: leftInset - 20.0, y: 0.0), size: CGSize(width: clearBounds.width - leftInset, height: size.height)) + let titleSideInset: CGFloat = 3.0 if size.height > 40.0 { var titleSize = self.titleNode.updateLayout(CGSize(width: clearBounds.width - leftIconWidth - credibilityIconWidth - rightIconWidth - titleSideInset * 2.0, height: size.height)) titleSize.width += credibilityIconWidth - let activitySize = self.activityNode.updateLayout(clearBounds.size, alignment: .center) + let activitySize = self.activityNode.updateLayout(clearBounds.size, alignment: .left) let titleInfoSpacing: CGFloat = 0.0 var titleFrame: CGRect if activitySize.height.isZero { - titleFrame = CGRect(origin: CGPoint(x: floor((clearBounds.width - titleSize.width) / 2.0), y: floor((size.height - titleSize.height) / 2.0)), size: titleSize) - if titleFrame.size.width < size.width { - titleFrame.origin.x = -clearBounds.minX + floor((size.width - titleFrame.width) / 2.0) - } + titleFrame = CGRect(origin: CGPoint(x: leftInset + leftIconWidth, y: floor((size.height - titleSize.height) / 2.0)), size: titleSize) self.titleNode.frame = titleFrame } else { let combinedHeight = titleSize.height + activitySize.height + titleInfoSpacing - titleFrame = CGRect(origin: CGPoint(x: floor((clearBounds.width - titleSize.width) / 2.0), y: floor((size.height - combinedHeight) / 2.0)), size: titleSize) - if titleFrame.size.width < size.width { - titleFrame.origin.x = -clearBounds.minX + floor((size.width - titleFrame.width) / 2.0) - } - titleFrame.origin.x = max(titleFrame.origin.x, clearBounds.minX + leftIconWidth) + titleFrame = CGRect(origin: CGPoint(x: leftInset + leftIconWidth, y: floor((size.height - combinedHeight) / 2.0)), size: titleSize) self.titleNode.frame = titleFrame - var activityFrame = CGRect(origin: CGPoint(x: floor((clearBounds.width - activitySize.width) / 2.0), y: floor((size.height - combinedHeight) / 2.0) + titleSize.height + titleInfoSpacing), size: activitySize) - if activitySize.width < size.width { - activityFrame.origin.x = -clearBounds.minX + floor((size.width - activityFrame.width) / 2.0) - } + var activityFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((size.height - combinedHeight) / 2.0) + titleSize.height + titleInfoSpacing), size: activitySize) self.activityNode.frame = activityFrame } @@ -662,13 +670,18 @@ final class ChatTitleView: UIView, NavigationBarTitleView { } @objc func buttonPressed() { - if let pressed = self.pressed { - pressed() - } + self.pressed?() } func animateLayoutTransition() { UIView.transition(with: self, duration: 0.25, options: [.transitionCrossDissolve], animations: { }, completion: nil) } + + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + if self.button.frame.contains(point) { + return self.button.view + } + return super.hitTest(point, with: event) + } } diff --git a/submodules/TelegramUI/TelegramUI/OpenAddContact.swift b/submodules/TelegramUI/TelegramUI/OpenAddContact.swift index 964bd20156..98c49ce1ba 100644 --- a/submodules/TelegramUI/TelegramUI/OpenAddContact.swift +++ b/submodules/TelegramUI/TelegramUI/OpenAddContact.swift @@ -18,7 +18,7 @@ func openAddContactImpl(context: AccountContext, firstName: String = "", lastNam let contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: firstName, lastName: lastName, phoneNumbers: [DeviceContactPhoneNumberData(label: label, value: phoneNumber)]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "") present(deviceContactInfoController(context: context, subject: .create(peer: nil, contactData: contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in if let peer = peer { - if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic) { + if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { pushController(infoController) } } else { diff --git a/submodules/TelegramUI/TelegramUI/OpenUrl.swift b/submodules/TelegramUI/TelegramUI/OpenUrl.swift index b7f18394e6..11f7c094e2 100644 --- a/submodules/TelegramUI/TelegramUI/OpenUrl.swift +++ b/submodules/TelegramUI/TelegramUI/OpenUrl.swift @@ -209,7 +209,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur case .info: let _ = (context.account.postbox.loadedPeerWithId(peerId) |> deliverOnMainQueue).start(next: { peer in - if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic) { + if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { context.sharedContext.applicationBindings.dismissNativeController() navigationController?.pushViewController(infoController) } @@ -491,7 +491,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur return transaction.getPeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: idValue)) } |> deliverOnMainQueue).start(next: { peer in - if let peer = peer, let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic) { + if let peer = peer, let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { navigationController?.pushViewController(controller) } }) diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift b/submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift index e1f5116a47..06811f13db 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift @@ -18,6 +18,8 @@ import NotificationMuteSettingsUI import NotificationSoundSelectionUI import OverlayStatusController import ShareController +import PhotoResources +import PeerAvatarGalleryUI private let avatarFont = avatarPlaceholderFont(size: 28.0) @@ -26,6 +28,7 @@ private enum PeerInfoHeaderButtonKey: Hashable { case call case mute case more + case addMember } private enum PeerInfoHeaderButtonIcon { @@ -34,11 +37,13 @@ private enum PeerInfoHeaderButtonIcon { case mute case unmute case more + case addMember } private final class PeerInfoHeaderButtonNode: HighlightableButtonNode { let key: PeerInfoHeaderButtonKey private let action: (PeerInfoHeaderButtonNode) -> Void + let containerNode: ASDisplayNode private let backgroundNode: ASImageNode private let textNode: ImmediateTextNode @@ -49,6 +54,8 @@ private final class PeerInfoHeaderButtonNode: HighlightableButtonNode { self.key = key self.action = action + self.containerNode = ASDisplayNode() + self.backgroundNode = ASImageNode() self.backgroundNode.displaysAsynchronously = false self.backgroundNode.displayWithoutProcessing = true @@ -58,8 +65,9 @@ private final class PeerInfoHeaderButtonNode: HighlightableButtonNode { super.init() - self.addSubnode(self.backgroundNode) - self.addSubnode(self.textNode) + self.addSubnode(self.containerNode) + self.containerNode.addSubnode(self.backgroundNode) + self.containerNode.addSubnode(self.textNode) self.highligthedChanged = { [weak self] highlighted in if let strongSelf = self { @@ -88,20 +96,22 @@ private final class PeerInfoHeaderButtonNode: HighlightableButtonNode { context.clear(CGRect(origin: CGPoint(), size: size)) context.setFillColor(presentationData.theme.list.itemAccentColor.cgColor) context.fillEllipse(in: CGRect(origin: CGPoint(), size: size)) - context.setBlendMode(.copy) - context.setFillColor(UIColor.clear.cgColor) + context.setBlendMode(.normal) + context.setFillColor(presentationData.theme.list.itemCheckColors.foregroundColor.cgColor) let imageName: String switch icon { case .message: - imageName = "Chat/Context Menu/Message" + imageName = "Peer Info/ButtonMessage" case .call: - imageName = "Chat/Context Menu/Call" + imageName = "Peer Info/ButtonCall" case .mute: - imageName = "Chat/Context Menu/Muted" + imageName = "Peer Info/ButtonMute" case .unmute: - imageName = "Chat/Context Menu/Unmute" + imageName = "Peer Info/ButtonUnmute" case .more: - imageName = "Chat/Context Menu/More" + imageName = "Peer Info/ButtonMore" + case .addMember: + imageName = "Peer Info/ButtonAddMember" } if let image = UIImage(bundleImageName: imageName) { let imageRect = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size) @@ -114,8 +124,351 @@ private final class PeerInfoHeaderButtonNode: HighlightableButtonNode { self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(12.0), textColor: presentationData.theme.list.itemAccentColor) let titleSize = self.textNode.updateLayout(CGSize(width: 120.0, height: .greatestFiniteMagnitude)) + transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(), size: size)) transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size)) transition.updateFrameAdditiveToCenter(node: self.textNode, frame: CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: size.height + 6.0), size: titleSize)) + transition.updateAlpha(node: self.textNode, alpha: isExpanded ? 0.0 : 1.0) + } +} + +private final class PeerInfoHeaderNavigationTransition { + let sourceNavigationBar: NavigationBar + let sourceTitleView: ChatTitleView + let sourceTitleFrame: CGRect + let sourceSubtitleFrame: CGRect + let fraction: CGFloat + + init(sourceNavigationBar: NavigationBar, sourceTitleView: ChatTitleView, sourceTitleFrame: CGRect, sourceSubtitleFrame: CGRect, fraction: CGFloat) { + self.sourceNavigationBar = sourceNavigationBar + self.sourceTitleView = sourceTitleView + self.sourceTitleFrame = sourceTitleFrame + self.sourceSubtitleFrame = sourceSubtitleFrame + self.fraction = fraction + } +} + +private enum PeerInfoAvatarListItem: Equatable { + case topImage([ImageRepresentationWithReference]) + case image(TelegramMediaImageReference?, [ImageRepresentationWithReference]) + + var id: WrappedMediaResourceId { + switch self { + case let .topImage(representations): + let representation = largestImageRepresentation(representations.map { $0.representation }) ?? representations[representations.count - 1].representation + return WrappedMediaResourceId(representation.resource.id) + case let .image(_, representations): + let representation = largestImageRepresentation(representations.map { $0.representation }) ?? representations[representations.count - 1].representation + return WrappedMediaResourceId(representation.resource.id) + } + } +} + +private final class PeerInfoAvatarListItemNode: ASDisplayNode { + private let imageNode: TransformImageNode + + let isReady = Promise() + private var didSetReady: Bool = false + + init(context: AccountContext, item: PeerInfoAvatarListItem) { + self.imageNode = TransformImageNode() + + super.init() + + self.addSubnode(self.imageNode) + let representations: [ImageRepresentationWithReference] + switch item { + case let .topImage(topRepresentations): + representations = topRepresentations + case let .image(_, imageRepresentations): + representations = imageRepresentations + } + self.imageNode.setSignal(chatAvatarGalleryPhoto(account: context.account, representations: representations, autoFetchFullSize: true), dispatchOnDisplayLink: false) + + self.imageNode.imageUpdated = { [weak self] _ in + guard let strongSelf = self else { + return + } + if !strongSelf.didSetReady { + strongSelf.didSetReady = true + strongSelf.isReady.set(.single(true)) + } + } + } + + func update(size: CGSize, transition: ContainedViewLayoutTransition) { + let makeLayout = self.imageNode.asyncLayout() + let applyLayout = makeLayout(TransformImageArguments(corners: ImageCorners(), imageSize: size, boundingSize: size, intrinsicInsets: UIEdgeInsets())) + let _ = applyLayout() + transition.updateFrame(node: self.imageNode, frame: CGRect(origin: CGPoint(), size: size)) + } +} + +private final class PeerInfoAvatarListContainerNode: ASDisplayNode { + private let context: AccountContext + + let contentNode: ASDisplayNode + private var items: [PeerInfoAvatarListItem] = [] + private var itemNodes: [WrappedMediaResourceId: PeerInfoAvatarListItemNode] = [:] + private var currentIndex: Int = 0 + private var transitionFraction: CGFloat = 0.0 + + private var validLayout: CGSize? + + private let disposable = MetaDisposable() + private var initializedList = false + + let isReady = Promise() + private var didSetReady = false + + init(context: AccountContext) { + self.context = context + + self.contentNode = ASDisplayNode() + + super.init() + + self.backgroundColor = .black + + self.addSubnode(self.contentNode) + + self.view.disablesInteractiveTransitionGestureRecognizer = true + self.view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))) + } + + deinit { + self.disposable.dispose() + } + + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + return super.hitTest(point, with: event) + } + + @objc private func panGesture(_ recognizer: UIPanGestureRecognizer) { + switch recognizer.state { + case .changed: + let translation = recognizer.translation(in: self.view) + var transitionFraction = translation.x / self.bounds.width + if self.currentIndex <= 0 { + transitionFraction = min(0.0, transitionFraction) + } + if self.currentIndex >= self.items.count - 1 { + transitionFraction = max(0.0, transitionFraction) + } + self.transitionFraction = transitionFraction + if let size = self.validLayout { + self.updateItems(size: size, transition: .animated(duration: 0.3, curve: .spring)) + } + case .cancelled, .ended: + let translation = recognizer.translation(in: self.view) + let velocity = recognizer.velocity(in: self.view) + var directionIsToRight = false + if abs(velocity.x) > 10.0 { + directionIsToRight = velocity.x < 0.0 + } else { + directionIsToRight = translation.x > self.bounds.width / 2.0 + } + var updatedIndex = self.currentIndex + if directionIsToRight { + updatedIndex = min(updatedIndex + 1, self.items.count - 1) + } else { + updatedIndex = max(updatedIndex - 1, 0) + } + self.currentIndex = updatedIndex + self.transitionFraction = 0.0 + if let size = self.validLayout { + self.updateItems(size: size, transition: .animated(duration: 0.3, curve: .spring)) + } + default: + break + } + } + + func update(size: CGSize, peer: Peer?, transition: ContainedViewLayoutTransition) { + self.validLayout = size + if let peer = peer, !self.initializedList { + self.initializedList = true + self.disposable.set((fetchedAvatarGalleryEntries(account: self.context.account, peer: peer) + |> deliverOnMainQueue).start(next: { [weak self] entries in + guard let strongSelf = self else { + return + } + var items: [PeerInfoAvatarListItem] = [] + for entry in entries { + switch entry { + case let .topImage(representations, _): + items.append(.topImage(representations)) + case let .image(reference, representations, _, _, _, _): + items.append(.image(reference, representations)) + } + } + strongSelf.items = items + if let size = strongSelf.validLayout { + strongSelf.updateItems(size: size, transition: .immediate) + } + if items.isEmpty { + if !strongSelf.didSetReady { + strongSelf.didSetReady = true + strongSelf.isReady.set(.single(true)) + } + } + })) + } + self.updateItems(size: size, transition: transition) + } + + private func updateItems(size: CGSize, transition: ContainedViewLayoutTransition) { + var validIds: [WrappedMediaResourceId] = [] + var addedItemNodesForAdditiveTransition: [PeerInfoAvatarListItemNode] = [] + var additiveTransitionOffset: CGFloat = 0.0 + if self.currentIndex >= 0 && self.currentIndex < self.items.count { + for i in max(0, self.currentIndex - 1) ... min(self.currentIndex + 1, self.items.count - 1) { + validIds.append(self.items[i].id) + let itemNode: PeerInfoAvatarListItemNode + var wasAdded = false + if let current = self.itemNodes[self.items[i].id] { + itemNode = current + } else { + wasAdded = true + itemNode = PeerInfoAvatarListItemNode(context: self.context, item: self.items[i]) + self.itemNodes[self.items[i].id] = itemNode + self.contentNode.addSubnode(itemNode) + } + let indexOffset = CGFloat(i - self.currentIndex) + let itemFrame = CGRect(origin: CGPoint(x: indexOffset * size.width + self.transitionFraction * size.width - size.width / 2.0, y: -size.height / 2.0), size: size) + + if wasAdded { + addedItemNodesForAdditiveTransition.append(itemNode) + itemNode.frame = itemFrame + itemNode.update(size: size, transition: .immediate) + } else { + additiveTransitionOffset = itemNode.frame.minX - itemFrame.minX + transition.updateFrame(node: itemNode, frame: itemFrame) + itemNode.update(size: size, transition: transition) + } + } + } + for itemNode in addedItemNodesForAdditiveTransition { + transition.animatePositionAdditive(node: itemNode, offset: CGPoint(x: additiveTransitionOffset, y: 0.0)) + } + var removeIds: [WrappedMediaResourceId] = [] + for (id, _) in self.itemNodes { + if !validIds.contains(id) { + removeIds.append(id) + } + } + for id in removeIds { + if let itemNode = self.itemNodes.removeValue(forKey: id) { + itemNode.removeFromSupernode() + } + } + + if let item = self.items.first, let itemNode = self.itemNodes[item.id] { + if !self.didSetReady { + self.didSetReady = true + self.isReady.set(itemNode.isReady.get()) + } + } + } +} + +private final class PeerInfoAvatarTransformContainerNode: ASDisplayNode { + let context: AccountContext + let avatarNode: AvatarNode + + var tapped: (() -> Void)? + + private var isFirstAvatarLoading = true + + init(context: AccountContext) { + self.context = context + self.avatarNode = AvatarNode(font: avatarFont) + + super.init() + + self.addSubnode(self.avatarNode) + self.avatarNode.frame = CGRect(origin: CGPoint(x: -50.0, y: -50.0), size: CGSize(width: 100.0, height: 100.0)) + + self.avatarNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))) + } + + @objc private func tapGesture(_ recognizer: UITapGestureRecognizer) { + if case .ended = recognizer.state { + self.tapped?() + } + } + + func update(peer: Peer?, theme: PresentationTheme) { + if let peer = peer { + self.avatarNode.setPeer(context: self.context, theme: theme, peer: peer, synchronousLoad: self.isFirstAvatarLoading, displayDimensions: CGSize(width: 100.0, height: 100.0)) + self.isFirstAvatarLoading = false + } + } +} + +private final class PeerInfoAvatarListNode: ASDisplayNode { + let avatarContainerNode: PeerInfoAvatarTransformContainerNode + let listContainerTransformNode: ASDisplayNode + let listContainerNode: PeerInfoAvatarListContainerNode + + let isReady = Promise() + + init(context: AccountContext, readyWhenGalleryLoads: Bool) { + self.avatarContainerNode = PeerInfoAvatarTransformContainerNode(context: context) + self.listContainerTransformNode = ASDisplayNode() + self.listContainerNode = PeerInfoAvatarListContainerNode(context: context) + self.listContainerNode.clipsToBounds = true + self.listContainerNode.isHidden = true + + super.init() + + self.addSubnode(self.avatarContainerNode) + self.listContainerTransformNode.addSubnode(self.listContainerNode) + self.addSubnode(self.listContainerTransformNode) + + let avatarReady = self.avatarContainerNode.avatarNode.ready + |> mapToSignal { _ -> Signal in + return .complete() + } + |> then(.single(true)) + + let galleryReady = self.listContainerNode.isReady.get() + |> filter { $0 } + |> take(1) + + let combinedSignal: Signal + if readyWhenGalleryLoads { + combinedSignal = combineLatest(queue: .mainQueue(), + avatarReady, + galleryReady + ) + |> map { lhs, rhs in + return lhs && rhs + } + } else { + combinedSignal = avatarReady + } + + self.isReady.set(combinedSignal + |> filter { $0 } + |> take(1)) + } + + func update(size: CGSize, isExpanded: Bool, peer: Peer?, theme: PresentationTheme, transition: ContainedViewLayoutTransition) { + self.avatarContainerNode.update(peer: peer, theme: theme) + } + + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + if !self.listContainerNode.isHidden { + if let result = self.listContainerNode.view.hitTest(self.view.convert(point, to: self.listContainerNode.view), with: event) { + return result + } + } else { + if let result = self.avatarContainerNode.avatarNode.view.hitTest(self.view.convert(point, to: self.avatarContainerNode.avatarNode.view), with: event) { + return result + } + } + + return super.hitTest(point, with: event) } } @@ -123,23 +476,37 @@ private final class PeerInfoHeaderNode: ASDisplayNode { private var context: AccountContext private var presentationData: PresentationData? - private let avatarNode: AvatarNode - private let titleNode: ImmediateTextNode - private let subtitleNode: ImmediateTextNode + private(set) var isAvatarExpanded: Bool + + private let avatarListNode: PeerInfoAvatarListNode + let titleNodeContainer: ASDisplayNode + let titleNodeRawContainer: ASDisplayNode + let titleNode: ImmediateTextNode + let subtitleNodeContainer: ASDisplayNode + let subtitleNodeRawContainer: ASDisplayNode + let subtitleNode: ImmediateTextNode private var buttonNodes: [PeerInfoHeaderButtonKey: PeerInfoHeaderButtonNode] = [:] private let backgroundNode: ASDisplayNode - private let separatorNode: ASDisplayNode + let separatorNode: ASDisplayNode var performButtonAction: ((PeerInfoHeaderButtonKey) -> Void)? + var requestAvatarExpansion: (() -> Void)? - init(context: AccountContext) { + var navigationTransition: PeerInfoHeaderNavigationTransition? + + init(context: AccountContext, avatarInitiallyExpanded: Bool) { self.context = context + self.isAvatarExpanded = avatarInitiallyExpanded - self.avatarNode = AvatarNode(font: avatarFont) + self.avatarListNode = PeerInfoAvatarListNode(context: context, readyWhenGalleryLoads: avatarInitiallyExpanded) + self.titleNodeContainer = ASDisplayNode() + self.titleNodeRawContainer = ASDisplayNode() self.titleNode = ImmediateTextNode() self.titleNode.displaysAsynchronously = false + self.subtitleNodeContainer = ASDisplayNode() + self.subtitleNodeRawContainer = ASDisplayNode() self.subtitleNode = ImmediateTextNode() self.subtitleNode.displaysAsynchronously = false @@ -153,18 +520,47 @@ private final class PeerInfoHeaderNode: ASDisplayNode { self.addSubnode(self.backgroundNode) self.addSubnode(self.separatorNode) - self.addSubnode(self.avatarNode) - self.addSubnode(self.titleNode) - self.addSubnode(self.subtitleNode) + self.addSubnode(self.avatarListNode) + self.titleNodeContainer.addSubnode(self.titleNode) + self.addSubnode(self.titleNodeContainer) + self.subtitleNodeContainer.addSubnode(self.subtitleNode) + self.addSubnode(self.subtitleNodeContainer) + + self.avatarListNode.avatarContainerNode.tapped = { [weak self] in + guard let strongSelf = self else { + return + } + if !strongSelf.isAvatarExpanded { + strongSelf.requestAvatarExpansion?() + } + } } - func update(width: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, notificationSettings: TelegramPeerNotificationSettings?, presence: TelegramUserPresence?, transition: ContainedViewLayoutTransition) -> CGFloat { + func update(width: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, contentOffset: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, notificationSettings: TelegramPeerNotificationSettings?, presence: TelegramUserPresence?, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat { self.presentationData = presentationData - self.backgroundNode.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor + var transitionSourceHeight: CGFloat = 0.0 + var transitionFraction: CGFloat = 0.0 + var transitionSourceAvatarFrame = CGRect() + var transitionSourceTitleFrame = CGRect() + var transitionSourceSubtitleFrame = CGRect() + if let navigationTransition = self.navigationTransition, let sourceAvatarNode = navigationTransition.sourceTitleView.avatarNode?.avatarNode { + transitionSourceHeight = navigationTransition.sourceNavigationBar.bounds.height + transitionFraction = navigationTransition.fraction + transitionSourceAvatarFrame = sourceAvatarNode.view.convert(sourceAvatarNode.view.bounds, to: navigationTransition.sourceNavigationBar.view) + transitionSourceTitleFrame = navigationTransition.sourceTitleFrame + transitionSourceSubtitleFrame = navigationTransition.sourceSubtitleFrame + + transition.updateBackgroundColor(node: self.backgroundNode, color: presentationData.theme.list.itemBlocksBackgroundColor.interpolateTo(presentationData.theme.rootController.navigationBar.backgroundColor, fraction: transitionFraction)!) + } else { + self.backgroundNode.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor + + let backgroundTransitionFraction: CGFloat = max(0.0, min(1.0, contentOffset / (212.0))) + transition.updateBackgroundColor(node: self.backgroundNode, color: presentationData.theme.list.itemBlocksBackgroundColor.interpolateTo(presentationData.theme.rootController.navigationBar.backgroundColor, fraction: backgroundTransitionFraction)!) + } + self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor - let avatarSize: CGFloat = 100.0 let defaultButtonSize: CGFloat = 40.0 let defaultMaxButtonSpacing: CGFloat = 40.0 @@ -176,9 +572,7 @@ private final class PeerInfoHeaderNode: ASDisplayNode { buttonKeys.append(.mute) buttonKeys.append(.more) - self.avatarNode.setPeer(context: self.context, theme: presentationData.theme, peer: peer, displayDimensions: CGSize(width: avatarSize, height: avatarSize)) - - self.titleNode.attributedText = NSAttributedString(string: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.medium(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor) + self.titleNode.attributedText = NSAttributedString(string: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.semibold(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor) let presence = presence ?? TelegramUserPresence(status: .none, lastActivity: 0) let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 @@ -193,24 +587,245 @@ private final class PeerInfoHeaderNode: ASDisplayNode { } let textSideInset: CGFloat = 16.0 + let expandedAvatarControlsHeight: CGFloat = 64.0 + let expandedAvatarHeight: CGFloat = width + expandedAvatarControlsHeight - var height: CGFloat = navigationHeight - height += 212.0 - + let avatarSize: CGFloat = 100.0 let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 10.0), size: CGSize(width: avatarSize, height: avatarSize)) - transition.updateFrame(node: self.avatarNode, frame: avatarFrame) + let avatarCenter = CGPoint(x: (1.0 - transitionFraction) * avatarFrame.midX + transitionFraction * transitionSourceAvatarFrame.midX, y: (1.0 - transitionFraction) * avatarFrame.midY + transitionFraction * transitionSourceAvatarFrame.midY) let titleSize = self.titleNode.updateLayout(CGSize(width: width - textSideInset * 2.0, height: .greatestFiniteMagnitude)) let subtitleSize = self.subtitleNode.updateLayout(CGSize(width: width - textSideInset * 2.0, height: .greatestFiniteMagnitude)) - let titleFrame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: avatarFrame.maxY + 10.0), size: titleSize) - let subtitleFrame = CGRect(origin: CGPoint(x: floor((width - subtitleSize.width) / 2.0), y: titleFrame.maxY + 1.0), size: subtitleSize) - transition.updateFrameAdditiveToCenter(node: self.titleNode, frame: titleFrame) - transition.updateFrameAdditiveToCenter(node: self.subtitleNode, frame: subtitleFrame) + let titleFrame: CGRect + let subtitleFrame: CGRect + if self.isAvatarExpanded { + titleFrame = CGRect(origin: CGPoint(x: 16.0, y: expandedAvatarHeight - expandedAvatarControlsHeight + 12.0), size: titleSize) + subtitleFrame = CGRect(origin: CGPoint(x: 16.0, y: titleFrame.maxY - 5.0), size: subtitleSize) + } else { + titleFrame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: avatarFrame.maxY + 10.0), size: titleSize) + subtitleFrame = CGRect(origin: CGPoint(x: floor((width - subtitleSize.width) / 2.0), y: titleFrame.maxY + 1.0), size: subtitleSize) + } - let buttonSpacing: CGFloat = min(defaultMaxButtonSpacing, width - floor(CGFloat(buttonKeys.count) * defaultButtonSize / CGFloat(buttonKeys.count + 1))) + let titleLockOffset: CGFloat = 7.0 + let titleMaxLockOffset: CGFloat = 7.0 + let titleCollapseOffset = titleFrame.midY - statusBarHeight - titleLockOffset + let titleOffset = -min(titleCollapseOffset, contentOffset) + let titleCollapseFraction = max(0.0, min(1.0, contentOffset / titleCollapseOffset)) + + let titleMinScale: CGFloat = 0.7 + let subtitleMinScale: CGFloat = 0.8 + let avatarMinScale: CGFloat = 0.7 + + let apparentTitleLockOffset = (1.0 - titleCollapseFraction) * 0.0 + titleCollapseFraction * titleMaxLockOffset + + let avatarScale: CGFloat + let avatarOffset: CGFloat + if self.navigationTransition != nil { + avatarScale = ((1.0 - transitionFraction) * avatarFrame.width + transitionFraction * transitionSourceAvatarFrame.width) / avatarFrame.width + avatarOffset = 0.0 + } else { + avatarScale = 1.0 * (1.0 - titleCollapseFraction) + avatarMinScale * titleCollapseFraction + avatarOffset = apparentTitleLockOffset + 0.0 * (1.0 - titleCollapseFraction) + 10.0 * titleCollapseFraction + } + let avatarListFrame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: width)) + + if self.isAvatarExpanded { + self.avatarListNode.listContainerNode.isHidden = false + if !transitionSourceAvatarFrame.width.isZero { + transition.updateCornerRadius(node: self.avatarListNode.listContainerNode, cornerRadius: transitionFraction * transitionSourceAvatarFrame.width / 2.0) + } else { + transition.updateCornerRadius(node: self.avatarListNode.listContainerNode, cornerRadius: 0.0) + } + } else if self.avatarListNode.listContainerNode.cornerRadius != 50.0 { + transition.updateCornerRadius(node: self.avatarListNode.listContainerNode, cornerRadius: 50.0, completion: { [weak self] _ in + guard let strongSelf = self else { + return + } + strongSelf.avatarListNode.listContainerNode.isHidden = true + }) + } + + self.avatarListNode.update(size: CGSize(), isExpanded: self.isAvatarExpanded, peer: peer, theme: presentationData.theme, transition: transition) + if additive { + transition.updateSublayerTransformScaleAdditive(node: self.avatarListNode.avatarContainerNode, scale: avatarScale) + } else { + transition.updateSublayerTransformScale(node: self.avatarListNode.avatarContainerNode, scale: avatarScale) + } + let apparentAvatarFrame: CGRect + if self.isAvatarExpanded { + let expandedAvatarCenter = CGPoint(x: width / 2.0, y: width / 2.0 - contentOffset / 2.0) + apparentAvatarFrame = CGRect(origin: CGPoint(x: expandedAvatarCenter.x * (1.0 - transitionFraction) + transitionFraction * avatarCenter.x, y: expandedAvatarCenter.y * (1.0 - transitionFraction) + transitionFraction * avatarCenter.y), size: CGSize()) + } else { + apparentAvatarFrame = CGRect(origin: CGPoint(x: avatarCenter.x - avatarFrame.width / 2.0, y: -contentOffset + avatarOffset + avatarCenter.y - avatarFrame.height / 2.0), size: avatarFrame.size) + } + if case let .animated(duration, curve) = transition, !transitionSourceAvatarFrame.width.isZero { + let previousFrame = self.avatarListNode.frame + self.avatarListNode.frame = CGRect(origin: apparentAvatarFrame.center, size: CGSize()) + let horizontalTransition: ContainedViewLayoutTransition + let verticalTransition: ContainedViewLayoutTransition + if transitionFraction < .ulpOfOne { + horizontalTransition = .animated(duration: duration * 0.85, curve: curve) + verticalTransition = .animated(duration: duration * 1.15, curve: curve) + } else { + horizontalTransition = transition + verticalTransition = .animated(duration: duration * 0.6, curve: curve) + } + horizontalTransition.animatePositionAdditive(node: self.avatarListNode, offset: CGPoint(x: previousFrame.midX - apparentAvatarFrame.midX, y: 0.0)) + verticalTransition.animatePositionAdditive(node: self.avatarListNode, offset: CGPoint(x: 0.0, y: previousFrame.midY - apparentAvatarFrame.midY)) + } else { + transition.updateFrameAdditive(node: self.avatarListNode, frame: CGRect(origin: apparentAvatarFrame.center, size: CGSize())) + } + + let avatarListContainerFrame: CGRect + let avatarListContainerScale: CGFloat + if self.isAvatarExpanded { + if !transitionSourceAvatarFrame.width.isZero { + let neutralAvatarListContainerSize = CGSize(width: width, height: width) + let avatarListContainerSize = CGSize(width: neutralAvatarListContainerSize.width * (1.0 - transitionFraction) + transitionSourceAvatarFrame.width * transitionFraction, height: neutralAvatarListContainerSize.height * (1.0 - transitionFraction) + transitionSourceAvatarFrame.height * transitionFraction) + avatarListContainerFrame = CGRect(origin: CGPoint(x: -avatarListContainerSize.width / 2.0, y: -avatarListContainerSize.height / 2.0), size: avatarListContainerSize) + } else { + avatarListContainerFrame = CGRect(origin: CGPoint(x: -width / 2.0, y: -width / 2.0), size: CGSize(width: width, height: width)) + } + avatarListContainerScale = 1.0 + max(0.0, -contentOffset / avatarListContainerFrame.width) + } else { + avatarListContainerFrame = CGRect(origin: CGPoint(x: -apparentAvatarFrame.width / 2.0, y: -apparentAvatarFrame.height / 2.0), size: apparentAvatarFrame.size) + avatarListContainerScale = avatarScale + } + transition.updateFrame(node: self.avatarListNode.listContainerNode, frame: avatarListContainerFrame) + let innerScale = avatarListContainerFrame.width / width + let innerDelta = (avatarListContainerFrame.width - width) / 2.0 + transition.updateSublayerTransformScale(node: self.avatarListNode.listContainerNode, scale: innerScale) + transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.contentNode, frame: CGRect(origin: CGPoint(x: innerDelta + width / 2.0, y: innerDelta + width / 2.0), size: CGSize())) + + if additive { + transition.updateSublayerTransformScaleAdditive(node: self.avatarListNode.listContainerTransformNode, scale: avatarListContainerScale) + } else { + transition.updateSublayerTransformScale(node: self.avatarListNode.listContainerTransformNode, scale: avatarListContainerScale) + } + + self.avatarListNode.listContainerNode.update(size: CGSize(width: width, height: width), peer: peer, transition: transition) + + let buttonsCollapseStart = titleCollapseOffset + let buttonsCollapseEnd = 212.0 - (navigationHeight - statusBarHeight) + 10.0 + + let buttonsCollapseFraction = max(0.0, contentOffset - buttonsCollapseStart) / (buttonsCollapseEnd - buttonsCollapseStart) + + let rawHeight: CGFloat + let height: CGFloat + if self.isAvatarExpanded { + rawHeight = expandedAvatarHeight + height = max(navigationHeight, rawHeight - contentOffset) + } else { + rawHeight = navigationHeight + 212.0 + height = navigationHeight + max(0.0, 212.0 - contentOffset) + } + + let apparentHeight = (1.0 - transitionFraction) * height + transitionFraction * transitionSourceHeight + + if !titleSize.width.isZero && !titleSize.height.isZero { + if self.navigationTransition != nil { + var neutralTitleScale: CGFloat = 1.0 + var neutralSubtitleScale: CGFloat = 1.0 + if self.isAvatarExpanded { + neutralTitleScale = 0.7 + neutralSubtitleScale = 1.0 + } + + let titleScale = (transitionFraction * transitionSourceTitleFrame.height + (1.0 - transitionFraction) * titleFrame.height * neutralTitleScale) / (titleFrame.height) + let subtitleScale = (transitionFraction * transitionSourceSubtitleFrame.height + (1.0 - transitionFraction) * subtitleFrame.height * neutralSubtitleScale) / (subtitleFrame.height) + + let titleOrigin = CGPoint(x: transitionFraction * transitionSourceTitleFrame.minX + (1.0 - transitionFraction) * titleFrame.minX, y: transitionFraction * transitionSourceTitleFrame.minY + (1.0 - transitionFraction) * titleFrame.minY) + let subtitleOrigin = CGPoint(x: transitionFraction * transitionSourceSubtitleFrame.minX + (1.0 - transitionFraction) * subtitleFrame.minX, y: transitionFraction * transitionSourceSubtitleFrame.minY + (1.0 - transitionFraction) * subtitleFrame.minY) + + let rawTitleFrame = CGRect(origin: titleOrigin, size: titleFrame.size) + self.titleNodeRawContainer.frame = rawTitleFrame + transition.updateFrameAdditiveToCenter(node: self.titleNodeContainer, frame: rawTitleFrame.offsetBy(dx: rawTitleFrame.width * 0.5 * (titleScale - 1.0), dy: titleOffset + rawTitleFrame.height * 0.5 * (titleScale - 1.0))) + transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(), size: titleFrame.size)) + let rawSubtitleFrame = CGRect(origin: subtitleOrigin, size: subtitleFrame.size) + self.subtitleNodeRawContainer.frame = rawSubtitleFrame + transition.updateFrameAdditiveToCenter(node: self.subtitleNodeContainer, frame: rawSubtitleFrame.offsetBy(dx: rawSubtitleFrame.width * 0.5 * (subtitleScale - 1.0), dy: titleOffset + rawSubtitleFrame.height * 0.5 * (subtitleScale - 1.0))) + transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(), size: subtitleFrame.size)) + transition.updateSublayerTransformScale(node: self.titleNodeContainer, scale: titleScale) + transition.updateSublayerTransformScale(node: self.subtitleNodeContainer, scale: subtitleScale) + } else { + let titleScale: CGFloat + let subtitleScale: CGFloat + if self.isAvatarExpanded { + titleScale = 0.7 + subtitleScale = 1.0 + } else { + titleScale = (1.0 - titleCollapseFraction) * 1.0 + titleCollapseFraction * titleMinScale + subtitleScale = (1.0 - titleCollapseFraction) * 1.0 + titleCollapseFraction * subtitleMinScale + } + + let rawTitleFrame = titleFrame + self.titleNodeRawContainer.frame = rawTitleFrame + transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(), size: titleFrame.size)) + let rawSubtitleFrame = subtitleFrame + self.subtitleNodeRawContainer.frame = rawSubtitleFrame + if self.isAvatarExpanded { + transition.updateFrameAdditive(node: self.titleNodeContainer, frame: rawTitleFrame.offsetBy(dx: 0.0, dy: titleOffset + apparentTitleLockOffset).offsetBy(dx: rawTitleFrame.width * 0.5 * (titleScale - 1.0), dy: rawTitleFrame.height * 0.5 * (titleScale - 1.0))) + transition.updateFrameAdditive(node: self.subtitleNodeContainer, frame: rawSubtitleFrame.offsetBy(dx: 0.0, dy: titleOffset).offsetBy(dx: rawSubtitleFrame.width * 0.5 * (subtitleScale - 1.0), dy: rawSubtitleFrame.height * 0.5 * (subtitleScale - 1.0))) + } else { + transition.updateFrameAdditiveToCenter(node: self.titleNodeContainer, frame: rawTitleFrame.offsetBy(dx: 0.0, dy: titleOffset + apparentTitleLockOffset)) + transition.updateFrameAdditiveToCenter(node: self.subtitleNodeContainer, frame: rawSubtitleFrame.offsetBy(dx: 0.0, dy: titleOffset)) + } + transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(), size: subtitleFrame.size)) + transition.updateSublayerTransformScaleAdditive(node: self.titleNodeContainer, scale: titleScale) + transition.updateSublayerTransformScaleAdditive(node: self.subtitleNodeContainer, scale: subtitleScale) + } + } + + let buttonSpacing: CGFloat + if self.isAvatarExpanded { + buttonSpacing = 16.0 + } else { + buttonSpacing = min(defaultMaxButtonSpacing, width - floor(CGFloat(buttonKeys.count) * defaultButtonSize / CGFloat(buttonKeys.count + 1))) + } + + let expandedButtonSize: CGFloat = 32.0 let buttonsWidth = buttonSpacing * CGFloat(buttonKeys.count - 1) + CGFloat(buttonKeys.count) * defaultButtonSize - var buttonRightOrigin = CGPoint(x: floor((width - buttonsWidth) / 2.0) + buttonsWidth, y: height - 74.0) + var buttonRightOrigin: CGPoint + if self.isAvatarExpanded { + buttonRightOrigin = CGPoint(x: width - 16.0, y: apparentHeight - 74.0) + } else { + buttonRightOrigin = CGPoint(x: floor((width - buttonsWidth) / 2.0) + buttonsWidth, y: apparentHeight - 74.0) + } + let buttonsScale: CGFloat + let buttonsAlpha: CGFloat + let apparentButtonSize: CGFloat + let buttonsVerticalOffset: CGFloat + if self.navigationTransition != nil { + if self.isAvatarExpanded { + apparentButtonSize = expandedButtonSize + } else { + apparentButtonSize = defaultButtonSize + } + let neutralButtonsScale = apparentButtonSize / defaultButtonSize + buttonsScale = (1.0 - transitionFraction) * neutralButtonsScale + 0.2 * transitionFraction + buttonsAlpha = 1.0 - transitionFraction + + let neutralButtonsOffset: CGFloat + if self.isAvatarExpanded { + neutralButtonsOffset = 74.0 - 15.0 - defaultButtonSize + (defaultButtonSize - apparentButtonSize) / 2.0 + } else { + neutralButtonsOffset = (1.0 - buttonsScale) * apparentButtonSize + } + + buttonsVerticalOffset = (1.0 - transitionFraction) * neutralButtonsOffset + ((1.0 - buttonsScale) * apparentButtonSize) * transitionFraction + } else { + apparentButtonSize = self.isAvatarExpanded ? expandedButtonSize : defaultButtonSize + if self.isAvatarExpanded { + buttonsScale = apparentButtonSize / defaultButtonSize + buttonsVerticalOffset = 74.0 - 15.0 - defaultButtonSize + (defaultButtonSize - apparentButtonSize) / 2.0 + } else { + buttonsScale = (1.0 - buttonsCollapseFraction) * 1.0 + 0.2 * buttonsCollapseFraction + buttonsVerticalOffset = (1.0 - buttonsScale) * apparentButtonSize + } + buttonsAlpha = 1.0 - buttonsCollapseFraction + } + let buttonsScaledOffset = (defaultButtonSize - apparentButtonSize) / 2.0 for buttonKey in buttonKeys.reversed() { let buttonNode: PeerInfoHeaderButtonNode var wasAdded = false @@ -225,10 +840,15 @@ private final class PeerInfoHeaderNode: ASDisplayNode { self.addSubnode(buttonNode) } - let buttonFrame = CGRect(origin: CGPoint(x: buttonRightOrigin.x - defaultButtonSize, y: buttonRightOrigin.y), size: CGSize(width: defaultButtonSize, height: defaultButtonSize)) - buttonRightOrigin.x -= defaultButtonSize + buttonSpacing + let buttonFrame = CGRect(origin: CGPoint(x: buttonRightOrigin.x - defaultButtonSize + buttonsScaledOffset, y: buttonRightOrigin.y), size: CGSize(width: defaultButtonSize, height: defaultButtonSize)) let buttonTransition: ContainedViewLayoutTransition = wasAdded ? .immediate : transition - buttonTransition.updateFrame(node: buttonNode, frame: buttonFrame) + + let apparentButtonFrame = buttonFrame.offsetBy(dx: 0.0, dy: buttonsVerticalOffset) + if additive { + buttonTransition.updateFrameAdditiveToCenter(node: buttonNode, frame: apparentButtonFrame) + } else { + buttonTransition.updateFrame(node: buttonNode, frame: apparentButtonFrame) + } let buttonText: String let buttonIcon: PeerInfoHeaderButtonIcon switch buttonKey { @@ -249,8 +869,32 @@ private final class PeerInfoHeaderNode: ASDisplayNode { case .more: buttonText = "More" buttonIcon = .more + case .addMember: + buttonText = "Add Member" + buttonIcon = .addMember + } + buttonNode.update(size: buttonFrame.size, text: buttonText, icon: buttonIcon, isExpanded: self.isAvatarExpanded, presentationData: presentationData, transition: buttonTransition) + transition.updateSublayerTransformScaleAdditive(node: buttonNode, scale: buttonsScale) + + transition.updateAlpha(node: buttonNode, alpha: buttonsAlpha) + if self.isAvatarExpanded, case .mute = buttonKey { + if case let .animated(duration, curve) = transition { + ContainedViewLayoutTransition.animated(duration: duration * 0.3, curve: curve).updateAlpha(node: buttonNode.containerNode, alpha: 0.0) + } else { + transition.updateAlpha(node: buttonNode.containerNode, alpha: 0.0) + } + } else { + if case .mute = buttonKey, buttonNode.containerNode.alpha.isZero, additive { + if case let .animated(duration, curve) = transition { + ContainedViewLayoutTransition.animated(duration: duration * 0.3, curve: curve).updateAlpha(node: buttonNode.containerNode, alpha: 1.0) + } else { + transition.updateAlpha(node: buttonNode.containerNode, alpha: 1.0) + } + } else { + transition.updateAlpha(node: buttonNode.containerNode, alpha: 1.0) + } + buttonRightOrigin.x -= apparentButtonSize + buttonSpacing } - buttonNode.update(size: buttonFrame.size, text: buttonText, icon: buttonIcon, isExpanded: false, presentationData: presentationData, transition: buttonTransition) } for key in self.buttonNodes.keys { @@ -262,15 +906,43 @@ private final class PeerInfoHeaderNode: ASDisplayNode { } } - transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -1000.0), size: CGSize(width: width, height: 1000.0 + height))) - transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: height), size: CGSize(width: width, height: UIScreenPixel))) + let backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -2000.0 + apparentHeight), size: CGSize(width: width, height: 2000.0)) + let separatorFrame = CGRect(origin: CGPoint(x: 0.0, y: apparentHeight), size: CGSize(width: width, height: UIScreenPixel)) + if additive { + transition.updateFrameAdditive(node: self.backgroundNode, frame: backgroundFrame) + transition.updateFrameAdditive(node: self.separatorNode, frame: separatorFrame) + } else { + transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame) + transition.updateFrame(node: self.separatorNode, frame: separatorFrame) + } - return height + if self.isAvatarExpanded { + return width + expandedAvatarControlsHeight + } else { + return 212.0 + navigationHeight + } } private func buttonPressed(_ buttonNode: PeerInfoHeaderButtonNode) { self.performButtonAction?(buttonNode.key) } + + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + if !self.backgroundNode.frame.contains(point) { + return nil + } + guard let result = super.hitTest(point, with: event) else { + return nil + } + if result == self.view { + return nil + } + return result + } + + func updateIsAvatarExpanded(_ isAvatarExpanded: Bool) { + self.isAvatarExpanded = isAvatarExpanded + } } protocol PeerInfoPaneNode: ASDisplayNode { @@ -511,7 +1183,7 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { let isReady = Promise() var didSetIsReady = false - private var currentParams: (size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData)? + private var currentParams: (size: CGSize, expansionFraction: CGFloat, presentationData: PresentationData)? private var availablePanes: [PeerInfoPaneKey] = [] private var currentPaneKey: PeerInfoPaneKey? @@ -581,8 +1253,8 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { let disposable = MetaDisposable() strongSelf.candidatePane = (PeerInfoPaneWrapper(key: key, node: paneNode), disposable) - if let (size, isScrollingLockedAtTop, presentationData) = strongSelf.currentParams { - strongSelf.update(size: size, isScrollingLockedAtTop: isScrollingLockedAtTop, presentationData: presentationData, transition: .immediate) + if let (size, expansionFraction, presentationData) = strongSelf.currentParams { + strongSelf.update(size: size, expansionFraction: expansionFraction, presentationData: presentationData, transition: .immediate) } disposable.set((paneNode.isReady @@ -597,8 +1269,8 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { strongSelf.currentPaneKey = candidatePane.key strongSelf.currentPane = candidatePane - if let (size, isScrollingLockedAtTop, presentationData) = strongSelf.currentParams { - strongSelf.update(size: size, isScrollingLockedAtTop: isScrollingLockedAtTop, presentationData: presentationData, transition: .animated(duration: 0.35, curve: .spring)) + if let (size, expansionFraction, presentationData) = strongSelf.currentParams { + strongSelf.update(size: size, expansionFraction: expansionFraction, presentationData: presentationData, transition: .animated(duration: 0.35, curve: .spring)) if let previousPane = previousPane { let directionToRight: Bool @@ -641,10 +1313,10 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { return self.currentPane?.node.transitionNodeForGallery(messageId: messageId, media: media) } - func update(size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) { - self.currentParams = (size, isScrollingLockedAtTop, presentationData) + func update(size: CGSize, expansionFraction: CGFloat, presentationData: PresentationData, transition: ContainedViewLayoutTransition) { + self.currentParams = (size, expansionFraction, presentationData) - transition.updateAlpha(node: self.coveringBackgroundNode, alpha: isScrollingLockedAtTop ? 0.0 : 1.0) + transition.updateAlpha(node: self.coveringBackgroundNode, alpha: expansionFraction) self.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor self.coveringBackgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.backgroundColor @@ -654,7 +1326,7 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { let tabsHeight: CGFloat = 48.0 transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: size.width, height: UIScreenPixel))) - transition.updateFrame(node: self.coveringBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: tabsHeight))) + transition.updateFrame(node: self.coveringBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: size.width, height: tabsHeight + UIScreenPixel))) transition.updateFrame(node: self.tapsSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: tabsHeight - UIScreenPixel), size: CGSize(width: size.width, height: UIScreenPixel))) @@ -714,12 +1386,12 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { let paneTransition: ContainedViewLayoutTransition = paneWasAdded ? .immediate : transition paneTransition.updateFrame(node: currentPane.node, frame: paneFrame) - currentPane.update(size: paneFrame.size, isScrollingLockedAtTop: isScrollingLockedAtTop, presentationData: presentationData, synchronous: paneWasAdded, transition: paneTransition) + currentPane.update(size: paneFrame.size, isScrollingLockedAtTop: expansionFraction < 1.0 - CGFloat.ulpOfOne, presentationData: presentationData, synchronous: paneWasAdded, transition: paneTransition) } if let (candidatePane, _) = self.candidatePane { let paneTransition: ContainedViewLayoutTransition = .immediate paneTransition.updateFrame(node: candidatePane.node, frame: paneFrame) - candidatePane.update(size: paneFrame.size, isScrollingLockedAtTop: isScrollingLockedAtTop, presentationData: presentationData, synchronous: true, transition: paneTransition) + candidatePane.update(size: paneFrame.size, isScrollingLockedAtTop: expansionFraction < 1.0 - CGFloat.ulpOfOne, presentationData: presentationData, synchronous: true, transition: paneTransition) } if !self.didSetIsReady { self.didSetIsReady = true @@ -930,99 +1602,27 @@ private func peerInfoSectionItems(data: PeerInfoScreenData?, presentationData: P return items } -private final class PeerInfoNavigationNode: ASDisplayNode { - private let backgroundNode: ASDisplayNode - private let separatorContainerNode: ASDisplayNode - private let separatorCoveringNode: ASDisplayNode - private let separatorNode: ASDisplayNode - private let titleNode: ImmediateTextNode - - private var currentParams: (PresentationData, Peer?)? - - override init() { - self.backgroundNode = ASDisplayNode() - self.backgroundNode.isLayerBacked = true - - self.separatorContainerNode = ASDisplayNode() - self.separatorContainerNode.isLayerBacked = true - self.separatorContainerNode.clipsToBounds = true - - self.separatorCoveringNode = ASDisplayNode() - self.separatorCoveringNode.isLayerBacked = true - - self.separatorNode = ASDisplayNode() - self.separatorNode.isLayerBacked = true - - self.titleNode = ImmediateTextNode() - - super.init() - - self.addSubnode(self.backgroundNode) - - self.separatorContainerNode.addSubnode(self.separatorNode) - self.separatorContainerNode.addSubnode(self.separatorCoveringNode) - self.addSubnode(self.separatorContainerNode) - - self.addSubnode(self.titleNode) - } - - func update(size: CGSize, statusBarHeight: CGFloat, navigationHeight: CGFloat, offset: CGFloat, paneContainerOffset: CGFloat, presentationData: PresentationData, peer: Peer?, transition: ContainedViewLayoutTransition) { - if let (currentPresentationData, currentPeer) = self.currentParams { - if currentPresentationData !== presentationData || currentPeer !== peer { - if let peer = peer { - self.titleNode.attributedText = NSAttributedString(string: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.semibold(17.0), textColor: presentationData.theme.rootController.navigationBar.primaryTextColor) - } - } - } - - if self.currentParams?.0.theme !== presentationData.theme { - self.backgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.backgroundColor - self.separatorNode.backgroundColor = presentationData.theme.rootController.navigationBar.separatorColor - self.separatorCoveringNode.backgroundColor = presentationData.theme.rootController.navigationBar.backgroundColor - } - - self.currentParams = (presentationData, peer) - - let titleSize = self.titleNode.updateLayout(CGSize(width: size.width - 100.0, height: .greatestFiniteMagnitude)) - let titleFrame = CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: statusBarHeight + floor((navigationHeight - statusBarHeight - titleSize.height) / 2.0)), size: titleSize) - transition.updateFrameAdditiveToCenter(node: self.titleNode, frame: titleFrame) - - transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size)) - transition.updateFrame(node: self.separatorContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: size.height), size: CGSize(width: size.width, height: UIScreenPixel))) - transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: UIScreenPixel))) - transition.updateFrame(node: self.separatorCoveringNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -offset + paneContainerOffset - size.height), size: CGSize(width: size.width, height: 10.0 + UIScreenPixel))) - - let revealOffset: CGFloat = 100.0 - let progress: CGFloat = max(0.0, min(1.0, offset / revealOffset)) - - transition.updateAlpha(node: self.backgroundNode, alpha: progress) - transition.updateAlpha(node: self.separatorNode, alpha: progress) - transition.updateAlpha(node: self.titleNode, alpha: progress) - } -} - private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate { private weak var controller: PeerInfoScreen? private let context: AccountContext private let peerId: PeerId private var presentationData: PresentationData - private let scrollNode: ASScrollNode + let scrollNode: ASScrollNode - private let navigationNode: PeerInfoNavigationNode - private let headerNode: PeerInfoHeaderNode + let headerNode: PeerInfoHeaderNode private let infoSection: PeerInfoScreenItemSectionContainerNode private let paneContainerNode: PeerInfoPaneContainerNode - private var isPaneAreaExpanded: Bool = false private var ignoreScrolling: Bool = false + private var hapticFeedback: HapticFeedback? private var _interaction: PeerInfoInteraction? private var interaction: PeerInfoInteraction { return self._interaction! } - private var validLayout: (ContainerViewLayout, CGFloat)? - private var data: PeerInfoScreenData? + private(set) var validLayout: (ContainerViewLayout, CGFloat)? + private(set) var data: PeerInfoScreenData? private var dataDisposable: Disposable? private let _ready = Promise() @@ -1031,7 +1631,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } private var didSetReady = false - init(controller: PeerInfoScreen, context: AccountContext, peerId: PeerId) { + init(controller: PeerInfoScreen, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool) { self.controller = controller self.context = context self.peerId = peerId @@ -1039,8 +1639,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self.scrollNode = ASScrollNode() - self.navigationNode = PeerInfoNavigationNode() - self.headerNode = PeerInfoHeaderNode(context: context) + self.headerNode = PeerInfoHeaderNode(context: context, avatarInitiallyExpanded: avatarInitiallyExpanded) self.infoSection = PeerInfoScreenItemSectionContainerNode(id: 0) self.paneContainerNode = PeerInfoPaneContainerNode(context: context, peerId: peerId) @@ -1064,11 +1663,9 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self.scrollNode.view.scrollsToTop = false self.scrollNode.view.delegate = self self.addSubnode(self.scrollNode) - self.addSubnode(self.navigationNode) - - self.scrollNode.addSubnode(self.headerNode) self.scrollNode.addSubnode(self.infoSection) self.scrollNode.addSubnode(self.paneContainerNode) + self.addSubnode(self.headerNode) self.paneContainerNode.openMessage = { [weak self] id in return self?.openMessage(id: id) ?? false @@ -1078,6 +1675,20 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self?.performButtonAction(key: key) } + self.headerNode.requestAvatarExpansion = { [weak self] in + guard let strongSelf = self else { + return + } + let transition: ContainedViewLayoutTransition = .animated(duration: 0.35, curve: .spring) + + strongSelf.headerNode.updateIsAvatarExpanded(true) + strongSelf.updateNavigationExpansionPresentation(isExpanded: true, animated: true) + + if let (layout, navigationHeight) = strongSelf.validLayout { + strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: transition, additive: true) + } + } + self.dataDisposable = (peerInfoScreenData(context: context, peerId: peerId) |> deliverOnMainQueue).start(next: { [weak self] data in guard let strongSelf = self else { @@ -1103,13 +1714,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } func scrollToTop() { - if self.isPaneAreaExpanded { - if !self.paneContainerNode.scrollToTop() { - - } - } else { - self.scrollNode.view.setContentOffset(CGPoint(), animated: true) - } + self.scrollNode.view.setContentOffset(CGPoint(), animated: true) } private func openMessage(id: MessageId) -> Bool { @@ -1149,7 +1754,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD switch key { case .message: if let navigationController = controller.navigationController as? NavigationController { - context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(self.peerId))) + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(self.peerId))) } case .call: self.requestCall() @@ -1206,6 +1811,8 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD ActionSheetItemGroup(items: [ActionSheetButtonItem(title: self.presentationData.strings.Common_Cancel, action: { dismissAction() })]) ]) controller.present(actionSheet, in: .window(.root)) + case .addMember: + break } } @@ -1373,47 +1980,62 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }) } - func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition) { + func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition, additive: Bool = false) { self.validLayout = (layout, navigationHeight) self.ignoreScrolling = true - transition.updateFrame(node: self.navigationNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: navigationHeight))) transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: layout.size)) let sectionSpacing: CGFloat = 24.0 var contentHeight: CGFloat = 0.0 - let headerHeight = self.headerNode.update(width: layout.size.width, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, presence: self.data?.presence, transition: transition) - transition.updateFrame(node: self.headerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: headerHeight))) + let headerHeight = self.headerNode.update(width: layout.size.width, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, contentOffset: self.scrollNode.view.contentOffset.y, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, presence: self.data?.presence, transition: transition, additive: additive) + let headerFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: headerHeight)) + if additive { + transition.updateFrameAdditive(node: self.headerNode, frame: headerFrame) + } else { + transition.updateFrame(node: self.headerNode, frame: headerFrame) + } contentHeight += headerHeight contentHeight += sectionSpacing let infoSectionHeight = self.infoSection.update(width: layout.size.width, presentationData: self.presentationData, items: peerInfoSectionItems(data: self.data, presentationData: self.presentationData, interaction: self.interaction), transition: transition) let infoSectionFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: infoSectionHeight)) - transition.updateFrame(node: self.infoSection, frame: infoSectionFrame) + if additive { + transition.updateFrameAdditive(node: self.infoSection, frame: infoSectionFrame) + } else { + transition.updateFrame(node: self.infoSection, frame: infoSectionFrame) + } contentHeight += infoSectionHeight contentHeight += sectionSpacing let paneContainerSize = CGSize(width: layout.size.width, height: layout.size.height - navigationHeight) - self.paneContainerNode.update(size: paneContainerSize, isScrollingLockedAtTop: !self.isPaneAreaExpanded, presentationData: self.presentationData, transition: transition) - transition.updateFrame(node: self.paneContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: paneContainerSize)) - contentHeight += layout.size.height - navigationHeight - - self.scrollNode.view.contentSize = CGSize(width: layout.size.width, height: contentHeight) - - if self.isPaneAreaExpanded { - transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: 0.0, y: contentHeight - self.scrollNode.bounds.height), size: self.scrollNode.bounds.size)) - } else { - let maxOffsetY = max(0.0, contentHeight - floor(self.scrollNode.bounds.height * 1.5)) - if self.scrollNode.view.contentOffset.y > maxOffsetY { - //transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: 0.0, y: maxOffsetY), size: self.scrollNode.bounds.size)) - } + var restoreContentOffset: CGPoint? + if additive { + restoreContentOffset = self.scrollNode.view.contentOffset + } + self.scrollNode.view.contentSize = CGSize(width: layout.size.width, height: contentHeight + paneContainerSize.height) + if let restoreContentOffset = restoreContentOffset { + self.scrollNode.view.contentOffset = restoreContentOffset } + let paneAreaExpansionDistance: CGFloat = 32.0 + var paneAreaExpansionDelta = (contentHeight - navigationHeight) - self.scrollNode.view.contentOffset.y + paneAreaExpansionDelta = max(0.0, min(paneAreaExpansionDelta, paneAreaExpansionDistance)) + let paneAreaExpansionFraction: CGFloat = 1.0 - paneAreaExpansionDelta / paneAreaExpansionDistance + + let paneContainerFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: paneContainerSize) + if additive { + transition.updateFrameAdditive(node: self.paneContainerNode, frame: paneContainerFrame) + } else { + transition.updateFrame(node: self.paneContainerNode, frame: paneContainerFrame) + } + contentHeight += layout.size.height - navigationHeight + self.ignoreScrolling = false - self.updateNavigation(transition: transition) + self.updateNavigation(transition: transition, additive: additive) if !self.didSetReady && self.data != nil { self.didSetReady = true @@ -1421,91 +2043,113 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } } - private func updateNavigation(transition: ContainedViewLayoutTransition) { + private func updateNavigation(transition: ContainedViewLayoutTransition, additive: Bool) { let offsetY = self.scrollNode.view.contentOffset.y - if offsetY <= 1.0 { + if offsetY <= 50.0 { self.scrollNode.view.bounces = true } else { self.scrollNode.view.bounces = false } if let (layout, navigationHeight) = self.validLayout { - self.navigationNode.update(size: CGSize(width: layout.size.width, height: navigationHeight), statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, offset: offsetY, paneContainerOffset: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, transition: transition) + if !additive { + self.headerNode.update(width: layout.size.width, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, contentOffset: offsetY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, presence: self.data?.presence, transition: transition, additive: additive) + } + + let paneAreaExpansionDistance: CGFloat = 32.0 + var paneAreaExpansionDelta = (self.paneContainerNode.frame.minY - navigationHeight) - self.scrollNode.view.contentOffset.y + paneAreaExpansionDelta = max(0.0, min(paneAreaExpansionDelta, paneAreaExpansionDistance)) + let paneAreaExpansionFraction: CGFloat = 1.0 - paneAreaExpansionDelta / paneAreaExpansionDistance + + transition.updateAlpha(node: self.headerNode.separatorNode, alpha: 1.0 - paneAreaExpansionFraction) + + self.paneContainerNode.update(size: self.paneContainerNode.bounds.size, expansionFraction: paneAreaExpansionFraction, presentationData: self.presentationData, transition: transition) } } + private var canUpdateAvatarExpansion = false + + func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { + self.canUpdateAvatarExpansion = true + } + func scrollViewDidScroll(_ scrollView: UIScrollView) { if self.ignoreScrolling { return } - self.updateNavigation(transition: .immediate) + self.updateNavigation(transition: .immediate, additive: false) + + if scrollView.isDragging && scrollView.isTracking { + let offsetY = self.scrollNode.view.contentOffset.y + var shouldBeExpanded: Bool? + if offsetY <= -32.0 { + shouldBeExpanded = true + } else if offsetY >= 4.0 { + shouldBeExpanded = false + } + if let shouldBeExpanded = shouldBeExpanded, self.canUpdateAvatarExpansion, shouldBeExpanded != self.headerNode.isAvatarExpanded { + let transition: ContainedViewLayoutTransition = .animated(duration: 0.35, curve: .spring) + + if self.hapticFeedback == nil { + self.hapticFeedback = HapticFeedback() + } + if shouldBeExpanded { + self.hapticFeedback?.impact() + } else { + self.hapticFeedback?.tap() + } + + self.headerNode.updateIsAvatarExpanded(shouldBeExpanded) + self.updateNavigationExpansionPresentation(isExpanded: shouldBeExpanded, animated: true) + + if let (layout, navigationHeight) = self.validLayout { + self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: transition, additive: true) + } + + if !shouldBeExpanded { + //scrollView.setContentOffset(CGPoint(), animated: true) + } + } + } + } + + private func updateNavigationExpansionPresentation(isExpanded: Bool, animated: Bool) { + if let controller = self.controller { + controller.statusBar.updateStatusBarStyle(isExpanded ? .White : self.presentationData.theme.rootController.statusBarStyle.style, animated: animated) + + let baseNavigationBarPresentationData = NavigationBarPresentationData(presentationData: self.presentationData) + let navigationBarPresentationData = NavigationBarPresentationData( + theme: NavigationBarTheme( + buttonColor: isExpanded ? .white : baseNavigationBarPresentationData.theme.buttonColor, + disabledButtonColor: baseNavigationBarPresentationData.theme.disabledButtonColor, + primaryTextColor: baseNavigationBarPresentationData.theme.primaryTextColor, + backgroundColor: .clear, + separatorColor: .clear, + badgeBackgroundColor: baseNavigationBarPresentationData.theme.badgeBackgroundColor, + badgeStrokeColor: baseNavigationBarPresentationData.theme.badgeStrokeColor, + badgeTextColor: baseNavigationBarPresentationData.theme.badgeTextColor + ), strings: baseNavigationBarPresentationData.strings) + + if let navigationBar = controller.navigationBar { + if animated { + UIView.transition(with: navigationBar.view, duration: 0.3, options: [.transitionCrossDissolve], animations: { + }, completion: nil) + } + navigationBar.updatePresentationData(navigationBarPresentationData) + } + } } func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { guard let (_, navigationHeight) = self.validLayout else { return } - let snapDurationFactor = max(0.5, min(1.5, abs(velocity.y) * 0.8)) - - var snapToOffset: CGFloat? - let offset = targetContentOffset.pointee.y - - let headerMaxOffset = self.headerNode.bounds.height - navigationHeight - let collapsedPanesOffset = max(0.0, scrollView.contentSize.height - floor(scrollNode.bounds.height * 1.5)) - let expandedPanesOffset = scrollView.contentSize.height - self.scrollNode.bounds.height - - if offset > collapsedPanesOffset { - if velocity.y < 0.0 { - var targetOffset = collapsedPanesOffset - if targetOffset < headerMaxOffset { - targetOffset = 0.0 - } - snapToOffset = targetOffset + if targetContentOffset.pointee.y < 212.0 { + if targetContentOffset.pointee.y < 212.0 / 2.0 { + targetContentOffset.pointee.y = 0.0 } else { - snapToOffset = expandedPanesOffset - } - } else if offset < headerMaxOffset && offset > 0.0 { - let directionIsDown: Bool - if abs(velocity.y) > 0.2 { - directionIsDown = velocity.y >= 0.0 - } else { - directionIsDown = offset >= headerMaxOffset / 2.0 - } - - if directionIsDown { - snapToOffset = headerMaxOffset - } else { - snapToOffset = 0.0 - } - } else if self.isPaneAreaExpanded && offset < expandedPanesOffset { - let directionIsDown: Bool - if abs(velocity.y) > 0.2 { - directionIsDown = velocity.y >= 0.0 - } else { - directionIsDown = offset >= headerMaxOffset / 2.0 - } - - if directionIsDown { - snapToOffset = headerMaxOffset - } else { - snapToOffset = 0.0 - } - } - - if let snapToOffset = snapToOffset { - targetContentOffset.pointee = scrollView.contentOffset - DispatchQueue.main.async { - let isPaneAreaExpanded = abs(snapToOffset - expandedPanesOffset) < CGFloat.ulpOfOne ? true : false - self.isPaneAreaExpanded = isPaneAreaExpanded - let currentOffset = scrollView.contentOffset - let transition: ContainedViewLayoutTransition = .animated(duration: 0.3 * Double(1.0 / snapDurationFactor), curve: .spring) - self.ignoreScrolling = true - transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: 0.0, y: snapToOffset), size: self.scrollNode.bounds.size)) - self.ignoreScrolling = false - if let (layout, navigationHeight) = self.validLayout { - self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: transition) - } + targetContentOffset.pointee.y = 212.0 } } } @@ -1541,6 +2185,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD public final class PeerInfoScreen: ViewController { private let context: AccountContext private let peerId: PeerId + private let avatarInitiallyExpanded: Bool private var presentationData: PresentationData @@ -1553,16 +2198,17 @@ public final class PeerInfoScreen: ViewController { return self._ready } - public init(context: AccountContext, peerId: PeerId) { + public init(context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool = false) { self.context = context self.peerId = peerId + self.avatarInitiallyExpanded = avatarInitiallyExpanded self.presentationData = context.sharedContext.currentPresentationData.with { $0 } let baseNavigationBarPresentationData = NavigationBarPresentationData(presentationData: self.presentationData) super.init(navigationBarPresentationData: NavigationBarPresentationData( theme: NavigationBarTheme( - buttonColor: baseNavigationBarPresentationData.theme.buttonColor, + buttonColor: avatarInitiallyExpanded ? .white : baseNavigationBarPresentationData.theme.buttonColor, disabledButtonColor: baseNavigationBarPresentationData.theme.disabledButtonColor, primaryTextColor: baseNavigationBarPresentationData.theme.primaryTextColor, backgroundColor: .clear, @@ -1571,8 +2217,20 @@ public final class PeerInfoScreen: ViewController { badgeStrokeColor: baseNavigationBarPresentationData.theme.badgeStrokeColor, badgeTextColor: baseNavigationBarPresentationData.theme.badgeTextColor ), strings: baseNavigationBarPresentationData.strings)) + self.navigationBar?.makeCustomTransitionNode = { [weak self] other in + guard let strongSelf = self else { + return nil + } + if strongSelf.controllerNode.scrollNode.view.contentOffset.y > .ulpOfOne { + return nil + } + if let tag = other.userInfo as? PeerInfoNavigationSourceTag, tag.peerId == peerId { + return PeerInfoNavigationTransitionNode(screenNode: strongSelf.controllerNode, presentationData: strongSelf.presentationData, headerNode: strongSelf.controllerNode.headerNode) + } + return nil + } - self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style + self.statusBar.statusBarStyle = avatarInitiallyExpanded ? .White : self.presentationData.theme.rootController.statusBarStyle.style self.scrollToTop = { [weak self] in self?.controllerNode.scrollToTop() @@ -1584,7 +2242,7 @@ public final class PeerInfoScreen: ViewController { } override public func loadDisplayNode() { - self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId) + self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded) self._ready.set(self.controllerNode.ready.get()) @@ -1616,3 +2274,162 @@ private func getUserPeer(postbox: Postbox, peerId: PeerId) -> Signal<(Peer?, Cac return (resultPeer, resultPeer.flatMap({ transaction.getPeerCachedData(peerId: $0.id) })) } } + +final class PeerInfoNavigationSourceTag { + let peerId: PeerId + + init(peerId: PeerId) { + self.peerId = peerId + } +} + +private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavigationTransitionNode { + private let screenNode: PeerInfoScreenNode + private let presentationData: PresentationData + + private var topNavigationBar: NavigationBar? + private var bottomNavigationBar: NavigationBar? + + private let headerNode: PeerInfoHeaderNode + + private var previousBackButtonArrow: ASDisplayNode? + private var currentBackButtonArrow: ASDisplayNode? + private var previousBackButtonBadge: ASDisplayNode? + private var previousRightButton: ASDisplayNode? + private var currentBackButton: ASDisplayNode? + + private var previousTitleNode: (ASDisplayNode, TextNode)? + private var previousStatusNode: (ASDisplayNode, ASDisplayNode)? + + private var didSetup: Bool = false + + init(screenNode: PeerInfoScreenNode, presentationData: PresentationData, headerNode: PeerInfoHeaderNode) { + self.screenNode = screenNode + self.presentationData = presentationData + self.headerNode = headerNode + + super.init() + + self.addSubnode(headerNode) + } + + func setup(topNavigationBar: NavigationBar, bottomNavigationBar: NavigationBar) { + self.topNavigationBar = topNavigationBar + self.bottomNavigationBar = bottomNavigationBar + + topNavigationBar.isHidden = true + bottomNavigationBar.isHidden = true + + if let previousBackButtonArrow = bottomNavigationBar.makeTransitionBackArrowNode(accentColor: self.presentationData.theme.rootController.navigationBar.accentTextColor) { + self.previousBackButtonArrow = previousBackButtonArrow + self.addSubnode(previousBackButtonArrow) + } + if self.screenNode.headerNode.isAvatarExpanded, let currentBackButtonArrow = topNavigationBar.makeTransitionBackArrowNode(accentColor: self.screenNode.headerNode.isAvatarExpanded ? .white : self.presentationData.theme.rootController.navigationBar.accentTextColor) { + self.currentBackButtonArrow = currentBackButtonArrow + self.addSubnode(currentBackButtonArrow) + } + if let previousBackButtonBadge = bottomNavigationBar.makeTransitionBadgeNode() { + self.previousBackButtonBadge = previousBackButtonBadge + self.addSubnode(previousBackButtonBadge) + } + if let previousRightButton = bottomNavigationBar.makeTransitionRightButtonNode(accentColor: self.presentationData.theme.rootController.navigationBar.accentTextColor) { + self.previousRightButton = previousRightButton + self.addSubnode(previousRightButton) + } + if let currentBackButton = topNavigationBar.makeTransitionBackButtonNode(accentColor: self.screenNode.headerNode.isAvatarExpanded ? .white : self.presentationData.theme.rootController.navigationBar.accentTextColor) { + self.currentBackButton = currentBackButton + self.addSubnode(currentBackButton) + } + if let previousTitleView = bottomNavigationBar.titleView as? ChatTitleView { + let previousTitleNode = previousTitleView.titleNode.makeCopy() + let previousTitleContainerNode = ASDisplayNode() + previousTitleContainerNode.addSubnode(previousTitleNode) + self.previousTitleNode = (previousTitleContainerNode, previousTitleNode) + self.addSubnode(previousTitleContainerNode) + + let previousStatusNode = previousTitleView.activityNode.makeCopy() + let previousStatusContainerNode = ASDisplayNode() + previousStatusContainerNode.addSubnode(previousStatusNode) + self.previousStatusNode = (previousStatusContainerNode, previousStatusNode) + self.addSubnode(previousStatusContainerNode) + } + } + + func update(containerSize: CGSize, fraction: CGFloat, transition: ContainedViewLayoutTransition) { + guard let topNavigationBar = self.topNavigationBar, let bottomNavigationBar = self.bottomNavigationBar else { + return + } + + if let previousBackButtonArrow = self.previousBackButtonArrow { + let previousBackButtonArrowFrame = bottomNavigationBar.backButtonArrow.view.convert(bottomNavigationBar.backButtonArrow.view.bounds, to: bottomNavigationBar.view) + previousBackButtonArrow.frame = previousBackButtonArrowFrame + } + + if let currentBackButtonArrow = self.currentBackButtonArrow { + let currentBackButtonArrowFrame = topNavigationBar.backButtonArrow.view.convert(topNavigationBar.backButtonArrow.view.bounds, to: topNavigationBar.view) + currentBackButtonArrow.frame = currentBackButtonArrowFrame + + transition.updateAlpha(node: currentBackButtonArrow, alpha: 1.0 - fraction) + if let previousBackButtonArrow = self.previousBackButtonArrow { + transition.updateAlpha(node: previousBackButtonArrow, alpha: fraction) + } + } + + if let previousBackButtonBadge = self.previousBackButtonBadge { + let previousBackButtonBadgeFrame = bottomNavigationBar.badgeNode.view.convert(bottomNavigationBar.badgeNode.view.bounds, to: bottomNavigationBar.view) + previousBackButtonBadge.frame = previousBackButtonBadgeFrame + + transition.updateAlpha(node: previousBackButtonBadge, alpha: fraction) + } + + if let previousRightButton = self.previousRightButton { + let previousRightButtonFrame = bottomNavigationBar.rightButtonNode.view.convert(bottomNavigationBar.rightButtonNode.view.bounds, to: bottomNavigationBar.view) + previousRightButton.frame = previousRightButtonFrame + transition.updateAlpha(node: previousRightButton, alpha: fraction) + } + + if let currentBackButton = self.currentBackButton { + let currentBackButtonFrame = topNavigationBar.backButtonNode.view.convert(topNavigationBar.backButtonNode.view.bounds, to: topNavigationBar.view) + transition.updateFrame(node: currentBackButton, frame: currentBackButtonFrame.offsetBy(dx: fraction * 12.0, dy: 0.0)) + + transition.updateAlpha(node: currentBackButton, alpha: (1.0 - fraction)) + } + + if let previousTitleView = bottomNavigationBar.titleView as? ChatTitleView, let avatarNode = previousTitleView.avatarNode, let (previousTitleContainerNode, previousTitleNode) = self.previousTitleNode, let (previousStatusContainerNode, previousStatusNode) = self.previousStatusNode { + let previousTitleFrame = previousTitleView.titleNode.view.convert(previousTitleView.titleNode.bounds, to: bottomNavigationBar.view) + let previousStatusFrame = previousTitleView.activityNode.view.convert(previousTitleView.activityNode.bounds, to: bottomNavigationBar.view) + + self.headerNode.navigationTransition = PeerInfoHeaderNavigationTransition(sourceNavigationBar: bottomNavigationBar, sourceTitleView: previousTitleView, sourceTitleFrame: previousTitleFrame, sourceSubtitleFrame: previousStatusFrame, fraction: fraction) + if let (layout, navigationHeight) = self.screenNode.validLayout { + self.headerNode.update(width: layout.size.width, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, contentOffset: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, notificationSettings: self.screenNode.data?.notificationSettings, presence: self.screenNode.data?.presence, transition: transition, additive: false) + } + + let titleScale = (fraction * previousTitleNode.bounds.height + (1.0 - fraction) * self.headerNode.titleNode.bounds.height) / previousTitleNode.bounds.height + let subtitleScale = (fraction * previousStatusNode.bounds.height + (1.0 - fraction) * self.headerNode.subtitleNode.bounds.height) / previousStatusNode.bounds.height + + transition.updateFrame(node: previousTitleContainerNode, frame: CGRect(origin: self.headerNode.titleNodeRawContainer.frame.origin.offsetBy(dx: previousTitleFrame.size.width * 0.5 * (titleScale - 1.0), dy: previousTitleFrame.size.height * 0.5 * (titleScale - 1.0)), size: previousTitleFrame.size)) + transition.updateFrame(node: previousTitleNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: previousTitleFrame.size)) + transition.updateFrame(node: previousStatusContainerNode, frame: CGRect(origin: self.headerNode.subtitleNodeRawContainer.frame.origin.offsetBy(dx: previousStatusFrame.size.width * 0.5 * (subtitleScale - 1.0), dy: previousStatusFrame.size.height * 0.5 * (subtitleScale - 1.0)), size: previousStatusFrame.size)) + transition.updateFrame(node: previousStatusNode, frame: CGRect(origin: CGPoint(), size: previousStatusFrame.size)) + + transition.updateSublayerTransformScale(node: previousTitleContainerNode, scale: titleScale) + transition.updateSublayerTransformScale(node: previousStatusContainerNode, scale: subtitleScale) + + transition.updateAlpha(node: self.headerNode.titleNode, alpha: (1.0 - fraction)) + transition.updateAlpha(node: previousTitleNode, alpha: fraction) + transition.updateAlpha(node: self.headerNode.subtitleNode, alpha: (1.0 - fraction)) + transition.updateAlpha(node: previousStatusNode, alpha: fraction) + } + } + + func restore() { + guard let topNavigationBar = self.topNavigationBar, let bottomNavigationBar = self.bottomNavigationBar else { + return + } + + topNavigationBar.isHidden = false + bottomNavigationBar.isHidden = false + self.headerNode.navigationTransition = nil + self.screenNode.insertSubnode(self.headerNode, aboveSubnode: self.screenNode.scrollNode) + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerMediaCollectionController.swift b/submodules/TelegramUI/TelegramUI/PeerMediaCollectionController.swift index 6863ff66a1..7374fc9577 100644 --- a/submodules/TelegramUI/TelegramUI/PeerMediaCollectionController.swift +++ b/submodules/TelegramUI/TelegramUI/PeerMediaCollectionController.swift @@ -759,7 +759,7 @@ public class PeerMediaCollectionController: TelegramBaseController { |> take(1) |> deliverOnMainQueue).start(next: { [weak self] peer in if let strongSelf = self, peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil { - if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic) { + if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { (strongSelf.navigationController as? NavigationController)?.pushViewController(infoController) } } diff --git a/submodules/TelegramUI/TelegramUI/PollResultsController.swift b/submodules/TelegramUI/TelegramUI/PollResultsController.swift index 177ca29828..a1a24b756a 100644 --- a/submodules/TelegramUI/TelegramUI/PollResultsController.swift +++ b/submodules/TelegramUI/TelegramUI/PollResultsController.swift @@ -303,7 +303,7 @@ public func pollResultsController(context: AccountContext, messageId: MessageId, }) }, openPeer: { peer in if let peer = peer.peers[peer.peerId] { - if let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic) { + if let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { pushControllerImpl?(controller) } } diff --git a/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift b/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift index 160fa6cfcc..50cdd8a69d 100644 --- a/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift +++ b/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift @@ -1004,8 +1004,8 @@ public final class SharedAccountContextImpl: SharedAccountContext { handleTextLinkActionImpl(context: context, peerId: peerId, navigateDisposable: navigateDisposable, controller: controller, action: action, itemLink: itemLink) } - public func makePeerInfoController(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode) -> ViewController? { - let controller = peerInfoControllerImpl(context: context, peer: peer, mode: mode) + public func makePeerInfoController(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool) -> ViewController? { + let controller = peerInfoControllerImpl(context: context, peer: peer, mode: mode, avatarInitiallyExpanded: avatarInitiallyExpanded) controller?.navigationPresentation = .modalInLargeLayout return controller } @@ -1245,7 +1245,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { private let defaultChatControllerInteraction = ChatControllerInteraction.default -private func peerInfoControllerImpl(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode) -> ViewController? { +private func peerInfoControllerImpl(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool) -> ViewController? { if let _ = peer as? TelegramGroup { return groupInfoController(context: context, peerId: peer.id) } else if let channel = peer as? TelegramChannel { @@ -1255,7 +1255,7 @@ private func peerInfoControllerImpl(context: AccountContext, peer: Peer, mode: P return channelInfoController(context: context, peerId: peer.id) } } else if peer is TelegramUser { - return PeerInfoScreen(context: context, peerId: peer.id) + return PeerInfoScreen(context: context, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded) } else if peer is TelegramSecretChat { return userInfoController(context: context, peerId: peer.id, mode: mode) } diff --git a/submodules/TelegramUI/TelegramUI/SharedWakeupManager.swift b/submodules/TelegramUI/TelegramUI/SharedWakeupManager.swift index 962ac8a234..638751b63f 100644 --- a/submodules/TelegramUI/TelegramUI/SharedWakeupManager.swift +++ b/submodules/TelegramUI/TelegramUI/SharedWakeupManager.swift @@ -315,7 +315,7 @@ public final class SharedWakeupManager { if let taskId = self.beginBackgroundTask("background-wakeup", { handleExpiration() }) { - let timer = SwiftSignalKit.Timer(timeout: min(30.0, self.backgroundTimeRemaining()), repeat: false, completion: { + let timer = SwiftSignalKit.Timer(timeout: min(30.0, max(0.0, self.backgroundTimeRemaining() - 5.0)), repeat: false, completion: { handleExpiration() }, queue: Queue.mainQueue()) self.currentTask = (taskId, currentTime, timer) diff --git a/submodules/TelegramUI/TelegramUI/TextLinkHandling.swift b/submodules/TelegramUI/TelegramUI/TextLinkHandling.swift index cc46c4172e..d8d1fd0fb2 100644 --- a/submodules/TelegramUI/TelegramUI/TextLinkHandling.swift +++ b/submodules/TelegramUI/TelegramUI/TextLinkHandling.swift @@ -32,7 +32,7 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: PeerId?, navigate peerSignal = context.account.postbox.loadedPeerWithId(peerId) |> map(Optional.init) navigateDisposable.set((peerSignal |> take(1) |> deliverOnMainQueue).start(next: { peer in if let controller = controller, let peer = peer { - if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic) { + if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { (controller.navigationController as? NavigationController)?.pushViewController(infoController) } } From f9ccae936a39e3b5f70a9e72e359c8d5aa9cd9aa Mon Sep 17 00:00:00 2001 From: Ali <> Date: Wed, 5 Feb 2020 11:23:20 +0000 Subject: [PATCH 05/30] Add merchant id --- .../BotPaymentsUI/Sources/BotCheckoutControllerNode.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/submodules/BotPaymentsUI/Sources/BotCheckoutControllerNode.swift b/submodules/BotPaymentsUI/Sources/BotCheckoutControllerNode.swift index 75896af9e9..51c459351e 100644 --- a/submodules/BotPaymentsUI/Sources/BotCheckoutControllerNode.swift +++ b/submodules/BotPaymentsUI/Sources/BotCheckoutControllerNode.swift @@ -335,7 +335,8 @@ private func formSupportApplePay(_ paymentForm: BotPaymentForm) -> Bool { "stripe", "sberbank", "yandex", - "privatbank" + "privatbank", + "tranzzo" ]) if !applePayProviders.contains(nativeProvider.name) { return false From e2071301c275230da1fb99657638a8e8a08c9d05 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 7 Feb 2020 14:23:25 +0000 Subject: [PATCH 06/30] User Info screen --- Telegram-iOS/en.lproj/Localizable.strings | 5 + .../ContainedViewLayoutTransition.swift | 8 +- .../Display/Display/NavigationBar.swift | 21 + .../Display/NavigationButtonNode.swift | 12 +- .../Sources/ItemListPeerItem.swift | 2 +- .../Sources/NotificationSoundSelection.swift | 3 + submodules/Postbox/Sources/Coding.swift | 2 +- .../Postbox/Sources/HistoryTagInfoView.swift | 76 + .../Sources/MessageHistoryTagsTable.swift | 9 + submodules/Postbox/Sources/Views.swift | 551 +- .../Sources/SearchDisplayController.swift | 31 +- .../Sources/AccountViewTracker.swift | 4 +- .../Sources/PresentationStrings.swift | 8072 +++++++++-------- .../TelegramUI/ChatController.swift | 9 +- .../ChatMessageInteractiveMediaBadge.swift | 4 +- .../TelegramUI/TelegramUI/ChatTitleView.swift | 329 +- .../TelegramUI/FileMediaResourceStatus.swift | 2 +- .../TelegramUI/ListMessageFileItemNode.swift | 146 +- .../TelegramUI/PeerInfoFilesPane.swift | 47 +- .../PeerInfoGroupsInCommonPaneNode.swift | 165 + .../TelegramUI/PeerInfoScreen.swift | 2480 ++++- .../TelegramUI/PeerInfoScreenActionItem.swift | 98 + .../PeerInfoScreenDisclosureItem.swift | 115 + .../TelegramUI/PeerInfoScreenSwitchItem.swift | 121 + .../TelegramUI/PeerInfoVisualMediaPane.swift | 135 +- .../Resources/PresentationStrings.mapping | Bin 144565 -> 144705 bytes .../WalletUI/Resources/WalletStrings.mapping | Bin 8384 -> 8384 bytes .../WalletUI/Sources/WalletStrings.swift | 4 +- 28 files changed, 7682 insertions(+), 4769 deletions(-) create mode 100644 submodules/Postbox/Sources/HistoryTagInfoView.swift create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfoGroupsInCommonPaneNode.swift create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfoScreenActionItem.swift create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfoScreenDisclosureItem.swift create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfoScreenSwitchItem.swift diff --git a/Telegram-iOS/en.lproj/Localizable.strings b/Telegram-iOS/en.lproj/Localizable.strings index 2a8e328ead..f3195ab473 100644 --- a/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram-iOS/en.lproj/Localizable.strings @@ -262,6 +262,11 @@ "State.Updating" = "Updating..."; "State.WaitingForNetwork" = "Waiting for network"; +"ChatState.Connecting" = "connecting..."; +"ChatState.ConnectingToProxy" = "connecting to proxy..."; +"ChatState.Updating" = "updating..."; +"ChatState.WaitingForNetwork" = "waiting for network..."; + // Presence "Presence.online" = "online"; diff --git a/submodules/Display/Display/ContainedViewLayoutTransition.swift b/submodules/Display/Display/ContainedViewLayoutTransition.swift index 286e3070e1..0200f6f212 100644 --- a/submodules/Display/Display/ContainedViewLayoutTransition.swift +++ b/submodules/Display/Display/ContainedViewLayoutTransition.swift @@ -351,7 +351,7 @@ public extension ContainedViewLayoutTransition { func animatePositionAdditive(node: ASDisplayNode, offset: CGFloat, removeOnCompletion: Bool = true, completion: @escaping (Bool) -> Void) { switch self { case .immediate: - break + completion(true) case let .animated(duration, curve): node.layer.animatePosition(from: CGPoint(x: 0.0, y: offset), to: CGPoint(), duration: duration, timingFunction: curve.timingFunction, mediaTimingFunction: curve.mediaTimingFunction, removeOnCompletion: removeOnCompletion, additive: true, completion: completion) } @@ -360,7 +360,7 @@ public extension ContainedViewLayoutTransition { func animatePositionAdditive(layer: CALayer, offset: CGFloat, removeOnCompletion: Bool = true, completion: @escaping (Bool) -> Void) { switch self { case .immediate: - break + completion(true) case let .animated(duration, curve): layer.animatePosition(from: CGPoint(x: 0.0, y: offset), to: CGPoint(), duration: duration, timingFunction: curve.timingFunction, mediaTimingFunction: curve.mediaTimingFunction, removeOnCompletion: removeOnCompletion, additive: true, completion: completion) } @@ -369,7 +369,7 @@ public extension ContainedViewLayoutTransition { func animatePositionAdditive(node: ASDisplayNode, offset: CGPoint, removeOnCompletion: Bool = true, completion: (() -> Void)? = nil) { switch self { case .immediate: - break + completion?() case let .animated(duration, curve): node.layer.animatePosition(from: offset, to: CGPoint(), duration: duration, timingFunction: curve.timingFunction, mediaTimingFunction: curve.mediaTimingFunction, removeOnCompletion: removeOnCompletion, additive: true, completion: { _ in completion?() @@ -380,7 +380,7 @@ public extension ContainedViewLayoutTransition { func animatePositionAdditive(layer: CALayer, offset: CGPoint, to toOffset: CGPoint = CGPoint(), removeOnCompletion: Bool = true, completion: (() -> Void)? = nil) { switch self { case .immediate: - break + completion?() case let .animated(duration, curve): layer.animatePosition(from: offset, to: toOffset, duration: duration, timingFunction: curve.timingFunction, mediaTimingFunction: curve.mediaTimingFunction, removeOnCompletion: removeOnCompletion, additive: true, completion: { _ in completion?() diff --git a/submodules/Display/Display/NavigationBar.swift b/submodules/Display/Display/NavigationBar.swift index 6fc314f111..2bd04661cd 100644 --- a/submodules/Display/Display/NavigationBar.swift +++ b/submodules/Display/Display/NavigationBar.swift @@ -1188,4 +1188,25 @@ open class NavigationBar: ASDisplayNode { } } } + + override open func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + if self.bounds.contains(point) { + if self.backButtonNode.supernode != nil && !self.backButtonNode.isHidden { + let effectiveBackButtonRect = CGRect(origin: CGPoint(), size: CGSize(width: self.backButtonNode.frame.maxX + 20.0, height: self.bounds.height)) + if effectiveBackButtonRect.contains(point) { + return self.backButtonNode.internalHitTest(self.view.convert(point, to: self.backButtonNode.view), with: event) + } + } + } + + guard let result = super.hitTest(point, with: event) else { + return nil + } + + if result == self.view || result == self.clippingNode.view { + return nil + } + + return result + } } diff --git a/submodules/Display/Display/NavigationButtonNode.swift b/submodules/Display/Display/NavigationButtonNode.swift index 29a6d37f0e..b237e14361 100644 --- a/submodules/Display/Display/NavigationButtonNode.swift +++ b/submodules/Display/Display/NavigationButtonNode.swift @@ -241,7 +241,7 @@ private final class NavigationButtonItemNode: ASTextNode { public override func touchesMoved(_ touches: Set, with event: UIEvent?) { super.touchesMoved(touches, with: event) - self.updateHighlightedState(self.touchInsideApparentBounds(touches.first!), animated: true) + //self.updateHighlightedState(self.touchInsideApparentBounds(touches.first!), animated: true) } public override func touchesEnded(_ touches: Set, with event: UIEvent?) { @@ -251,7 +251,7 @@ private final class NavigationButtonItemNode: ASTextNode { let previousTouchCount = self.touchCount self.touchCount = max(0, self.touchCount - touches.count) - if previousTouchCount != 0 && self.touchCount == 0 && self.isEnabled && self.touchInsideApparentBounds(touches.first!) { + if previousTouchCount != 0 && self.touchCount == 0 && self.isEnabled { self.pressed() } } @@ -455,4 +455,12 @@ public final class NavigationButtonNode: ASDisplayNode { } return totalSize } + + func internalHitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + if self.nodes.count == 1 { + return self.nodes[0].view + } else { + return super.hitTest(point, with: event) + } + } } diff --git a/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift b/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift index a40405c95f..59d93c72ca 100644 --- a/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift +++ b/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift @@ -424,7 +424,7 @@ public final class ItemListPeerItem: ListViewItem, ItemListItem { } } -private let avatarFont = avatarPlaceholderFont(size: 15.0) +private let avatarFont = avatarPlaceholderFont(size: floor(40.0 * 16.0 / 37.0)) private let badgeFont = Font.regular(15.0) public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNode { diff --git a/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift b/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift index 3e01be1a20..5a6806fcf7 100644 --- a/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift +++ b/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift @@ -304,6 +304,9 @@ public func notificationSoundSelectionController(context: AccountContext, isModa playSoundDisposable.dispose() }) controller.enableInteractiveDismiss = true + if isModal { + controller.navigationPresentation = .modal + } completeImpl = { [weak controller] in let sound = stateValue.with { state in diff --git a/submodules/Postbox/Sources/Coding.swift b/submodules/Postbox/Sources/Coding.swift index 0e73649666..e25c870781 100644 --- a/submodules/Postbox/Sources/Coding.swift +++ b/submodules/Postbox/Sources/Coding.swift @@ -77,7 +77,7 @@ public class MemoryBuffer: Equatable, CustomStringConvertible { data.copyBytes(to: self.memory.assumingMemoryBound(to: UInt8.self), count: data.count) self.capacity = data.count self.length = data.count - self.freeWhenDone = false + self.freeWhenDone = true } } diff --git a/submodules/Postbox/Sources/HistoryTagInfoView.swift b/submodules/Postbox/Sources/HistoryTagInfoView.swift new file mode 100644 index 0000000000..4b145600b2 --- /dev/null +++ b/submodules/Postbox/Sources/HistoryTagInfoView.swift @@ -0,0 +1,76 @@ +import Foundation + +final class MutableHistoryTagInfoView: MutablePostboxView { + fileprivate let peerId: PeerId + fileprivate let tag: MessageTags + + fileprivate var currentIndex: MessageIndex? + + init(postbox: Postbox, peerId: PeerId, tag: MessageTags) { + self.peerId = peerId + self.tag = tag + for namespace in postbox.messageHistoryIndexTable.existingNamespaces(peerId: self.peerId) { + if let index = postbox.messageHistoryTagsTable.latestIndex(tag: self.tag, peerId: self.peerId, namespace: namespace) { + self.currentIndex = index + break + } + } + } + + func replay(postbox: Postbox, transaction: PostboxTransaction) -> Bool { + if let operations = transaction.currentOperationsByPeerId[self.peerId] { + var updated = false + var refresh = false + for operation in operations { + switch operation { + case let .InsertMessage(message): + if self.currentIndex == nil { + if message.tags.contains(self.tag) { + self.currentIndex = message.index + updated = true + } + } + case let .Remove(indicesAndTags): + if self.currentIndex != nil { + for (index, tags) in indicesAndTags { + if tags.contains(self.tag) { + if index == self.currentIndex { + self.currentIndex = nil + updated = true + refresh = true + } + } + } + } + default: + break + } + } + + if refresh { + for namespace in postbox.messageHistoryIndexTable.existingNamespaces(peerId: self.peerId) { + if let index = postbox.messageHistoryTagsTable.latestIndex(tag: self.tag, peerId: self.peerId, namespace: namespace) { + self.currentIndex = index + break + } + } + } + + return updated + } else { + return false + } + } + + func immutableView() -> PostboxView { + return HistoryTagInfoView(self) + } +} + +public final class HistoryTagInfoView: PostboxView { + public let isEmpty: Bool + + init(_ view: MutableHistoryTagInfoView) { + self.isEmpty = view.currentIndex == nil + } +} diff --git a/submodules/Postbox/Sources/MessageHistoryTagsTable.swift b/submodules/Postbox/Sources/MessageHistoryTagsTable.swift index 0f4c7f6570..2af930855d 100644 --- a/submodules/Postbox/Sources/MessageHistoryTagsTable.swift +++ b/submodules/Postbox/Sources/MessageHistoryTagsTable.swift @@ -132,6 +132,15 @@ class MessageHistoryTagsTable: Table { return Int(self.valueBox.count(self.table, start: lowerBoundKey, end: upperBoundKey)) } + func latestIndex(tag: MessageTags, peerId: PeerId, namespace: MessageId.Namespace) -> MessageIndex? { + var result: MessageIndex? + self.valueBox.range(self.table, start: self.lowerBound(tag: tag, peerId: peerId, namespace: namespace), end: self.upperBound(tag: tag, peerId: peerId, namespace: namespace), keys: { key in + result = extractKey(key) + return true + }, limit: 1) + return result + } + func findRandomIndex(peerId: PeerId, namespace: MessageId.Namespace, tag: MessageTags, ignoreIds: ([MessageId], Set), isMessage: (MessageIndex) -> Bool) -> MessageIndex? { var indices: [MessageIndex] = [] self.valueBox.range(self.table, start: self.lowerBound(tag: tag, peerId: peerId, namespace: namespace), end: self.upperBound(tag: tag, peerId: peerId, namespace: namespace), keys: { key in diff --git a/submodules/Postbox/Sources/Views.swift b/submodules/Postbox/Sources/Views.swift index 962d0fe2ec..c593c746e7 100644 --- a/submodules/Postbox/Sources/Views.swift +++ b/submodules/Postbox/Sources/Views.swift @@ -28,289 +28,300 @@ public enum PostboxViewKey: Hashable { case peerChatInclusion(PeerId) case basicPeer(PeerId) case allChatListHoles(PeerGroupId) + case historyTagInfo(peerId: PeerId, tag: MessageTags) public var hashValue: Int { switch self { - case .itemCollectionInfos: - return 0 - case .itemCollectionIds: - return 1 - case let .peerChatState(peerId): - return peerId.hashValue - case let .itemCollectionInfo(id): - return id.hashValue - case let .orderedItemList(id): - return id.hashValue - case .preferences: - return 3 - case .globalMessageTags: - return 4 - case let .peer(peerId, _): - return peerId.hashValue - case let .pendingMessageActions(type): - return type.hashValue - case let .invalidatedMessageHistoryTagSummaries(tagMask, namespace): - return tagMask.rawValue.hashValue ^ namespace.hashValue - case let .pendingMessageActionsSummary(type, peerId, namespace): - return type.hashValue ^ peerId.hashValue ^ namespace.hashValue - case let .historyTagSummaryView(tag, peerId, namespace): - return tag.rawValue.hashValue ^ peerId.hashValue ^ namespace.hashValue - case let .cachedPeerData(peerId): - return peerId.hashValue - case .unreadCounts: - return 5 - case .peerNotificationSettings: - return 6 - case .pendingPeerNotificationSettings: - return 7 - case let .messageOfInterestHole(location, namespace, count): - return 8 &+ 31 &* location.hashValue &+ 31 &* namespace.hashValue &+ 31 &* count.hashValue - case let .localMessageTag(tag): - return tag.hashValue - case .messages: - return 10 - case .additionalChatListItems: - return 11 - case let .cachedItem(id): - return id.hashValue - case .peerPresences: - return 13 - case .synchronizeGroupMessageStats: - return 14 - case .peerNotificationSettingsBehaviorTimestampView: - return 15 - case let .peerChatInclusion(peerId): - return peerId.hashValue - case let .basicPeer(peerId): - return peerId.hashValue - case let .allChatListHoles(groupId): - return groupId.hashValue + case .itemCollectionInfos: + return 0 + case .itemCollectionIds: + return 1 + case let .peerChatState(peerId): + return peerId.hashValue + case let .itemCollectionInfo(id): + return id.hashValue + case let .orderedItemList(id): + return id.hashValue + case .preferences: + return 3 + case .globalMessageTags: + return 4 + case let .peer(peerId, _): + return peerId.hashValue + case let .pendingMessageActions(type): + return type.hashValue + case let .invalidatedMessageHistoryTagSummaries(tagMask, namespace): + return tagMask.rawValue.hashValue ^ namespace.hashValue + case let .pendingMessageActionsSummary(type, peerId, namespace): + return type.hashValue ^ peerId.hashValue ^ namespace.hashValue + case let .historyTagSummaryView(tag, peerId, namespace): + return tag.rawValue.hashValue ^ peerId.hashValue ^ namespace.hashValue + case let .cachedPeerData(peerId): + return peerId.hashValue + case .unreadCounts: + return 5 + case .peerNotificationSettings: + return 6 + case .pendingPeerNotificationSettings: + return 7 + case let .messageOfInterestHole(location, namespace, count): + return 8 &+ 31 &* location.hashValue &+ 31 &* namespace.hashValue &+ 31 &* count.hashValue + case let .localMessageTag(tag): + return tag.hashValue + case .messages: + return 10 + case .additionalChatListItems: + return 11 + case let .cachedItem(id): + return id.hashValue + case .peerPresences: + return 13 + case .synchronizeGroupMessageStats: + return 14 + case .peerNotificationSettingsBehaviorTimestampView: + return 15 + case let .peerChatInclusion(peerId): + return peerId.hashValue + case let .basicPeer(peerId): + return peerId.hashValue + case let .allChatListHoles(groupId): + return groupId.hashValue + case let .historyTagInfo(peerId, tag): + return peerId.hashValue ^ tag.hashValue } } public static func ==(lhs: PostboxViewKey, rhs: PostboxViewKey) -> Bool { switch lhs { - case let .itemCollectionInfos(lhsNamespaces): - if case let .itemCollectionInfos(rhsNamespaces) = rhs, lhsNamespaces == rhsNamespaces { - return true - } else { - return false - } - case let .itemCollectionIds(lhsNamespaces): - if case let .itemCollectionIds(rhsNamespaces) = rhs, lhsNamespaces == rhsNamespaces { - return true - } else { - return false - } - case let .itemCollectionInfo(id): - if case .itemCollectionInfo(id) = rhs { - return true - } else { - return false - } - case let .peerChatState(peerId): - if case .peerChatState(peerId) = rhs { - return true - } else { - return false - } - case let .orderedItemList(id): - if case .orderedItemList(id) = rhs { - return true - } else { - return false - } - case let .preferences(lhsKeys): - if case let .preferences(rhsKeys) = rhs, lhsKeys == rhsKeys { - return true - } else { - return false - } - case let .globalMessageTags(globalTag, position, count, _): - if case .globalMessageTags(globalTag, position, count, _) = rhs { - return true - } else { - return false - } - case let .peer(peerId, components): - if case .peer(peerId, components) = rhs { - return true - } else { - return false - } - case let .pendingMessageActions(type): - if case .pendingMessageActions(type) = rhs { - return true - } else { - return false - } - case .invalidatedMessageHistoryTagSummaries: - if case .invalidatedMessageHistoryTagSummaries = rhs { - return true - } else { - return false - } - case let .pendingMessageActionsSummary(type, peerId, namespace): - if case .pendingMessageActionsSummary(type, peerId, namespace) = rhs { - return true - } else { - return false - } - case let .historyTagSummaryView(tag, peerId, namespace): - if case .historyTagSummaryView(tag, peerId, namespace) = rhs { - return true - } else { - return false - } - case let .cachedPeerData(peerId): - if case .cachedPeerData(peerId) = rhs { - return true - } else { - return false - } - case let .unreadCounts(lhsItems): - if case let .unreadCounts(rhsItems) = rhs, lhsItems == rhsItems { - return true - } else { - return false - } - case let .peerNotificationSettings(peerIds): - if case .peerNotificationSettings(peerIds) = rhs { - return true - } else { - return false - } - case .pendingPeerNotificationSettings: - if case .pendingPeerNotificationSettings = rhs { - return true - } else { - return false - } - case let .messageOfInterestHole(peerId, namespace, count): - if case .messageOfInterestHole(peerId, namespace, count) = rhs { - return true - } else { - return false - } - case let .localMessageTag(tag): - if case .localMessageTag(tag) = rhs { - return true - } else { - return false - } - case let .messages(ids): - if case .messages(ids) = rhs { - return true - } else { - return false - } - case .additionalChatListItems: - if case .additionalChatListItems = rhs { - return true - } else { - return false - } - case let .cachedItem(id): - if case .cachedItem(id) = rhs { - return true - } else { - return false - } - case let .peerPresences(ids): - if case .peerPresences(ids) = rhs { - return true - } else { - return false - } - case .synchronizeGroupMessageStats: - if case .synchronizeGroupMessageStats = rhs { - return true - } else { - return false - } - case .peerNotificationSettingsBehaviorTimestampView: - if case .peerNotificationSettingsBehaviorTimestampView = rhs { - return true - } else { - return false - } - case let .peerChatInclusion(id): - if case .peerChatInclusion(id) = rhs { - return true - } else { - return false - } - case let .basicPeer(id): - if case .basicPeer(id) = rhs { - return true - } else { - return false - } - case let .allChatListHoles(groupId): - if case .allChatListHoles(groupId) = rhs { - return true - } else { - return false - } + case let .itemCollectionInfos(lhsNamespaces): + if case let .itemCollectionInfos(rhsNamespaces) = rhs, lhsNamespaces == rhsNamespaces { + return true + } else { + return false + } + case let .itemCollectionIds(lhsNamespaces): + if case let .itemCollectionIds(rhsNamespaces) = rhs, lhsNamespaces == rhsNamespaces { + return true + } else { + return false + } + case let .itemCollectionInfo(id): + if case .itemCollectionInfo(id) = rhs { + return true + } else { + return false + } + case let .peerChatState(peerId): + if case .peerChatState(peerId) = rhs { + return true + } else { + return false + } + case let .orderedItemList(id): + if case .orderedItemList(id) = rhs { + return true + } else { + return false + } + case let .preferences(lhsKeys): + if case let .preferences(rhsKeys) = rhs, lhsKeys == rhsKeys { + return true + } else { + return false + } + case let .globalMessageTags(globalTag, position, count, _): + if case .globalMessageTags(globalTag, position, count, _) = rhs { + return true + } else { + return false + } + case let .peer(peerId, components): + if case .peer(peerId, components) = rhs { + return true + } else { + return false + } + case let .pendingMessageActions(type): + if case .pendingMessageActions(type) = rhs { + return true + } else { + return false + } + case .invalidatedMessageHistoryTagSummaries: + if case .invalidatedMessageHistoryTagSummaries = rhs { + return true + } else { + return false + } + case let .pendingMessageActionsSummary(type, peerId, namespace): + if case .pendingMessageActionsSummary(type, peerId, namespace) = rhs { + return true + } else { + return false + } + case let .historyTagSummaryView(tag, peerId, namespace): + if case .historyTagSummaryView(tag, peerId, namespace) = rhs { + return true + } else { + return false + } + case let .cachedPeerData(peerId): + if case .cachedPeerData(peerId) = rhs { + return true + } else { + return false + } + case let .unreadCounts(lhsItems): + if case let .unreadCounts(rhsItems) = rhs, lhsItems == rhsItems { + return true + } else { + return false + } + case let .peerNotificationSettings(peerIds): + if case .peerNotificationSettings(peerIds) = rhs { + return true + } else { + return false + } + case .pendingPeerNotificationSettings: + if case .pendingPeerNotificationSettings = rhs { + return true + } else { + return false + } + case let .messageOfInterestHole(peerId, namespace, count): + if case .messageOfInterestHole(peerId, namespace, count) = rhs { + return true + } else { + return false + } + case let .localMessageTag(tag): + if case .localMessageTag(tag) = rhs { + return true + } else { + return false + } + case let .messages(ids): + if case .messages(ids) = rhs { + return true + } else { + return false + } + case .additionalChatListItems: + if case .additionalChatListItems = rhs { + return true + } else { + return false + } + case let .cachedItem(id): + if case .cachedItem(id) = rhs { + return true + } else { + return false + } + case let .peerPresences(ids): + if case .peerPresences(ids) = rhs { + return true + } else { + return false + } + case .synchronizeGroupMessageStats: + if case .synchronizeGroupMessageStats = rhs { + return true + } else { + return false + } + case .peerNotificationSettingsBehaviorTimestampView: + if case .peerNotificationSettingsBehaviorTimestampView = rhs { + return true + } else { + return false + } + case let .peerChatInclusion(id): + if case .peerChatInclusion(id) = rhs { + return true + } else { + return false + } + case let .basicPeer(id): + if case .basicPeer(id) = rhs { + return true + } else { + return false + } + case let .allChatListHoles(groupId): + if case .allChatListHoles(groupId) = rhs { + return true + } else { + return false + } + case let .historyTagInfo(peerId, tag): + if case .historyTagInfo(peerId, tag) = rhs { + return true + } else { + return false + } } } } func postboxViewForKey(postbox: Postbox, key: PostboxViewKey) -> MutablePostboxView { switch key { - case let .itemCollectionInfos(namespaces): - return MutableItemCollectionInfosView(postbox: postbox, namespaces: namespaces) - case let .itemCollectionIds(namespaces): - return MutableItemCollectionIdsView(postbox: postbox, namespaces: namespaces) - case let .itemCollectionInfo(id): - return MutableItemCollectionInfoView(postbox: postbox, id: id) - case let .peerChatState(peerId): - return MutablePeerChatStateView(postbox: postbox, peerId: peerId) - case let .orderedItemList(id): - return MutableOrderedItemListView(postbox: postbox, collectionId: id) - case let .preferences(keys): - return MutablePreferencesView(postbox: postbox, keys: keys) - case let .globalMessageTags(globalTag, position, count, groupingPredicate): - return MutableGlobalMessageTagsView(postbox: postbox, globalTag: globalTag, position: position, count: count, groupingPredicate: groupingPredicate) - case let .peer(peerId, components): - return MutablePeerView(postbox: postbox, peerId: peerId, components: components) - case let .pendingMessageActions(type): - return MutablePendingMessageActionsView(postbox: postbox, type: type) - case let .invalidatedMessageHistoryTagSummaries(tagMask, namespace): - return MutableInvalidatedMessageHistoryTagSummariesView(postbox: postbox, tagMask: tagMask, namespace: namespace) - case let .pendingMessageActionsSummary(type, peerId, namespace): - return MutablePendingMessageActionsSummaryView(postbox: postbox, type: type, peerId: peerId, namespace: namespace) - case let .historyTagSummaryView(tag, peerId, namespace): - return MutableMessageHistoryTagSummaryView(postbox: postbox, tag: tag, peerId: peerId, namespace: namespace) - case let .cachedPeerData(peerId): - return MutableCachedPeerDataView(postbox: postbox, peerId: peerId) - case let .unreadCounts(items): - return MutableUnreadMessageCountsView(postbox: postbox, items: items) - case let .peerNotificationSettings(peerIds): - return MutablePeerNotificationSettingsView(postbox: postbox, peerIds: peerIds) - case .pendingPeerNotificationSettings: - return MutablePendingPeerNotificationSettingsView(postbox: postbox) - case let .messageOfInterestHole(location, namespace, count): - return MutableMessageOfInterestHolesView(postbox: postbox, location: location, namespace: namespace, count: count) - case let .localMessageTag(tag): - return MutableLocalMessageTagsView(postbox: postbox, tag: tag) - case let .messages(ids): - return MutableMessagesView(postbox: postbox, ids: ids) - case .additionalChatListItems: - return MutableAdditionalChatListItemsView(postbox: postbox) - case let .cachedItem(id): - return MutableCachedItemView(postbox: postbox, id: id) - case let .peerPresences(ids): - return MutablePeerPresencesView(postbox: postbox, ids: ids) - case .synchronizeGroupMessageStats: - return MutableSynchronizeGroupMessageStatsView(postbox: postbox) - case .peerNotificationSettingsBehaviorTimestampView: - return MutablePeerNotificationSettingsBehaviorTimestampView(postbox: postbox) - case let .peerChatInclusion(peerId): - return MutablePeerChatInclusionView(postbox: postbox, peerId: peerId) - case let .basicPeer(peerId): - return MutableBasicPeerView(postbox: postbox, peerId: peerId) - case let .allChatListHoles(groupId): - return MutableAllChatListHolesView(postbox: postbox, groupId: groupId) + case let .itemCollectionInfos(namespaces): + return MutableItemCollectionInfosView(postbox: postbox, namespaces: namespaces) + case let .itemCollectionIds(namespaces): + return MutableItemCollectionIdsView(postbox: postbox, namespaces: namespaces) + case let .itemCollectionInfo(id): + return MutableItemCollectionInfoView(postbox: postbox, id: id) + case let .peerChatState(peerId): + return MutablePeerChatStateView(postbox: postbox, peerId: peerId) + case let .orderedItemList(id): + return MutableOrderedItemListView(postbox: postbox, collectionId: id) + case let .preferences(keys): + return MutablePreferencesView(postbox: postbox, keys: keys) + case let .globalMessageTags(globalTag, position, count, groupingPredicate): + return MutableGlobalMessageTagsView(postbox: postbox, globalTag: globalTag, position: position, count: count, groupingPredicate: groupingPredicate) + case let .peer(peerId, components): + return MutablePeerView(postbox: postbox, peerId: peerId, components: components) + case let .pendingMessageActions(type): + return MutablePendingMessageActionsView(postbox: postbox, type: type) + case let .invalidatedMessageHistoryTagSummaries(tagMask, namespace): + return MutableInvalidatedMessageHistoryTagSummariesView(postbox: postbox, tagMask: tagMask, namespace: namespace) + case let .pendingMessageActionsSummary(type, peerId, namespace): + return MutablePendingMessageActionsSummaryView(postbox: postbox, type: type, peerId: peerId, namespace: namespace) + case let .historyTagSummaryView(tag, peerId, namespace): + return MutableMessageHistoryTagSummaryView(postbox: postbox, tag: tag, peerId: peerId, namespace: namespace) + case let .cachedPeerData(peerId): + return MutableCachedPeerDataView(postbox: postbox, peerId: peerId) + case let .unreadCounts(items): + return MutableUnreadMessageCountsView(postbox: postbox, items: items) + case let .peerNotificationSettings(peerIds): + return MutablePeerNotificationSettingsView(postbox: postbox, peerIds: peerIds) + case .pendingPeerNotificationSettings: + return MutablePendingPeerNotificationSettingsView(postbox: postbox) + case let .messageOfInterestHole(location, namespace, count): + return MutableMessageOfInterestHolesView(postbox: postbox, location: location, namespace: namespace, count: count) + case let .localMessageTag(tag): + return MutableLocalMessageTagsView(postbox: postbox, tag: tag) + case let .messages(ids): + return MutableMessagesView(postbox: postbox, ids: ids) + case .additionalChatListItems: + return MutableAdditionalChatListItemsView(postbox: postbox) + case let .cachedItem(id): + return MutableCachedItemView(postbox: postbox, id: id) + case let .peerPresences(ids): + return MutablePeerPresencesView(postbox: postbox, ids: ids) + case .synchronizeGroupMessageStats: + return MutableSynchronizeGroupMessageStatsView(postbox: postbox) + case .peerNotificationSettingsBehaviorTimestampView: + return MutablePeerNotificationSettingsBehaviorTimestampView(postbox: postbox) + case let .peerChatInclusion(peerId): + return MutablePeerChatInclusionView(postbox: postbox, peerId: peerId) + case let .basicPeer(peerId): + return MutableBasicPeerView(postbox: postbox, peerId: peerId) + case let .allChatListHoles(groupId): + return MutableAllChatListHolesView(postbox: postbox, groupId: groupId) + case let .historyTagInfo(peerId, tag): + return MutableHistoryTagInfoView(postbox: postbox, peerId: peerId, tag: tag) } } diff --git a/submodules/SearchUI/Sources/SearchDisplayController.swift b/submodules/SearchUI/Sources/SearchDisplayController.swift index fa86bdf81f..66d5fd6e9b 100644 --- a/submodules/SearchUI/Sources/SearchDisplayController.swift +++ b/submodules/SearchUI/Sources/SearchDisplayController.swift @@ -99,7 +99,7 @@ public final class SearchDisplayController { self.contentNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: LayoutMetrics(), deviceMetrics: layout.deviceMetrics, intrinsicInsets: layout.intrinsicInsets, safeInsets: layout.safeInsets, statusBarHeight: nil, inputHeight: layout.inputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), navigationBarHeight: navigationBarFrame.maxY, transition: transition) } - public func activate(insertSubnode: (ASDisplayNode, Bool) -> Void, placeholder: SearchBarPlaceholderNode) { + public func activate(insertSubnode: (ASDisplayNode, Bool) -> Void, placeholder: SearchBarPlaceholderNode?) { guard let (layout, navigationBarHeight) = self.containerLayout else { return } @@ -110,19 +110,20 @@ public final class SearchDisplayController { self.contentNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: LayoutMetrics(), deviceMetrics: layout.deviceMetrics, intrinsicInsets: UIEdgeInsets(), safeInsets: layout.safeInsets, statusBarHeight: nil, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), navigationBarHeight: navigationBarHeight, transition: .immediate) - let initialTextBackgroundFrame = placeholder.convert(placeholder.backgroundNode.frame, to: nil) - - let contentNodePosition = self.contentNode.layer.position - var contentNavigationBarHeight = navigationBarHeight if layout.statusBarHeight == nil { contentNavigationBarHeight += 28.0 } - self.contentNode.layer.animatePosition(from: CGPoint(x: contentNodePosition.x, y: contentNodePosition.y + (initialTextBackgroundFrame.maxY + 8.0 - contentNavigationBarHeight)), to: contentNodePosition, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring) - self.contentNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) - - self.searchBar.placeholderString = placeholder.placeholderString + if let placeholder = placeholder { + let initialTextBackgroundFrame = placeholder.convert(placeholder.backgroundNode.frame, to: nil) + + let contentNodePosition = self.contentNode.layer.position + + self.contentNode.layer.animatePosition(from: CGPoint(x: contentNodePosition.x, y: contentNodePosition.y + (initialTextBackgroundFrame.maxY + 8.0 - contentNavigationBarHeight)), to: contentNodePosition, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring) + self.contentNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) + self.searchBar.placeholderString = placeholder.placeholderString + } let navigationBarFrame: CGRect switch self.mode { @@ -149,18 +150,26 @@ public final class SearchDisplayController { self.searchBar.layout() self.searchBar.activate() - self.searchBar.animateIn(from: placeholder, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring) + if let placeholder = placeholder { + self.searchBar.animateIn(from: placeholder, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring) + } else { + self.contentNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) + } } public func deactivate(placeholder: SearchBarPlaceholderNode?, animated: Bool = true) { self.searchBar.deactivate() + let searchBar = self.searchBar if let placeholder = placeholder { - let searchBar = self.searchBar searchBar.transitionOut(to: placeholder, transition: animated ? .animated(duration: 0.5, curve: .spring) : .immediate, completion: { [weak searchBar] in searchBar?.removeFromSupernode() }) + } else { + searchBar.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak searchBar] _ in + searchBar?.removeFromSupernode() + }) } let contentNode = self.contentNode diff --git a/submodules/TelegramCore/Sources/AccountViewTracker.swift b/submodules/TelegramCore/Sources/AccountViewTracker.swift index 23b6ecfb54..77d5c28d65 100644 --- a/submodules/TelegramCore/Sources/AccountViewTracker.swift +++ b/submodules/TelegramCore/Sources/AccountViewTracker.swift @@ -1064,7 +1064,7 @@ public final class AccountViewTracker { } } - public func aroundMessageHistoryViewForLocation(_ chatLocation: ChatLocation, index: MessageHistoryAnchorIndex, anchorIndex: MessageHistoryAnchorIndex, count: Int, fixedCombinedReadStates: MessageHistoryViewReadState?, tagMask: MessageTags? = nil, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { + public func aroundMessageHistoryViewForLocation(_ chatLocation: ChatLocation, index: MessageHistoryAnchorIndex, anchorIndex: MessageHistoryAnchorIndex, count: Int, clipHoles: Bool = true, fixedCombinedReadStates: MessageHistoryViewReadState?, tagMask: MessageTags? = nil, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { if let account = self.account { let inputAnchor: HistoryViewInputAnchor switch index { @@ -1075,7 +1075,7 @@ public final class AccountViewTracker { case let .message(index): inputAnchor = .index(index) } - let signal = account.postbox.aroundMessageHistoryViewForLocation(chatLocation, anchor: inputAnchor, count: count, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData)) + let signal = account.postbox.aroundMessageHistoryViewForLocation(chatLocation, anchor: inputAnchor, count: count, clipHoles: clipHoles, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData)) return wrappedMessageHistorySignal(chatLocation: chatLocation, signal: signal, addHoleIfNeeded: false) } else { return .never() diff --git a/submodules/TelegramPresentationData/Sources/PresentationStrings.swift b/submodules/TelegramPresentationData/Sources/PresentationStrings.swift index 05eee7ac5d..81d95743ff 100644 --- a/submodules/TelegramPresentationData/Sources/PresentationStrings.swift +++ b/submodules/TelegramPresentationData/Sources/PresentationStrings.swift @@ -239,4739 +239,4746 @@ public final class PresentationStrings: Equatable { public func MediaPicker_Nof(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[49]!, self._r[49]!, [_0]) } - public var EditTheme_Expand_Preview_IncomingReplyName: String { return self._s[50]! } - public var AutoDownloadSettings_MediaTypes: String { return self._s[52]! } - public var Watch_GroupInfo_Title: String { return self._s[53]! } - public var Passport_Identity_AddPersonalDetails: String { return self._s[54]! } - public var Channel_Info_Members: String { return self._s[55]! } - public var LoginPassword_InvalidPasswordError: String { return self._s[57]! } - public var Conversation_LiveLocation: String { return self._s[58]! } - public var Wallet_Month_ShortNovember: String { return self._s[59]! } - public var PrivacyLastSeenSettings_CustomShareSettingsHelp: String { return self._s[60]! } - public var NetworkUsageSettings_BytesReceived: String { return self._s[62]! } - public var Stickers_Search: String { return self._s[64]! } - public var NotificationsSound_Synth: String { return self._s[65]! } - public var LogoutOptions_LogOutInfo: String { return self._s[66]! } + public var ChatState_ConnectingToProxy: String { return self._s[50]! } + public var EditTheme_Expand_Preview_IncomingReplyName: String { return self._s[51]! } + public var AutoDownloadSettings_MediaTypes: String { return self._s[53]! } + public var Watch_GroupInfo_Title: String { return self._s[54]! } + public var Passport_Identity_AddPersonalDetails: String { return self._s[55]! } + public var Channel_Info_Members: String { return self._s[56]! } + public var LoginPassword_InvalidPasswordError: String { return self._s[58]! } + public var Conversation_LiveLocation: String { return self._s[59]! } + public var Wallet_Month_ShortNovember: String { return self._s[60]! } + public var PrivacyLastSeenSettings_CustomShareSettingsHelp: String { return self._s[61]! } + public var NetworkUsageSettings_BytesReceived: String { return self._s[63]! } + public var Stickers_Search: String { return self._s[65]! } + public var NotificationsSound_Synth: String { return self._s[66]! } + public var LogoutOptions_LogOutInfo: String { return self._s[67]! } public func VoiceOver_Chat_ForwardedFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[68]!, self._r[68]!, [_0]) + return formatWithArgumentRanges(self._s[69]!, self._r[69]!, [_0]) } - public var NetworkUsageSettings_MediaAudioDataSection: String { return self._s[69]! } - public var ChatList_Context_HideArchive: String { return self._s[71]! } - public var AutoNightTheme_UseSunsetSunrise: String { return self._s[72]! } - public var FastTwoStepSetup_Title: String { return self._s[73]! } - public var EditTheme_Create_Preview_IncomingReplyText: String { return self._s[74]! } - public var Channel_Info_BlackList: String { return self._s[75]! } - public var Channel_AdminLog_InfoPanelTitle: String { return self._s[76]! } - public var Conversation_OpenFile: String { return self._s[78]! } - public var SecretTimer_ImageDescription: String { return self._s[79]! } - public var StickerSettings_ContextInfo: String { return self._s[80]! } - public var TwoStepAuth_GenericHelp: String { return self._s[82]! } - public var AutoDownloadSettings_Unlimited: String { return self._s[83]! } - public var PrivacyLastSeenSettings_NeverShareWith_Title: String { return self._s[84]! } - public var AutoDownloadSettings_DataUsageHigh: String { return self._s[85]! } + public var NetworkUsageSettings_MediaAudioDataSection: String { return self._s[70]! } + public var ChatList_Context_HideArchive: String { return self._s[72]! } + public var AutoNightTheme_UseSunsetSunrise: String { return self._s[73]! } + public var FastTwoStepSetup_Title: String { return self._s[74]! } + public var EditTheme_Create_Preview_IncomingReplyText: String { return self._s[75]! } + public var Channel_Info_BlackList: String { return self._s[76]! } + public var Channel_AdminLog_InfoPanelTitle: String { return self._s[77]! } + public var Conversation_OpenFile: String { return self._s[79]! } + public var SecretTimer_ImageDescription: String { return self._s[80]! } + public var StickerSettings_ContextInfo: String { return self._s[81]! } + public var TwoStepAuth_GenericHelp: String { return self._s[83]! } + public var AutoDownloadSettings_Unlimited: String { return self._s[84]! } + public var PrivacyLastSeenSettings_NeverShareWith_Title: String { return self._s[85]! } + public var AutoDownloadSettings_DataUsageHigh: String { return self._s[86]! } public func PUSH_CHAT_MESSAGE_VIDEO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[86]!, self._r[86]!, [_1, _2]) + return formatWithArgumentRanges(self._s[87]!, self._r[87]!, [_1, _2]) } - public var AuthSessions_AddDevice_ScanInfo: String { return self._s[87]! } - public var Notifications_AddExceptionTitle: String { return self._s[88]! } - public var Watch_MessageView_Reply: String { return self._s[89]! } - public var Tour_Text6: String { return self._s[90]! } - public var TwoStepAuth_SetupPasswordEnterPasswordChange: String { return self._s[91]! } + public var AuthSessions_AddDevice_ScanInfo: String { return self._s[88]! } + public var Notifications_AddExceptionTitle: String { return self._s[89]! } + public var Watch_MessageView_Reply: String { return self._s[90]! } + public var Tour_Text6: String { return self._s[91]! } + public var TwoStepAuth_SetupPasswordEnterPasswordChange: String { return self._s[92]! } public func Notification_PinnedAnimationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[92]!, self._r[92]!, [_0]) - } - public func ShareFileTip_Text(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[93]!, self._r[93]!, [_0]) } - public var Wallet_Configuration_BlockchainIdPlaceholder: String { return self._s[94]! } - public var AccessDenied_LocationDenied: String { return self._s[95]! } - public var CallSettings_RecentCalls: String { return self._s[96]! } - public var ConversationProfile_LeaveDeleteAndExit: String { return self._s[97]! } - public var Channel_Members_AddAdminErrorBlacklisted: String { return self._s[99]! } - public var Passport_Authorize: String { return self._s[100]! } - public var StickerPacksSettings_ArchivedMasks_Info: String { return self._s[101]! } - public var AutoDownloadSettings_Videos: String { return self._s[102]! } - public var TwoStepAuth_ReEnterPasswordTitle: String { return self._s[103]! } - public var Wallet_Info_Send: String { return self._s[104]! } - public var AuthSessions_AddDevice_UrlLoginHint: String { return self._s[105]! } - public var Wallet_TransactionInfo_SendGrams: String { return self._s[106]! } - public var Tour_StartButton: String { return self._s[107]! } - public var Watch_AppName: String { return self._s[109]! } - public var StickerPack_ErrorNotFound: String { return self._s[110]! } - public var Channel_Info_Subscribers: String { return self._s[111]! } - public func Channel_AdminLog_MessageGroupPreHistoryVisible(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[112]!, self._r[112]!, [_0]) + public func ShareFileTip_Text(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[94]!, self._r[94]!, [_0]) } - public func DialogList_PinLimitError(_ _0: String) -> (String, [(Int, NSRange)]) { + public var Wallet_Configuration_BlockchainIdPlaceholder: String { return self._s[95]! } + public var AccessDenied_LocationDenied: String { return self._s[96]! } + public var CallSettings_RecentCalls: String { return self._s[97]! } + public var ConversationProfile_LeaveDeleteAndExit: String { return self._s[98]! } + public var Channel_Members_AddAdminErrorBlacklisted: String { return self._s[100]! } + public var Passport_Authorize: String { return self._s[101]! } + public var StickerPacksSettings_ArchivedMasks_Info: String { return self._s[102]! } + public var AutoDownloadSettings_Videos: String { return self._s[103]! } + public var TwoStepAuth_ReEnterPasswordTitle: String { return self._s[104]! } + public var Wallet_Info_Send: String { return self._s[105]! } + public var AuthSessions_AddDevice_UrlLoginHint: String { return self._s[106]! } + public var Wallet_TransactionInfo_SendGrams: String { return self._s[107]! } + public var Tour_StartButton: String { return self._s[108]! } + public var Watch_AppName: String { return self._s[110]! } + public var StickerPack_ErrorNotFound: String { return self._s[111]! } + public var Channel_Info_Subscribers: String { return self._s[112]! } + public func Channel_AdminLog_MessageGroupPreHistoryVisible(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[113]!, self._r[113]!, [_0]) } - public var Appearance_RemoveTheme: String { return self._s[114]! } + public func DialogList_PinLimitError(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[114]!, self._r[114]!, [_0]) + } + public var Appearance_RemoveTheme: String { return self._s[115]! } public func Wallet_Info_TransactionBlockchainFee(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[115]!, self._r[115]!, [_0]) + return formatWithArgumentRanges(self._s[116]!, self._r[116]!, [_0]) } - public var Conversation_StopLiveLocation: String { return self._s[118]! } - public var Channel_AdminLogFilter_EventsAll: String { return self._s[119]! } - public var GroupInfo_InviteLink_CopyAlert_Success: String { return self._s[121]! } - public var Username_LinkCopied: String { return self._s[123]! } - public var GroupRemoved_Title: String { return self._s[124]! } - public var SecretVideo_Title: String { return self._s[125]! } + public var Conversation_StopLiveLocation: String { return self._s[119]! } + public var Channel_AdminLogFilter_EventsAll: String { return self._s[120]! } + public var GroupInfo_InviteLink_CopyAlert_Success: String { return self._s[122]! } + public var Username_LinkCopied: String { return self._s[124]! } + public var GroupRemoved_Title: String { return self._s[125]! } + public var SecretVideo_Title: String { return self._s[126]! } public func PUSH_PINNED_VIDEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[126]!, self._r[126]!, [_1]) + return formatWithArgumentRanges(self._s[127]!, self._r[127]!, [_1]) } - public var AccessDenied_PhotosAndVideos: String { return self._s[127]! } - public var Appearance_ThemePreview_Chat_1_Text: String { return self._s[128]! } + public var AccessDenied_PhotosAndVideos: String { return self._s[128]! } + public var Appearance_ThemePreview_Chat_1_Text: String { return self._s[129]! } public func PUSH_CHANNEL_MESSAGE_GEOLIVE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[130]!, self._r[130]!, [_1]) + return formatWithArgumentRanges(self._s[131]!, self._r[131]!, [_1]) } - public var Map_OpenInGoogleMaps: String { return self._s[132]! } + public var Map_OpenInGoogleMaps: String { return self._s[133]! } public func Time_PreciseDate_m12(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[133]!, self._r[133]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[134]!, self._r[134]!, [_1, _2, _3]) } public func Channel_AdminLog_MessageKickedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[134]!, self._r[134]!, [_1, _2]) + return formatWithArgumentRanges(self._s[135]!, self._r[135]!, [_1, _2]) } - public var Call_StatusRinging: String { return self._s[135]! } - public var SettingsSearch_Synonyms_EditProfile_Username: String { return self._s[136]! } - public var Group_Username_InvalidStartsWithNumber: String { return self._s[137]! } - public var UserInfo_NotificationsEnabled: String { return self._s[138]! } - public var Map_Search: String { return self._s[139]! } - public var ClearCache_StorageFree: String { return self._s[141]! } - public var Login_TermsOfServiceHeader: String { return self._s[142]! } + public var Call_StatusRinging: String { return self._s[136]! } + public var SettingsSearch_Synonyms_EditProfile_Username: String { return self._s[137]! } + public var Group_Username_InvalidStartsWithNumber: String { return self._s[138]! } + public var UserInfo_NotificationsEnabled: String { return self._s[139]! } + public var Map_Search: String { return self._s[140]! } + public var ClearCache_StorageFree: String { return self._s[142]! } + public var Login_TermsOfServiceHeader: String { return self._s[143]! } public func Notification_PinnedVideoMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[143]!, self._r[143]!, [_0]) + return formatWithArgumentRanges(self._s[144]!, self._r[144]!, [_0]) } public func Channel_AdminLog_MessageToggleSignaturesOn(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[145]!, self._r[145]!, [_0]) + return formatWithArgumentRanges(self._s[146]!, self._r[146]!, [_0]) } - public var Wallet_Sent_Title: String { return self._s[146]! } - public var TwoStepAuth_SetupPasswordConfirmPassword: String { return self._s[147]! } - public var Weekday_Today: String { return self._s[148]! } + public var Wallet_Sent_Title: String { return self._s[147]! } + public var TwoStepAuth_SetupPasswordConfirmPassword: String { return self._s[148]! } + public var Weekday_Today: String { return self._s[149]! } public func InstantPage_AuthorAndDateTitle(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[150]!, self._r[150]!, [_1, _2]) + return formatWithArgumentRanges(self._s[151]!, self._r[151]!, [_1, _2]) } public func Conversation_MessageDialogRetryAll(_ _1: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[151]!, self._r[151]!, ["\(_1)"]) + return formatWithArgumentRanges(self._s[152]!, self._r[152]!, ["\(_1)"]) } - public var Notification_PassportValuePersonalDetails: String { return self._s[153]! } - public var Channel_AdminLog_MessagePreviousLink: String { return self._s[154]! } - public var ChangePhoneNumberNumber_NewNumber: String { return self._s[155]! } - public var ApplyLanguage_LanguageNotSupportedError: String { return self._s[156]! } - public var TwoStepAuth_ChangePasswordDescription: String { return self._s[157]! } - public var PhotoEditor_BlurToolLinear: String { return self._s[158]! } - public var Contacts_PermissionsAllowInSettings: String { return self._s[159]! } - public var Weekday_ShortMonday: String { return self._s[160]! } - public var Cache_KeepMedia: String { return self._s[161]! } - public var Passport_FieldIdentitySelfieHelp: String { return self._s[162]! } + public var Notification_PassportValuePersonalDetails: String { return self._s[154]! } + public var Channel_AdminLog_MessagePreviousLink: String { return self._s[155]! } + public var ChangePhoneNumberNumber_NewNumber: String { return self._s[156]! } + public var ApplyLanguage_LanguageNotSupportedError: String { return self._s[157]! } + public var TwoStepAuth_ChangePasswordDescription: String { return self._s[158]! } + public var PhotoEditor_BlurToolLinear: String { return self._s[159]! } + public var Contacts_PermissionsAllowInSettings: String { return self._s[160]! } + public var Weekday_ShortMonday: String { return self._s[161]! } + public var Cache_KeepMedia: String { return self._s[162]! } + public var Passport_FieldIdentitySelfieHelp: String { return self._s[163]! } public func PUSH_PINNED_STICKER(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[163]!, self._r[163]!, [_1, _2]) + return formatWithArgumentRanges(self._s[164]!, self._r[164]!, [_1, _2]) } public func Chat_SlowmodeTooltip(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[164]!, self._r[164]!, [_0]) + return formatWithArgumentRanges(self._s[165]!, self._r[165]!, [_0]) } - public var Wallet_Receive_ShareUrlInfo: String { return self._s[165]! } - public var Conversation_ClousStorageInfo_Description4: String { return self._s[166]! } - public var Wallet_RestoreFailed_Title: String { return self._s[167]! } - public var Passport_Language_ru: String { return self._s[168]! } + public var Wallet_Receive_ShareUrlInfo: String { return self._s[166]! } + public var Conversation_ClousStorageInfo_Description4: String { return self._s[167]! } + public var Wallet_RestoreFailed_Title: String { return self._s[168]! } + public var Passport_Language_ru: String { return self._s[169]! } public func Notification_CreatedChatWithTitle(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[169]!, self._r[169]!, [_0, _1]) + return formatWithArgumentRanges(self._s[170]!, self._r[170]!, [_0, _1]) } - public var WallpaperPreview_PatternIntensity: String { return self._s[170]! } - public var WebBrowser_InAppSafari: String { return self._s[173]! } - public var TwoStepAuth_RecoveryUnavailable: String { return self._s[174]! } - public var EnterPasscode_TouchId: String { return self._s[175]! } - public var PhotoEditor_QualityVeryHigh: String { return self._s[178]! } - public var Checkout_NewCard_SaveInfo: String { return self._s[180]! } - public var Gif_NoGifsPlaceholder: String { return self._s[182]! } + public var WallpaperPreview_PatternIntensity: String { return self._s[171]! } + public var WebBrowser_InAppSafari: String { return self._s[174]! } + public var TwoStepAuth_RecoveryUnavailable: String { return self._s[175]! } + public var EnterPasscode_TouchId: String { return self._s[176]! } + public var PhotoEditor_QualityVeryHigh: String { return self._s[179]! } + public var Checkout_NewCard_SaveInfo: String { return self._s[181]! } + public var Gif_NoGifsPlaceholder: String { return self._s[183]! } public func Notification_InvitedMultiple(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[184]!, self._r[184]!, [_0, _1]) + return formatWithArgumentRanges(self._s[185]!, self._r[185]!, [_0, _1]) } - public var ChatSettings_AutoDownloadEnabled: String { return self._s[185]! } - public var NetworkUsageSettings_BytesSent: String { return self._s[186]! } - public var Checkout_PasswordEntry_Pay: String { return self._s[187]! } - public var AuthSessions_TerminateSession: String { return self._s[188]! } - public var Message_File: String { return self._s[189]! } - public var MediaPicker_VideoMuteDescription: String { return self._s[190]! } - public var SocksProxySetup_ProxyStatusConnected: String { return self._s[191]! } - public var TwoStepAuth_RecoveryCode: String { return self._s[192]! } - public var EnterPasscode_EnterCurrentPasscode: String { return self._s[193]! } + public var ChatSettings_AutoDownloadEnabled: String { return self._s[186]! } + public var NetworkUsageSettings_BytesSent: String { return self._s[187]! } + public var Checkout_PasswordEntry_Pay: String { return self._s[188]! } + public var AuthSessions_TerminateSession: String { return self._s[189]! } + public var Message_File: String { return self._s[190]! } + public var MediaPicker_VideoMuteDescription: String { return self._s[191]! } + public var SocksProxySetup_ProxyStatusConnected: String { return self._s[192]! } + public var TwoStepAuth_RecoveryCode: String { return self._s[193]! } + public var EnterPasscode_EnterCurrentPasscode: String { return self._s[194]! } public func TwoStepAuth_EnterPasswordHint(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[194]!, self._r[194]!, [_0]) - } - public var Conversation_Moderate_Report: String { return self._s[196]! } - public var TwoStepAuth_EmailInvalid: String { return self._s[197]! } - public var Passport_Language_ms: String { return self._s[198]! } - public var Channel_Edit_AboutItem: String { return self._s[200]! } - public var DialogList_SearchSectionGlobal: String { return self._s[204]! } - public var AttachmentMenu_WebSearch: String { return self._s[205]! } - public var PasscodeSettings_TurnPasscodeOn: String { return self._s[206]! } - public var Channel_BanUser_Title: String { return self._s[207]! } - public var WallpaperPreview_SwipeTopText: String { return self._s[208]! } - public var ChatList_DeleteSavedMessagesConfirmationText: String { return self._s[209]! } - public var ArchivedChats_IntroText2: String { return self._s[210]! } - public var Conversation_OpenBotLinkTitle: String { return self._s[211]! } - public var ChatSearch_SearchPlaceholder: String { return self._s[213]! } - public var Notification_Exceptions_DeleteAll: String { return self._s[214]! } - public var Passport_FieldAddressTranslationHelp: String { return self._s[215]! } - public var NotificationsSound_Aurora: String { return self._s[216]! } - public func Channel_AdminLog_MessageTransferedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[217]!, self._r[217]!, [_1, _2]) + return formatWithArgumentRanges(self._s[195]!, self._r[195]!, [_0]) } + public var Conversation_Moderate_Report: String { return self._s[197]! } + public var TwoStepAuth_EmailInvalid: String { return self._s[198]! } + public var Passport_Language_ms: String { return self._s[199]! } + public var Channel_Edit_AboutItem: String { return self._s[201]! } + public var DialogList_SearchSectionGlobal: String { return self._s[205]! } + public var AttachmentMenu_WebSearch: String { return self._s[206]! } + public var ChatState_WaitingForNetwork: String { return self._s[207]! } + public var Channel_BanUser_Title: String { return self._s[208]! } + public var PasscodeSettings_TurnPasscodeOn: String { return self._s[209]! } + public var WallpaperPreview_SwipeTopText: String { return self._s[210]! } + public var ChatList_DeleteSavedMessagesConfirmationText: String { return self._s[211]! } + public var ArchivedChats_IntroText2: String { return self._s[212]! } + public var ChatSearch_SearchPlaceholder: String { return self._s[214]! } + public var Conversation_OpenBotLinkTitle: String { return self._s[215]! } + public var Passport_FieldAddressTranslationHelp: String { return self._s[216]! } + public var NotificationsSound_Aurora: String { return self._s[217]! } + public var Notification_Exceptions_DeleteAll: String { return self._s[218]! } public func FileSize_GB(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[218]!, self._r[218]!, [_0]) + return formatWithArgumentRanges(self._s[219]!, self._r[219]!, [_0]) } - public var AuthSessions_LoggedInWithTelegram: String { return self._s[221]! } + public var AuthSessions_LoggedInWithTelegram: String { return self._s[222]! } public func Privacy_GroupsAndChannels_InviteToGroupError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[222]!, self._r[222]!, [_0, _1]) + return formatWithArgumentRanges(self._s[223]!, self._r[223]!, [_0, _1]) } - public var Passport_PasswordNext: String { return self._s[223]! } - public var Bot_GroupStatusReadsHistory: String { return self._s[224]! } - public var EmptyGroupInfo_Line2: String { return self._s[225]! } - public var VoiceOver_Chat_SeenByRecipients: String { return self._s[226]! } - public var Settings_FAQ_Intro: String { return self._s[229]! } - public var PrivacySettings_PasscodeAndTouchId: String { return self._s[231]! } - public var FeaturedStickerPacks_Title: String { return self._s[232]! } - public var TwoStepAuth_PasswordRemoveConfirmation: String { return self._s[234]! } - public var Username_Title: String { return self._s[235]! } + public var Passport_PasswordNext: String { return self._s[224]! } + public var Bot_GroupStatusReadsHistory: String { return self._s[225]! } + public var EmptyGroupInfo_Line2: String { return self._s[226]! } + public func Channel_AdminLog_MessageTransferedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[227]!, self._r[227]!, [_1, _2]) + } + public var VoiceOver_Chat_SeenByRecipients: String { return self._s[228]! } + public var Settings_FAQ_Intro: String { return self._s[231]! } + public var PrivacySettings_PasscodeAndTouchId: String { return self._s[233]! } + public var FeaturedStickerPacks_Title: String { return self._s[234]! } + public var TwoStepAuth_PasswordRemoveConfirmation: String { return self._s[236]! } + public var Username_Title: String { return self._s[237]! } public func Message_StickerText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[236]!, self._r[236]!, [_0]) + return formatWithArgumentRanges(self._s[238]!, self._r[238]!, [_0]) } - public var PasscodeSettings_AlphanumericCode: String { return self._s[237]! } - public var Localization_LanguageOther: String { return self._s[238]! } - public var Stickers_SuggestStickers: String { return self._s[239]! } + public var PasscodeSettings_AlphanumericCode: String { return self._s[239]! } + public var Localization_LanguageOther: String { return self._s[240]! } + public var Stickers_SuggestStickers: String { return self._s[241]! } public func Channel_AdminLog_MessageRemovedGroupUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[240]!, self._r[240]!, [_0]) + return formatWithArgumentRanges(self._s[242]!, self._r[242]!, [_0]) } - public var NotificationSettings_ShowNotificationsFromAccountsSection: String { return self._s[241]! } - public var Channel_AdminLogFilter_EventsAdmins: String { return self._s[242]! } - public var Conversation_DefaultRestrictedStickers: String { return self._s[243]! } + public var NotificationSettings_ShowNotificationsFromAccountsSection: String { return self._s[243]! } + public var Channel_AdminLogFilter_EventsAdmins: String { return self._s[244]! } + public var Conversation_DefaultRestrictedStickers: String { return self._s[245]! } public func Notification_PinnedDeletedMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[244]!, self._r[244]!, [_0]) + return formatWithArgumentRanges(self._s[246]!, self._r[246]!, [_0]) } - public var Wallet_TransactionInfo_CopyAddress: String { return self._s[246]! } - public var Group_UpgradeConfirmation: String { return self._s[247]! } - public var DialogList_Unpin: String { return self._s[248]! } - public var Passport_Identity_DateOfBirth: String { return self._s[249]! } - public var Month_ShortOctober: String { return self._s[250]! } - public var SettingsSearch_Synonyms_Privacy_Data_ContactsSync: String { return self._s[251]! } - public var TwoFactorSetup_Done_Text: String { return self._s[252]! } - public var Notification_CallCanceledShort: String { return self._s[253]! } - public var Conversation_StopQuiz: String { return self._s[254]! } - public var Passport_Phone_Help: String { return self._s[255]! } - public var Passport_Language_az: String { return self._s[257]! } - public var CreatePoll_TextPlaceholder: String { return self._s[259]! } - public var VoiceOver_Chat_AnonymousPoll: String { return self._s[260]! } - public var Passport_Identity_DocumentNumber: String { return self._s[261]! } - public var PhotoEditor_CurvesRed: String { return self._s[262]! } - public var PhoneNumberHelp_Alert: String { return self._s[264]! } - public var SocksProxySetup_Port: String { return self._s[265]! } - public var Checkout_PayNone: String { return self._s[266]! } - public var AutoDownloadSettings_WiFi: String { return self._s[267]! } - public var GroupInfo_GroupType: String { return self._s[268]! } - public var StickerSettings_ContextHide: String { return self._s[269]! } - public var Passport_Address_OneOfTypeTemporaryRegistration: String { return self._s[270]! } - public var Group_Setup_HistoryTitle: String { return self._s[272]! } - public var Passport_Identity_FilesUploadNew: String { return self._s[273]! } - public var PasscodeSettings_AutoLock: String { return self._s[274]! } - public var Passport_Title: String { return self._s[275]! } - public var VoiceOver_Chat_ContactPhoneNumber: String { return self._s[276]! } - public var Channel_AdminLogFilter_EventsNewSubscribers: String { return self._s[277]! } - public var GroupPermission_NoSendGifs: String { return self._s[278]! } - public var PrivacySettings_PasscodeOn: String { return self._s[279]! } + public var Wallet_TransactionInfo_CopyAddress: String { return self._s[248]! } + public var Group_UpgradeConfirmation: String { return self._s[249]! } + public var DialogList_Unpin: String { return self._s[250]! } + public var Passport_Identity_DateOfBirth: String { return self._s[251]! } + public var Month_ShortOctober: String { return self._s[252]! } + public var SettingsSearch_Synonyms_Privacy_Data_ContactsSync: String { return self._s[253]! } + public var TwoFactorSetup_Done_Text: String { return self._s[254]! } + public var Notification_CallCanceledShort: String { return self._s[255]! } + public var Conversation_StopQuiz: String { return self._s[256]! } + public var Passport_Phone_Help: String { return self._s[257]! } + public var Passport_Language_az: String { return self._s[259]! } + public var CreatePoll_TextPlaceholder: String { return self._s[261]! } + public var VoiceOver_Chat_AnonymousPoll: String { return self._s[262]! } + public var Passport_Identity_DocumentNumber: String { return self._s[263]! } + public var PhotoEditor_CurvesRed: String { return self._s[264]! } + public var PhoneNumberHelp_Alert: String { return self._s[266]! } + public var SocksProxySetup_Port: String { return self._s[267]! } + public var Checkout_PayNone: String { return self._s[268]! } + public var AutoDownloadSettings_WiFi: String { return self._s[269]! } + public var GroupInfo_GroupType: String { return self._s[270]! } + public var StickerSettings_ContextHide: String { return self._s[271]! } + public var Passport_Address_OneOfTypeTemporaryRegistration: String { return self._s[272]! } + public var Group_Setup_HistoryTitle: String { return self._s[274]! } + public var Passport_Identity_FilesUploadNew: String { return self._s[275]! } + public var PasscodeSettings_AutoLock: String { return self._s[276]! } + public var Passport_Title: String { return self._s[277]! } + public var VoiceOver_Chat_ContactPhoneNumber: String { return self._s[278]! } + public var Channel_AdminLogFilter_EventsNewSubscribers: String { return self._s[279]! } + public var GroupPermission_NoSendGifs: String { return self._s[280]! } + public var PrivacySettings_PasscodeOn: String { return self._s[281]! } public func Conversation_ScheduleMessage_SendTomorrow(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[280]!, self._r[280]!, [_0]) + return formatWithArgumentRanges(self._s[282]!, self._r[282]!, [_0]) } - public var State_WaitingForNetwork: String { return self._s[283]! } + public var State_WaitingForNetwork: String { return self._s[285]! } public func Notification_Invited(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[284]!, self._r[284]!, [_0, _1]) + return formatWithArgumentRanges(self._s[286]!, self._r[286]!, [_0, _1]) } - public var Calls_NotNow: String { return self._s[286]! } + public var Calls_NotNow: String { return self._s[288]! } public func Channel_DiscussionGroup_HeaderSet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[287]!, self._r[287]!, [_0]) + return formatWithArgumentRanges(self._s[289]!, self._r[289]!, [_0]) } - public var UserInfo_SendMessage: String { return self._s[288]! } - public var TwoStepAuth_PasswordSet: String { return self._s[289]! } - public var Passport_DeleteDocument: String { return self._s[290]! } - public var SocksProxySetup_AddProxyTitle: String { return self._s[291]! } + public var UserInfo_SendMessage: String { return self._s[290]! } + public var TwoStepAuth_PasswordSet: String { return self._s[291]! } + public var Passport_DeleteDocument: String { return self._s[292]! } + public var SocksProxySetup_AddProxyTitle: String { return self._s[293]! } public func PUSH_MESSAGE_VIDEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[292]!, self._r[292]!, [_1]) + return formatWithArgumentRanges(self._s[294]!, self._r[294]!, [_1]) } - public var AuthSessions_AddedDeviceTitle: String { return self._s[293]! } - public var GroupRemoved_Remove: String { return self._s[294]! } - public var Passport_FieldIdentity: String { return self._s[295]! } - public var Group_Setup_TypePrivateHelp: String { return self._s[296]! } - public var Conversation_Processing: String { return self._s[299]! } - public var Wallet_Settings_BackupWallet: String { return self._s[301]! } - public var ChatSettings_AutoPlayAnimations: String { return self._s[302]! } - public var AuthSessions_LogOutApplicationsHelp: String { return self._s[305]! } - public var Forward_ErrorPublicQuizDisabledInChannels: String { return self._s[306]! } - public var Month_GenFebruary: String { return self._s[307]! } - public var Wallet_Send_NetworkErrorTitle: String { return self._s[308]! } + public var AuthSessions_AddedDeviceTitle: String { return self._s[295]! } + public var GroupRemoved_Remove: String { return self._s[296]! } + public var Passport_FieldIdentity: String { return self._s[297]! } + public var Group_Setup_TypePrivateHelp: String { return self._s[298]! } + public var Conversation_Processing: String { return self._s[301]! } + public var Wallet_Settings_BackupWallet: String { return self._s[303]! } + public var ChatSettings_AutoPlayAnimations: String { return self._s[304]! } + public var AuthSessions_LogOutApplicationsHelp: String { return self._s[307]! } + public var Forward_ErrorPublicQuizDisabledInChannels: String { return self._s[308]! } + public var Month_GenFebruary: String { return self._s[309]! } + public var Wallet_Send_NetworkErrorTitle: String { return self._s[310]! } public func Login_InvalidPhoneEmailBody(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[310]!, self._r[310]!, [_1, _2, _3, _4, _5]) + return formatWithArgumentRanges(self._s[312]!, self._r[312]!, [_1, _2, _3, _4, _5]) } - public var Passport_Identity_TypeIdentityCard: String { return self._s[311]! } - public var Wallet_Month_ShortJune: String { return self._s[313]! } - public var AutoDownloadSettings_DataUsageMedium: String { return self._s[314]! } - public var GroupInfo_AddParticipant: String { return self._s[315]! } - public var KeyCommand_SendMessage: String { return self._s[316]! } - public var VoiceOver_Chat_YourContact: String { return self._s[318]! } - public var Map_LiveLocationShowAll: String { return self._s[319]! } - public var WallpaperSearch_ColorOrange: String { return self._s[321]! } - public var Appearance_AppIconDefaultX: String { return self._s[322]! } - public var Checkout_Receipt_Title: String { return self._s[323]! } - public var Group_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[324]! } - public var WallpaperPreview_PreviewTopText: String { return self._s[325]! } - public var Message_Contact: String { return self._s[326]! } - public var Call_StatusIncoming: String { return self._s[327]! } - public var Wallet_TransactionInfo_StorageFeeInfo: String { return self._s[328]! } + public var Passport_Identity_TypeIdentityCard: String { return self._s[313]! } + public var Wallet_Month_ShortJune: String { return self._s[315]! } + public var AutoDownloadSettings_DataUsageMedium: String { return self._s[316]! } + public var GroupInfo_AddParticipant: String { return self._s[317]! } + public var KeyCommand_SendMessage: String { return self._s[318]! } + public var VoiceOver_Chat_YourContact: String { return self._s[320]! } + public var Map_LiveLocationShowAll: String { return self._s[321]! } + public var WallpaperSearch_ColorOrange: String { return self._s[323]! } + public var Appearance_AppIconDefaultX: String { return self._s[324]! } + public var Checkout_Receipt_Title: String { return self._s[325]! } + public var Group_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[326]! } + public var WallpaperPreview_PreviewTopText: String { return self._s[327]! } + public var Message_Contact: String { return self._s[328]! } + public var Call_StatusIncoming: String { return self._s[329]! } + public var Wallet_TransactionInfo_StorageFeeInfo: String { return self._s[330]! } public func Channel_AdminLog_MessageKickedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[329]!, self._r[329]!, [_1]) - } - public func PUSH_ENCRYPTED_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[331]!, self._r[331]!, [_1]) } - public var VoiceOver_Media_PlaybackRate: String { return self._s[332]! } - public var Passport_FieldIdentityDetailsHelp: String { return self._s[333]! } - public var Conversation_ViewChannel: String { return self._s[334]! } + public func PUSH_ENCRYPTED_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[333]!, self._r[333]!, [_1]) + } + public var VoiceOver_Media_PlaybackRate: String { return self._s[334]! } + public var Passport_FieldIdentityDetailsHelp: String { return self._s[335]! } + public var Conversation_ViewChannel: String { return self._s[336]! } public func Time_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[335]!, self._r[335]!, [_0]) + return formatWithArgumentRanges(self._s[337]!, self._r[337]!, [_0]) } - public var Theme_Colors_Accent: String { return self._s[336]! } - public var Passport_Language_nl: String { return self._s[338]! } - public var Camera_Retake: String { return self._s[339]! } + public var Theme_Colors_Accent: String { return self._s[338]! } + public var Passport_Language_nl: String { return self._s[340]! } + public var Camera_Retake: String { return self._s[341]! } public func UserInfo_BlockActionTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[340]!, self._r[340]!, [_0]) + return formatWithArgumentRanges(self._s[342]!, self._r[342]!, [_0]) } - public var AuthSessions_LogOutApplications: String { return self._s[341]! } - public var ApplyLanguage_ApplySuccess: String { return self._s[342]! } - public var Tour_Title6: String { return self._s[343]! } - public var Map_ChooseAPlace: String { return self._s[344]! } - public var CallSettings_Never: String { return self._s[346]! } + public var AuthSessions_LogOutApplications: String { return self._s[343]! } + public var ApplyLanguage_ApplySuccess: String { return self._s[344]! } + public var Tour_Title6: String { return self._s[345]! } + public var Map_ChooseAPlace: String { return self._s[346]! } + public var CallSettings_Never: String { return self._s[348]! } public func Notification_ChangedGroupPhoto(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[347]!, self._r[347]!, [_0]) - } - public var ChannelRemoved_RemoveInfo: String { return self._s[348]! } - public func AutoDownloadSettings_PreloadVideoInfo(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[349]!, self._r[349]!, [_0]) } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsExceptions: String { return self._s[350]! } - public func Conversation_ClearChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { + public var ChannelRemoved_RemoveInfo: String { return self._s[350]! } + public func AutoDownloadSettings_PreloadVideoInfo(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[351]!, self._r[351]!, [_0]) } - public var GroupInfo_InviteLink_Title: String { return self._s[352]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsExceptions: String { return self._s[352]! } + public func Conversation_ClearChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[353]!, self._r[353]!, [_0]) + } + public var GroupInfo_InviteLink_Title: String { return self._s[354]! } public func Channel_AdminLog_MessageUnkickedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[353]!, self._r[353]!, [_1, _2]) + return formatWithArgumentRanges(self._s[355]!, self._r[355]!, [_1, _2]) } - public var KeyCommand_ScrollUp: String { return self._s[354]! } - public var ContactInfo_URLLabelHomepage: String { return self._s[355]! } - public var Channel_OwnershipTransfer_ChangeOwner: String { return self._s[356]! } + public var KeyCommand_ScrollUp: String { return self._s[356]! } + public var ContactInfo_URLLabelHomepage: String { return self._s[357]! } + public var Channel_OwnershipTransfer_ChangeOwner: String { return self._s[358]! } public func Channel_AdminLog_DisabledSlowmode(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[357]!, self._r[357]!, [_0]) - } - public var TwoFactorSetup_Done_Title: String { return self._s[358]! } - public func Conversation_EncryptedPlaceholderTitleOutgoing(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[359]!, self._r[359]!, [_0]) } - public var CallFeedback_ReasonDistortedSpeech: String { return self._s[360]! } - public var Watch_LastSeen_WithinAWeek: String { return self._s[361]! } - public var ContactList_Context_SendMessage: String { return self._s[363]! } - public var Weekday_Tuesday: String { return self._s[364]! } - public var Wallet_Created_Title: String { return self._s[366]! } - public var ScheduledMessages_Delete: String { return self._s[367]! } - public var UserInfo_StartSecretChat: String { return self._s[368]! } - public var Passport_Identity_FilesTitle: String { return self._s[369]! } - public var Permissions_NotificationsAllow_v0: String { return self._s[370]! } - public var DialogList_DeleteConversationConfirmation: String { return self._s[372]! } - public var ChatList_UndoArchiveRevealedTitle: String { return self._s[373]! } + public var TwoFactorSetup_Done_Title: String { return self._s[360]! } + public func Conversation_EncryptedPlaceholderTitleOutgoing(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[361]!, self._r[361]!, [_0]) + } + public var CallFeedback_ReasonDistortedSpeech: String { return self._s[362]! } + public var Watch_LastSeen_WithinAWeek: String { return self._s[363]! } + public var ContactList_Context_SendMessage: String { return self._s[365]! } + public var Weekday_Tuesday: String { return self._s[366]! } + public var Wallet_Created_Title: String { return self._s[368]! } + public var ScheduledMessages_Delete: String { return self._s[369]! } + public var UserInfo_StartSecretChat: String { return self._s[370]! } + public var Passport_Identity_FilesTitle: String { return self._s[371]! } + public var Permissions_NotificationsAllow_v0: String { return self._s[372]! } + public var DialogList_DeleteConversationConfirmation: String { return self._s[374]! } + public var ChatList_UndoArchiveRevealedTitle: String { return self._s[375]! } public func Wallet_Configuration_ApplyErrorTextURLUnreachable(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[374]!, self._r[374]!, [_0]) + return formatWithArgumentRanges(self._s[376]!, self._r[376]!, [_0]) } - public var AuthSessions_Sessions: String { return self._s[375]! } + public var AuthSessions_Sessions: String { return self._s[377]! } public func Settings_KeepPhoneNumber(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[377]!, self._r[377]!, [_0]) + return formatWithArgumentRanges(self._s[379]!, self._r[379]!, [_0]) } - public var TwoStepAuth_RecoveryEmailChangeDescription: String { return self._s[378]! } - public var Call_StatusWaiting: String { return self._s[379]! } - public var CreateGroup_SoftUserLimitAlert: String { return self._s[380]! } - public var FastTwoStepSetup_HintHelp: String { return self._s[381]! } - public var WallpaperPreview_CustomColorBottomText: String { return self._s[382]! } - public var EditTheme_Expand_Preview_OutgoingText: String { return self._s[383]! } - public var LogoutOptions_AddAccountText: String { return self._s[384]! } - public var PasscodeSettings_6DigitCode: String { return self._s[385]! } - public var Settings_LogoutConfirmationText: String { return self._s[386]! } - public var Passport_Identity_TypePassport: String { return self._s[388]! } - public var Map_Work: String { return self._s[391]! } + public var TwoStepAuth_RecoveryEmailChangeDescription: String { return self._s[380]! } + public var Call_StatusWaiting: String { return self._s[381]! } + public var CreateGroup_SoftUserLimitAlert: String { return self._s[382]! } + public var FastTwoStepSetup_HintHelp: String { return self._s[383]! } + public var WallpaperPreview_CustomColorBottomText: String { return self._s[384]! } + public var EditTheme_Expand_Preview_OutgoingText: String { return self._s[385]! } + public var LogoutOptions_AddAccountText: String { return self._s[386]! } + public var PasscodeSettings_6DigitCode: String { return self._s[387]! } + public var Settings_LogoutConfirmationText: String { return self._s[388]! } + public var Passport_Identity_TypePassport: String { return self._s[390]! } + public var Map_Work: String { return self._s[393]! } public func PUSH_MESSAGE_VIDEOS(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[392]!, self._r[392]!, [_1, _2]) + return formatWithArgumentRanges(self._s[394]!, self._r[394]!, [_1, _2]) } - public var SocksProxySetup_SaveProxy: String { return self._s[393]! } - public var AccessDenied_SaveMedia: String { return self._s[394]! } - public var Checkout_ErrorInvoiceAlreadyPaid: String { return self._s[396]! } - public var CreatePoll_MultipleChoice: String { return self._s[397]! } - public var Settings_Title: String { return self._s[399]! } - public var VoiceOver_Chat_RecordModeVideoMessageInfo: String { return self._s[400]! } - public var Contacts_InviteSearchLabel: String { return self._s[402]! } - public var PrivacySettings_WebSessions: String { return self._s[403]! } - public var ConvertToSupergroup_Title: String { return self._s[404]! } + public var SocksProxySetup_SaveProxy: String { return self._s[395]! } + public var AccessDenied_SaveMedia: String { return self._s[396]! } + public var Checkout_ErrorInvoiceAlreadyPaid: String { return self._s[398]! } + public var CreatePoll_MultipleChoice: String { return self._s[399]! } + public var Settings_Title: String { return self._s[401]! } + public var VoiceOver_Chat_RecordModeVideoMessageInfo: String { return self._s[402]! } + public var Contacts_InviteSearchLabel: String { return self._s[404]! } + public var PrivacySettings_WebSessions: String { return self._s[405]! } + public var ConvertToSupergroup_Title: String { return self._s[406]! } public func Channel_AdminLog_CaptionEdited(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[405]!, self._r[405]!, [_0]) + return formatWithArgumentRanges(self._s[407]!, self._r[407]!, [_0]) } - public var TwoFactorSetup_Hint_Text: String { return self._s[406]! } - public var InfoPlist_NSSiriUsageDescription: String { return self._s[407]! } + public var TwoFactorSetup_Hint_Text: String { return self._s[408]! } + public var InfoPlist_NSSiriUsageDescription: String { return self._s[409]! } public func PUSH_MESSAGE_CHANNEL_MESSAGE_GAME_SCORE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[408]!, self._r[408]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[410]!, self._r[410]!, [_1, _2, _3]) } - public var ChatSettings_AutomaticPhotoDownload: String { return self._s[409]! } - public var UserInfo_BotHelp: String { return self._s[410]! } - public var PrivacySettings_LastSeenEverybody: String { return self._s[411]! } - public var Checkout_Name: String { return self._s[412]! } - public var AutoDownloadSettings_DataUsage: String { return self._s[413]! } - public var Channel_BanUser_BlockFor: String { return self._s[414]! } - public var Checkout_ShippingAddress: String { return self._s[415]! } - public var AutoDownloadSettings_MaxVideoSize: String { return self._s[416]! } - public var Privacy_PaymentsClearInfoDoneHelp: String { return self._s[417]! } - public var Privacy_Forwards: String { return self._s[418]! } - public var Channel_BanUser_PermissionSendPolls: String { return self._s[419]! } - public var Appearance_ThemeCarouselNewNight: String { return self._s[420]! } + public var ChatSettings_AutomaticPhotoDownload: String { return self._s[411]! } + public var UserInfo_BotHelp: String { return self._s[412]! } + public var PrivacySettings_LastSeenEverybody: String { return self._s[413]! } + public var Checkout_Name: String { return self._s[414]! } + public var AutoDownloadSettings_DataUsage: String { return self._s[415]! } + public var Channel_BanUser_BlockFor: String { return self._s[416]! } + public var Checkout_ShippingAddress: String { return self._s[417]! } + public var AutoDownloadSettings_MaxVideoSize: String { return self._s[418]! } + public var Privacy_PaymentsClearInfoDoneHelp: String { return self._s[419]! } + public var Privacy_Forwards: String { return self._s[420]! } + public var Channel_BanUser_PermissionSendPolls: String { return self._s[421]! } + public var Appearance_ThemeCarouselNewNight: String { return self._s[422]! } public func SecretVideo_NotViewedYet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[423]!, self._r[423]!, [_0]) + return formatWithArgumentRanges(self._s[425]!, self._r[425]!, [_0]) } - public var Contacts_SortedByName: String { return self._s[424]! } - public var Group_OwnershipTransfer_Title: String { return self._s[425]! } - public var VoiceOver_Chat_OpenHint: String { return self._s[427]! } - public var Group_LeaveGroup: String { return self._s[428]! } - public var Settings_UsernameEmpty: String { return self._s[429]! } + public var Contacts_SortedByName: String { return self._s[426]! } + public var Group_OwnershipTransfer_Title: String { return self._s[427]! } + public var VoiceOver_Chat_OpenHint: String { return self._s[429]! } + public var Group_LeaveGroup: String { return self._s[430]! } + public var Settings_UsernameEmpty: String { return self._s[431]! } public func Notification_PinnedPollMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[430]!, self._r[430]!, [_0]) + return formatWithArgumentRanges(self._s[432]!, self._r[432]!, [_0]) } public func TwoStepAuth_ConfirmEmailDescription(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[431]!, self._r[431]!, [_1]) + return formatWithArgumentRanges(self._s[433]!, self._r[433]!, [_1]) } public func Channel_OwnershipTransfer_DescriptionInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[432]!, self._r[432]!, [_1, _2]) + return formatWithArgumentRanges(self._s[434]!, self._r[434]!, [_1, _2]) } - public var Message_ImageExpired: String { return self._s[433]! } - public var TwoStepAuth_RecoveryFailed: String { return self._s[435]! } - public var EditTheme_Edit_Preview_OutgoingText: String { return self._s[436]! } - public var UserInfo_AddToExisting: String { return self._s[437]! } - public var TwoStepAuth_EnabledSuccess: String { return self._s[438]! } - public var Wallet_Send_SyncInProgress: String { return self._s[439]! } - public var SettingsSearch_Synonyms_Appearance_ChatBackground_SetColor: String { return self._s[440]! } + public var Message_ImageExpired: String { return self._s[435]! } + public var TwoStepAuth_RecoveryFailed: String { return self._s[437]! } + public var EditTheme_Edit_Preview_OutgoingText: String { return self._s[438]! } + public var UserInfo_AddToExisting: String { return self._s[439]! } + public var TwoStepAuth_EnabledSuccess: String { return self._s[440]! } + public var Wallet_Send_SyncInProgress: String { return self._s[441]! } + public var SettingsSearch_Synonyms_Appearance_ChatBackground_SetColor: String { return self._s[442]! } public func PUSH_CHANNEL_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[441]!, self._r[441]!, [_1]) + return formatWithArgumentRanges(self._s[443]!, self._r[443]!, [_1]) } - public var Notifications_GroupNotificationsAlert: String { return self._s[442]! } - public var Passport_Language_km: String { return self._s[443]! } - public var SocksProxySetup_AdNoticeHelp: String { return self._s[445]! } - public var VoiceOver_Media_PlaybackPlay: String { return self._s[446]! } - public var Notification_CallMissedShort: String { return self._s[447]! } - public var Wallet_Info_YourBalance: String { return self._s[448]! } - public var ReportPeer_ReasonOther_Send: String { return self._s[449]! } - public var Watch_Compose_Send: String { return self._s[450]! } - public var Passport_Identity_TypeInternalPassportUploadScan: String { return self._s[453]! } - public var TwoFactorSetup_Email_Action: String { return self._s[454]! } - public var Conversation_HoldForVideo: String { return self._s[455]! } - public var Wallet_Configuration_ApplyErrorTextURLInvalidData: String { return self._s[456]! } - public var AuthSessions_OtherDevices: String { return self._s[457]! } - public var Wallet_TransactionInfo_CommentHeader: String { return self._s[458]! } - public var CheckoutInfo_ErrorCityInvalid: String { return self._s[460]! } - public var Appearance_AutoNightThemeDisabled: String { return self._s[462]! } - public var Channel_LinkItem: String { return self._s[463]! } + public var Notifications_GroupNotificationsAlert: String { return self._s[444]! } + public var Passport_Language_km: String { return self._s[445]! } + public var SocksProxySetup_AdNoticeHelp: String { return self._s[447]! } + public var VoiceOver_Media_PlaybackPlay: String { return self._s[448]! } + public var Notification_CallMissedShort: String { return self._s[449]! } + public var Wallet_Info_YourBalance: String { return self._s[450]! } + public var ReportPeer_ReasonOther_Send: String { return self._s[451]! } + public var Watch_Compose_Send: String { return self._s[452]! } + public var Passport_Identity_TypeInternalPassportUploadScan: String { return self._s[455]! } + public var TwoFactorSetup_Email_Action: String { return self._s[456]! } + public var Conversation_HoldForVideo: String { return self._s[457]! } + public var Wallet_Configuration_ApplyErrorTextURLInvalidData: String { return self._s[458]! } + public var AuthSessions_OtherDevices: String { return self._s[459]! } + public var Wallet_TransactionInfo_CommentHeader: String { return self._s[460]! } + public var CheckoutInfo_ErrorCityInvalid: String { return self._s[462]! } + public var Appearance_AutoNightThemeDisabled: String { return self._s[464]! } + public var Channel_LinkItem: String { return self._s[465]! } public func PrivacySettings_LastSeenContactsMinusPlus(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[464]!, self._r[464]!, [_0, _1]) + return formatWithArgumentRanges(self._s[466]!, self._r[466]!, [_0, _1]) } public func Passport_Identity_NativeNameTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[467]!, self._r[467]!, [_0]) + return formatWithArgumentRanges(self._s[469]!, self._r[469]!, [_0]) } - public var VoiceOver_Recording_StopAndPreview: String { return self._s[468]! } - public var Passport_Language_dv: String { return self._s[469]! } - public var Undo_LeftChannel: String { return self._s[470]! } - public var Notifications_ExceptionsMuted: String { return self._s[471]! } - public var ChatList_UnhideAction: String { return self._s[472]! } - public var Conversation_ContextMenuShare: String { return self._s[473]! } - public var Conversation_ContextMenuStickerPackInfo: String { return self._s[474]! } - public var ShareFileTip_Title: String { return self._s[475]! } - public var NotificationsSound_Chord: String { return self._s[476]! } - public var Wallet_TransactionInfo_OtherFeeHeader: String { return self._s[477]! } + public var VoiceOver_Recording_StopAndPreview: String { return self._s[470]! } + public var Passport_Language_dv: String { return self._s[471]! } + public var Undo_LeftChannel: String { return self._s[472]! } + public var Notifications_ExceptionsMuted: String { return self._s[473]! } + public var ChatList_UnhideAction: String { return self._s[474]! } + public var Conversation_ContextMenuShare: String { return self._s[475]! } + public var Conversation_ContextMenuStickerPackInfo: String { return self._s[476]! } + public var ShareFileTip_Title: String { return self._s[477]! } + public var NotificationsSound_Chord: String { return self._s[478]! } + public var Wallet_TransactionInfo_OtherFeeHeader: String { return self._s[479]! } public func PUSH_CHAT_RETURNED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[478]!, self._r[478]!, [_1, _2]) + return formatWithArgumentRanges(self._s[480]!, self._r[480]!, [_1, _2]) } - public var Passport_Address_EditTemporaryRegistration: String { return self._s[479]! } + public var Passport_Address_EditTemporaryRegistration: String { return self._s[481]! } public func Notification_Joined(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[480]!, self._r[480]!, [_0]) + return formatWithArgumentRanges(self._s[482]!, self._r[482]!, [_0]) } public func Wallet_Time_PreciseDate_m3(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[481]!, self._r[481]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[483]!, self._r[483]!, [_1, _2, _3]) } - public var Wallet_Settings_ConfigurationInfo: String { return self._s[482]! } - public var Wallpaper_ErrorNotFound: String { return self._s[483]! } - public var Notification_CallOutgoingShort: String { return self._s[485]! } - public var Wallet_WordImport_IncorrectText: String { return self._s[486]! } + public var Wallet_Settings_ConfigurationInfo: String { return self._s[484]! } + public var Wallpaper_ErrorNotFound: String { return self._s[485]! } + public var Notification_CallOutgoingShort: String { return self._s[487]! } + public var Wallet_WordImport_IncorrectText: String { return self._s[488]! } public func Watch_Time_ShortFullAt(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[487]!, self._r[487]!, [_1, _2]) + return formatWithArgumentRanges(self._s[489]!, self._r[489]!, [_1, _2]) } - public var Passport_Address_TypeUtilityBill: String { return self._s[488]! } - public var Privacy_Forwards_LinkIfAllowed: String { return self._s[489]! } - public var ReportPeer_Report: String { return self._s[490]! } - public var SettingsSearch_Synonyms_Proxy_Title: String { return self._s[491]! } - public var GroupInfo_DeactivatedStatus: String { return self._s[492]! } + public var Passport_Address_TypeUtilityBill: String { return self._s[490]! } + public var Privacy_Forwards_LinkIfAllowed: String { return self._s[491]! } + public var ReportPeer_Report: String { return self._s[492]! } + public var SettingsSearch_Synonyms_Proxy_Title: String { return self._s[493]! } + public var GroupInfo_DeactivatedStatus: String { return self._s[494]! } public func VoiceOver_Chat_MusicTitle(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[493]!, self._r[493]!, [_1, _2]) + return formatWithArgumentRanges(self._s[495]!, self._r[495]!, [_1, _2]) } - public var StickerPack_Send: String { return self._s[494]! } - public var Login_CodeSentInternal: String { return self._s[495]! } - public var Wallet_Month_GenJanuary: String { return self._s[496]! } - public var GroupInfo_InviteLink_LinkSection: String { return self._s[497]! } + public var StickerPack_Send: String { return self._s[496]! } + public var Login_CodeSentInternal: String { return self._s[497]! } + public var Wallet_Month_GenJanuary: String { return self._s[498]! } + public var GroupInfo_InviteLink_LinkSection: String { return self._s[499]! } public func Channel_AdminLog_MessageDeleted(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[498]!, self._r[498]!, [_0]) - } - public func Conversation_EncryptionWaiting(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[500]!, self._r[500]!, [_0]) } - public var Channel_BanUser_PermissionSendStickersAndGifs: String { return self._s[501]! } - public func PUSH_PINNED_GAME(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[502]!, self._r[502]!, [_1]) + public func Conversation_EncryptionWaiting(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[502]!, self._r[502]!, [_0]) } - public var ReportPeer_ReasonViolence: String { return self._s[504]! } - public var Appearance_ShareThemeColor: String { return self._s[505]! } - public var Map_Locating: String { return self._s[506]! } + public var Channel_BanUser_PermissionSendStickersAndGifs: String { return self._s[503]! } + public func PUSH_PINNED_GAME(_ _1: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[504]!, self._r[504]!, [_1]) + } + public var ReportPeer_ReasonViolence: String { return self._s[506]! } + public var Appearance_ShareThemeColor: String { return self._s[507]! } + public var Map_Locating: String { return self._s[508]! } public func VoiceOver_Chat_VideoFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[507]!, self._r[507]!, [_0]) + return formatWithArgumentRanges(self._s[509]!, self._r[509]!, [_0]) } public func PUSH_ALBUM(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[508]!, self._r[508]!, [_1]) + return formatWithArgumentRanges(self._s[510]!, self._r[510]!, [_1]) } - public var AutoDownloadSettings_GroupChats: String { return self._s[510]! } - public var CheckoutInfo_SaveInfo: String { return self._s[511]! } - public var SharedMedia_EmptyLinksText: String { return self._s[513]! } - public var Passport_Address_CityPlaceholder: String { return self._s[514]! } - public var CheckoutInfo_ErrorStateInvalid: String { return self._s[515]! } - public var Privacy_ProfilePhoto_CustomHelp: String { return self._s[516]! } - public var Wallet_Send_OwnAddressAlertTitle: String { return self._s[518]! } - public var Channel_AdminLog_CanAddAdmins: String { return self._s[519]! } + public var AutoDownloadSettings_GroupChats: String { return self._s[512]! } + public var CheckoutInfo_SaveInfo: String { return self._s[513]! } + public var SharedMedia_EmptyLinksText: String { return self._s[515]! } + public var Passport_Address_CityPlaceholder: String { return self._s[516]! } + public var CheckoutInfo_ErrorStateInvalid: String { return self._s[517]! } + public var Privacy_ProfilePhoto_CustomHelp: String { return self._s[518]! } + public var Wallet_Send_OwnAddressAlertTitle: String { return self._s[520]! } + public var Channel_AdminLog_CanAddAdmins: String { return self._s[521]! } public func PUSH_CHANNEL_MESSAGE_FWD(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[520]!, self._r[520]!, [_1]) + return formatWithArgumentRanges(self._s[522]!, self._r[522]!, [_1]) } public func Time_MonthOfYear_m8(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[521]!, self._r[521]!, [_0]) + return formatWithArgumentRanges(self._s[523]!, self._r[523]!, [_0]) } - public var InfoPlist_NSLocationWhenInUseUsageDescription: String { return self._s[522]! } - public var GroupInfo_InviteLink_RevokeAlert_Success: String { return self._s[523]! } - public var ChangePhoneNumberCode_Code: String { return self._s[524]! } - public var Appearance_CreateTheme: String { return self._s[525]! } + public var InfoPlist_NSLocationWhenInUseUsageDescription: String { return self._s[524]! } + public var GroupInfo_InviteLink_RevokeAlert_Success: String { return self._s[525]! } + public var ChangePhoneNumberCode_Code: String { return self._s[526]! } + public var Appearance_CreateTheme: String { return self._s[527]! } public func UserInfo_NotificationsDefaultSound(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[526]!, self._r[526]!, [_0]) + return formatWithArgumentRanges(self._s[528]!, self._r[528]!, [_0]) } - public var TwoStepAuth_SetupEmail: String { return self._s[527]! } - public var HashtagSearch_AllChats: String { return self._s[528]! } - public var MediaPlayer_UnknownTrack: String { return self._s[529]! } - public var SettingsSearch_Synonyms_Data_AutoDownloadUsingCellular: String { return self._s[531]! } + public var TwoStepAuth_SetupEmail: String { return self._s[529]! } + public var HashtagSearch_AllChats: String { return self._s[530]! } + public var MediaPlayer_UnknownTrack: String { return self._s[531]! } + public var SettingsSearch_Synonyms_Data_AutoDownloadUsingCellular: String { return self._s[533]! } public func ChatList_DeleteForEveryone(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[532]!, self._r[532]!, [_0]) + return formatWithArgumentRanges(self._s[534]!, self._r[534]!, [_0]) } - public var PhotoEditor_QualityHigh: String { return self._s[534]! } + public var PhotoEditor_QualityHigh: String { return self._s[536]! } public func Passport_Phone_UseTelegramNumber(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[535]!, self._r[535]!, [_0]) + return formatWithArgumentRanges(self._s[537]!, self._r[537]!, [_0]) } - public var ApplyLanguage_ApplyLanguageAction: String { return self._s[536]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsPreview: String { return self._s[537]! } - public var Message_LiveLocation: String { return self._s[538]! } - public var Cache_LowDiskSpaceText: String { return self._s[539]! } - public var Wallet_Receive_ShareAddress: String { return self._s[540]! } - public var EditTheme_ErrorLinkTaken: String { return self._s[541]! } - public var Conversation_SendMessage: String { return self._s[542]! } - public var AuthSessions_EmptyTitle: String { return self._s[543]! } - public var Privacy_PhoneNumber: String { return self._s[544]! } - public var PeopleNearby_CreateGroup: String { return self._s[545]! } - public var CallSettings_UseLessData: String { return self._s[546]! } - public var NetworkUsageSettings_MediaDocumentDataSection: String { return self._s[547]! } - public var Stickers_AddToFavorites: String { return self._s[548]! } - public var Wallet_WordImport_Title: String { return self._s[549]! } - public var PhotoEditor_QualityLow: String { return self._s[550]! } - public var Watch_UserInfo_Unblock: String { return self._s[551]! } - public var Settings_Logout: String { return self._s[552]! } + public var ApplyLanguage_ApplyLanguageAction: String { return self._s[538]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsPreview: String { return self._s[539]! } + public var Message_LiveLocation: String { return self._s[540]! } + public var Cache_LowDiskSpaceText: String { return self._s[541]! } + public var Wallet_Receive_ShareAddress: String { return self._s[542]! } + public var EditTheme_ErrorLinkTaken: String { return self._s[543]! } + public var Conversation_SendMessage: String { return self._s[544]! } + public var AuthSessions_EmptyTitle: String { return self._s[545]! } + public var Privacy_PhoneNumber: String { return self._s[546]! } + public var PeopleNearby_CreateGroup: String { return self._s[547]! } + public var CallSettings_UseLessData: String { return self._s[548]! } + public var NetworkUsageSettings_MediaDocumentDataSection: String { return self._s[549]! } + public var Stickers_AddToFavorites: String { return self._s[550]! } + public var Wallet_WordImport_Title: String { return self._s[551]! } + public var PhotoEditor_QualityLow: String { return self._s[552]! } + public var Watch_UserInfo_Unblock: String { return self._s[553]! } + public var Settings_Logout: String { return self._s[554]! } public func PUSH_MESSAGE_ROUND(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[553]!, self._r[553]!, [_1]) + return formatWithArgumentRanges(self._s[555]!, self._r[555]!, [_1]) } - public var ContactInfo_PhoneLabelWork: String { return self._s[554]! } - public var ChannelInfo_Stats: String { return self._s[555]! } - public var TextFormat_Link: String { return self._s[556]! } + public var ContactInfo_PhoneLabelWork: String { return self._s[556]! } + public var ChannelInfo_Stats: String { return self._s[557]! } + public var TextFormat_Link: String { return self._s[558]! } public func Date_ChatDateHeader(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[557]!, self._r[557]!, [_1, _2]) + return formatWithArgumentRanges(self._s[559]!, self._r[559]!, [_1, _2]) } - public var Wallet_TransactionInfo_Title: String { return self._s[558]! } + public var Wallet_TransactionInfo_Title: String { return self._s[560]! } public func Message_ForwardedMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[559]!, self._r[559]!, [_0]) + return formatWithArgumentRanges(self._s[561]!, self._r[561]!, [_0]) } - public var Watch_Notification_Joined: String { return self._s[560]! } - public var Group_Setup_TypePublicHelp: String { return self._s[561]! } - public var Passport_Scans_UploadNew: String { return self._s[562]! } - public var Checkout_LiabilityAlertTitle: String { return self._s[563]! } - public var DialogList_Title: String { return self._s[566]! } - public var NotificationSettings_ContactJoined: String { return self._s[567]! } - public var GroupInfo_LabelAdmin: String { return self._s[568]! } - public var KeyCommand_ChatInfo: String { return self._s[569]! } - public var Conversation_EditingCaptionPanelTitle: String { return self._s[570]! } - public var Call_ReportIncludeLog: String { return self._s[571]! } + public var Watch_Notification_Joined: String { return self._s[562]! } + public var Group_Setup_TypePublicHelp: String { return self._s[563]! } + public var Passport_Scans_UploadNew: String { return self._s[564]! } + public var Checkout_LiabilityAlertTitle: String { return self._s[565]! } + public var DialogList_Title: String { return self._s[568]! } + public var NotificationSettings_ContactJoined: String { return self._s[569]! } + public var GroupInfo_LabelAdmin: String { return self._s[570]! } + public var KeyCommand_ChatInfo: String { return self._s[571]! } + public var Conversation_EditingCaptionPanelTitle: String { return self._s[572]! } + public var Call_ReportIncludeLog: String { return self._s[573]! } public func Notifications_ExceptionsChangeSound(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[574]!, self._r[574]!, [_0]) + return formatWithArgumentRanges(self._s[576]!, self._r[576]!, [_0]) } - public var Channel_AdminLog_InfoPanelChannelAlertText: String { return self._s[575]! } - public var ChatAdmins_AllMembersAreAdmins: String { return self._s[576]! } - public var LocalGroup_IrrelevantWarning: String { return self._s[577]! } - public var Conversation_DefaultRestrictedInline: String { return self._s[578]! } - public var Message_Sticker: String { return self._s[579]! } - public var LastSeen_JustNow: String { return self._s[581]! } - public var Passport_Email_EmailPlaceholder: String { return self._s[583]! } - public var SettingsSearch_Synonyms_AppLanguage: String { return self._s[584]! } - public var Channel_AdminLogFilter_EventsEditedMessages: String { return self._s[585]! } - public var Channel_EditAdmin_PermissionsHeader: String { return self._s[586]! } - public var TwoStepAuth_Email: String { return self._s[587]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsSound: String { return self._s[588]! } - public var PhotoEditor_BlurToolOff: String { return self._s[589]! } - public var Message_PinnedStickerMessage: String { return self._s[590]! } - public var ContactInfo_PhoneLabelPager: String { return self._s[591]! } - public var SettingsSearch_Synonyms_Appearance_TextSize: String { return self._s[592]! } - public var Passport_DiscardMessageTitle: String { return self._s[593]! } - public var Privacy_PaymentsTitle: String { return self._s[594]! } - public var EditTheme_Edit_Preview_IncomingReplyName: String { return self._s[595]! } - public var ClearCache_StorageCache: String { return self._s[596]! } - public var Appearance_TextSizeSetting: String { return self._s[597]! } - public var Channel_DiscussionGroup_Header: String { return self._s[599]! } - public var VoiceOver_Chat_OptionSelected: String { return self._s[600]! } - public var Appearance_ColorTheme: String { return self._s[601]! } - public var UserInfo_ShareContact: String { return self._s[602]! } - public var Passport_Address_TypePassportRegistration: String { return self._s[603]! } - public var Common_More: String { return self._s[604]! } - public var Watch_Message_Call: String { return self._s[605]! } - public var Profile_EncryptionKey: String { return self._s[608]! } - public var Privacy_TopPeers: String { return self._s[609]! } - public var Conversation_StopPollConfirmation: String { return self._s[610]! } - public var Wallet_Words_NotDoneText: String { return self._s[612]! } - public var Privacy_TopPeersWarning: String { return self._s[614]! } - public var SettingsSearch_Synonyms_Data_DownloadInBackground: String { return self._s[615]! } - public var SettingsSearch_Synonyms_Data_Storage_KeepMedia: String { return self._s[616]! } - public var Wallet_RestoreFailed_EnterWords: String { return self._s[619]! } - public var DialogList_SearchSectionMessages: String { return self._s[620]! } - public var Notifications_ChannelNotifications: String { return self._s[621]! } - public var CheckoutInfo_ShippingInfoAddress1Placeholder: String { return self._s[622]! } - public var Passport_Language_sk: String { return self._s[623]! } - public var Notification_MessageLifetime1h: String { return self._s[624]! } - public var Wallpaper_ResetWallpapersInfo: String { return self._s[625]! } - public var Appearance_ThemePreview_Chat_5_Text: String { return self._s[626]! } - public var Call_ReportSkip: String { return self._s[628]! } - public var Cache_ServiceFiles: String { return self._s[629]! } - public var Group_ErrorAddTooMuchAdmins: String { return self._s[630]! } - public var VoiceOver_Chat_YourFile: String { return self._s[631]! } - public var Map_Hybrid: String { return self._s[632]! } - public var Contacts_SearchUsersAndGroupsLabel: String { return self._s[634]! } + public var Channel_AdminLog_InfoPanelChannelAlertText: String { return self._s[577]! } + public var ChatAdmins_AllMembersAreAdmins: String { return self._s[578]! } + public var LocalGroup_IrrelevantWarning: String { return self._s[579]! } + public var Conversation_DefaultRestrictedInline: String { return self._s[580]! } + public var Message_Sticker: String { return self._s[581]! } + public var LastSeen_JustNow: String { return self._s[583]! } + public var Passport_Email_EmailPlaceholder: String { return self._s[585]! } + public var SettingsSearch_Synonyms_AppLanguage: String { return self._s[586]! } + public var Channel_AdminLogFilter_EventsEditedMessages: String { return self._s[587]! } + public var Channel_EditAdmin_PermissionsHeader: String { return self._s[588]! } + public var TwoStepAuth_Email: String { return self._s[589]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsSound: String { return self._s[590]! } + public var PhotoEditor_BlurToolOff: String { return self._s[591]! } + public var Message_PinnedStickerMessage: String { return self._s[592]! } + public var ContactInfo_PhoneLabelPager: String { return self._s[593]! } + public var SettingsSearch_Synonyms_Appearance_TextSize: String { return self._s[594]! } + public var Passport_DiscardMessageTitle: String { return self._s[595]! } + public var Privacy_PaymentsTitle: String { return self._s[596]! } + public var EditTheme_Edit_Preview_IncomingReplyName: String { return self._s[597]! } + public var ClearCache_StorageCache: String { return self._s[598]! } + public var Appearance_TextSizeSetting: String { return self._s[599]! } + public var Channel_DiscussionGroup_Header: String { return self._s[601]! } + public var VoiceOver_Chat_OptionSelected: String { return self._s[602]! } + public var Appearance_ColorTheme: String { return self._s[603]! } + public var UserInfo_ShareContact: String { return self._s[604]! } + public var Passport_Address_TypePassportRegistration: String { return self._s[605]! } + public var Common_More: String { return self._s[606]! } + public var Watch_Message_Call: String { return self._s[607]! } + public var Profile_EncryptionKey: String { return self._s[610]! } + public var Privacy_TopPeers: String { return self._s[611]! } + public var Conversation_StopPollConfirmation: String { return self._s[612]! } + public var Wallet_Words_NotDoneText: String { return self._s[614]! } + public var Privacy_TopPeersWarning: String { return self._s[616]! } + public var SettingsSearch_Synonyms_Data_DownloadInBackground: String { return self._s[617]! } + public var SettingsSearch_Synonyms_Data_Storage_KeepMedia: String { return self._s[618]! } + public var Wallet_RestoreFailed_EnterWords: String { return self._s[621]! } + public var DialogList_SearchSectionMessages: String { return self._s[622]! } + public var Notifications_ChannelNotifications: String { return self._s[623]! } + public var CheckoutInfo_ShippingInfoAddress1Placeholder: String { return self._s[624]! } + public var Passport_Language_sk: String { return self._s[625]! } + public var Notification_MessageLifetime1h: String { return self._s[626]! } + public var Wallpaper_ResetWallpapersInfo: String { return self._s[627]! } + public var Appearance_ThemePreview_Chat_5_Text: String { return self._s[628]! } + public var Call_ReportSkip: String { return self._s[630]! } + public var Cache_ServiceFiles: String { return self._s[631]! } + public var Group_ErrorAddTooMuchAdmins: String { return self._s[632]! } + public var VoiceOver_Chat_YourFile: String { return self._s[633]! } + public var Map_Hybrid: String { return self._s[634]! } + public var Contacts_SearchUsersAndGroupsLabel: String { return self._s[636]! } public func PUSH_MESSAGE_QUIZ(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[635]!, self._r[635]!, [_1]) + return formatWithArgumentRanges(self._s[637]!, self._r[637]!, [_1]) } - public var ChatSettings_AutoDownloadVideos: String { return self._s[637]! } - public var Channel_BanUser_PermissionEmbedLinks: String { return self._s[638]! } - public var InfoPlist_NSLocationAlwaysAndWhenInUseUsageDescription: String { return self._s[639]! } - public var SocksProxySetup_ProxyTelegram: String { return self._s[642]! } + public var ChatSettings_AutoDownloadVideos: String { return self._s[639]! } + public var Channel_BanUser_PermissionEmbedLinks: String { return self._s[640]! } + public var InfoPlist_NSLocationAlwaysAndWhenInUseUsageDescription: String { return self._s[641]! } + public var SocksProxySetup_ProxyTelegram: String { return self._s[644]! } public func PUSH_MESSAGE_AUDIO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[643]!, self._r[643]!, [_1]) + return formatWithArgumentRanges(self._s[645]!, self._r[645]!, [_1]) } - public var Channel_Username_CreatePrivateLinkHelp: String { return self._s[645]! } - public var ScheduledMessages_ScheduledToday: String { return self._s[646]! } + public var Channel_Username_CreatePrivateLinkHelp: String { return self._s[647]! } + public var ScheduledMessages_ScheduledToday: String { return self._s[648]! } public func PUSH_CHAT_TITLE_EDITED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[647]!, self._r[647]!, [_1, _2]) + return formatWithArgumentRanges(self._s[649]!, self._r[649]!, [_1, _2]) } - public var Conversation_LiveLocationYou: String { return self._s[648]! } - public var SettingsSearch_Synonyms_Privacy_Calls: String { return self._s[649]! } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsPreview: String { return self._s[650]! } - public var UserInfo_ShareBot: String { return self._s[653]! } + public var Conversation_LiveLocationYou: String { return self._s[650]! } + public var SettingsSearch_Synonyms_Privacy_Calls: String { return self._s[651]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsPreview: String { return self._s[652]! } + public var UserInfo_ShareBot: String { return self._s[655]! } public func PUSH_AUTH_REGION(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[654]!, self._r[654]!, [_1, _2]) + return formatWithArgumentRanges(self._s[656]!, self._r[656]!, [_1, _2]) } - public var Conversation_ClearCache: String { return self._s[655]! } - public var PhotoEditor_ShadowsTint: String { return self._s[656]! } - public var Message_Audio: String { return self._s[657]! } - public var Passport_Language_lt: String { return self._s[658]! } + public var Conversation_ClearCache: String { return self._s[657]! } + public var PhotoEditor_ShadowsTint: String { return self._s[658]! } + public var Message_Audio: String { return self._s[659]! } + public var Passport_Language_lt: String { return self._s[660]! } public func Message_PinnedTextMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[659]!, self._r[659]!, [_0]) + return formatWithArgumentRanges(self._s[661]!, self._r[661]!, [_0]) } - public var Permissions_SiriText_v0: String { return self._s[660]! } - public var Conversation_FileICloudDrive: String { return self._s[661]! } - public var ChatList_DeleteForEveryoneConfirmationTitle: String { return self._s[662]! } - public var Notifications_Badge_IncludeMutedChats: String { return self._s[663]! } + public var Permissions_SiriText_v0: String { return self._s[662]! } + public var Conversation_FileICloudDrive: String { return self._s[663]! } + public var ChatList_DeleteForEveryoneConfirmationTitle: String { return self._s[664]! } + public var Notifications_Badge_IncludeMutedChats: String { return self._s[665]! } public func Notification_NewAuthDetected(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String, _ _6: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[664]!, self._r[664]!, [_1, _2, _3, _4, _5, _6]) + return formatWithArgumentRanges(self._s[666]!, self._r[666]!, [_1, _2, _3, _4, _5, _6]) } - public var DialogList_ProxyConnectionIssuesTooltip: String { return self._s[665]! } + public var DialogList_ProxyConnectionIssuesTooltip: String { return self._s[667]! } public func Time_MonthOfYear_m5(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[666]!, self._r[666]!, [_0]) + return formatWithArgumentRanges(self._s[668]!, self._r[668]!, [_0]) } - public var Channel_SignMessages: String { return self._s[667]! } + public var Channel_SignMessages: String { return self._s[669]! } public func PUSH_MESSAGE_NOTEXT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[668]!, self._r[668]!, [_1]) + return formatWithArgumentRanges(self._s[670]!, self._r[670]!, [_1]) } - public var Compose_ChannelTokenListPlaceholder: String { return self._s[669]! } - public var Passport_ScanPassport: String { return self._s[670]! } - public var Watch_Suggestion_Thanks: String { return self._s[671]! } - public var BlockedUsers_AddNew: String { return self._s[672]! } + public var Compose_ChannelTokenListPlaceholder: String { return self._s[671]! } + public var Passport_ScanPassport: String { return self._s[672]! } + public var Watch_Suggestion_Thanks: String { return self._s[673]! } + public var BlockedUsers_AddNew: String { return self._s[674]! } public func PUSH_CHAT_MESSAGE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[673]!, self._r[673]!, [_1, _2]) + return formatWithArgumentRanges(self._s[675]!, self._r[675]!, [_1, _2]) } - public var Watch_Message_Invoice: String { return self._s[674]! } - public var SettingsSearch_Synonyms_Privacy_LastSeen: String { return self._s[675]! } - public var Month_GenJuly: String { return self._s[676]! } - public var CreatePoll_QuizInfo: String { return self._s[677]! } - public var UserInfo_StartSecretChatStart: String { return self._s[678]! } - public var SocksProxySetup_ProxySocks5: String { return self._s[679]! } - public var IntentsSettings_SuggestByShare: String { return self._s[681]! } - public var Notification_Exceptions_DeleteAllConfirmation: String { return self._s[682]! } - public var Notification_ChannelInviterSelf: String { return self._s[683]! } - public var CheckoutInfo_ReceiverInfoEmail: String { return self._s[684]! } + public var Watch_Message_Invoice: String { return self._s[676]! } + public var SettingsSearch_Synonyms_Privacy_LastSeen: String { return self._s[677]! } + public var Month_GenJuly: String { return self._s[678]! } + public var CreatePoll_QuizInfo: String { return self._s[679]! } + public var UserInfo_StartSecretChatStart: String { return self._s[680]! } + public var SocksProxySetup_ProxySocks5: String { return self._s[681]! } + public var IntentsSettings_SuggestByShare: String { return self._s[683]! } + public var Notification_Exceptions_DeleteAllConfirmation: String { return self._s[684]! } + public var Notification_ChannelInviterSelf: String { return self._s[685]! } + public var CheckoutInfo_ReceiverInfoEmail: String { return self._s[686]! } public func ApplyLanguage_ChangeLanguageUnofficialText(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[685]!, self._r[685]!, [_1, _2]) + return formatWithArgumentRanges(self._s[687]!, self._r[687]!, [_1, _2]) } - public var CheckoutInfo_Title: String { return self._s[686]! } - public var Watch_Stickers_RecentPlaceholder: String { return self._s[687]! } + public var CheckoutInfo_Title: String { return self._s[688]! } + public var Watch_Stickers_RecentPlaceholder: String { return self._s[689]! } public func Map_DistanceAway(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[688]!, self._r[688]!, [_0]) + return formatWithArgumentRanges(self._s[690]!, self._r[690]!, [_0]) } - public var Passport_Identity_MainPage: String { return self._s[689]! } - public var TwoStepAuth_ConfirmEmailResendCode: String { return self._s[690]! } - public var Passport_Language_de: String { return self._s[691]! } - public var Update_Title: String { return self._s[692]! } - public var ContactInfo_PhoneLabelWorkFax: String { return self._s[693]! } - public var Channel_AdminLog_BanEmbedLinks: String { return self._s[694]! } - public var Passport_Email_UseTelegramEmailHelp: String { return self._s[695]! } - public var Notifications_ChannelNotificationsPreview: String { return self._s[696]! } - public var NotificationsSound_Telegraph: String { return self._s[697]! } - public var Watch_LastSeen_ALongTimeAgo: String { return self._s[698]! } - public var ChannelMembers_WhoCanAddMembers: String { return self._s[699]! } + public var Passport_Identity_MainPage: String { return self._s[691]! } + public var TwoStepAuth_ConfirmEmailResendCode: String { return self._s[692]! } + public var Passport_Language_de: String { return self._s[693]! } + public var Update_Title: String { return self._s[694]! } + public var ContactInfo_PhoneLabelWorkFax: String { return self._s[695]! } + public var Channel_AdminLog_BanEmbedLinks: String { return self._s[696]! } + public var Passport_Email_UseTelegramEmailHelp: String { return self._s[697]! } + public var Notifications_ChannelNotificationsPreview: String { return self._s[698]! } + public var NotificationsSound_Telegraph: String { return self._s[699]! } + public var Watch_LastSeen_ALongTimeAgo: String { return self._s[700]! } + public var ChannelMembers_WhoCanAddMembers: String { return self._s[701]! } public func AutoDownloadSettings_UpTo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[700]!, self._r[700]!, [_0]) + return formatWithArgumentRanges(self._s[702]!, self._r[702]!, [_0]) } - public var ClearCache_Description: String { return self._s[701]! } - public var Stickers_SuggestAll: String { return self._s[702]! } - public var Conversation_ForwardTitle: String { return self._s[703]! } - public var Appearance_ThemePreview_ChatList_7_Name: String { return self._s[704]! } + public var ClearCache_Description: String { return self._s[703]! } + public var Stickers_SuggestAll: String { return self._s[704]! } + public var Conversation_ForwardTitle: String { return self._s[705]! } + public var Appearance_ThemePreview_ChatList_7_Name: String { return self._s[706]! } public func Notification_JoinedChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[705]!, self._r[705]!, [_0]) + return formatWithArgumentRanges(self._s[707]!, self._r[707]!, [_0]) } - public var Calls_NewCall: String { return self._s[706]! } - public var Call_StatusEnded: String { return self._s[707]! } - public var AutoDownloadSettings_DataUsageLow: String { return self._s[708]! } - public var Settings_ProxyConnected: String { return self._s[709]! } - public var Channel_AdminLogFilter_EventsPinned: String { return self._s[710]! } - public var PhotoEditor_QualityVeryLow: String { return self._s[711]! } - public var Channel_AdminLogFilter_EventsDeletedMessages: String { return self._s[712]! } - public var Passport_PasswordPlaceholder: String { return self._s[713]! } - public var Message_PinnedInvoice: String { return self._s[714]! } - public var Passport_Identity_IssueDate: String { return self._s[715]! } - public var Passport_Language_pl: String { return self._s[716]! } + public var Calls_NewCall: String { return self._s[708]! } + public var Call_StatusEnded: String { return self._s[709]! } + public var AutoDownloadSettings_DataUsageLow: String { return self._s[710]! } + public var Settings_ProxyConnected: String { return self._s[711]! } + public var Channel_AdminLogFilter_EventsPinned: String { return self._s[712]! } + public var PhotoEditor_QualityVeryLow: String { return self._s[713]! } + public var Channel_AdminLogFilter_EventsDeletedMessages: String { return self._s[714]! } + public var Passport_PasswordPlaceholder: String { return self._s[715]! } + public var Message_PinnedInvoice: String { return self._s[716]! } + public var Passport_Identity_IssueDate: String { return self._s[717]! } + public var Passport_Language_pl: String { return self._s[718]! } public func ChannelInfo_ChannelForbidden(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[717]!, self._r[717]!, [_0]) + return formatWithArgumentRanges(self._s[719]!, self._r[719]!, [_0]) } - public var SocksProxySetup_PasteFromClipboard: String { return self._s[718]! } - public var Call_StatusConnecting: String { return self._s[719]! } + public var Call_StatusConnecting: String { return self._s[720]! } + public var SocksProxySetup_PasteFromClipboard: String { return self._s[721]! } public func Username_UsernameIsAvailable(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[720]!, self._r[720]!, [_0]) + return formatWithArgumentRanges(self._s[722]!, self._r[722]!, [_0]) } - public var ChatSettings_ConnectionType_UseProxy: String { return self._s[722]! } - public var Common_Edit: String { return self._s[723]! } - public var PrivacySettings_LastSeenNobody: String { return self._s[724]! } + public var ChatSettings_ConnectionType_UseProxy: String { return self._s[724]! } + public var Common_Edit: String { return self._s[725]! } + public var PrivacySettings_LastSeenNobody: String { return self._s[726]! } public func Notification_LeftChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[725]!, self._r[725]!, [_0]) + return formatWithArgumentRanges(self._s[727]!, self._r[727]!, [_0]) } - public var GroupInfo_ChatAdmins: String { return self._s[726]! } - public var PrivateDataSettings_Title: String { return self._s[727]! } - public var Login_CancelPhoneVerificationStop: String { return self._s[728]! } - public var ChatList_Read: String { return self._s[729]! } - public var Wallet_WordImport_Text: String { return self._s[730]! } - public var Undo_ChatClearedForBothSides: String { return self._s[731]! } - public var GroupPermission_SectionTitle: String { return self._s[732]! } - public var TwoFactorSetup_Intro_Title: String { return self._s[734]! } + public var GroupInfo_ChatAdmins: String { return self._s[728]! } + public var PrivateDataSettings_Title: String { return self._s[729]! } + public var Login_CancelPhoneVerificationStop: String { return self._s[730]! } + public var ChatList_Read: String { return self._s[731]! } + public var Wallet_WordImport_Text: String { return self._s[732]! } + public var Undo_ChatClearedForBothSides: String { return self._s[733]! } + public var GroupPermission_SectionTitle: String { return self._s[734]! } + public var TwoFactorSetup_Intro_Title: String { return self._s[736]! } public func PUSH_CHAT_LEFT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[735]!, self._r[735]!, [_1, _2]) + return formatWithArgumentRanges(self._s[737]!, self._r[737]!, [_1, _2]) } - public var Checkout_ErrorPaymentFailed: String { return self._s[736]! } - public var Update_UpdateApp: String { return self._s[737]! } - public var Group_Username_RevokeExistingUsernamesInfo: String { return self._s[738]! } - public var Settings_Appearance: String { return self._s[739]! } - public var SettingsSearch_Synonyms_Stickers_SuggestStickers: String { return self._s[743]! } - public var Watch_Location_Access: String { return self._s[744]! } - public var ShareMenu_CopyShareLink: String { return self._s[746]! } - public var TwoStepAuth_SetupHintTitle: String { return self._s[747]! } - public var Conversation_Theme: String { return self._s[749]! } + public var Checkout_ErrorPaymentFailed: String { return self._s[738]! } + public var Update_UpdateApp: String { return self._s[739]! } + public var Group_Username_RevokeExistingUsernamesInfo: String { return self._s[740]! } + public var Settings_Appearance: String { return self._s[741]! } + public var SettingsSearch_Synonyms_Stickers_SuggestStickers: String { return self._s[745]! } + public var Watch_Location_Access: String { return self._s[746]! } + public var ShareMenu_CopyShareLink: String { return self._s[748]! } + public var TwoStepAuth_SetupHintTitle: String { return self._s[749]! } + public var Conversation_Theme: String { return self._s[751]! } public func DialogList_SingleRecordingVideoMessageSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[750]!, self._r[750]!, [_0]) + return formatWithArgumentRanges(self._s[752]!, self._r[752]!, [_0]) } - public var Notifications_ClassicTones: String { return self._s[751]! } - public var Weekday_ShortWednesday: String { return self._s[752]! } - public var WallpaperPreview_SwipeColorsBottomText: String { return self._s[753]! } - public var Undo_LeftGroup: String { return self._s[756]! } - public var Wallet_RestoreFailed_Text: String { return self._s[757]! } - public var Conversation_LinkDialogCopy: String { return self._s[758]! } - public var Wallet_TransactionInfo_NoAddress: String { return self._s[760]! } - public var Wallet_Navigation_Back: String { return self._s[761]! } - public var KeyCommand_FocusOnInputField: String { return self._s[762]! } - public var Contacts_SelectAll: String { return self._s[763]! } - public var Preview_SaveToCameraRoll: String { return self._s[764]! } - public var PrivacySettings_PasscodeOff: String { return self._s[765]! } - public var Appearance_ThemePreview_ChatList_6_Name: String { return self._s[766]! } + public var Notifications_ClassicTones: String { return self._s[753]! } + public var Weekday_ShortWednesday: String { return self._s[754]! } + public var WallpaperPreview_SwipeColorsBottomText: String { return self._s[755]! } + public var Undo_LeftGroup: String { return self._s[758]! } + public var Wallet_RestoreFailed_Text: String { return self._s[759]! } + public var Conversation_LinkDialogCopy: String { return self._s[760]! } + public var Wallet_TransactionInfo_NoAddress: String { return self._s[762]! } + public var Wallet_Navigation_Back: String { return self._s[763]! } + public var KeyCommand_FocusOnInputField: String { return self._s[764]! } + public var Contacts_SelectAll: String { return self._s[765]! } + public var Preview_SaveToCameraRoll: String { return self._s[766]! } + public var PrivacySettings_PasscodeOff: String { return self._s[767]! } + public var Appearance_ThemePreview_ChatList_6_Name: String { return self._s[768]! } public func PUSH_CHANNEL_MESSAGE_QUIZ(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[767]!, self._r[767]!, [_1]) + return formatWithArgumentRanges(self._s[769]!, self._r[769]!, [_1]) } - public var Wallpaper_Title: String { return self._s[768]! } - public var Conversation_FilePhotoOrVideo: String { return self._s[769]! } - public var AccessDenied_Camera: String { return self._s[770]! } - public var Watch_Compose_CurrentLocation: String { return self._s[771]! } - public var Channel_DiscussionGroup_MakeHistoryPublicProceed: String { return self._s[773]! } + public var Wallpaper_Title: String { return self._s[770]! } + public var Conversation_FilePhotoOrVideo: String { return self._s[771]! } + public var AccessDenied_Camera: String { return self._s[772]! } + public var Watch_Compose_CurrentLocation: String { return self._s[773]! } + public var Channel_DiscussionGroup_MakeHistoryPublicProceed: String { return self._s[775]! } public func SecretImage_NotViewedYet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[774]!, self._r[774]!, [_0]) + return formatWithArgumentRanges(self._s[776]!, self._r[776]!, [_0]) } - public var GroupInfo_InvitationLinkDoesNotExist: String { return self._s[775]! } - public var Passport_Language_ro: String { return self._s[776]! } - public var EditTheme_UploadNewTheme: String { return self._s[777]! } - public var CheckoutInfo_SaveInfoHelp: String { return self._s[778]! } - public var Wallet_Intro_Terms: String { return self._s[779]! } + public var GroupInfo_InvitationLinkDoesNotExist: String { return self._s[777]! } + public var Passport_Language_ro: String { return self._s[778]! } + public var EditTheme_UploadNewTheme: String { return self._s[779]! } + public var CheckoutInfo_SaveInfoHelp: String { return self._s[780]! } + public var Wallet_Intro_Terms: String { return self._s[781]! } public func Notification_SecretChatMessageScreenshot(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[780]!, self._r[780]!, [_0]) + return formatWithArgumentRanges(self._s[782]!, self._r[782]!, [_0]) } - public var Login_CancelPhoneVerification: String { return self._s[781]! } - public var State_ConnectingToProxy: String { return self._s[782]! } - public var Calls_RatingTitle: String { return self._s[783]! } - public var Generic_ErrorMoreInfo: String { return self._s[784]! } - public var ChatList_Search_ShowMore: String { return self._s[785]! } - public var Appearance_PreviewReplyText: String { return self._s[786]! } - public var CheckoutInfo_ShippingInfoPostcodePlaceholder: String { return self._s[787]! } + public var Login_CancelPhoneVerification: String { return self._s[783]! } + public var State_ConnectingToProxy: String { return self._s[784]! } + public var Calls_RatingTitle: String { return self._s[785]! } + public var Generic_ErrorMoreInfo: String { return self._s[786]! } + public var ChatList_Search_ShowMore: String { return self._s[787]! } + public var Appearance_PreviewReplyText: String { return self._s[788]! } + public var CheckoutInfo_ShippingInfoPostcodePlaceholder: String { return self._s[789]! } public func Wallet_Send_Balance(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[788]!, self._r[788]!, [_0]) + return formatWithArgumentRanges(self._s[790]!, self._r[790]!, [_0]) } - public var IntentsSettings_SuggestedChatsContacts: String { return self._s[789]! } - public var SharedMedia_CategoryLinks: String { return self._s[790]! } - public var Calls_Missed: String { return self._s[791]! } - public var Cache_Photos: String { return self._s[795]! } - public var GroupPermission_NoAddMembers: String { return self._s[796]! } - public var ScheduledMessages_Title: String { return self._s[797]! } + public var IntentsSettings_SuggestedChatsContacts: String { return self._s[791]! } + public var SharedMedia_CategoryLinks: String { return self._s[792]! } + public var Calls_Missed: String { return self._s[793]! } + public var Cache_Photos: String { return self._s[797]! } + public var GroupPermission_NoAddMembers: String { return self._s[798]! } + public var ScheduledMessages_Title: String { return self._s[799]! } public func Channel_AdminLog_MessageUnpinned(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[798]!, self._r[798]!, [_0]) + return formatWithArgumentRanges(self._s[800]!, self._r[800]!, [_0]) } - public var Conversation_ShareBotLocationConfirmationTitle: String { return self._s[799]! } - public var Settings_ProxyDisabled: String { return self._s[800]! } + public var Conversation_ShareBotLocationConfirmationTitle: String { return self._s[801]! } + public var Settings_ProxyDisabled: String { return self._s[802]! } public func Settings_ApplyProxyAlertCredentials(_ _1: String, _ _2: String, _ _3: String, _ _4: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[801]!, self._r[801]!, [_1, _2, _3, _4]) + return formatWithArgumentRanges(self._s[803]!, self._r[803]!, [_1, _2, _3, _4]) } public func Conversation_RestrictedMediaTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[802]!, self._r[802]!, [_0]) + return formatWithArgumentRanges(self._s[804]!, self._r[804]!, [_0]) } - public var ChatList_Context_RemoveFromRecents: String { return self._s[804]! } - public var Appearance_Title: String { return self._s[805]! } + public var ChatList_Context_RemoveFromRecents: String { return self._s[806]! } + public var Appearance_Title: String { return self._s[807]! } public func Time_MonthOfYear_m2(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[807]!, self._r[807]!, [_0]) + return formatWithArgumentRanges(self._s[809]!, self._r[809]!, [_0]) } - public var Conversation_WalletRequiredText: String { return self._s[808]! } - public var StickerPacksSettings_ShowStickersButtonHelp: String { return self._s[809]! } - public var OldChannels_NoticeCreateText: String { return self._s[810]! } - public var Channel_EditMessageErrorGeneric: String { return self._s[811]! } - public var Privacy_Calls_IntegrationHelp: String { return self._s[812]! } - public var Preview_DeletePhoto: String { return self._s[813]! } - public var Appearance_AppIconFilledX: String { return self._s[814]! } - public var PrivacySettings_PrivacyTitle: String { return self._s[815]! } + public var Conversation_WalletRequiredText: String { return self._s[810]! } + public var StickerPacksSettings_ShowStickersButtonHelp: String { return self._s[811]! } + public var OldChannels_NoticeCreateText: String { return self._s[812]! } + public var Channel_EditMessageErrorGeneric: String { return self._s[813]! } + public var Privacy_Calls_IntegrationHelp: String { return self._s[814]! } + public var Preview_DeletePhoto: String { return self._s[815]! } + public var Appearance_AppIconFilledX: String { return self._s[816]! } + public var PrivacySettings_PrivacyTitle: String { return self._s[817]! } public func Conversation_BotInteractiveUrlAlert(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[816]!, self._r[816]!, [_0]) + return formatWithArgumentRanges(self._s[818]!, self._r[818]!, [_0]) } - public var Coub_TapForSound: String { return self._s[819]! } - public var Map_LocatingError: String { return self._s[820]! } - public var TwoStepAuth_EmailChangeSuccess: String { return self._s[822]! } - public var Conversation_SendMessage_SendSilently: String { return self._s[823]! } - public var VoiceOver_MessageContextOpenMessageMenu: String { return self._s[824]! } + public var Coub_TapForSound: String { return self._s[821]! } + public var Map_LocatingError: String { return self._s[822]! } + public var TwoStepAuth_EmailChangeSuccess: String { return self._s[824]! } + public var Conversation_SendMessage_SendSilently: String { return self._s[825]! } + public var VoiceOver_MessageContextOpenMessageMenu: String { return self._s[826]! } public func Wallet_Time_PreciseDate_m8(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[825]!, self._r[825]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[827]!, self._r[827]!, [_1, _2, _3]) } - public var Passport_ForgottenPassword: String { return self._s[826]! } - public var GroupInfo_InviteLink_RevokeLink: String { return self._s[827]! } - public var StickerPacksSettings_ArchivedPacks: String { return self._s[828]! } - public var Login_TermsOfServiceSignupDecline: String { return self._s[830]! } - public var Channel_Moderator_AccessLevelRevoke: String { return self._s[831]! } - public var Message_Location: String { return self._s[832]! } - public var Passport_Identity_NamePlaceholder: String { return self._s[833]! } - public var Channel_Management_Title: String { return self._s[834]! } - public var DialogList_SearchSectionDialogs: String { return self._s[836]! } - public var Compose_NewChannel_Members: String { return self._s[837]! } + public var Passport_ForgottenPassword: String { return self._s[828]! } + public var GroupInfo_InviteLink_RevokeLink: String { return self._s[829]! } + public var StickerPacksSettings_ArchivedPacks: String { return self._s[830]! } + public var Login_TermsOfServiceSignupDecline: String { return self._s[832]! } + public var Channel_Moderator_AccessLevelRevoke: String { return self._s[833]! } + public var Message_Location: String { return self._s[834]! } + public var Passport_Identity_NamePlaceholder: String { return self._s[835]! } + public var Channel_Management_Title: String { return self._s[836]! } + public var DialogList_SearchSectionDialogs: String { return self._s[838]! } + public var Compose_NewChannel_Members: String { return self._s[839]! } public func DialogList_SingleUploadingFileSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[838]!, self._r[838]!, [_0]) + return formatWithArgumentRanges(self._s[840]!, self._r[840]!, [_0]) } - public var GroupInfo_Location: String { return self._s[839]! } - public var Appearance_ThemePreview_ChatList_5_Name: String { return self._s[840]! } - public var ClearCache_Clear: String { return self._s[841]! } - public var AutoNightTheme_ScheduledFrom: String { return self._s[842]! } - public var PhotoEditor_WarmthTool: String { return self._s[843]! } - public var Passport_Language_tr: String { return self._s[844]! } + public var GroupInfo_Location: String { return self._s[841]! } + public var Appearance_ThemePreview_ChatList_5_Name: String { return self._s[842]! } + public var ClearCache_Clear: String { return self._s[843]! } + public var AutoNightTheme_ScheduledFrom: String { return self._s[844]! } + public var PhotoEditor_WarmthTool: String { return self._s[845]! } + public var Passport_Language_tr: String { return self._s[846]! } public func PUSH_MESSAGE_GAME_SCORE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[845]!, self._r[845]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[847]!, self._r[847]!, [_1, _2, _3]) } - public var OldChannels_NoticeUpgradeText: String { return self._s[846]! } - public var Login_ResetAccountProtected_Reset: String { return self._s[848]! } - public var Watch_PhotoView_Title: String { return self._s[849]! } - public var Passport_Phone_Delete: String { return self._s[850]! } - public var Undo_ChatDeletedForBothSides: String { return self._s[851]! } - public var Conversation_EditingMessageMediaEditCurrentPhoto: String { return self._s[852]! } - public var GroupInfo_Permissions: String { return self._s[853]! } - public var PasscodeSettings_TurnPasscodeOff: String { return self._s[854]! } - public var Profile_ShareContactButton: String { return self._s[855]! } - public var ChatSettings_Other: String { return self._s[856]! } - public var UserInfo_NotificationsDisabled: String { return self._s[857]! } - public var CheckoutInfo_ShippingInfoCity: String { return self._s[858]! } - public var LastSeen_WithinAMonth: String { return self._s[859]! } - public var VoiceOver_Chat_PlayHint: String { return self._s[860]! } - public var Conversation_ReportGroupLocation: String { return self._s[861]! } - public var Conversation_EncryptionCanceled: String { return self._s[862]! } - public var MediaPicker_GroupDescription: String { return self._s[863]! } - public var WebSearch_Images: String { return self._s[864]! } + public var OldChannels_NoticeUpgradeText: String { return self._s[848]! } + public var Login_ResetAccountProtected_Reset: String { return self._s[850]! } + public var Watch_PhotoView_Title: String { return self._s[851]! } + public var Passport_Phone_Delete: String { return self._s[852]! } + public var Undo_ChatDeletedForBothSides: String { return self._s[853]! } + public var Conversation_EditingMessageMediaEditCurrentPhoto: String { return self._s[854]! } + public var GroupInfo_Permissions: String { return self._s[855]! } + public var PasscodeSettings_TurnPasscodeOff: String { return self._s[856]! } + public var Profile_ShareContactButton: String { return self._s[857]! } + public var ChatSettings_Other: String { return self._s[858]! } + public var UserInfo_NotificationsDisabled: String { return self._s[859]! } + public var CheckoutInfo_ShippingInfoCity: String { return self._s[860]! } + public var LastSeen_WithinAMonth: String { return self._s[861]! } + public var VoiceOver_Chat_PlayHint: String { return self._s[862]! } + public var Conversation_ReportGroupLocation: String { return self._s[863]! } + public var Conversation_EncryptionCanceled: String { return self._s[864]! } + public var MediaPicker_GroupDescription: String { return self._s[865]! } + public var WebSearch_Images: String { return self._s[866]! } public func Channel_Management_PromotedBy(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[865]!, self._r[865]!, [_0]) + return formatWithArgumentRanges(self._s[867]!, self._r[867]!, [_0]) } - public var Message_Photo: String { return self._s[866]! } - public var PasscodeSettings_HelpBottom: String { return self._s[867]! } - public var AutoDownloadSettings_VideosTitle: String { return self._s[868]! } - public var VoiceOver_Media_PlaybackRateChange: String { return self._s[869]! } - public var Passport_Identity_AddDriversLicense: String { return self._s[870]! } - public var TwoStepAuth_EnterPasswordPassword: String { return self._s[871]! } - public var NotificationsSound_Calypso: String { return self._s[872]! } - public var Map_Map: String { return self._s[873]! } + public var Message_Photo: String { return self._s[868]! } + public var PasscodeSettings_HelpBottom: String { return self._s[869]! } + public var AutoDownloadSettings_VideosTitle: String { return self._s[870]! } + public var VoiceOver_Media_PlaybackRateChange: String { return self._s[871]! } + public var Passport_Identity_AddDriversLicense: String { return self._s[872]! } + public var TwoStepAuth_EnterPasswordPassword: String { return self._s[873]! } + public var NotificationsSound_Calypso: String { return self._s[874]! } + public var Map_Map: String { return self._s[875]! } public func Conversation_LiveLocationYouAndOther(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[874]!, self._r[874]!, [_0]) + return formatWithArgumentRanges(self._s[876]!, self._r[876]!, [_0]) } - public var CheckoutInfo_ReceiverInfoTitle: String { return self._s[876]! } - public var ChatSettings_TextSizeUnits: String { return self._s[877]! } + public var CheckoutInfo_ReceiverInfoTitle: String { return self._s[878]! } + public var ChatSettings_TextSizeUnits: String { return self._s[879]! } public func VoiceOver_Chat_FileFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[878]!, self._r[878]!, [_0]) + return formatWithArgumentRanges(self._s[880]!, self._r[880]!, [_0]) } - public var Common_of: String { return self._s[879]! } - public var Conversation_ForwardContacts: String { return self._s[882]! } - public var IntentsSettings_SuggestByAll: String { return self._s[884]! } + public var Common_of: String { return self._s[881]! } + public var Conversation_ForwardContacts: String { return self._s[884]! } + public var IntentsSettings_SuggestByAll: String { return self._s[886]! } public func Call_AnsweringWithAccount(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[885]!, self._r[885]!, [_0]) + return formatWithArgumentRanges(self._s[887]!, self._r[887]!, [_0]) } - public var Passport_Language_hy: String { return self._s[886]! } - public var Notifications_MessageNotificationsHelp: String { return self._s[887]! } - public var AutoDownloadSettings_Reset: String { return self._s[888]! } - public var Wallet_TransactionInfo_AddressCopied: String { return self._s[889]! } - public var Paint_ClearConfirm: String { return self._s[890]! } - public var Camera_VideoMode: String { return self._s[891]! } + public var Passport_Language_hy: String { return self._s[888]! } + public var Notifications_MessageNotificationsHelp: String { return self._s[889]! } + public var AutoDownloadSettings_Reset: String { return self._s[890]! } + public var Wallet_TransactionInfo_AddressCopied: String { return self._s[891]! } + public var Paint_ClearConfirm: String { return self._s[892]! } + public var Camera_VideoMode: String { return self._s[893]! } public func Conversation_RestrictedStickersTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[892]!, self._r[892]!, [_0]) + return formatWithArgumentRanges(self._s[894]!, self._r[894]!, [_0]) } - public var Privacy_Calls_AlwaysAllow_Placeholder: String { return self._s[893]! } - public var Conversation_ViewBackground: String { return self._s[894]! } + public var Privacy_Calls_AlwaysAllow_Placeholder: String { return self._s[895]! } + public var Conversation_ViewBackground: String { return self._s[896]! } public func Wallet_Info_TransactionDateHeaderYear(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[895]!, self._r[895]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[897]!, self._r[897]!, [_1, _2, _3]) } - public var Passport_Language_el: String { return self._s[896]! } - public var PhotoEditor_Original: String { return self._s[897]! } - public var Settings_FAQ_Button: String { return self._s[899]! } - public var Channel_Setup_PublicNoLink: String { return self._s[901]! } - public var Conversation_UnsupportedMedia: String { return self._s[902]! } - public var Conversation_SlideToCancel: String { return self._s[903]! } - public var Appearance_ThemePreview_ChatList_4_Name: String { return self._s[904]! } - public var Passport_Identity_OneOfTypeInternalPassport: String { return self._s[905]! } - public var CheckoutInfo_ShippingInfoPostcode: String { return self._s[906]! } - public var Conversation_ReportSpamChannelConfirmation: String { return self._s[907]! } - public var AutoNightTheme_NotAvailable: String { return self._s[908]! } - public var Conversation_Owner: String { return self._s[909]! } - public var Common_Create: String { return self._s[910]! } - public var Settings_ApplyProxyAlertEnable: String { return self._s[911]! } - public var ContactList_Context_Call: String { return self._s[912]! } - public var Localization_ChooseLanguage: String { return self._s[914]! } - public var ChatList_Context_AddToContacts: String { return self._s[916]! } - public var OldChannels_NoticeTitle: String { return self._s[917]! } - public var Settings_Proxy: String { return self._s[919]! } - public var Privacy_TopPeersHelp: String { return self._s[920]! } - public var CheckoutInfo_ShippingInfoCountryPlaceholder: String { return self._s[921]! } - public var Chat_UnsendMyMessages: String { return self._s[922]! } + public var Passport_Language_el: String { return self._s[898]! } + public var PhotoEditor_Original: String { return self._s[899]! } + public var Settings_FAQ_Button: String { return self._s[901]! } + public var Channel_Setup_PublicNoLink: String { return self._s[903]! } + public var Conversation_UnsupportedMedia: String { return self._s[904]! } + public var Conversation_SlideToCancel: String { return self._s[905]! } + public var Appearance_ThemePreview_ChatList_4_Name: String { return self._s[906]! } + public var Passport_Identity_OneOfTypeInternalPassport: String { return self._s[907]! } + public var CheckoutInfo_ShippingInfoPostcode: String { return self._s[908]! } + public var Conversation_ReportSpamChannelConfirmation: String { return self._s[909]! } + public var AutoNightTheme_NotAvailable: String { return self._s[910]! } + public var Conversation_Owner: String { return self._s[911]! } + public var Common_Create: String { return self._s[912]! } + public var Settings_ApplyProxyAlertEnable: String { return self._s[913]! } + public var ContactList_Context_Call: String { return self._s[914]! } + public var Localization_ChooseLanguage: String { return self._s[916]! } + public var ChatList_Context_AddToContacts: String { return self._s[918]! } + public var OldChannels_NoticeTitle: String { return self._s[919]! } + public var Settings_Proxy: String { return self._s[921]! } + public var Privacy_TopPeersHelp: String { return self._s[922]! } + public var CheckoutInfo_ShippingInfoCountryPlaceholder: String { return self._s[923]! } + public var Chat_UnsendMyMessages: String { return self._s[924]! } public func VoiceOver_Chat_Duration(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[923]!, self._r[923]!, [_0]) + return formatWithArgumentRanges(self._s[925]!, self._r[925]!, [_0]) } - public var TwoStepAuth_ConfirmationAbort: String { return self._s[924]! } + public var TwoStepAuth_ConfirmationAbort: String { return self._s[926]! } public func Contacts_AccessDeniedHelpPortrait(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[926]!, self._r[926]!, [_0]) + return formatWithArgumentRanges(self._s[928]!, self._r[928]!, [_0]) } - public var Contacts_SortedByPresence: String { return self._s[927]! } - public var Passport_Identity_SurnamePlaceholder: String { return self._s[928]! } - public var Cache_Title: String { return self._s[929]! } + public var Contacts_SortedByPresence: String { return self._s[929]! } + public var Passport_Identity_SurnamePlaceholder: String { return self._s[930]! } + public var Cache_Title: String { return self._s[931]! } public func Login_PhoneBannedEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[930]!, self._r[930]!, [_0]) + return formatWithArgumentRanges(self._s[932]!, self._r[932]!, [_0]) } - public var TwoStepAuth_EmailCodeExpired: String { return self._s[931]! } - public var Channel_Moderator_Title: String { return self._s[932]! } - public var InstantPage_AutoNightTheme: String { return self._s[934]! } + public var TwoStepAuth_EmailCodeExpired: String { return self._s[933]! } + public var Channel_Moderator_Title: String { return self._s[934]! } + public var InstantPage_AutoNightTheme: String { return self._s[936]! } public func PUSH_MESSAGE_POLL(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[937]!, self._r[937]!, [_1]) + return formatWithArgumentRanges(self._s[939]!, self._r[939]!, [_1]) } - public var Passport_Scans_Upload: String { return self._s[938]! } - public var Undo_Undo: String { return self._s[940]! } - public var Contacts_AccessDeniedHelpON: String { return self._s[941]! } - public var TwoStepAuth_RemovePassword: String { return self._s[942]! } - public var Common_Delete: String { return self._s[943]! } - public var Contacts_AddPeopleNearby: String { return self._s[945]! } - public var Conversation_ContextMenuDelete: String { return self._s[946]! } - public var SocksProxySetup_Credentials: String { return self._s[947]! } - public var Appearance_EditTheme: String { return self._s[949]! } - public var ClearCache_StorageOtherApps: String { return self._s[950]! } - public var PasscodeSettings_AutoLock_Disabled: String { return self._s[951]! } - public var Wallet_Send_NetworkErrorText: String { return self._s[952]! } - public var AuthSessions_DevicesTitle: String { return self._s[954]! } - public var Passport_Address_OneOfTypeRentalAgreement: String { return self._s[956]! } - public var Conversation_ShareBotContactConfirmationTitle: String { return self._s[957]! } - public var Passport_Language_id: String { return self._s[959]! } - public var WallpaperSearch_ColorTeal: String { return self._s[960]! } - public var ChannelIntro_Title: String { return self._s[961]! } + public var Passport_Scans_Upload: String { return self._s[940]! } + public var Undo_Undo: String { return self._s[942]! } + public var Contacts_AccessDeniedHelpON: String { return self._s[943]! } + public var TwoStepAuth_RemovePassword: String { return self._s[944]! } + public var Common_Delete: String { return self._s[945]! } + public var Contacts_AddPeopleNearby: String { return self._s[947]! } + public var Conversation_ContextMenuDelete: String { return self._s[948]! } + public var SocksProxySetup_Credentials: String { return self._s[949]! } + public var Appearance_EditTheme: String { return self._s[951]! } + public var ClearCache_StorageOtherApps: String { return self._s[952]! } + public var PasscodeSettings_AutoLock_Disabled: String { return self._s[953]! } + public var Wallet_Send_NetworkErrorText: String { return self._s[954]! } + public var AuthSessions_DevicesTitle: String { return self._s[956]! } + public var Passport_Address_OneOfTypeRentalAgreement: String { return self._s[958]! } + public var Conversation_ShareBotContactConfirmationTitle: String { return self._s[959]! } + public var Passport_Language_id: String { return self._s[961]! } + public var WallpaperSearch_ColorTeal: String { return self._s[962]! } + public var ChannelIntro_Title: String { return self._s[963]! } public func Channel_AdminLog_MessageToggleSignaturesOff(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[962]!, self._r[962]!, [_0]) + return formatWithArgumentRanges(self._s[964]!, self._r[964]!, [_0]) } - public var VoiceOver_Chat_OpenLinkHint: String { return self._s[964]! } - public var VoiceOver_Chat_Reply: String { return self._s[965]! } - public var ScheduledMessages_BotActionUnavailable: String { return self._s[966]! } - public var Channel_Info_Description: String { return self._s[967]! } - public var Stickers_FavoriteStickers: String { return self._s[968]! } - public var Channel_BanUser_PermissionAddMembers: String { return self._s[969]! } - public var Notifications_DisplayNamesOnLockScreen: String { return self._s[970]! } - public var ChatSearch_ResultsTooltip: String { return self._s[971]! } - public var Wallet_VoiceOver_Editing_ClearText: String { return self._s[972]! } - public var Calls_NoMissedCallsPlacehoder: String { return self._s[973]! } - public var Group_PublicLink_Placeholder: String { return self._s[974]! } - public var Notifications_ExceptionsDefaultSound: String { return self._s[975]! } + public var VoiceOver_Chat_OpenLinkHint: String { return self._s[966]! } + public var VoiceOver_Chat_Reply: String { return self._s[967]! } + public var ScheduledMessages_BotActionUnavailable: String { return self._s[968]! } + public var Channel_Info_Description: String { return self._s[969]! } + public var Stickers_FavoriteStickers: String { return self._s[970]! } + public var Channel_BanUser_PermissionAddMembers: String { return self._s[971]! } + public var Notifications_DisplayNamesOnLockScreen: String { return self._s[972]! } + public var ChatSearch_ResultsTooltip: String { return self._s[973]! } + public var Wallet_VoiceOver_Editing_ClearText: String { return self._s[974]! } + public var Calls_NoMissedCallsPlacehoder: String { return self._s[975]! } + public var Group_PublicLink_Placeholder: String { return self._s[976]! } + public var Notifications_ExceptionsDefaultSound: String { return self._s[977]! } public func PUSH_CHANNEL_MESSAGE_POLL(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[976]!, self._r[976]!, [_1]) + return formatWithArgumentRanges(self._s[978]!, self._r[978]!, [_1]) } - public var TextFormat_Underline: String { return self._s[977]! } + public var TextFormat_Underline: String { return self._s[979]! } public func DialogList_SearchSubtitleFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[979]!, self._r[979]!, [_1, _2]) + return formatWithArgumentRanges(self._s[981]!, self._r[981]!, [_1, _2]) } public func Channel_AdminLog_MessageRemovedGroupStickerPack(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[980]!, self._r[980]!, [_0]) + return formatWithArgumentRanges(self._s[982]!, self._r[982]!, [_0]) } - public var Appearance_ThemePreview_ChatList_3_Name: String { return self._s[981]! } + public var Appearance_ThemePreview_ChatList_3_Name: String { return self._s[983]! } public func Channel_OwnershipTransfer_TransferCompleted(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[982]!, self._r[982]!, [_1, _2]) + return formatWithArgumentRanges(self._s[984]!, self._r[984]!, [_1, _2]) } - public var Wallet_Intro_ImportExisting: String { return self._s[983]! } - public var GroupPermission_Delete: String { return self._s[984]! } - public var Passport_Language_uk: String { return self._s[985]! } - public var StickerPack_HideStickers: String { return self._s[987]! } - public var ChangePhoneNumberNumber_NumberPlaceholder: String { return self._s[988]! } + public var Wallet_Intro_ImportExisting: String { return self._s[985]! } + public var GroupPermission_Delete: String { return self._s[986]! } + public var Passport_Language_uk: String { return self._s[987]! } + public var StickerPack_HideStickers: String { return self._s[989]! } + public var ChangePhoneNumberNumber_NumberPlaceholder: String { return self._s[990]! } public func PUSH_CHAT_MESSAGE_PHOTO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[989]!, self._r[989]!, [_1, _2]) + return formatWithArgumentRanges(self._s[991]!, self._r[991]!, [_1, _2]) } - public var Activity_UploadingVideoMessage: String { return self._s[990]! } + public var Activity_UploadingVideoMessage: String { return self._s[992]! } public func GroupPermission_ApplyAlertText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[991]!, self._r[991]!, [_0]) + return formatWithArgumentRanges(self._s[993]!, self._r[993]!, [_0]) } - public var Channel_TitleInfo: String { return self._s[992]! } - public var StickerPacksSettings_ArchivedPacks_Info: String { return self._s[993]! } - public var Settings_CallSettings: String { return self._s[994]! } - public var Camera_SquareMode: String { return self._s[995]! } - public var Conversation_SendMessage_ScheduleMessage: String { return self._s[996]! } - public var GroupInfo_SharedMediaNone: String { return self._s[997]! } + public var Channel_TitleInfo: String { return self._s[994]! } + public var StickerPacksSettings_ArchivedPacks_Info: String { return self._s[995]! } + public var Settings_CallSettings: String { return self._s[996]! } + public var Camera_SquareMode: String { return self._s[997]! } + public var Conversation_SendMessage_ScheduleMessage: String { return self._s[998]! } + public var GroupInfo_SharedMediaNone: String { return self._s[999]! } public func PUSH_MESSAGE_VIDEO_SECRET(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[998]!, self._r[998]!, [_1]) + return formatWithArgumentRanges(self._s[1000]!, self._r[1000]!, [_1]) } - public var Bot_GenericBotStatus: String { return self._s[999]! } - public var Application_Update: String { return self._s[1001]! } - public var Month_ShortJanuary: String { return self._s[1002]! } - public var Contacts_PermissionsKeepDisabled: String { return self._s[1003]! } - public var Channel_AdminLog_BanReadMessages: String { return self._s[1004]! } - public var Settings_AppLanguage_Unofficial: String { return self._s[1005]! } - public var Passport_Address_Street2Placeholder: String { return self._s[1006]! } + public var Bot_GenericBotStatus: String { return self._s[1001]! } + public var Application_Update: String { return self._s[1003]! } + public var Month_ShortJanuary: String { return self._s[1004]! } + public var Contacts_PermissionsKeepDisabled: String { return self._s[1005]! } + public var Channel_AdminLog_BanReadMessages: String { return self._s[1006]! } + public var Settings_AppLanguage_Unofficial: String { return self._s[1007]! } + public var Passport_Address_Street2Placeholder: String { return self._s[1008]! } public func Map_LiveLocationShortHour(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1007]!, self._r[1007]!, [_0]) + return formatWithArgumentRanges(self._s[1009]!, self._r[1009]!, [_0]) } - public var NetworkUsageSettings_Cellular: String { return self._s[1008]! } - public var Appearance_PreviewOutgoingText: String { return self._s[1009]! } + public var NetworkUsageSettings_Cellular: String { return self._s[1010]! } + public var Appearance_PreviewOutgoingText: String { return self._s[1011]! } public func StickerPackActionInfo_RemovedText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1010]!, self._r[1010]!, [_0]) + return formatWithArgumentRanges(self._s[1012]!, self._r[1012]!, [_0]) } - public var Notifications_PermissionsAllowInSettings: String { return self._s[1011]! } - public var AutoDownloadSettings_OnForAll: String { return self._s[1013]! } - public var Map_Directions: String { return self._s[1014]! } - public var Passport_FieldIdentityTranslationHelp: String { return self._s[1016]! } - public var Appearance_ThemeDay: String { return self._s[1017]! } - public var LogoutOptions_LogOut: String { return self._s[1018]! } - public var Group_PublicLink_Title: String { return self._s[1020]! } - public var Channel_AddBotErrorNoRights: String { return self._s[1021]! } - public var ChatList_Search_ShowLess: String { return self._s[1022]! } - public var Passport_Identity_AddPassport: String { return self._s[1023]! } - public var LocalGroup_ButtonTitle: String { return self._s[1024]! } - public var Call_Message: String { return self._s[1025]! } - public var PhotoEditor_ExposureTool: String { return self._s[1026]! } - public var Wallet_Receive_CommentInfo: String { return self._s[1028]! } - public var Passport_FieldOneOf_Delimeter: String { return self._s[1029]! } - public var Channel_AdminLog_CanBanUsers: String { return self._s[1031]! } - public var Appearance_ThemePreview_ChatList_2_Name: String { return self._s[1032]! } - public var Appearance_Preview: String { return self._s[1033]! } - public var Compose_ChannelMembers: String { return self._s[1034]! } - public var Conversation_DeleteManyMessages: String { return self._s[1035]! } - public var ReportPeer_ReasonOther_Title: String { return self._s[1036]! } - public var Checkout_ErrorProviderAccountTimeout: String { return self._s[1037]! } - public var TwoStepAuth_ResetAccountConfirmation: String { return self._s[1038]! } - public var Channel_Stickers_CreateYourOwn: String { return self._s[1041]! } - public var Conversation_UpdateTelegram: String { return self._s[1042]! } - public var EditTheme_Create_TopInfo: String { return self._s[1043]! } + public var Notifications_PermissionsAllowInSettings: String { return self._s[1013]! } + public var AutoDownloadSettings_OnForAll: String { return self._s[1015]! } + public var Map_Directions: String { return self._s[1016]! } + public var Passport_FieldIdentityTranslationHelp: String { return self._s[1018]! } + public var Appearance_ThemeDay: String { return self._s[1019]! } + public var LogoutOptions_LogOut: String { return self._s[1020]! } + public var Group_PublicLink_Title: String { return self._s[1022]! } + public var Channel_AddBotErrorNoRights: String { return self._s[1023]! } + public var ChatList_Search_ShowLess: String { return self._s[1024]! } + public var Passport_Identity_AddPassport: String { return self._s[1025]! } + public var LocalGroup_ButtonTitle: String { return self._s[1026]! } + public var Call_Message: String { return self._s[1027]! } + public var PhotoEditor_ExposureTool: String { return self._s[1028]! } + public var Wallet_Receive_CommentInfo: String { return self._s[1030]! } + public var Passport_FieldOneOf_Delimeter: String { return self._s[1031]! } + public var Channel_AdminLog_CanBanUsers: String { return self._s[1033]! } + public var Appearance_ThemePreview_ChatList_2_Name: String { return self._s[1034]! } + public var Appearance_Preview: String { return self._s[1035]! } + public var Compose_ChannelMembers: String { return self._s[1036]! } + public var Conversation_DeleteManyMessages: String { return self._s[1037]! } + public var ReportPeer_ReasonOther_Title: String { return self._s[1038]! } + public var Checkout_ErrorProviderAccountTimeout: String { return self._s[1039]! } + public var TwoStepAuth_ResetAccountConfirmation: String { return self._s[1040]! } + public var Channel_Stickers_CreateYourOwn: String { return self._s[1043]! } + public var Conversation_UpdateTelegram: String { return self._s[1044]! } + public var EditTheme_Create_TopInfo: String { return self._s[1045]! } public func Notification_PinnedPhotoMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1044]!, self._r[1044]!, [_0]) + return formatWithArgumentRanges(self._s[1046]!, self._r[1046]!, [_0]) } - public var Wallet_WordCheck_Continue: String { return self._s[1045]! } - public var TwoFactorSetup_Hint_Action: String { return self._s[1046]! } - public var IntentsSettings_ResetAll: String { return self._s[1047]! } + public var Wallet_WordCheck_Continue: String { return self._s[1047]! } + public var TwoFactorSetup_Hint_Action: String { return self._s[1048]! } + public var IntentsSettings_ResetAll: String { return self._s[1049]! } public func PUSH_PINNED_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1048]!, self._r[1048]!, [_1]) + return formatWithArgumentRanges(self._s[1050]!, self._r[1050]!, [_1]) } - public var GroupInfo_Administrators_Title: String { return self._s[1049]! } - public var Privacy_Forwards_PreviewMessageText: String { return self._s[1050]! } + public var GroupInfo_Administrators_Title: String { return self._s[1051]! } + public var Privacy_Forwards_PreviewMessageText: String { return self._s[1052]! } public func PrivacySettings_LastSeenNobodyPlus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1051]!, self._r[1051]!, [_0]) + return formatWithArgumentRanges(self._s[1053]!, self._r[1053]!, [_0]) } - public var Tour_Title3: String { return self._s[1052]! } - public var Channel_EditAdmin_PermissionInviteSubscribers: String { return self._s[1053]! } - public var Clipboard_SendPhoto: String { return self._s[1057]! } - public var MediaPicker_Videos: String { return self._s[1058]! } - public var Passport_Email_Title: String { return self._s[1059]! } + public var Tour_Title3: String { return self._s[1054]! } + public var Channel_EditAdmin_PermissionInviteSubscribers: String { return self._s[1055]! } + public var Clipboard_SendPhoto: String { return self._s[1059]! } + public var MediaPicker_Videos: String { return self._s[1060]! } + public var Passport_Email_Title: String { return self._s[1061]! } public func PrivacySettings_LastSeenEverybodyMinus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1060]!, self._r[1060]!, [_0]) + return formatWithArgumentRanges(self._s[1062]!, self._r[1062]!, [_0]) } - public var StickerPacksSettings_Title: String { return self._s[1061]! } - public var Conversation_MessageDialogDelete: String { return self._s[1062]! } - public var Privacy_Calls_CustomHelp: String { return self._s[1064]! } - public var Message_Wallpaper: String { return self._s[1065]! } - public var MemberSearch_BotSection: String { return self._s[1066]! } - public var GroupInfo_SetSound: String { return self._s[1067]! } - public var Core_ServiceUserStatus: String { return self._s[1068]! } - public var LiveLocationUpdated_JustNow: String { return self._s[1069]! } - public var Call_StatusFailed: String { return self._s[1070]! } - public var TwoFactorSetup_Email_Placeholder: String { return self._s[1071]! } - public var TwoStepAuth_SetupPasswordDescription: String { return self._s[1072]! } - public var TwoStepAuth_SetPassword: String { return self._s[1073]! } - public var Permissions_PeopleNearbyText_v0: String { return self._s[1074]! } + public var StickerPacksSettings_Title: String { return self._s[1063]! } + public var Conversation_MessageDialogDelete: String { return self._s[1064]! } + public var Privacy_Calls_CustomHelp: String { return self._s[1066]! } + public var Message_Wallpaper: String { return self._s[1067]! } + public var MemberSearch_BotSection: String { return self._s[1068]! } + public var GroupInfo_SetSound: String { return self._s[1069]! } + public var Core_ServiceUserStatus: String { return self._s[1070]! } + public var LiveLocationUpdated_JustNow: String { return self._s[1071]! } + public var Call_StatusFailed: String { return self._s[1072]! } + public var TwoFactorSetup_Email_Placeholder: String { return self._s[1073]! } + public var TwoStepAuth_SetupPasswordDescription: String { return self._s[1074]! } + public var TwoStepAuth_SetPassword: String { return self._s[1075]! } + public var Permissions_PeopleNearbyText_v0: String { return self._s[1076]! } public func SocksProxySetup_ProxyStatusPing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1076]!, self._r[1076]!, [_0]) + return formatWithArgumentRanges(self._s[1078]!, self._r[1078]!, [_0]) } - public var Calls_SubmitRating: String { return self._s[1077]! } - public var Map_NoPlacesNearby: String { return self._s[1078]! } - public var Profile_Username: String { return self._s[1079]! } - public var Bot_DescriptionTitle: String { return self._s[1080]! } - public var MaskStickerSettings_Title: String { return self._s[1081]! } - public var SharedMedia_CategoryOther: String { return self._s[1082]! } - public var GroupInfo_SetGroupPhoto: String { return self._s[1083]! } - public var Common_NotNow: String { return self._s[1084]! } - public var CallFeedback_IncludeLogsInfo: String { return self._s[1085]! } - public var Conversation_ShareMyPhoneNumber: String { return self._s[1086]! } - public var Map_Location: String { return self._s[1087]! } - public var Invitation_JoinGroup: String { return self._s[1088]! } - public var AutoDownloadSettings_Title: String { return self._s[1090]! } - public var Conversation_DiscardVoiceMessageDescription: String { return self._s[1091]! } - public var Channel_ErrorAddBlocked: String { return self._s[1092]! } - public var Conversation_UnblockUser: String { return self._s[1093]! } - public var EditTheme_Edit_TopInfo: String { return self._s[1094]! } - public var Watch_Bot_Restart: String { return self._s[1095]! } - public var TwoStepAuth_Title: String { return self._s[1096]! } - public var Channel_AdminLog_BanSendMessages: String { return self._s[1097]! } - public var Checkout_ShippingMethod: String { return self._s[1098]! } - public var Passport_Identity_OneOfTypeIdentityCard: String { return self._s[1099]! } + public var Calls_SubmitRating: String { return self._s[1079]! } + public var Map_NoPlacesNearby: String { return self._s[1080]! } + public var Profile_Username: String { return self._s[1081]! } + public var Bot_DescriptionTitle: String { return self._s[1082]! } + public var MaskStickerSettings_Title: String { return self._s[1083]! } + public var SharedMedia_CategoryOther: String { return self._s[1084]! } + public var GroupInfo_SetGroupPhoto: String { return self._s[1085]! } + public var Common_NotNow: String { return self._s[1086]! } + public var CallFeedback_IncludeLogsInfo: String { return self._s[1087]! } + public var Conversation_ShareMyPhoneNumber: String { return self._s[1088]! } + public var Map_Location: String { return self._s[1089]! } + public var Invitation_JoinGroup: String { return self._s[1090]! } + public var AutoDownloadSettings_Title: String { return self._s[1092]! } + public var Conversation_DiscardVoiceMessageDescription: String { return self._s[1093]! } + public var Channel_ErrorAddBlocked: String { return self._s[1094]! } + public var Conversation_UnblockUser: String { return self._s[1095]! } + public var EditTheme_Edit_TopInfo: String { return self._s[1096]! } + public var Watch_Bot_Restart: String { return self._s[1097]! } + public var TwoStepAuth_Title: String { return self._s[1098]! } + public var Channel_AdminLog_BanSendMessages: String { return self._s[1099]! } + public var Checkout_ShippingMethod: String { return self._s[1100]! } + public var Passport_Identity_OneOfTypeIdentityCard: String { return self._s[1101]! } public func PUSH_CHAT_MESSAGE_STICKER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1100]!, self._r[1100]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1102]!, self._r[1102]!, [_1, _2, _3]) } - public var EditTheme_ChangeColors: String { return self._s[1102]! } + public var EditTheme_ChangeColors: String { return self._s[1104]! } public func Chat_UnsendMyMessagesAlertTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1103]!, self._r[1103]!, [_0]) + return formatWithArgumentRanges(self._s[1105]!, self._r[1105]!, [_0]) } public func Channel_Username_LinkHint(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1104]!, self._r[1104]!, [_0]) + return formatWithArgumentRanges(self._s[1106]!, self._r[1106]!, [_0]) } - public var Appearance_ThemePreview_ChatList_1_Name: String { return self._s[1105]! } - public var SettingsSearch_Synonyms_Data_AutoplayGifs: String { return self._s[1106]! } - public var AuthSessions_TerminateOtherSessions: String { return self._s[1107]! } - public var Contacts_FailedToSendInvitesMessage: String { return self._s[1108]! } - public var PrivacySettings_TwoStepAuth: String { return self._s[1109]! } - public var Notification_Exceptions_PreviewAlwaysOn: String { return self._s[1110]! } - public var SettingsSearch_Synonyms_Privacy_Passcode: String { return self._s[1111]! } - public var Conversation_EditingMessagePanelMedia: String { return self._s[1112]! } - public var Checkout_PaymentMethod_Title: String { return self._s[1113]! } - public var SocksProxySetup_Connection: String { return self._s[1114]! } - public var Group_MessagePhotoRemoved: String { return self._s[1115]! } - public var Channel_Stickers_NotFound: String { return self._s[1118]! } - public var Group_About_Help: String { return self._s[1119]! } - public var Notification_PassportValueProofOfIdentity: String { return self._s[1120]! } - public var PeopleNearby_Title: String { return self._s[1122]! } + public var Appearance_ThemePreview_ChatList_1_Name: String { return self._s[1107]! } + public var SettingsSearch_Synonyms_Data_AutoplayGifs: String { return self._s[1108]! } + public var AuthSessions_TerminateOtherSessions: String { return self._s[1109]! } + public var Contacts_FailedToSendInvitesMessage: String { return self._s[1110]! } + public var PrivacySettings_TwoStepAuth: String { return self._s[1111]! } + public var Notification_Exceptions_PreviewAlwaysOn: String { return self._s[1112]! } + public var SettingsSearch_Synonyms_Privacy_Passcode: String { return self._s[1113]! } + public var Conversation_EditingMessagePanelMedia: String { return self._s[1114]! } + public var Checkout_PaymentMethod_Title: String { return self._s[1115]! } + public var SocksProxySetup_Connection: String { return self._s[1116]! } + public var Group_MessagePhotoRemoved: String { return self._s[1117]! } + public var Channel_Stickers_NotFound: String { return self._s[1120]! } + public var Group_About_Help: String { return self._s[1121]! } + public var Notification_PassportValueProofOfIdentity: String { return self._s[1122]! } + public var PeopleNearby_Title: String { return self._s[1124]! } public func ApplyLanguage_ChangeLanguageOfficialText(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1123]!, self._r[1123]!, [_1]) + return formatWithArgumentRanges(self._s[1125]!, self._r[1125]!, [_1]) } - public var Map_Home: String { return self._s[1124]! } - public var CheckoutInfo_ShippingInfoStatePlaceholder: String { return self._s[1126]! } - public var Notifications_GroupNotificationsExceptionsHelp: String { return self._s[1127]! } - public var SocksProxySetup_Password: String { return self._s[1128]! } - public var Notifications_PermissionsEnable: String { return self._s[1129]! } - public var TwoStepAuth_ChangeEmail: String { return self._s[1131]! } + public var Map_Home: String { return self._s[1126]! } + public var CheckoutInfo_ShippingInfoStatePlaceholder: String { return self._s[1128]! } + public var Notifications_GroupNotificationsExceptionsHelp: String { return self._s[1129]! } + public var SocksProxySetup_Password: String { return self._s[1130]! } + public var Notifications_PermissionsEnable: String { return self._s[1131]! } + public var TwoStepAuth_ChangeEmail: String { return self._s[1133]! } public func Channel_AdminLog_MessageInvitedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1132]!, self._r[1132]!, [_1]) + return formatWithArgumentRanges(self._s[1134]!, self._r[1134]!, [_1]) } public func Time_MonthOfYear_m10(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1134]!, self._r[1134]!, [_0]) + return formatWithArgumentRanges(self._s[1136]!, self._r[1136]!, [_0]) } - public var Passport_Identity_TypeDriversLicense: String { return self._s[1135]! } - public var ArchivedPacksAlert_Title: String { return self._s[1136]! } - public var Wallet_Receive_InvoiceUrlCopied: String { return self._s[1137]! } - public var Map_PlacesNearby: String { return self._s[1138]! } + public var Passport_Identity_TypeDriversLicense: String { return self._s[1137]! } + public var ArchivedPacksAlert_Title: String { return self._s[1138]! } + public var Wallet_Receive_InvoiceUrlCopied: String { return self._s[1139]! } + public var Map_PlacesNearby: String { return self._s[1140]! } public func Time_PreciseDate_m7(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1139]!, self._r[1139]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1141]!, self._r[1141]!, [_1, _2, _3]) } - public var PrivacyLastSeenSettings_GroupsAndChannelsHelp: String { return self._s[1140]! } - public var Privacy_Calls_NeverAllow_Placeholder: String { return self._s[1142]! } - public var Conversation_StatusTyping: String { return self._s[1143]! } - public var Broadcast_AdminLog_EmptyText: String { return self._s[1144]! } - public var Notification_PassportValueProofOfAddress: String { return self._s[1145]! } - public var UserInfo_CreateNewContact: String { return self._s[1146]! } - public var Passport_Identity_FrontSide: String { return self._s[1147]! } - public var Login_PhoneNumberAlreadyAuthorizedSwitch: String { return self._s[1148]! } - public var Calls_CallTabTitle: String { return self._s[1149]! } - public var Channel_AdminLog_ChannelEmptyText: String { return self._s[1150]! } + public var PrivacyLastSeenSettings_GroupsAndChannelsHelp: String { return self._s[1142]! } + public var Privacy_Calls_NeverAllow_Placeholder: String { return self._s[1144]! } + public var Conversation_StatusTyping: String { return self._s[1145]! } + public var Broadcast_AdminLog_EmptyText: String { return self._s[1146]! } + public var Notification_PassportValueProofOfAddress: String { return self._s[1147]! } + public var UserInfo_CreateNewContact: String { return self._s[1148]! } + public var Passport_Identity_FrontSide: String { return self._s[1149]! } + public var Login_PhoneNumberAlreadyAuthorizedSwitch: String { return self._s[1150]! } + public var Calls_CallTabTitle: String { return self._s[1151]! } + public var Channel_AdminLog_ChannelEmptyText: String { return self._s[1152]! } public func Login_BannedPhoneBody(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1152]!, self._r[1152]!, [_0]) + return formatWithArgumentRanges(self._s[1154]!, self._r[1154]!, [_0]) } - public var Watch_UserInfo_MuteTitle: String { return self._s[1153]! } - public var Group_EditAdmin_RankAdminPlaceholder: String { return self._s[1154]! } - public var SharedMedia_EmptyMusicText: String { return self._s[1155]! } - public var Wallet_Completed_Text: String { return self._s[1156]! } - public var PasscodeSettings_AutoLock_IfAwayFor_1minute: String { return self._s[1157]! } - public var Paint_Stickers: String { return self._s[1158]! } - public var Privacy_GroupsAndChannels: String { return self._s[1159]! } - public var ChatList_Context_Delete: String { return self._s[1161]! } - public var UserInfo_AddContact: String { return self._s[1162]! } + public var Watch_UserInfo_MuteTitle: String { return self._s[1155]! } + public var Group_EditAdmin_RankAdminPlaceholder: String { return self._s[1156]! } + public var SharedMedia_EmptyMusicText: String { return self._s[1157]! } + public var Wallet_Completed_Text: String { return self._s[1158]! } + public var PasscodeSettings_AutoLock_IfAwayFor_1minute: String { return self._s[1159]! } + public var Paint_Stickers: String { return self._s[1160]! } + public var Privacy_GroupsAndChannels: String { return self._s[1161]! } + public var ChatList_Context_Delete: String { return self._s[1163]! } + public var UserInfo_AddContact: String { return self._s[1164]! } public func Conversation_MessageViaUser(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1163]!, self._r[1163]!, [_0]) + return formatWithArgumentRanges(self._s[1165]!, self._r[1165]!, [_0]) } - public var PhoneNumberHelp_ChangeNumber: String { return self._s[1165]! } + public var PhoneNumberHelp_ChangeNumber: String { return self._s[1167]! } public func ChatList_ClearChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1167]!, self._r[1167]!, [_0]) + return formatWithArgumentRanges(self._s[1169]!, self._r[1169]!, [_0]) } - public var DialogList_NoMessagesTitle: String { return self._s[1168]! } - public var EditProfile_NameAndPhotoHelp: String { return self._s[1169]! } - public var BlockedUsers_BlockUser: String { return self._s[1170]! } - public var Notifications_PermissionsOpenSettings: String { return self._s[1171]! } - public var MediaPicker_UngroupDescription: String { return self._s[1173]! } - public var Watch_NoConnection: String { return self._s[1174]! } - public var Month_GenSeptember: String { return self._s[1175]! } - public var Conversation_ViewGroup: String { return self._s[1177]! } - public var Channel_AdminLogFilter_EventsLeavingSubscribers: String { return self._s[1180]! } - public var Privacy_Forwards_AlwaysLink: String { return self._s[1181]! } - public var Channel_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[1182]! } - public var Passport_FieldOneOf_FinalDelimeter: String { return self._s[1183]! } - public var Wallet_WordCheck_IncorrectHeader: String { return self._s[1184]! } - public var MediaPicker_CameraRoll: String { return self._s[1186]! } - public var Month_GenAugust: String { return self._s[1187]! } - public var Wallet_Configuration_SourceHeader: String { return self._s[1188]! } - public var AccessDenied_VideoMessageMicrophone: String { return self._s[1189]! } - public var SharedMedia_EmptyText: String { return self._s[1190]! } - public var Map_ShareLiveLocation: String { return self._s[1191]! } - public var Calls_All: String { return self._s[1192]! } - public var Map_SendThisPlace: String { return self._s[1194]! } - public var Appearance_ThemeNight: String { return self._s[1196]! } - public var Conversation_HoldForAudio: String { return self._s[1197]! } - public var SettingsSearch_Synonyms_Support: String { return self._s[1200]! } - public var GroupInfo_GroupHistoryHidden: String { return self._s[1201]! } - public var SocksProxySetup_Secret: String { return self._s[1202]! } + public var DialogList_NoMessagesTitle: String { return self._s[1170]! } + public var EditProfile_NameAndPhotoHelp: String { return self._s[1171]! } + public var BlockedUsers_BlockUser: String { return self._s[1172]! } + public var Notifications_PermissionsOpenSettings: String { return self._s[1173]! } + public var MediaPicker_UngroupDescription: String { return self._s[1175]! } + public var Watch_NoConnection: String { return self._s[1176]! } + public var Month_GenSeptember: String { return self._s[1177]! } + public var Conversation_ViewGroup: String { return self._s[1179]! } + public var Channel_AdminLogFilter_EventsLeavingSubscribers: String { return self._s[1182]! } + public var Privacy_Forwards_AlwaysLink: String { return self._s[1183]! } + public var Channel_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[1184]! } + public var Passport_FieldOneOf_FinalDelimeter: String { return self._s[1185]! } + public var Wallet_WordCheck_IncorrectHeader: String { return self._s[1186]! } + public var MediaPicker_CameraRoll: String { return self._s[1188]! } + public var Month_GenAugust: String { return self._s[1189]! } + public var Wallet_Configuration_SourceHeader: String { return self._s[1190]! } + public var AccessDenied_VideoMessageMicrophone: String { return self._s[1191]! } + public var SharedMedia_EmptyText: String { return self._s[1192]! } + public var Map_ShareLiveLocation: String { return self._s[1193]! } + public var Calls_All: String { return self._s[1194]! } + public var Map_SendThisPlace: String { return self._s[1196]! } + public var Appearance_ThemeNight: String { return self._s[1198]! } + public var Conversation_HoldForAudio: String { return self._s[1199]! } + public var SettingsSearch_Synonyms_Support: String { return self._s[1202]! } + public var GroupInfo_GroupHistoryHidden: String { return self._s[1203]! } + public var SocksProxySetup_Secret: String { return self._s[1204]! } public func Activity_RemindAboutChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1203]!, self._r[1203]!, [_0]) + return formatWithArgumentRanges(self._s[1205]!, self._r[1205]!, [_0]) } - public var Channel_BanList_RestrictedTitle: String { return self._s[1205]! } - public var Conversation_Location: String { return self._s[1206]! } + public var Channel_BanList_RestrictedTitle: String { return self._s[1207]! } + public var Conversation_Location: String { return self._s[1208]! } public func AutoDownloadSettings_UpToFor(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1207]!, self._r[1207]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1209]!, self._r[1209]!, [_1, _2]) } - public var ChatSettings_AutoDownloadPhotos: String { return self._s[1209]! } - public var SettingsSearch_Synonyms_Privacy_Title: String { return self._s[1210]! } - public var Notifications_PermissionsText: String { return self._s[1211]! } - public var SettingsSearch_Synonyms_Data_SaveIncomingPhotos: String { return self._s[1212]! } - public var Call_Flip: String { return self._s[1213]! } - public var Channel_AdminLog_CanDeleteMessagesOfOthers: String { return self._s[1215]! } - public var SocksProxySetup_ProxyStatusConnecting: String { return self._s[1216]! } - public var Wallet_TransactionInfo_StorageFeeInfoUrl: String { return self._s[1217]! } - public var PrivacyPhoneNumberSettings_DiscoveryHeader: String { return self._s[1218]! } - public var Channel_EditAdmin_PermissionPinMessages: String { return self._s[1220]! } - public var TwoStepAuth_ReEnterPasswordDescription: String { return self._s[1222]! } - public var Channel_TooMuchBots: String { return self._s[1224]! } - public var Passport_DeletePassportConfirmation: String { return self._s[1225]! } - public var Login_InvalidCodeError: String { return self._s[1226]! } - public var StickerPacksSettings_FeaturedPacks: String { return self._s[1227]! } + public var ChatSettings_AutoDownloadPhotos: String { return self._s[1211]! } + public var SettingsSearch_Synonyms_Privacy_Title: String { return self._s[1212]! } + public var Notifications_PermissionsText: String { return self._s[1213]! } + public var SettingsSearch_Synonyms_Data_SaveIncomingPhotos: String { return self._s[1214]! } + public var Call_Flip: String { return self._s[1215]! } + public var Channel_AdminLog_CanDeleteMessagesOfOthers: String { return self._s[1217]! } + public var SocksProxySetup_ProxyStatusConnecting: String { return self._s[1218]! } + public var Wallet_TransactionInfo_StorageFeeInfoUrl: String { return self._s[1219]! } + public var PrivacyPhoneNumberSettings_DiscoveryHeader: String { return self._s[1220]! } + public var Channel_EditAdmin_PermissionPinMessages: String { return self._s[1222]! } + public var TwoStepAuth_ReEnterPasswordDescription: String { return self._s[1224]! } + public var Channel_TooMuchBots: String { return self._s[1226]! } + public var Passport_DeletePassportConfirmation: String { return self._s[1227]! } + public var Login_InvalidCodeError: String { return self._s[1228]! } + public var StickerPacksSettings_FeaturedPacks: String { return self._s[1229]! } public func ChatList_DeleteSecretChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1228]!, self._r[1228]!, [_0]) + return formatWithArgumentRanges(self._s[1230]!, self._r[1230]!, [_0]) } public func GroupInfo_InvitationLinkAcceptChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1229]!, self._r[1229]!, [_0]) + return formatWithArgumentRanges(self._s[1231]!, self._r[1231]!, [_0]) } - public var VoiceOver_Navigation_ProxySettings: String { return self._s[1230]! } - public var Call_CallInProgressTitle: String { return self._s[1231]! } - public var Month_ShortSeptember: String { return self._s[1232]! } - public var Watch_ChannelInfo_Title: String { return self._s[1233]! } - public var ChatList_DeleteSavedMessagesConfirmation: String { return self._s[1236]! } - public var DialogList_PasscodeLockHelp: String { return self._s[1237]! } - public var Chat_MultipleTextMessagesDisabled: String { return self._s[1238]! } - public var Wallet_Receive_Title: String { return self._s[1239]! } - public var Notifications_Badge_IncludePublicGroups: String { return self._s[1240]! } - public var Channel_AdminLogFilter_EventsTitle: String { return self._s[1241]! } - public var PhotoEditor_CropReset: String { return self._s[1242]! } - public var Group_Username_CreatePrivateLinkHelp: String { return self._s[1244]! } - public var Channel_Management_LabelEditor: String { return self._s[1245]! } - public var Passport_Identity_LatinNameHelp: String { return self._s[1247]! } - public var PhotoEditor_HighlightsTool: String { return self._s[1248]! } - public var Wallet_Info_WalletCreated: String { return self._s[1249]! } - public var UserInfo_Title: String { return self._s[1250]! } - public var ChatList_HideAction: String { return self._s[1251]! } - public var AccessDenied_Title: String { return self._s[1252]! } - public var DialogList_SearchLabel: String { return self._s[1253]! } - public var Group_Setup_HistoryHidden: String { return self._s[1254]! } - public var TwoStepAuth_PasswordChangeSuccess: String { return self._s[1255]! } - public var State_Updating: String { return self._s[1257]! } - public var Contacts_TabTitle: String { return self._s[1258]! } - public var Notifications_Badge_CountUnreadMessages: String { return self._s[1260]! } - public var GroupInfo_GroupHistory: String { return self._s[1261]! } - public var Conversation_UnsupportedMediaPlaceholder: String { return self._s[1262]! } - public var Wallpaper_SetColor: String { return self._s[1263]! } - public var CheckoutInfo_ShippingInfoCountry: String { return self._s[1264]! } - public var SettingsSearch_Synonyms_SavedMessages: String { return self._s[1265]! } - public var Chat_AttachmentLimitReached: String { return self._s[1266]! } - public var Passport_Identity_OneOfTypeDriversLicense: String { return self._s[1267]! } - public var Contacts_NotRegisteredSection: String { return self._s[1268]! } + public var VoiceOver_Navigation_ProxySettings: String { return self._s[1232]! } + public var Call_CallInProgressTitle: String { return self._s[1233]! } + public var Month_ShortSeptember: String { return self._s[1234]! } + public var Watch_ChannelInfo_Title: String { return self._s[1235]! } + public var ChatList_DeleteSavedMessagesConfirmation: String { return self._s[1238]! } + public var DialogList_PasscodeLockHelp: String { return self._s[1239]! } + public var Chat_MultipleTextMessagesDisabled: String { return self._s[1240]! } + public var Wallet_Receive_Title: String { return self._s[1241]! } + public var Notifications_Badge_IncludePublicGroups: String { return self._s[1242]! } + public var Channel_AdminLogFilter_EventsTitle: String { return self._s[1243]! } + public var PhotoEditor_CropReset: String { return self._s[1244]! } + public var Group_Username_CreatePrivateLinkHelp: String { return self._s[1246]! } + public var Channel_Management_LabelEditor: String { return self._s[1247]! } + public var Passport_Identity_LatinNameHelp: String { return self._s[1249]! } + public var PhotoEditor_HighlightsTool: String { return self._s[1250]! } + public var Wallet_Info_WalletCreated: String { return self._s[1251]! } + public var UserInfo_Title: String { return self._s[1252]! } + public var ChatList_HideAction: String { return self._s[1253]! } + public var AccessDenied_Title: String { return self._s[1254]! } + public var DialogList_SearchLabel: String { return self._s[1255]! } + public var Group_Setup_HistoryHidden: String { return self._s[1256]! } + public var TwoStepAuth_PasswordChangeSuccess: String { return self._s[1257]! } + public var State_Updating: String { return self._s[1259]! } + public var Contacts_TabTitle: String { return self._s[1260]! } + public var Notifications_Badge_CountUnreadMessages: String { return self._s[1262]! } + public var GroupInfo_GroupHistory: String { return self._s[1263]! } + public var Conversation_UnsupportedMediaPlaceholder: String { return self._s[1264]! } + public var Wallpaper_SetColor: String { return self._s[1265]! } + public var CheckoutInfo_ShippingInfoCountry: String { return self._s[1266]! } + public var SettingsSearch_Synonyms_SavedMessages: String { return self._s[1267]! } + public var Chat_AttachmentLimitReached: String { return self._s[1268]! } + public var Passport_Identity_OneOfTypeDriversLicense: String { return self._s[1269]! } + public var Contacts_NotRegisteredSection: String { return self._s[1270]! } public func Time_PreciseDate_m4(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1269]!, self._r[1269]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1271]!, self._r[1271]!, [_1, _2, _3]) } - public var Paint_Clear: String { return self._s[1270]! } - public var StickerPacksSettings_ArchivedMasks: String { return self._s[1271]! } - public var SocksProxySetup_Connecting: String { return self._s[1272]! } - public var ExplicitContent_AlertChannel: String { return self._s[1273]! } - public var CreatePoll_AllOptionsAdded: String { return self._s[1274]! } - public var Conversation_Contact: String { return self._s[1275]! } - public var Login_CodeExpired: String { return self._s[1276]! } - public var Passport_DiscardMessageAction: String { return self._s[1277]! } - public var ChatList_Context_Unpin: String { return self._s[1278]! } - public var Channel_AdminLog_MessagePreviousDescription: String { return self._s[1279]! } + public var Paint_Clear: String { return self._s[1272]! } + public var StickerPacksSettings_ArchivedMasks: String { return self._s[1273]! } + public var SocksProxySetup_Connecting: String { return self._s[1274]! } + public var ExplicitContent_AlertChannel: String { return self._s[1275]! } + public var CreatePoll_AllOptionsAdded: String { return self._s[1276]! } + public var Conversation_Contact: String { return self._s[1277]! } + public var Login_CodeExpired: String { return self._s[1278]! } + public var Passport_DiscardMessageAction: String { return self._s[1279]! } + public var ChatList_Context_Unpin: String { return self._s[1280]! } + public var Channel_AdminLog_MessagePreviousDescription: String { return self._s[1281]! } public func VoiceOver_Chat_MusicFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1280]!, self._r[1280]!, [_0]) + return formatWithArgumentRanges(self._s[1282]!, self._r[1282]!, [_0]) } - public var Channel_AdminLog_EmptyMessageText: String { return self._s[1281]! } - public var SettingsSearch_Synonyms_Data_NetworkUsage: String { return self._s[1282]! } + public var Channel_AdminLog_EmptyMessageText: String { return self._s[1283]! } + public var SettingsSearch_Synonyms_Data_NetworkUsage: String { return self._s[1284]! } public func Group_EditAdmin_RankInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1283]!, self._r[1283]!, [_0]) + return formatWithArgumentRanges(self._s[1285]!, self._r[1285]!, [_0]) } - public var Month_ShortApril: String { return self._s[1284]! } - public var AuthSessions_CurrentSession: String { return self._s[1285]! } - public var Chat_AttachmentMultipleFilesDisabled: String { return self._s[1288]! } - public var Wallet_Navigation_Cancel: String { return self._s[1290]! } - public var WallpaperPreview_CropTopText: String { return self._s[1291]! } - public var PrivacySettings_DeleteAccountIfAwayFor: String { return self._s[1292]! } - public var CheckoutInfo_ShippingInfoTitle: String { return self._s[1293]! } + public var Month_ShortApril: String { return self._s[1286]! } + public var AuthSessions_CurrentSession: String { return self._s[1287]! } + public var Chat_AttachmentMultipleFilesDisabled: String { return self._s[1290]! } + public var Wallet_Navigation_Cancel: String { return self._s[1292]! } + public var WallpaperPreview_CropTopText: String { return self._s[1293]! } + public var PrivacySettings_DeleteAccountIfAwayFor: String { return self._s[1294]! } + public var CheckoutInfo_ShippingInfoTitle: String { return self._s[1295]! } public func Conversation_ScheduleMessage_SendOn(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1294]!, self._r[1294]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1296]!, self._r[1296]!, [_0, _1]) } - public var Appearance_ThemePreview_Chat_2_Text: String { return self._s[1295]! } - public var Channel_Setup_TypePrivate: String { return self._s[1297]! } - public var Forward_ChannelReadOnly: String { return self._s[1300]! } - public var PhotoEditor_CurvesBlue: String { return self._s[1301]! } - public var AddContact_SharedContactException: String { return self._s[1302]! } - public var UserInfo_BotPrivacy: String { return self._s[1304]! } - public var Wallet_CreateInvoice_Title: String { return self._s[1305]! } - public var Notification_PassportValueEmail: String { return self._s[1306]! } - public var EmptyGroupInfo_Subtitle: String { return self._s[1307]! } - public var GroupPermission_NewTitle: String { return self._s[1308]! } - public var CallFeedback_ReasonDropped: String { return self._s[1309]! } - public var GroupInfo_Permissions_AddException: String { return self._s[1310]! } - public var Channel_SignMessages_Help: String { return self._s[1312]! } - public var Undo_ChatDeleted: String { return self._s[1314]! } - public var Conversation_ChatBackground: String { return self._s[1315]! } + public var Appearance_ThemePreview_Chat_2_Text: String { return self._s[1297]! } + public var Channel_Setup_TypePrivate: String { return self._s[1299]! } + public var Forward_ChannelReadOnly: String { return self._s[1302]! } + public var PhotoEditor_CurvesBlue: String { return self._s[1303]! } + public var AddContact_SharedContactException: String { return self._s[1304]! } + public var UserInfo_BotPrivacy: String { return self._s[1306]! } + public var Wallet_CreateInvoice_Title: String { return self._s[1307]! } + public var Notification_PassportValueEmail: String { return self._s[1308]! } + public var EmptyGroupInfo_Subtitle: String { return self._s[1309]! } + public var GroupPermission_NewTitle: String { return self._s[1310]! } + public var CallFeedback_ReasonDropped: String { return self._s[1311]! } + public var GroupInfo_Permissions_AddException: String { return self._s[1312]! } + public var Channel_SignMessages_Help: String { return self._s[1314]! } + public var Undo_ChatDeleted: String { return self._s[1316]! } + public var Conversation_ChatBackground: String { return self._s[1317]! } public func Wallet_WordCheck_Text(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1316]!, self._r[1316]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1318]!, self._r[1318]!, [_1, _2, _3]) } public func PUSH_CHAT_MESSAGE_QUIZ(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1317]!, self._r[1317]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1319]!, self._r[1319]!, [_1, _2, _3]) } - public var ChannelMembers_WhoCanAddMembers_Admins: String { return self._s[1318]! } - public var FastTwoStepSetup_EmailPlaceholder: String { return self._s[1319]! } - public var Passport_Language_pt: String { return self._s[1320]! } - public var VoiceOver_Chat_YourVoiceMessage: String { return self._s[1321]! } - public var NotificationsSound_Popcorn: String { return self._s[1324]! } - public var AutoNightTheme_Disabled: String { return self._s[1325]! } - public var BlockedUsers_LeavePrefix: String { return self._s[1326]! } - public var WallpaperPreview_CustomColorTopText: String { return self._s[1327]! } - public var Contacts_PermissionsSuppressWarningText: String { return self._s[1328]! } - public var WallpaperSearch_ColorBlue: String { return self._s[1329]! } + public var ChannelMembers_WhoCanAddMembers_Admins: String { return self._s[1320]! } + public var FastTwoStepSetup_EmailPlaceholder: String { return self._s[1321]! } + public var Passport_Language_pt: String { return self._s[1322]! } + public var VoiceOver_Chat_YourVoiceMessage: String { return self._s[1323]! } + public var NotificationsSound_Popcorn: String { return self._s[1326]! } + public var AutoNightTheme_Disabled: String { return self._s[1327]! } + public var BlockedUsers_LeavePrefix: String { return self._s[1328]! } + public var WallpaperPreview_CustomColorTopText: String { return self._s[1329]! } + public var Contacts_PermissionsSuppressWarningText: String { return self._s[1330]! } + public var WallpaperSearch_ColorBlue: String { return self._s[1331]! } public func CancelResetAccount_TextSMS(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1330]!, self._r[1330]!, [_0]) + return formatWithArgumentRanges(self._s[1332]!, self._r[1332]!, [_0]) } - public var CheckoutInfo_ErrorNameInvalid: String { return self._s[1331]! } - public var SocksProxySetup_UseForCalls: String { return self._s[1332]! } - public var Passport_DeleteDocumentConfirmation: String { return self._s[1334]! } + public var CheckoutInfo_ErrorNameInvalid: String { return self._s[1333]! } + public var SocksProxySetup_UseForCalls: String { return self._s[1334]! } + public var Passport_DeleteDocumentConfirmation: String { return self._s[1336]! } public func Conversation_Megabytes(_ _0: Float) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1335]!, self._r[1335]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[1337]!, self._r[1337]!, ["\(_0)"]) } - public var SocksProxySetup_Hostname: String { return self._s[1338]! } - public var ChatSettings_AutoDownloadSettings_OffForAll: String { return self._s[1339]! } - public var Compose_NewEncryptedChat: String { return self._s[1340]! } - public var Login_CodeFloodError: String { return self._s[1341]! } - public var Calls_TabTitle: String { return self._s[1342]! } - public var Privacy_ProfilePhoto: String { return self._s[1343]! } - public var Passport_Language_he: String { return self._s[1344]! } + public var SocksProxySetup_Hostname: String { return self._s[1340]! } + public var ChatSettings_AutoDownloadSettings_OffForAll: String { return self._s[1341]! } + public var Compose_NewEncryptedChat: String { return self._s[1342]! } + public var Login_CodeFloodError: String { return self._s[1343]! } + public var Calls_TabTitle: String { return self._s[1344]! } + public var Privacy_ProfilePhoto: String { return self._s[1345]! } + public var Passport_Language_he: String { return self._s[1346]! } public func Conversation_SetReminder_RemindToday(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1345]!, self._r[1345]!, [_0]) - } - public var GroupPermission_Title: String { return self._s[1346]! } - public func Channel_AdminLog_MessageGroupPreHistoryHidden(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1347]!, self._r[1347]!, [_0]) } - public var Wallet_TransactionInfo_SenderHeader: String { return self._s[1348]! } - public var GroupPermission_NoChangeInfo: String { return self._s[1349]! } - public var ChatList_DeleteForCurrentUser: String { return self._s[1350]! } - public var Tour_Text1: String { return self._s[1351]! } - public var Channel_EditAdmin_TransferOwnership: String { return self._s[1352]! } - public var Month_ShortFebruary: String { return self._s[1353]! } - public var TwoStepAuth_EmailSkip: String { return self._s[1354]! } + public var GroupPermission_Title: String { return self._s[1348]! } + public func Channel_AdminLog_MessageGroupPreHistoryHidden(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1349]!, self._r[1349]!, [_0]) + } + public var Wallet_TransactionInfo_SenderHeader: String { return self._s[1350]! } + public var GroupPermission_NoChangeInfo: String { return self._s[1351]! } + public var ChatList_DeleteForCurrentUser: String { return self._s[1352]! } + public var Tour_Text1: String { return self._s[1353]! } + public var Channel_EditAdmin_TransferOwnership: String { return self._s[1354]! } + public var Month_ShortFebruary: String { return self._s[1355]! } + public var TwoStepAuth_EmailSkip: String { return self._s[1356]! } public func Wallet_Time_PreciseDate_m4(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1355]!, self._r[1355]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1357]!, self._r[1357]!, [_1, _2, _3]) } - public var NotificationsSound_Glass: String { return self._s[1356]! } - public var Appearance_ThemeNightBlue: String { return self._s[1357]! } - public var CheckoutInfo_Pay: String { return self._s[1358]! } - public var Invite_LargeRecipientsCountWarning: String { return self._s[1360]! } - public var Call_CallAgain: String { return self._s[1362]! } - public var AttachmentMenu_SendAsFile: String { return self._s[1363]! } - public var AccessDenied_MicrophoneRestricted: String { return self._s[1364]! } - public var Passport_InvalidPasswordError: String { return self._s[1365]! } - public var Watch_Message_Game: String { return self._s[1366]! } - public var Stickers_Install: String { return self._s[1367]! } - public var VoiceOver_Chat_Message: String { return self._s[1368]! } - public var PrivacyLastSeenSettings_NeverShareWith: String { return self._s[1369]! } - public var Passport_Identity_ResidenceCountry: String { return self._s[1371]! } - public var Notifications_GroupNotificationsHelp: String { return self._s[1372]! } - public var AuthSessions_OtherSessions: String { return self._s[1373]! } - public var Channel_Username_Help: String { return self._s[1374]! } - public var Camera_Title: String { return self._s[1375]! } - public var IntentsSettings_Title: String { return self._s[1376]! } - public var GroupInfo_SetGroupPhotoDelete: String { return self._s[1378]! } - public var Privacy_ProfilePhoto_NeverShareWith_Title: String { return self._s[1379]! } - public var Channel_AdminLog_SendPolls: String { return self._s[1380]! } - public var Channel_AdminLog_TitleAllEvents: String { return self._s[1381]! } - public var Channel_EditAdmin_PermissionInviteMembers: String { return self._s[1382]! } - public var Contacts_MemberSearchSectionTitleGroup: String { return self._s[1383]! } - public var ScheduledMessages_DeleteMany: String { return self._s[1384]! } - public var Conversation_RestrictedStickers: String { return self._s[1385]! } - public var Notifications_ExceptionsResetToDefaults: String { return self._s[1387]! } - public var UserInfo_TelegramCall: String { return self._s[1389]! } - public var TwoStepAuth_SetupResendEmailCode: String { return self._s[1390]! } - public var CreatePoll_OptionsHeader: String { return self._s[1391]! } - public var SettingsSearch_Synonyms_Data_CallsUseLessData: String { return self._s[1392]! } - public var ArchivedChats_IntroTitle1: String { return self._s[1393]! } - public var Privacy_GroupsAndChannels_AlwaysAllow_Title: String { return self._s[1394]! } - public var Theme_Colors_Proceed: String { return self._s[1395]! } - public var Passport_Identity_EditPersonalDetails: String { return self._s[1396]! } + public var NotificationsSound_Glass: String { return self._s[1358]! } + public var Appearance_ThemeNightBlue: String { return self._s[1359]! } + public var CheckoutInfo_Pay: String { return self._s[1360]! } + public var Invite_LargeRecipientsCountWarning: String { return self._s[1362]! } + public var Call_CallAgain: String { return self._s[1364]! } + public var AttachmentMenu_SendAsFile: String { return self._s[1365]! } + public var AccessDenied_MicrophoneRestricted: String { return self._s[1366]! } + public var Passport_InvalidPasswordError: String { return self._s[1367]! } + public var Watch_Message_Game: String { return self._s[1368]! } + public var Stickers_Install: String { return self._s[1369]! } + public var VoiceOver_Chat_Message: String { return self._s[1370]! } + public var PrivacyLastSeenSettings_NeverShareWith: String { return self._s[1371]! } + public var Passport_Identity_ResidenceCountry: String { return self._s[1373]! } + public var Notifications_GroupNotificationsHelp: String { return self._s[1374]! } + public var AuthSessions_OtherSessions: String { return self._s[1375]! } + public var Channel_Username_Help: String { return self._s[1376]! } + public var Camera_Title: String { return self._s[1377]! } + public var IntentsSettings_Title: String { return self._s[1378]! } + public var GroupInfo_SetGroupPhotoDelete: String { return self._s[1380]! } + public var Privacy_ProfilePhoto_NeverShareWith_Title: String { return self._s[1381]! } + public var Channel_AdminLog_SendPolls: String { return self._s[1382]! } + public var Channel_AdminLog_TitleAllEvents: String { return self._s[1383]! } + public var Channel_EditAdmin_PermissionInviteMembers: String { return self._s[1384]! } + public var Contacts_MemberSearchSectionTitleGroup: String { return self._s[1385]! } + public var ScheduledMessages_DeleteMany: String { return self._s[1386]! } + public var Conversation_RestrictedStickers: String { return self._s[1387]! } + public var Notifications_ExceptionsResetToDefaults: String { return self._s[1389]! } + public var UserInfo_TelegramCall: String { return self._s[1391]! } + public var TwoStepAuth_SetupResendEmailCode: String { return self._s[1392]! } + public var CreatePoll_OptionsHeader: String { return self._s[1393]! } + public var SettingsSearch_Synonyms_Data_CallsUseLessData: String { return self._s[1394]! } + public var ArchivedChats_IntroTitle1: String { return self._s[1395]! } + public var Privacy_GroupsAndChannels_AlwaysAllow_Title: String { return self._s[1396]! } + public var Theme_Colors_Proceed: String { return self._s[1397]! } + public var Passport_Identity_EditPersonalDetails: String { return self._s[1398]! } public func Time_PreciseDate_m1(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1397]!, self._r[1397]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1399]!, self._r[1399]!, [_1, _2, _3]) } - public var Wallet_Month_GenAugust: String { return self._s[1398]! } - public var Settings_SaveEditedPhotos: String { return self._s[1399]! } - public var TwoStepAuth_ConfirmationTitle: String { return self._s[1400]! } - public var Privacy_GroupsAndChannels_NeverAllow_Title: String { return self._s[1401]! } - public var Conversation_MessageDialogRetry: String { return self._s[1402]! } - public var ChatList_Context_MarkAsUnread: String { return self._s[1403]! } - public var MessagePoll_SubmitVote: String { return self._s[1404]! } - public var Conversation_DiscardVoiceMessageAction: String { return self._s[1405]! } - public var Permissions_PeopleNearbyTitle_v0: String { return self._s[1406]! } - public var Group_Setup_TypeHeader: String { return self._s[1407]! } - public var Paint_RecentStickers: String { return self._s[1408]! } - public var PhotoEditor_GrainTool: String { return self._s[1409]! } - public var CheckoutInfo_ShippingInfoState: String { return self._s[1410]! } - public var EmptyGroupInfo_Line4: String { return self._s[1411]! } - public var Watch_AuthRequired: String { return self._s[1413]! } + public var Wallet_Month_GenAugust: String { return self._s[1400]! } + public var Settings_SaveEditedPhotos: String { return self._s[1401]! } + public var TwoStepAuth_ConfirmationTitle: String { return self._s[1402]! } + public var Privacy_GroupsAndChannels_NeverAllow_Title: String { return self._s[1403]! } + public var Conversation_MessageDialogRetry: String { return self._s[1404]! } + public var ChatList_Context_MarkAsUnread: String { return self._s[1405]! } + public var MessagePoll_SubmitVote: String { return self._s[1406]! } + public var Conversation_DiscardVoiceMessageAction: String { return self._s[1407]! } + public var Permissions_PeopleNearbyTitle_v0: String { return self._s[1408]! } + public var Group_Setup_TypeHeader: String { return self._s[1409]! } + public var Paint_RecentStickers: String { return self._s[1410]! } + public var PhotoEditor_GrainTool: String { return self._s[1411]! } + public var CheckoutInfo_ShippingInfoState: String { return self._s[1412]! } + public var EmptyGroupInfo_Line4: String { return self._s[1413]! } + public var Watch_AuthRequired: String { return self._s[1415]! } public func Passport_Email_UseTelegramEmail(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1414]!, self._r[1414]!, [_0]) + return formatWithArgumentRanges(self._s[1416]!, self._r[1416]!, [_0]) } - public var Conversation_EncryptedDescriptionTitle: String { return self._s[1415]! } - public var ChannelIntro_Text: String { return self._s[1416]! } - public var DialogList_DeleteBotConfirmation: String { return self._s[1417]! } - public var GroupPermission_NoSendMedia: String { return self._s[1418]! } - public var Calls_AddTab: String { return self._s[1419]! } - public var Message_ReplyActionButtonShowReceipt: String { return self._s[1420]! } - public var Channel_AdminLog_EmptyFilterText: String { return self._s[1421]! } - public var Conversation_WalletRequiredSetup: String { return self._s[1422]! } - public var Notification_MessageLifetime1d: String { return self._s[1423]! } - public var Notifications_ChannelNotificationsExceptionsHelp: String { return self._s[1424]! } - public var Channel_BanUser_PermissionsHeader: String { return self._s[1425]! } - public var Passport_Identity_GenderFemale: String { return self._s[1426]! } - public var BlockedUsers_BlockTitle: String { return self._s[1427]! } + public var Conversation_EncryptedDescriptionTitle: String { return self._s[1417]! } + public var ChannelIntro_Text: String { return self._s[1418]! } + public var DialogList_DeleteBotConfirmation: String { return self._s[1419]! } + public var GroupPermission_NoSendMedia: String { return self._s[1420]! } + public var Calls_AddTab: String { return self._s[1421]! } + public var Message_ReplyActionButtonShowReceipt: String { return self._s[1422]! } + public var Channel_AdminLog_EmptyFilterText: String { return self._s[1423]! } + public var Conversation_WalletRequiredSetup: String { return self._s[1424]! } + public var Notification_MessageLifetime1d: String { return self._s[1425]! } + public var Notifications_ChannelNotificationsExceptionsHelp: String { return self._s[1426]! } + public var Channel_BanUser_PermissionsHeader: String { return self._s[1427]! } + public var Passport_Identity_GenderFemale: String { return self._s[1428]! } + public var BlockedUsers_BlockTitle: String { return self._s[1429]! } public func PUSH_CHANNEL_MESSAGE_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1428]!, self._r[1428]!, [_1]) + return formatWithArgumentRanges(self._s[1430]!, self._r[1430]!, [_1]) } - public var Weekday_Yesterday: String { return self._s[1429]! } - public var WallpaperSearch_ColorBlack: String { return self._s[1430]! } - public var Settings_Context_Logout: String { return self._s[1431]! } - public var Wallet_Info_UnknownTransaction: String { return self._s[1432]! } - public var ChatList_ArchiveAction: String { return self._s[1433]! } - public var AutoNightTheme_Scheduled: String { return self._s[1434]! } - public var TwoFactorSetup_Email_SkipAction: String { return self._s[1435]! } - public var Settings_Devices: String { return self._s[1436]! } - public var ContactInfo_Note: String { return self._s[1437]! } + public var Weekday_Yesterday: String { return self._s[1431]! } + public var WallpaperSearch_ColorBlack: String { return self._s[1432]! } + public var Settings_Context_Logout: String { return self._s[1433]! } + public var Wallet_Info_UnknownTransaction: String { return self._s[1434]! } + public var ChatList_ArchiveAction: String { return self._s[1435]! } + public var AutoNightTheme_Scheduled: String { return self._s[1436]! } + public var TwoFactorSetup_Email_SkipAction: String { return self._s[1437]! } + public var Settings_Devices: String { return self._s[1438]! } + public var ContactInfo_Note: String { return self._s[1439]! } public func Login_PhoneGenericEmailBody(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String, _ _6: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1438]!, self._r[1438]!, [_1, _2, _3, _4, _5, _6]) + return formatWithArgumentRanges(self._s[1440]!, self._r[1440]!, [_1, _2, _3, _4, _5, _6]) } - public var EditTheme_ThemeTemplateAlertTitle: String { return self._s[1439]! } - public var Wallet_Receive_CreateInvoice: String { return self._s[1440]! } - public var PrivacyPolicy_DeclineDeleteNow: String { return self._s[1441]! } - public var Theme_Colors_ColorWallpaperWarningProceed: String { return self._s[1442]! } + public var EditTheme_ThemeTemplateAlertTitle: String { return self._s[1441]! } + public var Wallet_Receive_CreateInvoice: String { return self._s[1442]! } + public var PrivacyPolicy_DeclineDeleteNow: String { return self._s[1443]! } + public var Theme_Colors_ColorWallpaperWarningProceed: String { return self._s[1444]! } public func PUSH_CHAT_JOINED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1443]!, self._r[1443]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1445]!, self._r[1445]!, [_1, _2]) } - public var CreatePoll_Create: String { return self._s[1444]! } - public var Channel_Members_AddBannedErrorAdmin: String { return self._s[1445]! } + public var CreatePoll_Create: String { return self._s[1446]! } + public var Channel_Members_AddBannedErrorAdmin: String { return self._s[1447]! } public func Notification_CallFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1446]!, self._r[1446]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1448]!, self._r[1448]!, [_1, _2]) } - public var ScheduledMessages_ClearAllConfirmation: String { return self._s[1447]! } - public var Checkout_ErrorProviderAccountInvalid: String { return self._s[1448]! } - public var Notifications_InAppNotificationsSounds: String { return self._s[1450]! } + public var ScheduledMessages_ClearAllConfirmation: String { return self._s[1449]! } + public var Checkout_ErrorProviderAccountInvalid: String { return self._s[1450]! } + public var Notifications_InAppNotificationsSounds: String { return self._s[1452]! } public func PUSH_PINNED_GAME_SCORE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1451]!, self._r[1451]!, [_1]) + return formatWithArgumentRanges(self._s[1453]!, self._r[1453]!, [_1]) } - public var Preview_OpenInInstagram: String { return self._s[1452]! } - public var Notification_MessageLifetimeRemovedOutgoing: String { return self._s[1453]! } + public var Preview_OpenInInstagram: String { return self._s[1454]! } + public var Notification_MessageLifetimeRemovedOutgoing: String { return self._s[1455]! } public func PUSH_CHAT_ADD_MEMBER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1454]!, self._r[1454]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1456]!, self._r[1456]!, [_1, _2, _3]) } public func Passport_PrivacyPolicy(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1455]!, self._r[1455]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1457]!, self._r[1457]!, [_1, _2]) } - public var Channel_AdminLog_InfoPanelAlertTitle: String { return self._s[1456]! } - public var ArchivedChats_IntroText3: String { return self._s[1457]! } - public var ChatList_UndoArchiveHiddenText: String { return self._s[1458]! } - public var NetworkUsageSettings_TotalSection: String { return self._s[1459]! } - public var Wallet_Month_GenSeptember: String { return self._s[1460]! } - public var Channel_Setup_TypePrivateHelp: String { return self._s[1461]! } + public var Channel_AdminLog_InfoPanelAlertTitle: String { return self._s[1458]! } + public var ArchivedChats_IntroText3: String { return self._s[1459]! } + public var ChatList_UndoArchiveHiddenText: String { return self._s[1460]! } + public var NetworkUsageSettings_TotalSection: String { return self._s[1461]! } + public var Wallet_Month_GenSeptember: String { return self._s[1462]! } + public var Channel_Setup_TypePrivateHelp: String { return self._s[1463]! } public func PUSH_CHAT_MESSAGE_POLL(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1462]!, self._r[1462]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1464]!, self._r[1464]!, [_1, _2, _3]) } - public var Privacy_GroupsAndChannels_NeverAllow_Placeholder: String { return self._s[1464]! } - public var FastTwoStepSetup_HintSection: String { return self._s[1465]! } - public var Wallpaper_PhotoLibrary: String { return self._s[1466]! } - public var TwoStepAuth_SetupResendEmailCodeAlert: String { return self._s[1467]! } - public var Gif_NoGifsFound: String { return self._s[1468]! } - public var Watch_LastSeen_WithinAMonth: String { return self._s[1469]! } - public var VoiceOver_MessageContextDelete: String { return self._s[1470]! } - public var EditTheme_Preview: String { return self._s[1471]! } + public var Privacy_GroupsAndChannels_NeverAllow_Placeholder: String { return self._s[1466]! } + public var FastTwoStepSetup_HintSection: String { return self._s[1467]! } + public var Wallpaper_PhotoLibrary: String { return self._s[1468]! } + public var TwoStepAuth_SetupResendEmailCodeAlert: String { return self._s[1469]! } + public var Gif_NoGifsFound: String { return self._s[1470]! } + public var Watch_LastSeen_WithinAMonth: String { return self._s[1471]! } + public var VoiceOver_MessageContextDelete: String { return self._s[1472]! } + public var EditTheme_Preview: String { return self._s[1473]! } public func ClearCache_StorageTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1472]!, self._r[1472]!, [_0]) + return formatWithArgumentRanges(self._s[1474]!, self._r[1474]!, [_0]) } - public var GroupInfo_ActionPromote: String { return self._s[1473]! } - public var PasscodeSettings_SimplePasscode: String { return self._s[1474]! } - public var GroupInfo_Permissions_Title: String { return self._s[1475]! } - public var Permissions_ContactsText_v0: String { return self._s[1476]! } - public var PrivacyPhoneNumberSettings_CustomDisabledHelp: String { return self._s[1477]! } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedPublicGroups: String { return self._s[1478]! } - public var PrivacySettings_DataSettingsHelp: String { return self._s[1481]! } - public var Passport_FieldEmailHelp: String { return self._s[1482]! } + public var GroupInfo_ActionPromote: String { return self._s[1475]! } + public var PasscodeSettings_SimplePasscode: String { return self._s[1476]! } + public var GroupInfo_Permissions_Title: String { return self._s[1477]! } + public var Permissions_ContactsText_v0: String { return self._s[1478]! } + public var PrivacyPhoneNumberSettings_CustomDisabledHelp: String { return self._s[1479]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedPublicGroups: String { return self._s[1480]! } + public var PrivacySettings_DataSettingsHelp: String { return self._s[1483]! } + public var Passport_FieldEmailHelp: String { return self._s[1484]! } public func Activity_RemindAboutUser(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1483]!, self._r[1483]!, [_0]) + return formatWithArgumentRanges(self._s[1485]!, self._r[1485]!, [_0]) } - public var Passport_Identity_GenderPlaceholder: String { return self._s[1484]! } - public var Weekday_ShortSaturday: String { return self._s[1485]! } - public var ContactInfo_PhoneLabelMain: String { return self._s[1486]! } - public var Watch_Conversation_UserInfo: String { return self._s[1487]! } - public var CheckoutInfo_ShippingInfoCityPlaceholder: String { return self._s[1488]! } - public var GroupPermission_PermissionDisabledByDefault: String { return self._s[1489]! } - public var PrivacyLastSeenSettings_Title: String { return self._s[1490]! } - public var Conversation_ShareBotLocationConfirmation: String { return self._s[1491]! } - public var PhotoEditor_VignetteTool: String { return self._s[1492]! } - public var Passport_Address_Street1Placeholder: String { return self._s[1493]! } - public var Passport_Language_et: String { return self._s[1494]! } - public var AppUpgrade_Running: String { return self._s[1495]! } - public var Channel_DiscussionGroup_Info: String { return self._s[1497]! } - public var EditTheme_Create_Preview_IncomingReplyName: String { return self._s[1498]! } - public var Passport_Language_bg: String { return self._s[1499]! } - public var Stickers_NoStickersFound: String { return self._s[1501]! } + public var Passport_Identity_GenderPlaceholder: String { return self._s[1486]! } + public var Weekday_ShortSaturday: String { return self._s[1487]! } + public var ContactInfo_PhoneLabelMain: String { return self._s[1488]! } + public var Watch_Conversation_UserInfo: String { return self._s[1489]! } + public var CheckoutInfo_ShippingInfoCityPlaceholder: String { return self._s[1490]! } + public var GroupPermission_PermissionDisabledByDefault: String { return self._s[1491]! } + public var PrivacyLastSeenSettings_Title: String { return self._s[1492]! } + public var Conversation_ShareBotLocationConfirmation: String { return self._s[1493]! } + public var PhotoEditor_VignetteTool: String { return self._s[1494]! } + public var Passport_Address_Street1Placeholder: String { return self._s[1495]! } + public var Passport_Language_et: String { return self._s[1496]! } + public var AppUpgrade_Running: String { return self._s[1497]! } + public var Channel_DiscussionGroup_Info: String { return self._s[1499]! } + public var EditTheme_Create_Preview_IncomingReplyName: String { return self._s[1500]! } + public var Passport_Language_bg: String { return self._s[1501]! } + public var Stickers_NoStickersFound: String { return self._s[1503]! } public func PUSH_CHANNEL_MESSAGE_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1503]!, self._r[1503]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1505]!, self._r[1505]!, [_1, _2]) } public func VoiceOver_Chat_ContactFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1504]!, self._r[1504]!, [_0]) + return formatWithArgumentRanges(self._s[1506]!, self._r[1506]!, [_0]) } - public var Wallet_Month_GenJuly: String { return self._s[1505]! } - public var Wallet_Receive_AddressHeader: String { return self._s[1506]! } - public var Wallet_Send_AmountText: String { return self._s[1507]! } - public var Settings_About: String { return self._s[1508]! } + public var Wallet_Month_GenJuly: String { return self._s[1507]! } + public var Wallet_Receive_AddressHeader: String { return self._s[1508]! } + public var Wallet_Send_AmountText: String { return self._s[1509]! } + public var Settings_About: String { return self._s[1510]! } public func Channel_AdminLog_MessageRestricted(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1509]!, self._r[1509]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[1511]!, self._r[1511]!, [_0, _1, _2]) } - public var ChatList_Context_MarkAsRead: String { return self._s[1511]! } - public var KeyCommand_NewMessage: String { return self._s[1512]! } - public var Group_ErrorAddBlocked: String { return self._s[1513]! } + public var ChatList_Context_MarkAsRead: String { return self._s[1513]! } + public var KeyCommand_NewMessage: String { return self._s[1514]! } + public var Group_ErrorAddBlocked: String { return self._s[1515]! } public func Message_PaymentSent(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1514]!, self._r[1514]!, [_0]) + return formatWithArgumentRanges(self._s[1516]!, self._r[1516]!, [_0]) } - public var Map_LocationTitle: String { return self._s[1515]! } - public var ReportGroupLocation_Title: String { return self._s[1516]! } - public var CallSettings_UseLessDataLongDescription: String { return self._s[1517]! } - public var Cache_ClearProgress: String { return self._s[1518]! } + public var Map_LocationTitle: String { return self._s[1517]! } + public var ReportGroupLocation_Title: String { return self._s[1518]! } + public var CallSettings_UseLessDataLongDescription: String { return self._s[1519]! } + public var Cache_ClearProgress: String { return self._s[1520]! } public func Channel_Management_ErrorNotMember(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1519]!, self._r[1519]!, [_0]) + return formatWithArgumentRanges(self._s[1521]!, self._r[1521]!, [_0]) } - public var GroupRemoved_AddToGroup: String { return self._s[1520]! } - public var Passport_UpdateRequiredError: String { return self._s[1521]! } - public var Wallet_SecureStorageNotAvailable_Text: String { return self._s[1522]! } + public var GroupRemoved_AddToGroup: String { return self._s[1522]! } + public var Passport_UpdateRequiredError: String { return self._s[1523]! } + public var Wallet_SecureStorageNotAvailable_Text: String { return self._s[1524]! } public func PUSH_MESSAGE_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1523]!, self._r[1523]!, [_1]) + return formatWithArgumentRanges(self._s[1525]!, self._r[1525]!, [_1]) } - public var Notifications_PermissionsSuppressWarningText: String { return self._s[1525]! } - public var Passport_Identity_MainPageHelp: String { return self._s[1526]! } - public var Conversation_StatusKickedFromGroup: String { return self._s[1527]! } - public var Passport_Language_ka: String { return self._s[1528]! } + public var Notifications_PermissionsSuppressWarningText: String { return self._s[1527]! } + public var Passport_Identity_MainPageHelp: String { return self._s[1528]! } + public var Conversation_StatusKickedFromGroup: String { return self._s[1529]! } + public var Passport_Language_ka: String { return self._s[1530]! } public func Wallet_Time_PreciseDate_m12(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1529]!, self._r[1529]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1531]!, self._r[1531]!, [_1, _2, _3]) } - public var Call_Decline: String { return self._s[1530]! } - public var SocksProxySetup_ProxyEnabled: String { return self._s[1531]! } - public var TwoFactorSetup_Email_SkipConfirmationText: String { return self._s[1534]! } + public var Call_Decline: String { return self._s[1532]! } + public var SocksProxySetup_ProxyEnabled: String { return self._s[1533]! } + public var TwoFactorSetup_Email_SkipConfirmationText: String { return self._s[1536]! } public func AuthCode_Alert(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1535]!, self._r[1535]!, [_0]) + return formatWithArgumentRanges(self._s[1537]!, self._r[1537]!, [_0]) } - public var CallFeedback_Send: String { return self._s[1536]! } - public var EditTheme_EditTitle: String { return self._s[1537]! } + public var CallFeedback_Send: String { return self._s[1538]! } + public var EditTheme_EditTitle: String { return self._s[1539]! } public func Channel_AdminLog_MessagePromotedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1538]!, self._r[1538]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1540]!, self._r[1540]!, [_1, _2]) } - public var Passport_Phone_UseTelegramNumberHelp: String { return self._s[1539]! } + public var Passport_Phone_UseTelegramNumberHelp: String { return self._s[1541]! } public func Wallet_Updated_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1541]!, self._r[1541]!, [_0]) + return formatWithArgumentRanges(self._s[1543]!, self._r[1543]!, [_0]) } - public var SettingsSearch_Synonyms_Data_Title: String { return self._s[1542]! } - public var Passport_DeletePassport: String { return self._s[1543]! } - public var Appearance_AppIconFilled: String { return self._s[1544]! } - public var Privacy_Calls_P2PAlways: String { return self._s[1545]! } - public var Month_ShortDecember: String { return self._s[1546]! } - public var Channel_AdminLog_CanEditMessages: String { return self._s[1548]! } + public var SettingsSearch_Synonyms_Data_Title: String { return self._s[1544]! } + public var Passport_DeletePassport: String { return self._s[1545]! } + public var Appearance_AppIconFilled: String { return self._s[1546]! } + public var Privacy_Calls_P2PAlways: String { return self._s[1547]! } + public var Month_ShortDecember: String { return self._s[1548]! } + public var Channel_AdminLog_CanEditMessages: String { return self._s[1550]! } public func Contacts_AccessDeniedHelpLandscape(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1549]!, self._r[1549]!, [_0]) + return formatWithArgumentRanges(self._s[1551]!, self._r[1551]!, [_0]) } - public var Channel_Stickers_Searching: String { return self._s[1550]! } - public var Conversation_EncryptedDescription1: String { return self._s[1551]! } - public var Conversation_EncryptedDescription2: String { return self._s[1552]! } - public var PasscodeSettings_PasscodeOptions: String { return self._s[1553]! } - public var Conversation_EncryptedDescription3: String { return self._s[1555]! } - public var PhotoEditor_SharpenTool: String { return self._s[1556]! } - public var Wallet_Configuration_Title: String { return self._s[1557]! } + public var Channel_Stickers_Searching: String { return self._s[1552]! } + public var Conversation_EncryptedDescription1: String { return self._s[1553]! } + public var Conversation_EncryptedDescription2: String { return self._s[1554]! } + public var PasscodeSettings_PasscodeOptions: String { return self._s[1555]! } + public var Conversation_EncryptedDescription3: String { return self._s[1557]! } + public var PhotoEditor_SharpenTool: String { return self._s[1558]! } + public var Wallet_Configuration_Title: String { return self._s[1559]! } public func Conversation_AddNameToContacts(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1558]!, self._r[1558]!, [_0]) + return formatWithArgumentRanges(self._s[1560]!, self._r[1560]!, [_0]) } - public var Conversation_EncryptedDescription4: String { return self._s[1560]! } - public var Channel_Members_AddMembers: String { return self._s[1561]! } - public var Wallpaper_Search: String { return self._s[1562]! } - public var Weekday_Friday: String { return self._s[1564]! } - public var Privacy_ContactsSync: String { return self._s[1565]! } - public var SettingsSearch_Synonyms_Privacy_Data_ContactsReset: String { return self._s[1566]! } - public var ApplyLanguage_ChangeLanguageAction: String { return self._s[1567]! } + public var Conversation_EncryptedDescription4: String { return self._s[1562]! } + public var Channel_Members_AddMembers: String { return self._s[1563]! } + public var Wallpaper_Search: String { return self._s[1564]! } + public var Weekday_Friday: String { return self._s[1566]! } + public var Privacy_ContactsSync: String { return self._s[1567]! } + public var SettingsSearch_Synonyms_Privacy_Data_ContactsReset: String { return self._s[1568]! } + public var ApplyLanguage_ChangeLanguageAction: String { return self._s[1569]! } public func Channel_Management_RestrictedBy(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1568]!, self._r[1568]!, [_0]) + return formatWithArgumentRanges(self._s[1570]!, self._r[1570]!, [_0]) } - public var Wallet_Configuration_BlockchainIdHeader: String { return self._s[1569]! } - public var GroupInfo_Permissions_Removed: String { return self._s[1570]! } - public var ScheduledMessages_ScheduledOnline: String { return self._s[1571]! } - public var Passport_Identity_GenderMale: String { return self._s[1572]! } + public var Wallet_Configuration_BlockchainIdHeader: String { return self._s[1571]! } + public var GroupInfo_Permissions_Removed: String { return self._s[1572]! } + public var ScheduledMessages_ScheduledOnline: String { return self._s[1573]! } + public var Passport_Identity_GenderMale: String { return self._s[1574]! } public func Call_StatusBar(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1573]!, self._r[1573]!, [_0]) + return formatWithArgumentRanges(self._s[1575]!, self._r[1575]!, [_0]) } - public var Notifications_PermissionsKeepDisabled: String { return self._s[1574]! } - public var Conversation_JumpToDate: String { return self._s[1575]! } - public var Contacts_GlobalSearch: String { return self._s[1576]! } - public var AutoDownloadSettings_ResetHelp: String { return self._s[1577]! } - public var SettingsSearch_Synonyms_FAQ: String { return self._s[1578]! } - public var Profile_MessageLifetime1d: String { return self._s[1579]! } + public var Notifications_PermissionsKeepDisabled: String { return self._s[1576]! } + public var Conversation_JumpToDate: String { return self._s[1577]! } + public var Contacts_GlobalSearch: String { return self._s[1578]! } + public var AutoDownloadSettings_ResetHelp: String { return self._s[1579]! } + public var SettingsSearch_Synonyms_FAQ: String { return self._s[1580]! } + public var Profile_MessageLifetime1d: String { return self._s[1581]! } public func MESSAGE_INVOICE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1580]!, self._r[1580]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1582]!, self._r[1582]!, [_1, _2]) } - public var StickerPack_BuiltinPackName: String { return self._s[1583]! } + public var StickerPack_BuiltinPackName: String { return self._s[1585]! } public func PUSH_CHAT_MESSAGE_AUDIO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1584]!, self._r[1584]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1586]!, self._r[1586]!, [_1, _2]) } - public var VoiceOver_Chat_RecordModeVoiceMessageInfo: String { return self._s[1585]! } - public var Passport_InfoTitle: String { return self._s[1587]! } - public var Notifications_PermissionsUnreachableText: String { return self._s[1588]! } + public var VoiceOver_Chat_RecordModeVoiceMessageInfo: String { return self._s[1587]! } + public var Passport_InfoTitle: String { return self._s[1589]! } + public var Notifications_PermissionsUnreachableText: String { return self._s[1590]! } public func NetworkUsageSettings_CellularUsageSince(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1592]!, self._r[1592]!, [_0]) + return formatWithArgumentRanges(self._s[1594]!, self._r[1594]!, [_0]) } public func PUSH_CHAT_MESSAGE_GEO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1593]!, self._r[1593]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1595]!, self._r[1595]!, [_1, _2]) } - public var Passport_Address_TypePassportRegistrationUploadScan: String { return self._s[1594]! } - public var Profile_BotInfo: String { return self._s[1595]! } - public var Watch_Compose_CreateMessage: String { return self._s[1596]! } - public var AutoDownloadSettings_VoiceMessagesInfo: String { return self._s[1597]! } - public var Month_ShortNovember: String { return self._s[1598]! } - public var Conversation_ScamWarning: String { return self._s[1599]! } - public var Wallpaper_SetCustomBackground: String { return self._s[1600]! } - public var Appearance_TextSize_Title: String { return self._s[1601]! } - public var Passport_Identity_TranslationsHelp: String { return self._s[1602]! } - public var NotificationsSound_Chime: String { return self._s[1603]! } - public var Passport_Language_ko: String { return self._s[1605]! } - public var InviteText_URL: String { return self._s[1606]! } - public var TextFormat_Monospace: String { return self._s[1607]! } + public var Passport_Address_TypePassportRegistrationUploadScan: String { return self._s[1596]! } + public var Profile_BotInfo: String { return self._s[1597]! } + public var Watch_Compose_CreateMessage: String { return self._s[1598]! } + public var AutoDownloadSettings_VoiceMessagesInfo: String { return self._s[1599]! } + public var Month_ShortNovember: String { return self._s[1600]! } + public var Conversation_ScamWarning: String { return self._s[1601]! } + public var Wallpaper_SetCustomBackground: String { return self._s[1602]! } + public var Appearance_TextSize_Title: String { return self._s[1603]! } + public var Passport_Identity_TranslationsHelp: String { return self._s[1604]! } + public var NotificationsSound_Chime: String { return self._s[1605]! } + public var Passport_Language_ko: String { return self._s[1607]! } + public var InviteText_URL: String { return self._s[1608]! } + public var TextFormat_Monospace: String { return self._s[1609]! } public func Time_PreciseDate_m11(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1608]!, self._r[1608]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1610]!, self._r[1610]!, [_1, _2, _3]) } - public var EditTheme_Edit_BottomInfo: String { return self._s[1609]! } + public var EditTheme_Edit_BottomInfo: String { return self._s[1611]! } public func Login_WillSendSms(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1610]!, self._r[1610]!, [_0]) + return formatWithArgumentRanges(self._s[1612]!, self._r[1612]!, [_0]) } public func Watch_Time_ShortWeekdayAt(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1611]!, self._r[1611]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1613]!, self._r[1613]!, [_1, _2]) } - public var Wallet_Words_Title: String { return self._s[1612]! } - public var Wallet_Month_ShortMay: String { return self._s[1613]! } - public var EditTheme_CreateTitle: String { return self._s[1615]! } - public var Passport_InfoLearnMore: String { return self._s[1616]! } - public var TwoStepAuth_EmailPlaceholder: String { return self._s[1617]! } - public var Passport_Identity_AddIdentityCard: String { return self._s[1618]! } - public var Your_card_has_expired: String { return self._s[1619]! } - public var StickerPacksSettings_StickerPacksSection: String { return self._s[1620]! } - public var GroupInfo_InviteLink_Help: String { return self._s[1621]! } - public var TwoFactorSetup_EmailVerification_ResendAction: String { return self._s[1625]! } - public var Conversation_Report: String { return self._s[1627]! } - public var Notifications_MessageNotificationsSound: String { return self._s[1628]! } - public var Notification_MessageLifetime1m: String { return self._s[1629]! } - public var Privacy_ContactsTitle: String { return self._s[1630]! } - public var Conversation_ShareMyContactInfo: String { return self._s[1631]! } - public var Wallet_WordCheck_Title: String { return self._s[1632]! } - public var ChannelMembers_WhoCanAddMembersAdminsHelp: String { return self._s[1633]! } - public var Channel_Members_Title: String { return self._s[1634]! } - public var Map_OpenInWaze: String { return self._s[1635]! } - public var Appearance_RemoveThemeColorConfirmation: String { return self._s[1636]! } - public var Login_PhoneBannedError: String { return self._s[1637]! } + public var Wallet_Words_Title: String { return self._s[1614]! } + public var Wallet_Month_ShortMay: String { return self._s[1615]! } + public var EditTheme_CreateTitle: String { return self._s[1617]! } + public var Passport_InfoLearnMore: String { return self._s[1618]! } + public var TwoStepAuth_EmailPlaceholder: String { return self._s[1619]! } + public var Passport_Identity_AddIdentityCard: String { return self._s[1620]! } + public var Your_card_has_expired: String { return self._s[1621]! } + public var StickerPacksSettings_StickerPacksSection: String { return self._s[1622]! } + public var GroupInfo_InviteLink_Help: String { return self._s[1623]! } + public var TwoFactorSetup_EmailVerification_ResendAction: String { return self._s[1627]! } + public var Conversation_Report: String { return self._s[1629]! } + public var Notifications_MessageNotificationsSound: String { return self._s[1630]! } + public var Notification_MessageLifetime1m: String { return self._s[1631]! } + public var Privacy_ContactsTitle: String { return self._s[1632]! } + public var Conversation_ShareMyContactInfo: String { return self._s[1633]! } + public var Wallet_WordCheck_Title: String { return self._s[1634]! } + public var ChannelMembers_WhoCanAddMembersAdminsHelp: String { return self._s[1635]! } + public var Channel_Members_Title: String { return self._s[1636]! } + public var Map_OpenInWaze: String { return self._s[1637]! } + public var Appearance_RemoveThemeColorConfirmation: String { return self._s[1638]! } + public var Login_PhoneBannedError: String { return self._s[1639]! } public func LiveLocationUpdated_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1638]!, self._r[1638]!, [_0]) + return formatWithArgumentRanges(self._s[1640]!, self._r[1640]!, [_0]) } - public var IntentsSettings_MainAccount: String { return self._s[1639]! } - public var Group_Management_AddModeratorHelp: String { return self._s[1640]! } - public var AutoDownloadSettings_WifiTitle: String { return self._s[1641]! } - public var Common_OK: String { return self._s[1642]! } - public var Passport_Address_TypeBankStatementUploadScan: String { return self._s[1643]! } - public var Wallet_Words_NotDoneResponse: String { return self._s[1644]! } - public var Cache_Music: String { return self._s[1645]! } - public var Wallet_Configuration_SourceURL: String { return self._s[1646]! } - public var SettingsSearch_Synonyms_EditProfile_PhoneNumber: String { return self._s[1647]! } - public var PasscodeSettings_UnlockWithTouchId: String { return self._s[1649]! } - public var TwoStepAuth_HintPlaceholder: String { return self._s[1650]! } + public var IntentsSettings_MainAccount: String { return self._s[1641]! } + public var Group_Management_AddModeratorHelp: String { return self._s[1642]! } + public var AutoDownloadSettings_WifiTitle: String { return self._s[1643]! } + public var Common_OK: String { return self._s[1644]! } + public var Passport_Address_TypeBankStatementUploadScan: String { return self._s[1645]! } + public var Wallet_Words_NotDoneResponse: String { return self._s[1646]! } + public var Cache_Music: String { return self._s[1647]! } + public var Wallet_Configuration_SourceURL: String { return self._s[1648]! } + public var SettingsSearch_Synonyms_EditProfile_PhoneNumber: String { return self._s[1649]! } + public var PasscodeSettings_UnlockWithTouchId: String { return self._s[1651]! } + public var TwoStepAuth_HintPlaceholder: String { return self._s[1652]! } public func PUSH_PINNED_INVOICE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1651]!, self._r[1651]!, [_1]) + return formatWithArgumentRanges(self._s[1653]!, self._r[1653]!, [_1]) } public func Passport_RequestHeader(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1652]!, self._r[1652]!, [_0]) - } - public var TwoFactorSetup_Done_Action: String { return self._s[1653]! } - public func VoiceOver_Chat_ContactOrganization(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1654]!, self._r[1654]!, [_0]) } - public var Wallet_Send_ErrorNotEnoughFundsText: String { return self._s[1655]! } - public var Watch_MessageView_ViewOnPhone: String { return self._s[1657]! } - public var Privacy_Calls_CustomShareHelp: String { return self._s[1658]! } - public var Wallet_Receive_CreateInvoiceInfo: String { return self._s[1660]! } - public var ChangePhoneNumberNumber_Title: String { return self._s[1661]! } - public var State_ConnectingToProxyInfo: String { return self._s[1662]! } - public var Conversation_SwipeToReplyHintTitle: String { return self._s[1663]! } - public var Message_VideoMessage: String { return self._s[1665]! } - public var ChannelInfo_DeleteChannel: String { return self._s[1666]! } - public var ContactInfo_PhoneLabelOther: String { return self._s[1667]! } - public var Channel_EditAdmin_CannotEdit: String { return self._s[1668]! } - public var Passport_DeleteAddressConfirmation: String { return self._s[1669]! } - public func Wallet_Time_PreciseDate_m9(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1670]!, self._r[1670]!, [_1, _2, _3]) + public var TwoFactorSetup_Done_Action: String { return self._s[1655]! } + public func VoiceOver_Chat_ContactOrganization(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1656]!, self._r[1656]!, [_0]) } - public var WallpaperPreview_SwipeBottomText: String { return self._s[1671]! } - public var Activity_RecordingAudio: String { return self._s[1672]! } - public var SettingsSearch_Synonyms_Watch: String { return self._s[1673]! } - public var PasscodeSettings_TryAgainIn1Minute: String { return self._s[1674]! } - public var Wallet_Info_Address: String { return self._s[1675]! } + public var Wallet_Send_ErrorNotEnoughFundsText: String { return self._s[1657]! } + public var Watch_MessageView_ViewOnPhone: String { return self._s[1659]! } + public var Privacy_Calls_CustomShareHelp: String { return self._s[1660]! } + public var Wallet_Receive_CreateInvoiceInfo: String { return self._s[1662]! } + public var ChangePhoneNumberNumber_Title: String { return self._s[1663]! } + public var State_ConnectingToProxyInfo: String { return self._s[1664]! } + public var Conversation_SwipeToReplyHintTitle: String { return self._s[1665]! } + public var Message_VideoMessage: String { return self._s[1667]! } + public var ChannelInfo_DeleteChannel: String { return self._s[1668]! } + public var ContactInfo_PhoneLabelOther: String { return self._s[1669]! } + public var Channel_EditAdmin_CannotEdit: String { return self._s[1670]! } + public var Passport_DeleteAddressConfirmation: String { return self._s[1671]! } + public func Wallet_Time_PreciseDate_m9(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1672]!, self._r[1672]!, [_1, _2, _3]) + } + public var WallpaperPreview_SwipeBottomText: String { return self._s[1673]! } + public var Activity_RecordingAudio: String { return self._s[1674]! } + public var SettingsSearch_Synonyms_Watch: String { return self._s[1675]! } + public var PasscodeSettings_TryAgainIn1Minute: String { return self._s[1676]! } + public var Wallet_Info_Address: String { return self._s[1677]! } public func Notification_ChangedGroupName(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1677]!, self._r[1677]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1679]!, self._r[1679]!, [_0, _1]) } public func EmptyGroupInfo_Line1(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1681]!, self._r[1681]!, [_0]) + return formatWithArgumentRanges(self._s[1683]!, self._r[1683]!, [_0]) } - public var Conversation_ApplyLocalization: String { return self._s[1682]! } - public var TwoFactorSetup_Intro_Action: String { return self._s[1683]! } - public var UserInfo_AddPhone: String { return self._s[1684]! } - public var Map_ShareLiveLocationHelp: String { return self._s[1685]! } + public var Conversation_ApplyLocalization: String { return self._s[1684]! } + public var TwoFactorSetup_Intro_Action: String { return self._s[1685]! } + public var UserInfo_AddPhone: String { return self._s[1686]! } + public var Map_ShareLiveLocationHelp: String { return self._s[1687]! } public func Passport_Identity_NativeNameGenericHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1686]!, self._r[1686]!, [_0]) + return formatWithArgumentRanges(self._s[1688]!, self._r[1688]!, [_0]) } - public var Passport_Scans: String { return self._s[1688]! } - public var BlockedUsers_Unblock: String { return self._s[1689]! } + public var Passport_Scans: String { return self._s[1690]! } + public var BlockedUsers_Unblock: String { return self._s[1691]! } public func PUSH_ENCRYPTION_REQUEST(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1690]!, self._r[1690]!, [_1]) + return formatWithArgumentRanges(self._s[1692]!, self._r[1692]!, [_1]) } - public var Channel_Management_LabelCreator: String { return self._s[1691]! } - public var Conversation_ReportSpamAndLeave: String { return self._s[1692]! } - public var SettingsSearch_Synonyms_EditProfile_Bio: String { return self._s[1693]! } - public var ChatList_UndoArchiveMultipleTitle: String { return self._s[1694]! } - public var Passport_Identity_NativeNameGenericTitle: String { return self._s[1695]! } + public var Channel_Management_LabelCreator: String { return self._s[1693]! } + public var Conversation_ReportSpamAndLeave: String { return self._s[1694]! } + public var SettingsSearch_Synonyms_EditProfile_Bio: String { return self._s[1695]! } + public var ChatList_UndoArchiveMultipleTitle: String { return self._s[1696]! } + public var Passport_Identity_NativeNameGenericTitle: String { return self._s[1697]! } public func Login_EmailPhoneBody(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1696]!, self._r[1696]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[1698]!, self._r[1698]!, [_0, _1, _2]) } - public var Login_PhoneNumberHelp: String { return self._s[1697]! } - public var LastSeen_ALongTimeAgo: String { return self._s[1698]! } - public var Channel_AdminLog_CanPinMessages: String { return self._s[1699]! } - public var ChannelIntro_CreateChannel: String { return self._s[1700]! } - public var Conversation_UnreadMessages: String { return self._s[1701]! } - public var SettingsSearch_Synonyms_Stickers_ArchivedPacks: String { return self._s[1702]! } - public var Channel_AdminLog_EmptyText: String { return self._s[1703]! } - public var Theme_Context_Apply: String { return self._s[1704]! } - public var Notification_GroupActivated: String { return self._s[1705]! } - public var NotificationSettings_ContactJoinedInfo: String { return self._s[1706]! } - public var Wallet_Intro_CreateWallet: String { return self._s[1707]! } + public var Login_PhoneNumberHelp: String { return self._s[1699]! } + public var LastSeen_ALongTimeAgo: String { return self._s[1700]! } + public var Channel_AdminLog_CanPinMessages: String { return self._s[1701]! } + public var ChannelIntro_CreateChannel: String { return self._s[1702]! } + public var Conversation_UnreadMessages: String { return self._s[1703]! } + public var SettingsSearch_Synonyms_Stickers_ArchivedPacks: String { return self._s[1704]! } + public var Channel_AdminLog_EmptyText: String { return self._s[1705]! } + public var Theme_Context_Apply: String { return self._s[1706]! } + public var Notification_GroupActivated: String { return self._s[1707]! } + public var NotificationSettings_ContactJoinedInfo: String { return self._s[1708]! } + public var Wallet_Intro_CreateWallet: String { return self._s[1709]! } public func Notification_PinnedContactMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1708]!, self._r[1708]!, [_0]) + return formatWithArgumentRanges(self._s[1710]!, self._r[1710]!, [_0]) } public func DownloadingStatus(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1709]!, self._r[1709]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1711]!, self._r[1711]!, [_0, _1]) } - public var GroupInfo_ConvertToSupergroup: String { return self._s[1711]! } + public var GroupInfo_ConvertToSupergroup: String { return self._s[1713]! } public func PrivacyPolicy_AgeVerificationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1712]!, self._r[1712]!, [_0]) + return formatWithArgumentRanges(self._s[1714]!, self._r[1714]!, [_0]) } - public var Undo_DeletedChannel: String { return self._s[1713]! } - public var CallFeedback_AddComment: String { return self._s[1714]! } + public var Undo_DeletedChannel: String { return self._s[1715]! } + public var CallFeedback_AddComment: String { return self._s[1716]! } public func Conversation_OpenBotLinkAllowMessages(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1715]!, self._r[1715]!, [_0]) - } - public var Document_TargetConfirmationFormat: String { return self._s[1716]! } - public func Call_StatusOngoing(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1717]!, self._r[1717]!, [_0]) } - public var LogoutOptions_SetPasscodeTitle: String { return self._s[1718]! } + public var Document_TargetConfirmationFormat: String { return self._s[1718]! } + public func Call_StatusOngoing(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1719]!, self._r[1719]!, [_0]) + } + public var LogoutOptions_SetPasscodeTitle: String { return self._s[1720]! } public func PUSH_CHAT_MESSAGE_GAME_SCORE(_ _1: String, _ _2: String, _ _3: String, _ _4: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1719]!, self._r[1719]!, [_1, _2, _3, _4]) + return formatWithArgumentRanges(self._s[1721]!, self._r[1721]!, [_1, _2, _3, _4]) } - public var Wallet_SecureStorageChanged_PasscodeText: String { return self._s[1720]! } - public var Theme_ErrorNotFound: String { return self._s[1721]! } - public var Contacts_SortByName: String { return self._s[1722]! } - public var SettingsSearch_Synonyms_Privacy_Forwards: String { return self._s[1723]! } + public var Wallet_SecureStorageChanged_PasscodeText: String { return self._s[1722]! } + public var Theme_ErrorNotFound: String { return self._s[1723]! } + public var Contacts_SortByName: String { return self._s[1724]! } + public var SettingsSearch_Synonyms_Privacy_Forwards: String { return self._s[1725]! } public func CHAT_MESSAGE_INVOICE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1725]!, self._r[1725]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1727]!, self._r[1727]!, [_1, _2, _3]) } - public var Notification_Exceptions_RemoveFromExceptions: String { return self._s[1726]! } - public var ScheduledMessages_EditTime: String { return self._s[1727]! } - public var Conversation_ClearSelfHistory: String { return self._s[1728]! } - public var Checkout_NewCard_PostcodePlaceholder: String { return self._s[1729]! } - public var PasscodeSettings_DoNotMatch: String { return self._s[1730]! } - public var Stickers_SuggestNone: String { return self._s[1731]! } - public var ChatSettings_Cache: String { return self._s[1732]! } - public var Settings_SaveIncomingPhotos: String { return self._s[1733]! } - public var Media_ShareThisPhoto: String { return self._s[1734]! } - public var Chat_SlowmodeTooltipPending: String { return self._s[1735]! } - public var InfoPlist_NSContactsUsageDescription: String { return self._s[1736]! } - public var Conversation_ContextMenuCopyLink: String { return self._s[1737]! } - public var PrivacyPolicy_AgeVerificationTitle: String { return self._s[1738]! } - public var SettingsSearch_Synonyms_Stickers_Masks: String { return self._s[1739]! } - public var TwoStepAuth_SetupPasswordEnterPasswordNew: String { return self._s[1740]! } - public var Appearance_ThemePreview_Chat_6_Text: String { return self._s[1741]! } + public var Notification_Exceptions_RemoveFromExceptions: String { return self._s[1728]! } + public var ScheduledMessages_EditTime: String { return self._s[1729]! } + public var Conversation_ClearSelfHistory: String { return self._s[1730]! } + public var Checkout_NewCard_PostcodePlaceholder: String { return self._s[1731]! } + public var PasscodeSettings_DoNotMatch: String { return self._s[1732]! } + public var Stickers_SuggestNone: String { return self._s[1733]! } + public var ChatSettings_Cache: String { return self._s[1734]! } + public var Settings_SaveIncomingPhotos: String { return self._s[1735]! } + public var Media_ShareThisPhoto: String { return self._s[1736]! } + public var Chat_SlowmodeTooltipPending: String { return self._s[1737]! } + public var InfoPlist_NSContactsUsageDescription: String { return self._s[1738]! } + public var Conversation_ContextMenuCopyLink: String { return self._s[1739]! } + public var PrivacyPolicy_AgeVerificationTitle: String { return self._s[1740]! } + public var SettingsSearch_Synonyms_Stickers_Masks: String { return self._s[1741]! } + public var TwoStepAuth_SetupPasswordEnterPasswordNew: String { return self._s[1742]! } + public var Appearance_ThemePreview_Chat_6_Text: String { return self._s[1743]! } public func Wallet_SecureStorageReset_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1742]!, self._r[1742]!, [_0]) + return formatWithArgumentRanges(self._s[1744]!, self._r[1744]!, [_0]) } - public var Permissions_CellularDataTitle_v0: String { return self._s[1743]! } - public var WallpaperSearch_ColorWhite: String { return self._s[1745]! } - public var Channel_AdminLog_DefaultRestrictionsUpdated: String { return self._s[1746]! } - public var Conversation_ErrorInaccessibleMessage: String { return self._s[1747]! } - public var Map_OpenIn: String { return self._s[1748]! } + public var Permissions_CellularDataTitle_v0: String { return self._s[1745]! } + public var WallpaperSearch_ColorWhite: String { return self._s[1747]! } + public var Channel_AdminLog_DefaultRestrictionsUpdated: String { return self._s[1748]! } + public var Conversation_ErrorInaccessibleMessage: String { return self._s[1749]! } + public var Map_OpenIn: String { return self._s[1750]! } public func PUSH_PHONE_CALL_MISSED(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1751]!, self._r[1751]!, [_1]) + return formatWithArgumentRanges(self._s[1753]!, self._r[1753]!, [_1]) } public func ChannelInfo_AddParticipantConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1752]!, self._r[1752]!, [_0]) + return formatWithArgumentRanges(self._s[1754]!, self._r[1754]!, [_0]) } - public var GroupInfo_Permissions_SlowmodeHeader: String { return self._s[1753]! } - public var MessagePoll_LabelClosed: String { return self._s[1754]! } - public var GroupPermission_PermissionGloballyDisabled: String { return self._s[1756]! } - public var Wallet_Send_SendAnyway: String { return self._s[1757]! } - public var Passport_Identity_MiddleNamePlaceholder: String { return self._s[1758]! } - public var UserInfo_FirstNamePlaceholder: String { return self._s[1759]! } - public var PrivacyLastSeenSettings_WhoCanSeeMyTimestamp: String { return self._s[1760]! } - public var Map_SetThisPlace: String { return self._s[1761]! } - public var Login_SelectCountry_Title: String { return self._s[1762]! } - public var Channel_EditAdmin_PermissionBanUsers: String { return self._s[1763]! } + public var GroupInfo_Permissions_SlowmodeHeader: String { return self._s[1755]! } + public var MessagePoll_LabelClosed: String { return self._s[1756]! } + public var GroupPermission_PermissionGloballyDisabled: String { return self._s[1758]! } + public var Wallet_Send_SendAnyway: String { return self._s[1759]! } + public var Passport_Identity_MiddleNamePlaceholder: String { return self._s[1760]! } + public var UserInfo_FirstNamePlaceholder: String { return self._s[1761]! } + public var PrivacyLastSeenSettings_WhoCanSeeMyTimestamp: String { return self._s[1762]! } + public var Map_SetThisPlace: String { return self._s[1763]! } + public var Login_SelectCountry_Title: String { return self._s[1764]! } + public var Channel_EditAdmin_PermissionBanUsers: String { return self._s[1765]! } public func Conversation_OpenBotLinkLogin(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1764]!, self._r[1764]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1766]!, self._r[1766]!, [_1, _2]) } - public var Channel_AdminLog_ChangeInfo: String { return self._s[1765]! } - public var Watch_Suggestion_BRB: String { return self._s[1766]! } - public var Passport_Identity_EditIdentityCard: String { return self._s[1767]! } - public var Contacts_PermissionsTitle: String { return self._s[1768]! } - public var Conversation_RestrictedInline: String { return self._s[1769]! } - public var Appearance_RemoveThemeColor: String { return self._s[1771]! } - public var StickerPack_ViewPack: String { return self._s[1772]! } - public var Wallet_UnknownError: String { return self._s[1773]! } + public var Channel_AdminLog_ChangeInfo: String { return self._s[1767]! } + public var Watch_Suggestion_BRB: String { return self._s[1768]! } + public var Passport_Identity_EditIdentityCard: String { return self._s[1769]! } + public var Contacts_PermissionsTitle: String { return self._s[1770]! } + public var Conversation_RestrictedInline: String { return self._s[1771]! } + public var Appearance_RemoveThemeColor: String { return self._s[1773]! } + public var StickerPack_ViewPack: String { return self._s[1774]! } + public var Wallet_UnknownError: String { return self._s[1775]! } public func Update_AppVersion(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1774]!, self._r[1774]!, [_0]) + return formatWithArgumentRanges(self._s[1776]!, self._r[1776]!, [_0]) } - public var Compose_NewChannel: String { return self._s[1776]! } - public var ChatSettings_AutoDownloadSettings_TypePhoto: String { return self._s[1779]! } - public var MessagePoll_LabelQuiz: String { return self._s[1781]! } - public var Conversation_ReportSpamGroupConfirmation: String { return self._s[1782]! } - public var Channel_Info_Stickers: String { return self._s[1783]! } - public var AutoNightTheme_PreferredTheme: String { return self._s[1784]! } - public var PrivacyPolicy_AgeVerificationAgree: String { return self._s[1785]! } - public var Passport_DeletePersonalDetails: String { return self._s[1786]! } - public var LogoutOptions_AddAccountTitle: String { return self._s[1787]! } - public var Channel_DiscussionGroupInfo: String { return self._s[1788]! } - public var Group_EditAdmin_RankOwnerPlaceholder: String { return self._s[1789]! } - public var Conversation_SearchNoResults: String { return self._s[1792]! } - public var Wallet_Configuration_ApplyErrorTextURLInvalid: String { return self._s[1793]! } - public var MessagePoll_LabelAnonymous: String { return self._s[1794]! } - public var Channel_Members_AddAdminErrorNotAMember: String { return self._s[1795]! } - public var Login_Code: String { return self._s[1796]! } - public var EditTheme_Create_BottomInfo: String { return self._s[1797]! } - public var Watch_Suggestion_WhatsUp: String { return self._s[1798]! } - public var Weekday_ShortThursday: String { return self._s[1799]! } - public var Resolve_ErrorNotFound: String { return self._s[1801]! } - public var LastSeen_Offline: String { return self._s[1802]! } - public var PeopleNearby_NoMembers: String { return self._s[1803]! } - public var GroupPermission_AddMembersNotAvailable: String { return self._s[1804]! } - public var Privacy_Calls_AlwaysAllow_Title: String { return self._s[1805]! } - public var GroupInfo_Title: String { return self._s[1807]! } - public var NotificationsSound_Note: String { return self._s[1808]! } - public var Conversation_EditingMessagePanelTitle: String { return self._s[1809]! } - public var Watch_Message_Poll: String { return self._s[1810]! } - public var Privacy_Calls: String { return self._s[1811]! } + public var Compose_NewChannel: String { return self._s[1778]! } + public var ChatSettings_AutoDownloadSettings_TypePhoto: String { return self._s[1781]! } + public var MessagePoll_LabelQuiz: String { return self._s[1783]! } + public var Conversation_ReportSpamGroupConfirmation: String { return self._s[1784]! } + public var Channel_Info_Stickers: String { return self._s[1785]! } + public var AutoNightTheme_PreferredTheme: String { return self._s[1786]! } + public var PrivacyPolicy_AgeVerificationAgree: String { return self._s[1787]! } + public var Passport_DeletePersonalDetails: String { return self._s[1788]! } + public var LogoutOptions_AddAccountTitle: String { return self._s[1789]! } + public var Channel_DiscussionGroupInfo: String { return self._s[1790]! } + public var Group_EditAdmin_RankOwnerPlaceholder: String { return self._s[1791]! } + public var Conversation_SearchNoResults: String { return self._s[1794]! } + public var Wallet_Configuration_ApplyErrorTextURLInvalid: String { return self._s[1795]! } + public var MessagePoll_LabelAnonymous: String { return self._s[1796]! } + public var Channel_Members_AddAdminErrorNotAMember: String { return self._s[1797]! } + public var Login_Code: String { return self._s[1798]! } + public var EditTheme_Create_BottomInfo: String { return self._s[1799]! } + public var Watch_Suggestion_WhatsUp: String { return self._s[1800]! } + public var Weekday_ShortThursday: String { return self._s[1801]! } + public var Resolve_ErrorNotFound: String { return self._s[1803]! } + public var LastSeen_Offline: String { return self._s[1804]! } + public var PeopleNearby_NoMembers: String { return self._s[1805]! } + public var GroupPermission_AddMembersNotAvailable: String { return self._s[1806]! } + public var Privacy_Calls_AlwaysAllow_Title: String { return self._s[1807]! } + public var GroupInfo_Title: String { return self._s[1809]! } + public var NotificationsSound_Note: String { return self._s[1810]! } + public var Conversation_EditingMessagePanelTitle: String { return self._s[1811]! } + public var Watch_Message_Poll: String { return self._s[1812]! } + public var Privacy_Calls: String { return self._s[1813]! } public func Channel_AdminLog_MessageRankUsername(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1812]!, self._r[1812]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1814]!, self._r[1814]!, [_1, _2, _3]) } - public var Month_ShortAugust: String { return self._s[1813]! } - public var TwoStepAuth_SetPasswordHelp: String { return self._s[1814]! } - public var Notifications_Reset: String { return self._s[1815]! } - public var Conversation_Pin: String { return self._s[1816]! } - public var Passport_Language_lv: String { return self._s[1817]! } - public var Permissions_PeopleNearbyAllowInSettings_v0: String { return self._s[1818]! } - public var BlockedUsers_Info: String { return self._s[1819]! } - public var SettingsSearch_Synonyms_Data_AutoplayVideos: String { return self._s[1821]! } - public var Watch_Conversation_Unblock: String { return self._s[1823]! } + public var Month_ShortAugust: String { return self._s[1815]! } + public var TwoStepAuth_SetPasswordHelp: String { return self._s[1816]! } + public var Notifications_Reset: String { return self._s[1817]! } + public var Conversation_Pin: String { return self._s[1818]! } + public var Passport_Language_lv: String { return self._s[1819]! } + public var Permissions_PeopleNearbyAllowInSettings_v0: String { return self._s[1820]! } + public var BlockedUsers_Info: String { return self._s[1821]! } + public var SettingsSearch_Synonyms_Data_AutoplayVideos: String { return self._s[1823]! } + public var Watch_Conversation_Unblock: String { return self._s[1825]! } public func Time_MonthOfYear_m9(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1824]!, self._r[1824]!, [_0]) + return formatWithArgumentRanges(self._s[1826]!, self._r[1826]!, [_0]) } - public var CloudStorage_Title: String { return self._s[1825]! } - public var GroupInfo_DeleteAndExitConfirmation: String { return self._s[1826]! } + public var CloudStorage_Title: String { return self._s[1827]! } + public var GroupInfo_DeleteAndExitConfirmation: String { return self._s[1828]! } public func NetworkUsageSettings_WifiUsageSince(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1827]!, self._r[1827]!, [_0]) + return formatWithArgumentRanges(self._s[1829]!, self._r[1829]!, [_0]) } - public var Channel_AdminLogFilter_AdminsTitle: String { return self._s[1828]! } - public var Watch_Suggestion_OnMyWay: String { return self._s[1829]! } - public var TwoStepAuth_RecoveryEmailTitle: String { return self._s[1830]! } - public var Passport_Address_EditBankStatement: String { return self._s[1831]! } + public var Channel_AdminLogFilter_AdminsTitle: String { return self._s[1830]! } + public var Watch_Suggestion_OnMyWay: String { return self._s[1831]! } + public var TwoStepAuth_RecoveryEmailTitle: String { return self._s[1832]! } + public var Passport_Address_EditBankStatement: String { return self._s[1833]! } public func Channel_AdminLog_MessageChangedUnlinkedGroup(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1832]!, self._r[1832]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1834]!, self._r[1834]!, [_1, _2]) } - public var ChatSettings_DownloadInBackgroundInfo: String { return self._s[1833]! } - public var ShareMenu_Comment: String { return self._s[1834]! } - public var Permissions_ContactsTitle_v0: String { return self._s[1835]! } - public var Notifications_PermissionsTitle: String { return self._s[1836]! } - public var GroupPermission_NoSendLinks: String { return self._s[1837]! } - public var Privacy_Forwards_NeverAllow_Title: String { return self._s[1838]! } - public var Wallet_SecureStorageChanged_ImportWallet: String { return self._s[1839]! } - public var Settings_Support: String { return self._s[1840]! } - public var Notifications_ChannelNotificationsSound: String { return self._s[1841]! } - public var SettingsSearch_Synonyms_Data_AutoDownloadReset: String { return self._s[1842]! } - public var Privacy_Forwards_Preview: String { return self._s[1843]! } - public var GroupPermission_ApplyAlertAction: String { return self._s[1844]! } - public var Watch_Stickers_StickerPacks: String { return self._s[1845]! } - public var Common_Select: String { return self._s[1847]! } - public var CheckoutInfo_ErrorEmailInvalid: String { return self._s[1848]! } - public var WallpaperSearch_ColorGray: String { return self._s[1851]! } - public var TwoFactorSetup_Password_PlaceholderPassword: String { return self._s[1852]! } - public var TwoFactorSetup_Hint_SkipAction: String { return self._s[1853]! } - public var ChatAdmins_AllMembersAreAdminsOffHelp: String { return self._s[1854]! } - public var PollResults_Title: String { return self._s[1855]! } - public var PasscodeSettings_AutoLock_IfAwayFor_5hours: String { return self._s[1856]! } - public var Appearance_PreviewReplyAuthor: String { return self._s[1857]! } - public var TwoStepAuth_RecoveryTitle: String { return self._s[1858]! } - public var Widget_AuthRequired: String { return self._s[1859]! } - public var Camera_FlashOn: String { return self._s[1860]! } - public var Conversation_ContextMenuLookUp: String { return self._s[1861]! } - public var Channel_Stickers_NotFoundHelp: String { return self._s[1862]! } - public var Watch_Suggestion_OK: String { return self._s[1863]! } + public var ChatSettings_DownloadInBackgroundInfo: String { return self._s[1835]! } + public var ShareMenu_Comment: String { return self._s[1836]! } + public var Permissions_ContactsTitle_v0: String { return self._s[1837]! } + public var Notifications_PermissionsTitle: String { return self._s[1838]! } + public var GroupPermission_NoSendLinks: String { return self._s[1839]! } + public var Privacy_Forwards_NeverAllow_Title: String { return self._s[1840]! } + public var Wallet_SecureStorageChanged_ImportWallet: String { return self._s[1841]! } + public var Settings_Support: String { return self._s[1842]! } + public var Notifications_ChannelNotificationsSound: String { return self._s[1843]! } + public var SettingsSearch_Synonyms_Data_AutoDownloadReset: String { return self._s[1844]! } + public var Privacy_Forwards_Preview: String { return self._s[1845]! } + public var GroupPermission_ApplyAlertAction: String { return self._s[1846]! } + public var Watch_Stickers_StickerPacks: String { return self._s[1847]! } + public var Common_Select: String { return self._s[1849]! } + public var CheckoutInfo_ErrorEmailInvalid: String { return self._s[1850]! } + public var WallpaperSearch_ColorGray: String { return self._s[1853]! } + public var TwoFactorSetup_Password_PlaceholderPassword: String { return self._s[1854]! } + public var TwoFactorSetup_Hint_SkipAction: String { return self._s[1855]! } + public var ChatAdmins_AllMembersAreAdminsOffHelp: String { return self._s[1856]! } + public var PollResults_Title: String { return self._s[1857]! } + public var PasscodeSettings_AutoLock_IfAwayFor_5hours: String { return self._s[1858]! } + public var Appearance_PreviewReplyAuthor: String { return self._s[1859]! } + public var TwoStepAuth_RecoveryTitle: String { return self._s[1860]! } + public var Widget_AuthRequired: String { return self._s[1861]! } + public var Camera_FlashOn: String { return self._s[1862]! } + public var Conversation_ContextMenuLookUp: String { return self._s[1863]! } + public var Channel_Stickers_NotFoundHelp: String { return self._s[1864]! } + public var Watch_Suggestion_OK: String { return self._s[1865]! } public func Username_LinkHint(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1865]!, self._r[1865]!, [_0]) - } - public func Notification_PinnedLiveLocationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1867]!, self._r[1867]!, [_0]) } - public var TextFormat_Strikethrough: String { return self._s[1868]! } - public var DialogList_AdLabel: String { return self._s[1869]! } - public var WatchRemote_NotificationText: String { return self._s[1870]! } - public var IntentsSettings_SuggestedChatsSavedMessages: String { return self._s[1871]! } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsAlert: String { return self._s[1872]! } - public var Conversation_ReportSpam: String { return self._s[1873]! } - public var SettingsSearch_Synonyms_Privacy_Data_TopPeers: String { return self._s[1874]! } - public var Settings_LogoutConfirmationTitle: String { return self._s[1876]! } - public var PhoneLabel_Title: String { return self._s[1877]! } - public var Passport_Address_EditRentalAgreement: String { return self._s[1878]! } - public var Settings_ChangePhoneNumber: String { return self._s[1879]! } - public var Notifications_ExceptionsTitle: String { return self._s[1880]! } - public var Notifications_AlertTones: String { return self._s[1881]! } - public var Call_ReportIncludeLogDescription: String { return self._s[1882]! } - public var SettingsSearch_Synonyms_Notifications_ResetAllNotifications: String { return self._s[1883]! } - public var AutoDownloadSettings_PrivateChats: String { return self._s[1884]! } - public var VoiceOver_Chat_Photo: String { return self._s[1886]! } - public var TwoStepAuth_AddHintTitle: String { return self._s[1887]! } - public var ReportPeer_ReasonOther: String { return self._s[1888]! } - public var ChatList_Context_JoinChannel: String { return self._s[1889]! } - public var KeyCommand_ScrollDown: String { return self._s[1891]! } - public var Conversation_ScheduleMessage_Title: String { return self._s[1892]! } + public func Notification_PinnedLiveLocationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1869]!, self._r[1869]!, [_0]) + } + public var TextFormat_Strikethrough: String { return self._s[1870]! } + public var DialogList_AdLabel: String { return self._s[1871]! } + public var WatchRemote_NotificationText: String { return self._s[1872]! } + public var IntentsSettings_SuggestedChatsSavedMessages: String { return self._s[1873]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsAlert: String { return self._s[1874]! } + public var Conversation_ReportSpam: String { return self._s[1875]! } + public var SettingsSearch_Synonyms_Privacy_Data_TopPeers: String { return self._s[1876]! } + public var Settings_LogoutConfirmationTitle: String { return self._s[1878]! } + public var PhoneLabel_Title: String { return self._s[1879]! } + public var Passport_Address_EditRentalAgreement: String { return self._s[1880]! } + public var Settings_ChangePhoneNumber: String { return self._s[1881]! } + public var Notifications_ExceptionsTitle: String { return self._s[1882]! } + public var Notifications_AlertTones: String { return self._s[1883]! } + public var Call_ReportIncludeLogDescription: String { return self._s[1884]! } + public var SettingsSearch_Synonyms_Notifications_ResetAllNotifications: String { return self._s[1885]! } + public var AutoDownloadSettings_PrivateChats: String { return self._s[1886]! } + public var VoiceOver_Chat_Photo: String { return self._s[1888]! } + public var TwoStepAuth_AddHintTitle: String { return self._s[1889]! } + public var ReportPeer_ReasonOther: String { return self._s[1890]! } + public var ChatList_Context_JoinChannel: String { return self._s[1891]! } + public var KeyCommand_ScrollDown: String { return self._s[1893]! } + public var Conversation_ScheduleMessage_Title: String { return self._s[1894]! } public func Login_BannedPhoneSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1893]!, self._r[1893]!, [_0]) + return formatWithArgumentRanges(self._s[1895]!, self._r[1895]!, [_0]) } - public var NetworkUsageSettings_MediaVideoDataSection: String { return self._s[1894]! } - public var ChannelInfo_DeleteGroupConfirmation: String { return self._s[1895]! } - public var AuthSessions_LogOut: String { return self._s[1896]! } - public var Passport_Identity_TypeInternalPassport: String { return self._s[1897]! } - public var ChatSettings_AutoDownloadVoiceMessages: String { return self._s[1898]! } - public var Passport_Phone_Title: String { return self._s[1899]! } - public var ContactList_Context_StartSecretChat: String { return self._s[1900]! } - public var Settings_PhoneNumber: String { return self._s[1901]! } + public var NetworkUsageSettings_MediaVideoDataSection: String { return self._s[1896]! } + public var ChannelInfo_DeleteGroupConfirmation: String { return self._s[1897]! } + public var AuthSessions_LogOut: String { return self._s[1898]! } + public var Passport_Identity_TypeInternalPassport: String { return self._s[1899]! } + public var ChatSettings_AutoDownloadVoiceMessages: String { return self._s[1900]! } + public var Passport_Phone_Title: String { return self._s[1901]! } + public var ContactList_Context_StartSecretChat: String { return self._s[1902]! } + public var Settings_PhoneNumber: String { return self._s[1903]! } public func Conversation_ScheduleMessage_SendToday(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1902]!, self._r[1902]!, [_0]) + return formatWithArgumentRanges(self._s[1904]!, self._r[1904]!, [_0]) } - public var NotificationsSound_Alert: String { return self._s[1904]! } - public var Wallet_SecureStorageChanged_CreateWallet: String { return self._s[1905]! } - public var WebSearch_SearchNoResults: String { return self._s[1906]! } - public var Privacy_ProfilePhoto_AlwaysShareWith_Title: String { return self._s[1908]! } - public var Wallet_Configuration_SourceInfo: String { return self._s[1909]! } - public var LogoutOptions_AlternativeOptionsSection: String { return self._s[1910]! } - public var SettingsSearch_Synonyms_Passport: String { return self._s[1911]! } - public var PhotoEditor_CurvesTool: String { return self._s[1912]! } - public var Checkout_PaymentMethod: String { return self._s[1914]! } + public var NotificationsSound_Alert: String { return self._s[1906]! } + public var Wallet_SecureStorageChanged_CreateWallet: String { return self._s[1907]! } + public var WebSearch_SearchNoResults: String { return self._s[1908]! } + public var Privacy_ProfilePhoto_AlwaysShareWith_Title: String { return self._s[1910]! } + public var Wallet_Configuration_SourceInfo: String { return self._s[1911]! } + public var LogoutOptions_AlternativeOptionsSection: String { return self._s[1912]! } + public var SettingsSearch_Synonyms_Passport: String { return self._s[1913]! } + public var PhotoEditor_CurvesTool: String { return self._s[1914]! } + public var Checkout_PaymentMethod: String { return self._s[1916]! } public func PUSH_CHAT_ADD_YOU(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1915]!, self._r[1915]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1917]!, self._r[1917]!, [_1, _2]) } - public var Contacts_AccessDeniedError: String { return self._s[1916]! } - public var Camera_PhotoMode: String { return self._s[1919]! } - public var EditTheme_Expand_Preview_IncomingText: String { return self._s[1920]! } - public var Appearance_TextSize_Apply: String { return self._s[1921]! } - public var Passport_Address_AddUtilityBill: String { return self._s[1923]! } - public var CallSettings_OnMobile: String { return self._s[1924]! } - public var Tour_Text2: String { return self._s[1925]! } + public var Contacts_AccessDeniedError: String { return self._s[1918]! } + public var Camera_PhotoMode: String { return self._s[1921]! } + public var EditTheme_Expand_Preview_IncomingText: String { return self._s[1922]! } + public var Appearance_TextSize_Apply: String { return self._s[1923]! } + public var Passport_Address_AddUtilityBill: String { return self._s[1925]! } + public var CallSettings_OnMobile: String { return self._s[1926]! } + public var Tour_Text2: String { return self._s[1927]! } public func PUSH_CHAT_MESSAGE_ROUND(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1926]!, self._r[1926]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1928]!, self._r[1928]!, [_1, _2]) } - public var DialogList_EncryptionProcessing: String { return self._s[1928]! } - public var Permissions_Skip: String { return self._s[1929]! } - public var Wallet_Words_NotDoneOk: String { return self._s[1930]! } - public var SecretImage_Title: String { return self._s[1931]! } - public var Watch_MessageView_Title: String { return self._s[1932]! } - public var Channel_DiscussionGroupAdd: String { return self._s[1933]! } - public var AttachmentMenu_Poll: String { return self._s[1934]! } + public var DialogList_EncryptionProcessing: String { return self._s[1930]! } + public var Permissions_Skip: String { return self._s[1931]! } + public var Wallet_Words_NotDoneOk: String { return self._s[1932]! } + public var SecretImage_Title: String { return self._s[1933]! } + public var Watch_MessageView_Title: String { return self._s[1934]! } + public var Channel_DiscussionGroupAdd: String { return self._s[1935]! } + public var AttachmentMenu_Poll: String { return self._s[1936]! } public func Notification_GroupInviter(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1935]!, self._r[1935]!, [_0]) + return formatWithArgumentRanges(self._s[1937]!, self._r[1937]!, [_0]) } public func Channel_DiscussionGroup_PrivateChannelLink(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1936]!, self._r[1936]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1938]!, self._r[1938]!, [_1, _2]) } - public var Notification_CallCanceled: String { return self._s[1937]! } - public var WallpaperPreview_Title: String { return self._s[1938]! } - public var Privacy_PaymentsClear_PaymentInfo: String { return self._s[1939]! } - public var Settings_ProxyConnecting: String { return self._s[1940]! } - public var Settings_CheckPhoneNumberText: String { return self._s[1942]! } - public var VoiceOver_Chat_YourVideo: String { return self._s[1943]! } - public var Wallet_Intro_Title: String { return self._s[1944]! } - public var TwoFactorSetup_Password_Action: String { return self._s[1945]! } - public var Profile_MessageLifetime5s: String { return self._s[1946]! } - public var Username_InvalidCharacters: String { return self._s[1947]! } - public var VoiceOver_Media_PlaybackRateFast: String { return self._s[1948]! } - public var ScheduledMessages_ClearAll: String { return self._s[1949]! } - public var WallpaperPreview_CropBottomText: String { return self._s[1950]! } - public var AutoDownloadSettings_LimitBySize: String { return self._s[1951]! } - public var Settings_AddAccount: String { return self._s[1952]! } - public var Notification_CreatedChannel: String { return self._s[1955]! } + public var Notification_CallCanceled: String { return self._s[1939]! } + public var WallpaperPreview_Title: String { return self._s[1940]! } + public var Privacy_PaymentsClear_PaymentInfo: String { return self._s[1941]! } + public var Settings_ProxyConnecting: String { return self._s[1942]! } + public var Settings_CheckPhoneNumberText: String { return self._s[1944]! } + public var VoiceOver_Chat_YourVideo: String { return self._s[1945]! } + public var Wallet_Intro_Title: String { return self._s[1946]! } + public var TwoFactorSetup_Password_Action: String { return self._s[1947]! } + public var Profile_MessageLifetime5s: String { return self._s[1948]! } + public var Username_InvalidCharacters: String { return self._s[1949]! } + public var VoiceOver_Media_PlaybackRateFast: String { return self._s[1950]! } + public var ScheduledMessages_ClearAll: String { return self._s[1951]! } + public var WallpaperPreview_CropBottomText: String { return self._s[1952]! } + public var AutoDownloadSettings_LimitBySize: String { return self._s[1953]! } + public var Settings_AddAccount: String { return self._s[1954]! } + public var Notification_CreatedChannel: String { return self._s[1957]! } public func PUSH_CHAT_DELETE_MEMBER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1956]!, self._r[1956]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1958]!, self._r[1958]!, [_1, _2, _3]) } - public var Passcode_AppLockedAlert: String { return self._s[1958]! } - public var StickerPacksSettings_AnimatedStickersInfo: String { return self._s[1959]! } - public var VoiceOver_Media_PlaybackStop: String { return self._s[1960]! } - public var Contacts_TopSection: String { return self._s[1961]! } - public var ChatList_DeleteForEveryoneConfirmationAction: String { return self._s[1962]! } + public var Passcode_AppLockedAlert: String { return self._s[1960]! } + public var StickerPacksSettings_AnimatedStickersInfo: String { return self._s[1961]! } + public var VoiceOver_Media_PlaybackStop: String { return self._s[1962]! } + public var Contacts_TopSection: String { return self._s[1963]! } + public var ChatList_DeleteForEveryoneConfirmationAction: String { return self._s[1964]! } public func Conversation_SetReminder_RemindOn(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1963]!, self._r[1963]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1965]!, self._r[1965]!, [_0, _1]) } - public var Wallet_Info_Receive: String { return self._s[1964]! } - public var Wallet_Completed_ViewWallet: String { return self._s[1965]! } + public var Wallet_Info_Receive: String { return self._s[1966]! } + public var Wallet_Completed_ViewWallet: String { return self._s[1967]! } public func Time_MonthOfYear_m6(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1966]!, self._r[1966]!, [_0]) + return formatWithArgumentRanges(self._s[1968]!, self._r[1968]!, [_0]) } - public var ReportPeer_ReasonSpam: String { return self._s[1967]! } - public var UserInfo_TapToCall: String { return self._s[1968]! } - public var Conversation_ForwardAuthorHiddenTooltip: String { return self._s[1970]! } - public var AutoDownloadSettings_DataUsageCustom: String { return self._s[1971]! } - public var Common_Search: String { return self._s[1972]! } - public var ScheduledMessages_EmptyPlaceholder: String { return self._s[1973]! } + public var ReportPeer_ReasonSpam: String { return self._s[1969]! } + public var UserInfo_TapToCall: String { return self._s[1970]! } + public var Conversation_ForwardAuthorHiddenTooltip: String { return self._s[1972]! } + public var AutoDownloadSettings_DataUsageCustom: String { return self._s[1973]! } + public var Common_Search: String { return self._s[1974]! } + public var ScheduledMessages_EmptyPlaceholder: String { return self._s[1975]! } public func Channel_AdminLog_MessageChangedGroupGeoLocation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1974]!, self._r[1974]!, [_0]) + return formatWithArgumentRanges(self._s[1976]!, self._r[1976]!, [_0]) } - public var Wallet_Month_ShortJuly: String { return self._s[1975]! } - public var AuthSessions_IncompleteAttemptsInfo: String { return self._s[1977]! } - public var Message_InvoiceLabel: String { return self._s[1978]! } - public var Conversation_InputTextPlaceholder: String { return self._s[1979]! } - public var NetworkUsageSettings_MediaImageDataSection: String { return self._s[1980]! } + public var Wallet_Month_ShortJuly: String { return self._s[1977]! } + public var AuthSessions_IncompleteAttemptsInfo: String { return self._s[1979]! } + public var Message_InvoiceLabel: String { return self._s[1980]! } + public var Conversation_InputTextPlaceholder: String { return self._s[1981]! } + public var NetworkUsageSettings_MediaImageDataSection: String { return self._s[1982]! } public func Passport_Address_UploadOneOfScan(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1981]!, self._r[1981]!, [_0]) + return formatWithArgumentRanges(self._s[1983]!, self._r[1983]!, [_0]) } - public var IntentsSettings_Reset: String { return self._s[1982]! } - public var Conversation_Info: String { return self._s[1983]! } - public var Login_InfoDeletePhoto: String { return self._s[1984]! } - public var Passport_Language_vi: String { return self._s[1986]! } - public var UserInfo_ScamUserWarning: String { return self._s[1987]! } - public var Conversation_Search: String { return self._s[1988]! } - public var DialogList_DeleteBotConversationConfirmation: String { return self._s[1990]! } - public var ReportPeer_ReasonPornography: String { return self._s[1991]! } - public var AutoDownloadSettings_PhotosTitle: String { return self._s[1992]! } - public var Conversation_SendMessageErrorGroupRestricted: String { return self._s[1993]! } - public var Map_LiveLocationGroupDescription: String { return self._s[1994]! } - public var Channel_Setup_TypeHeader: String { return self._s[1995]! } - public var AuthSessions_LoggedIn: String { return self._s[1996]! } - public var Privacy_Forwards_AlwaysAllow_Title: String { return self._s[1997]! } - public var Login_SmsRequestState3: String { return self._s[1998]! } - public var Passport_Address_EditUtilityBill: String { return self._s[1999]! } - public var Appearance_ReduceMotionInfo: String { return self._s[2000]! } - public var Join_ChannelsTooMuch: String { return self._s[2001]! } - public var Channel_Edit_LinkItem: String { return self._s[2002]! } - public var Privacy_Calls_P2PNever: String { return self._s[2003]! } - public var Conversation_AddToReadingList: String { return self._s[2005]! } - public var Share_MultipleMessagesDisabled: String { return self._s[2006]! } - public var Message_Animation: String { return self._s[2007]! } - public var Conversation_DefaultRestrictedMedia: String { return self._s[2008]! } - public var Map_Unknown: String { return self._s[2009]! } - public var AutoDownloadSettings_LastDelimeter: String { return self._s[2010]! } + public var IntentsSettings_Reset: String { return self._s[1984]! } + public var Conversation_Info: String { return self._s[1985]! } + public var Login_InfoDeletePhoto: String { return self._s[1986]! } + public var Passport_Language_vi: String { return self._s[1988]! } + public var UserInfo_ScamUserWarning: String { return self._s[1989]! } + public var Conversation_Search: String { return self._s[1990]! } + public var DialogList_DeleteBotConversationConfirmation: String { return self._s[1992]! } + public var ReportPeer_ReasonPornography: String { return self._s[1993]! } + public var AutoDownloadSettings_PhotosTitle: String { return self._s[1994]! } + public var Conversation_SendMessageErrorGroupRestricted: String { return self._s[1995]! } + public var Map_LiveLocationGroupDescription: String { return self._s[1996]! } + public var Channel_Setup_TypeHeader: String { return self._s[1997]! } + public var AuthSessions_LoggedIn: String { return self._s[1998]! } + public var Privacy_Forwards_AlwaysAllow_Title: String { return self._s[1999]! } + public var Login_SmsRequestState3: String { return self._s[2000]! } + public var Passport_Address_EditUtilityBill: String { return self._s[2001]! } + public var Appearance_ReduceMotionInfo: String { return self._s[2002]! } + public var Join_ChannelsTooMuch: String { return self._s[2003]! } + public var Channel_Edit_LinkItem: String { return self._s[2004]! } + public var Privacy_Calls_P2PNever: String { return self._s[2005]! } + public var Conversation_AddToReadingList: String { return self._s[2007]! } + public var Share_MultipleMessagesDisabled: String { return self._s[2008]! } + public var Message_Animation: String { return self._s[2009]! } + public var Conversation_DefaultRestrictedMedia: String { return self._s[2010]! } + public var Map_Unknown: String { return self._s[2011]! } + public var AutoDownloadSettings_LastDelimeter: String { return self._s[2012]! } public func PUSH_PINNED_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2011]!, self._r[2011]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2013]!, self._r[2013]!, [_1, _2]) } public func Passport_FieldOneOf_Or(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2012]!, self._r[2012]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2014]!, self._r[2014]!, [_1, _2]) } - public var Call_StatusRequesting: String { return self._s[2013]! } - public var Conversation_SecretChatContextBotAlert: String { return self._s[2014]! } - public var SocksProxySetup_ProxyStatusChecking: String { return self._s[2015]! } + public var Call_StatusRequesting: String { return self._s[2015]! } + public var Conversation_SecretChatContextBotAlert: String { return self._s[2016]! } + public var SocksProxySetup_ProxyStatusChecking: String { return self._s[2017]! } public func PUSH_CHAT_MESSAGE_DOC(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2016]!, self._r[2016]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2018]!, self._r[2018]!, [_1, _2]) } public func Notification_PinnedLocationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2017]!, self._r[2017]!, [_0]) + return formatWithArgumentRanges(self._s[2019]!, self._r[2019]!, [_0]) } - public var Update_Skip: String { return self._s[2018]! } - public var Group_Username_RemoveExistingUsernamesInfo: String { return self._s[2019]! } - public var BlockedUsers_Title: String { return self._s[2020]! } - public var Weekday_Monday: String { return self._s[2021]! } + public var Update_Skip: String { return self._s[2020]! } + public var Group_Username_RemoveExistingUsernamesInfo: String { return self._s[2021]! } + public var BlockedUsers_Title: String { return self._s[2022]! } + public var Weekday_Monday: String { return self._s[2023]! } public func PUSH_CHANNEL_MESSAGE_AUDIO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2022]!, self._r[2022]!, [_1]) + return formatWithArgumentRanges(self._s[2024]!, self._r[2024]!, [_1]) } - public var Username_CheckingUsername: String { return self._s[2023]! } - public var NotificationsSound_Bell: String { return self._s[2024]! } - public var Conversation_SendMessageErrorFlood: String { return self._s[2025]! } - public var SettingsSearch_Synonyms_Notifications_DisplayNamesOnLockScreen: String { return self._s[2026]! } - public var ChannelMembers_ChannelAdminsTitle: String { return self._s[2027]! } - public var ChatSettings_Groups: String { return self._s[2028]! } - public var WallpaperPreview_PatternPaternDiscard: String { return self._s[2029]! } + public var Username_CheckingUsername: String { return self._s[2025]! } + public var NotificationsSound_Bell: String { return self._s[2026]! } + public var Conversation_SendMessageErrorFlood: String { return self._s[2027]! } + public var SettingsSearch_Synonyms_Notifications_DisplayNamesOnLockScreen: String { return self._s[2028]! } + public var ChannelMembers_ChannelAdminsTitle: String { return self._s[2029]! } + public var ChatSettings_Groups: String { return self._s[2030]! } + public var WallpaperPreview_PatternPaternDiscard: String { return self._s[2031]! } public func Conversation_SetReminder_RemindTomorrow(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2030]!, self._r[2030]!, [_0]) + return formatWithArgumentRanges(self._s[2032]!, self._r[2032]!, [_0]) } - public var Your_card_was_declined: String { return self._s[2031]! } - public var TwoStepAuth_EnterPasswordHelp: String { return self._s[2033]! } - public var Wallet_Month_ShortApril: String { return self._s[2034]! } - public var ChatList_Unmute: String { return self._s[2035]! } - public var AuthSessions_AddDevice_ScanTitle: String { return self._s[2036]! } - public var PhotoEditor_CurvesAll: String { return self._s[2037]! } - public var Weekday_ShortTuesday: String { return self._s[2038]! } - public var DialogList_Read: String { return self._s[2039]! } - public var Appearance_AppIconClassic: String { return self._s[2040]! } - public var ChannelMembers_WhoCanAddMembers_AllMembers: String { return self._s[2041]! } - public var Passport_Identity_Gender: String { return self._s[2042]! } + public var Your_card_was_declined: String { return self._s[2033]! } + public var TwoStepAuth_EnterPasswordHelp: String { return self._s[2035]! } + public var Wallet_Month_ShortApril: String { return self._s[2036]! } + public var ChatList_Unmute: String { return self._s[2037]! } + public var AuthSessions_AddDevice_ScanTitle: String { return self._s[2038]! } + public var PhotoEditor_CurvesAll: String { return self._s[2039]! } + public var Weekday_ShortTuesday: String { return self._s[2040]! } + public var DialogList_Read: String { return self._s[2041]! } + public var Appearance_AppIconClassic: String { return self._s[2042]! } + public var ChannelMembers_WhoCanAddMembers_AllMembers: String { return self._s[2043]! } + public var Passport_Identity_Gender: String { return self._s[2044]! } public func Target_ShareGameConfirmationPrivate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2043]!, self._r[2043]!, [_0]) + return formatWithArgumentRanges(self._s[2045]!, self._r[2045]!, [_0]) } - public var Target_SelectGroup: String { return self._s[2044]! } - public var Map_HomeAndWorkInfo: String { return self._s[2046]! } + public var Target_SelectGroup: String { return self._s[2046]! } + public var Map_HomeAndWorkInfo: String { return self._s[2048]! } public func DialogList_EncryptedChatStartedIncoming(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2047]!, self._r[2047]!, [_0]) + return formatWithArgumentRanges(self._s[2049]!, self._r[2049]!, [_0]) } - public var Passport_Language_en: String { return self._s[2048]! } - public var AutoDownloadSettings_AutodownloadPhotos: String { return self._s[2049]! } - public var Channel_Username_CreatePublicLinkHelp: String { return self._s[2050]! } - public var Login_CancelPhoneVerificationContinue: String { return self._s[2051]! } - public var ScheduledMessages_SendNow: String { return self._s[2052]! } - public var Checkout_NewCard_PaymentCard: String { return self._s[2054]! } - public var Login_InfoHelp: String { return self._s[2055]! } - public var Appearance_BubbleCorners_AdjustAdjacent: String { return self._s[2056]! } - public var Contacts_PermissionsSuppressWarningTitle: String { return self._s[2057]! } - public var SettingsSearch_Synonyms_Stickers_FeaturedPacks: String { return self._s[2058]! } + public var Passport_Language_en: String { return self._s[2050]! } + public var AutoDownloadSettings_AutodownloadPhotos: String { return self._s[2051]! } + public var Channel_Username_CreatePublicLinkHelp: String { return self._s[2052]! } + public var Login_CancelPhoneVerificationContinue: String { return self._s[2053]! } + public var ScheduledMessages_SendNow: String { return self._s[2054]! } + public var Checkout_NewCard_PaymentCard: String { return self._s[2056]! } + public var Login_InfoHelp: String { return self._s[2057]! } + public var Appearance_BubbleCorners_AdjustAdjacent: String { return self._s[2058]! } + public var Contacts_PermissionsSuppressWarningTitle: String { return self._s[2059]! } + public var SettingsSearch_Synonyms_Stickers_FeaturedPacks: String { return self._s[2060]! } public func Channel_AdminLog_MessageChangedLinkedChannel(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2059]!, self._r[2059]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2061]!, self._r[2061]!, [_1, _2]) } - public var SocksProxySetup_AddProxy: String { return self._s[2062]! } - public var CreatePoll_Title: String { return self._s[2063]! } - public var MessagePoll_QuizNoUsers: String { return self._s[2064]! } - public var Conversation_ViewTheme: String { return self._s[2065]! } - public var SettingsSearch_Synonyms_Privacy_Data_SecretChatLinkPreview: String { return self._s[2066]! } - public var PasscodeSettings_SimplePasscodeHelp: String { return self._s[2067]! } - public var TwoFactorSetup_Intro_Text: String { return self._s[2068]! } - public var UserInfo_GroupsInCommon: String { return self._s[2069]! } - public var TelegramWallet_Intro_TermsUrl: String { return self._s[2070]! } - public var Call_AudioRouteHide: String { return self._s[2071]! } + public var SocksProxySetup_AddProxy: String { return self._s[2064]! } + public var CreatePoll_Title: String { return self._s[2065]! } + public var MessagePoll_QuizNoUsers: String { return self._s[2066]! } + public var Conversation_ViewTheme: String { return self._s[2067]! } + public var SettingsSearch_Synonyms_Privacy_Data_SecretChatLinkPreview: String { return self._s[2068]! } + public var PasscodeSettings_SimplePasscodeHelp: String { return self._s[2069]! } + public var TwoFactorSetup_Intro_Text: String { return self._s[2070]! } + public var UserInfo_GroupsInCommon: String { return self._s[2071]! } + public var TelegramWallet_Intro_TermsUrl: String { return self._s[2072]! } + public var Call_AudioRouteHide: String { return self._s[2073]! } public func Wallet_Info_TransactionDateHeader(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2073]!, self._r[2073]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2075]!, self._r[2075]!, [_1, _2]) } - public var ContactInfo_PhoneLabelMobile: String { return self._s[2074]! } - public var IntentsSettings_SuggestedChatsInfo: String { return self._s[2075]! } - public var CreatePoll_QuizOptionsHeader: String { return self._s[2076]! } + public var ContactInfo_PhoneLabelMobile: String { return self._s[2076]! } + public var IntentsSettings_SuggestedChatsInfo: String { return self._s[2077]! } + public var CreatePoll_QuizOptionsHeader: String { return self._s[2078]! } public func ChatList_LeaveGroupConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2077]!, self._r[2077]!, [_0]) + return formatWithArgumentRanges(self._s[2079]!, self._r[2079]!, [_0]) } - public var TextFormat_Bold: String { return self._s[2078]! } - public var FastTwoStepSetup_EmailSection: String { return self._s[2079]! } - public var StickerPackActionInfo_AddedTitle: String { return self._s[2080]! } - public var Notifications_Title: String { return self._s[2081]! } - public var Group_Username_InvalidTooShort: String { return self._s[2082]! } - public var Channel_ErrorAddTooMuch: String { return self._s[2083]! } + public var TextFormat_Bold: String { return self._s[2080]! } + public var FastTwoStepSetup_EmailSection: String { return self._s[2081]! } + public var StickerPackActionInfo_AddedTitle: String { return self._s[2082]! } + public var Notifications_Title: String { return self._s[2083]! } + public var Group_Username_InvalidTooShort: String { return self._s[2084]! } + public var Channel_ErrorAddTooMuch: String { return self._s[2085]! } public func DialogList_MultipleTypingSuffix(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2084]!, self._r[2084]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[2086]!, self._r[2086]!, ["\(_0)"]) } - public var VoiceOver_DiscardPreparedContent: String { return self._s[2086]! } - public var Stickers_SuggestAdded: String { return self._s[2087]! } - public var Login_CountryCode: String { return self._s[2088]! } - public var ChatSettings_AutoPlayVideos: String { return self._s[2089]! } - public var Map_GetDirections: String { return self._s[2090]! } - public var Wallet_Receive_ShareInvoiceUrl: String { return self._s[2091]! } - public var Login_PhoneFloodError: String { return self._s[2092]! } + public var VoiceOver_DiscardPreparedContent: String { return self._s[2088]! } + public var Stickers_SuggestAdded: String { return self._s[2089]! } + public var Login_CountryCode: String { return self._s[2090]! } + public var ChatSettings_AutoPlayVideos: String { return self._s[2091]! } + public var Map_GetDirections: String { return self._s[2092]! } + public var Wallet_Receive_ShareInvoiceUrl: String { return self._s[2093]! } + public var Login_PhoneFloodError: String { return self._s[2094]! } public func Time_MonthOfYear_m3(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2093]!, self._r[2093]!, [_0]) + return formatWithArgumentRanges(self._s[2095]!, self._r[2095]!, [_0]) } public func Wallet_Time_PreciseDate_m10(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2094]!, self._r[2094]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2096]!, self._r[2096]!, [_1, _2, _3]) } - public var IntentsSettings_SuggestedChatsPrivateChats: String { return self._s[2095]! } - public var Settings_SetUsername: String { return self._s[2097]! } - public var Group_Location_ChangeLocation: String { return self._s[2098]! } - public var Notification_GroupInviterSelf: String { return self._s[2099]! } - public var InstantPage_TapToOpenLink: String { return self._s[2100]! } + public var IntentsSettings_SuggestedChatsPrivateChats: String { return self._s[2097]! } + public var Settings_SetUsername: String { return self._s[2099]! } + public var Group_Location_ChangeLocation: String { return self._s[2100]! } + public var Notification_GroupInviterSelf: String { return self._s[2101]! } + public var InstantPage_TapToOpenLink: String { return self._s[2102]! } public func Notification_ChannelInviter(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2101]!, self._r[2101]!, [_0]) + return formatWithArgumentRanges(self._s[2103]!, self._r[2103]!, [_0]) } - public var Watch_Suggestion_TalkLater: String { return self._s[2102]! } - public var SecretChat_Title: String { return self._s[2103]! } - public var Group_UpgradeNoticeText1: String { return self._s[2104]! } - public var AuthSessions_Title: String { return self._s[2105]! } + public var Watch_Suggestion_TalkLater: String { return self._s[2104]! } + public var SecretChat_Title: String { return self._s[2105]! } + public var Group_UpgradeNoticeText1: String { return self._s[2106]! } + public var AuthSessions_Title: String { return self._s[2107]! } public func TextFormat_AddLinkText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2106]!, self._r[2106]!, [_0]) + return formatWithArgumentRanges(self._s[2108]!, self._r[2108]!, [_0]) } - public var PhotoEditor_CropAuto: String { return self._s[2107]! } - public var Channel_About_Title: String { return self._s[2108]! } - public var Theme_ThemeChanged: String { return self._s[2109]! } - public var FastTwoStepSetup_EmailHelp: String { return self._s[2110]! } + public var PhotoEditor_CropAuto: String { return self._s[2109]! } + public var Channel_About_Title: String { return self._s[2110]! } + public var Theme_ThemeChanged: String { return self._s[2111]! } + public var FastTwoStepSetup_EmailHelp: String { return self._s[2112]! } public func Conversation_Bytes(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2112]!, self._r[2112]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[2114]!, self._r[2114]!, ["\(_0)"]) } - public var VoiceOver_MessageContextReport: String { return self._s[2113]! } - public var Conversation_PinMessageAlert_OnlyPin: String { return self._s[2115]! } - public var Group_Setup_HistoryVisibleHelp: String { return self._s[2116]! } + public var VoiceOver_MessageContextReport: String { return self._s[2115]! } + public var Conversation_PinMessageAlert_OnlyPin: String { return self._s[2117]! } + public var Group_Setup_HistoryVisibleHelp: String { return self._s[2118]! } public func PUSH_MESSAGE_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2117]!, self._r[2117]!, [_1]) + return formatWithArgumentRanges(self._s[2119]!, self._r[2119]!, [_1]) } public func SharedMedia_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2119]!, self._r[2119]!, [_0]) + return formatWithArgumentRanges(self._s[2121]!, self._r[2121]!, [_0]) } public func TwoStepAuth_RecoveryEmailUnavailable(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2120]!, self._r[2120]!, [_0]) + return formatWithArgumentRanges(self._s[2122]!, self._r[2122]!, [_0]) } - public var Privacy_PaymentsClearInfoHelp: String { return self._s[2121]! } - public var Presence_online: String { return self._s[2124]! } - public var PasscodeSettings_Title: String { return self._s[2125]! } - public var Passport_Identity_ExpiryDatePlaceholder: String { return self._s[2126]! } - public var Web_OpenExternal: String { return self._s[2127]! } - public var AutoDownloadSettings_AutoDownload: String { return self._s[2129]! } - public var Channel_OwnershipTransfer_EnterPasswordText: String { return self._s[2130]! } - public var LocalGroup_Title: String { return self._s[2131]! } + public var Privacy_PaymentsClearInfoHelp: String { return self._s[2123]! } + public var Presence_online: String { return self._s[2126]! } + public var PasscodeSettings_Title: String { return self._s[2127]! } + public var Passport_Identity_ExpiryDatePlaceholder: String { return self._s[2128]! } + public var Web_OpenExternal: String { return self._s[2129]! } + public var AutoDownloadSettings_AutoDownload: String { return self._s[2131]! } + public var Channel_OwnershipTransfer_EnterPasswordText: String { return self._s[2132]! } + public var LocalGroup_Title: String { return self._s[2133]! } public func AutoNightTheme_AutomaticHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2132]!, self._r[2132]!, [_0]) + return formatWithArgumentRanges(self._s[2134]!, self._r[2134]!, [_0]) } - public var FastTwoStepSetup_PasswordConfirmationPlaceholder: String { return self._s[2133]! } - public var Conversation_StopQuizConfirmation: String { return self._s[2134]! } - public var Map_YouAreHere: String { return self._s[2135]! } + public var FastTwoStepSetup_PasswordConfirmationPlaceholder: String { return self._s[2135]! } + public var Conversation_StopQuizConfirmation: String { return self._s[2136]! } + public var Map_YouAreHere: String { return self._s[2137]! } public func AuthSessions_Message(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2136]!, self._r[2136]!, [_0]) + return formatWithArgumentRanges(self._s[2138]!, self._r[2138]!, [_0]) } public func ChatList_DeleteChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2137]!, self._r[2137]!, [_0]) + return formatWithArgumentRanges(self._s[2139]!, self._r[2139]!, [_0]) } - public var Theme_Context_ChangeColors: String { return self._s[2138]! } - public var PrivacyLastSeenSettings_AlwaysShareWith: String { return self._s[2139]! } - public var Target_InviteToGroupErrorAlreadyInvited: String { return self._s[2140]! } + public var Theme_Context_ChangeColors: String { return self._s[2140]! } + public var PrivacyLastSeenSettings_AlwaysShareWith: String { return self._s[2141]! } + public var Target_InviteToGroupErrorAlreadyInvited: String { return self._s[2142]! } public func AuthSessions_AppUnofficial(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2141]!, self._r[2141]!, [_0]) + return formatWithArgumentRanges(self._s[2143]!, self._r[2143]!, [_0]) } public func DialogList_LiveLocationSharingTo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2142]!, self._r[2142]!, [_0]) + return formatWithArgumentRanges(self._s[2144]!, self._r[2144]!, [_0]) } - public var SocksProxySetup_Username: String { return self._s[2143]! } - public var Bot_Start: String { return self._s[2144]! } + public var SocksProxySetup_Username: String { return self._s[2145]! } + public var Bot_Start: String { return self._s[2146]! } public func Channel_AdminLog_EmptyFilterQueryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2145]!, self._r[2145]!, [_0]) + return formatWithArgumentRanges(self._s[2147]!, self._r[2147]!, [_0]) } public func Channel_AdminLog_MessagePinned(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2146]!, self._r[2146]!, [_0]) + return formatWithArgumentRanges(self._s[2148]!, self._r[2148]!, [_0]) } - public var Contacts_SortByPresence: String { return self._s[2147]! } - public var AccentColor_Title: String { return self._s[2149]! } - public var Conversation_DiscardVoiceMessageTitle: String { return self._s[2150]! } + public var Contacts_SortByPresence: String { return self._s[2149]! } + public var AccentColor_Title: String { return self._s[2151]! } + public var Conversation_DiscardVoiceMessageTitle: String { return self._s[2152]! } public func PUSH_CHAT_CREATED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2151]!, self._r[2151]!, [_1, _2]) - } - public func PrivacySettings_LastSeenContactsMinus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2152]!, self._r[2152]!, [_0]) - } - public func Channel_AdminLog_MessageChangedLinkedGroup(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2153]!, self._r[2153]!, [_1, _2]) } - public var Passport_Email_EnterOtherEmail: String { return self._s[2154]! } - public var Login_InfoAvatarPhoto: String { return self._s[2155]! } - public var Privacy_PaymentsClear_ShippingInfo: String { return self._s[2156]! } - public var Tour_Title4: String { return self._s[2157]! } - public var Passport_Identity_Translation: String { return self._s[2158]! } - public var SettingsSearch_Synonyms_Notifications_ContactJoined: String { return self._s[2159]! } - public var Login_TermsOfServiceLabel: String { return self._s[2161]! } - public var Passport_Language_it: String { return self._s[2162]! } - public var KeyCommand_JumpToNextUnreadChat: String { return self._s[2163]! } - public var Passport_Identity_SelfieHelp: String { return self._s[2164]! } - public var Conversation_ClearAll: String { return self._s[2166]! } - public var Wallet_Send_UninitializedText: String { return self._s[2168]! } - public var Channel_OwnershipTransfer_Title: String { return self._s[2169]! } - public var TwoStepAuth_FloodError: String { return self._s[2170]! } + public func PrivacySettings_LastSeenContactsMinus(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2154]!, self._r[2154]!, [_0]) + } + public func Channel_AdminLog_MessageChangedLinkedGroup(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2155]!, self._r[2155]!, [_1, _2]) + } + public var Passport_Email_EnterOtherEmail: String { return self._s[2156]! } + public var Login_InfoAvatarPhoto: String { return self._s[2157]! } + public var Privacy_PaymentsClear_ShippingInfo: String { return self._s[2158]! } + public var Tour_Title4: String { return self._s[2159]! } + public var Passport_Identity_Translation: String { return self._s[2160]! } + public var SettingsSearch_Synonyms_Notifications_ContactJoined: String { return self._s[2161]! } + public var Login_TermsOfServiceLabel: String { return self._s[2163]! } + public var Passport_Language_it: String { return self._s[2164]! } + public var KeyCommand_JumpToNextUnreadChat: String { return self._s[2165]! } + public var Passport_Identity_SelfieHelp: String { return self._s[2166]! } + public var Conversation_ClearAll: String { return self._s[2168]! } + public var Wallet_Send_UninitializedText: String { return self._s[2170]! } + public var Channel_OwnershipTransfer_Title: String { return self._s[2171]! } + public var TwoStepAuth_FloodError: String { return self._s[2172]! } public func PUSH_CHANNEL_MESSAGE_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2171]!, self._r[2171]!, [_1]) + return formatWithArgumentRanges(self._s[2173]!, self._r[2173]!, [_1]) } - public var Paint_Delete: String { return self._s[2172]! } + public var Paint_Delete: String { return self._s[2174]! } public func Wallet_Sent_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2173]!, self._r[2173]!, [_0]) + return formatWithArgumentRanges(self._s[2175]!, self._r[2175]!, [_0]) } - public var Privacy_AddNewPeer: String { return self._s[2174]! } + public var Privacy_AddNewPeer: String { return self._s[2176]! } public func Channel_AdminLog_MessageRank(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2175]!, self._r[2175]!, [_1]) + return formatWithArgumentRanges(self._s[2177]!, self._r[2177]!, [_1]) } - public var LogoutOptions_SetPasscodeText: String { return self._s[2176]! } + public var LogoutOptions_SetPasscodeText: String { return self._s[2178]! } public func Passport_AcceptHelp(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2177]!, self._r[2177]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2179]!, self._r[2179]!, [_1, _2]) } - public var Message_PinnedAudioMessage: String { return self._s[2178]! } + public var Message_PinnedAudioMessage: String { return self._s[2180]! } public func Watch_Time_ShortTodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2179]!, self._r[2179]!, [_0]) + return formatWithArgumentRanges(self._s[2181]!, self._r[2181]!, [_0]) } - public var Notification_Mute1hMin: String { return self._s[2180]! } - public var Notifications_GroupNotificationsSound: String { return self._s[2181]! } - public var Wallet_Month_GenNovember: String { return self._s[2182]! } - public var SocksProxySetup_ShareProxyList: String { return self._s[2183]! } - public var Conversation_MessageEditedLabel: String { return self._s[2184]! } + public var Notification_Mute1hMin: String { return self._s[2182]! } + public var Notifications_GroupNotificationsSound: String { return self._s[2183]! } + public var Wallet_Month_GenNovember: String { return self._s[2184]! } + public var SocksProxySetup_ShareProxyList: String { return self._s[2185]! } + public var Conversation_MessageEditedLabel: String { return self._s[2186]! } public func ClearCache_Success(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2185]!, self._r[2185]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2187]!, self._r[2187]!, [_0, _1]) } - public var Notification_Exceptions_AlwaysOff: String { return self._s[2186]! } - public var Notification_Exceptions_NewException_MessagePreviewHeader: String { return self._s[2187]! } + public var Notification_Exceptions_AlwaysOff: String { return self._s[2188]! } + public var Notification_Exceptions_NewException_MessagePreviewHeader: String { return self._s[2189]! } public func Channel_AdminLog_MessageAdmin(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2188]!, self._r[2188]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[2190]!, self._r[2190]!, [_0, _1, _2]) } - public var NetworkUsageSettings_ResetStats: String { return self._s[2189]! } + public var NetworkUsageSettings_ResetStats: String { return self._s[2191]! } public func PUSH_MESSAGE_GEOLIVE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2190]!, self._r[2190]!, [_1]) + return formatWithArgumentRanges(self._s[2192]!, self._r[2192]!, [_1]) } - public var AccessDenied_LocationTracking: String { return self._s[2191]! } - public var Month_GenOctober: String { return self._s[2192]! } - public var GroupInfo_InviteLink_RevokeAlert_Revoke: String { return self._s[2193]! } - public var EnterPasscode_EnterPasscode: String { return self._s[2194]! } - public var MediaPicker_TimerTooltip: String { return self._s[2196]! } - public var SharedMedia_TitleAll: String { return self._s[2197]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsExceptions: String { return self._s[2200]! } - public var Conversation_RestrictedMedia: String { return self._s[2201]! } - public var AccessDenied_PhotosRestricted: String { return self._s[2202]! } - public var Privacy_Forwards_WhoCanForward: String { return self._s[2204]! } - public var ChangePhoneNumberCode_Called: String { return self._s[2205]! } + public var AccessDenied_LocationTracking: String { return self._s[2193]! } + public var Month_GenOctober: String { return self._s[2194]! } + public var GroupInfo_InviteLink_RevokeAlert_Revoke: String { return self._s[2195]! } + public var EnterPasscode_EnterPasscode: String { return self._s[2196]! } + public var MediaPicker_TimerTooltip: String { return self._s[2198]! } + public var SharedMedia_TitleAll: String { return self._s[2199]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsExceptions: String { return self._s[2202]! } + public var Conversation_RestrictedMedia: String { return self._s[2203]! } + public var AccessDenied_PhotosRestricted: String { return self._s[2204]! } + public var Privacy_Forwards_WhoCanForward: String { return self._s[2206]! } + public var ChangePhoneNumberCode_Called: String { return self._s[2207]! } public func Notification_PinnedDocumentMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2206]!, self._r[2206]!, [_0]) + return formatWithArgumentRanges(self._s[2208]!, self._r[2208]!, [_0]) } - public var Conversation_SavedMessages: String { return self._s[2209]! } - public var Your_cards_expiration_month_is_invalid: String { return self._s[2211]! } - public var FastTwoStepSetup_PasswordPlaceholder: String { return self._s[2212]! } + public var Conversation_SavedMessages: String { return self._s[2211]! } + public var Your_cards_expiration_month_is_invalid: String { return self._s[2213]! } + public var FastTwoStepSetup_PasswordPlaceholder: String { return self._s[2214]! } public func Target_ShareGameConfirmationGroup(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2214]!, self._r[2214]!, [_0]) - } - public var VoiceOver_Chat_YourMessage: String { return self._s[2215]! } - public func VoiceOver_Chat_Title(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2216]!, self._r[2216]!, [_0]) } - public var ReportPeer_AlertSuccess: String { return self._s[2217]! } - public var PhotoEditor_CropAspectRatioOriginal: String { return self._s[2218]! } + public var VoiceOver_Chat_YourMessage: String { return self._s[2217]! } + public func VoiceOver_Chat_Title(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2218]!, self._r[2218]!, [_0]) + } + public var ReportPeer_AlertSuccess: String { return self._s[2219]! } + public var PhotoEditor_CropAspectRatioOriginal: String { return self._s[2220]! } public func InstantPage_RelatedArticleAuthorAndDateTitle(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2219]!, self._r[2219]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2221]!, self._r[2221]!, [_1, _2]) } - public var Checkout_PasswordEntry_Title: String { return self._s[2220]! } - public var PhotoEditor_FadeTool: String { return self._s[2221]! } - public var Privacy_ContactsReset: String { return self._s[2222]! } + public var Checkout_PasswordEntry_Title: String { return self._s[2222]! } + public var PhotoEditor_FadeTool: String { return self._s[2223]! } + public var Privacy_ContactsReset: String { return self._s[2224]! } public func Channel_AdminLog_MessageRestrictedUntil(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2224]!, self._r[2224]!, [_0]) + return formatWithArgumentRanges(self._s[2226]!, self._r[2226]!, [_0]) } - public var Message_PinnedVideoMessage: String { return self._s[2225]! } - public var ChatList_Mute: String { return self._s[2226]! } + public var Message_PinnedVideoMessage: String { return self._s[2227]! } + public var ChatList_Mute: String { return self._s[2228]! } public func Wallet_Time_PreciseDate_m5(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2227]!, self._r[2227]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2229]!, self._r[2229]!, [_1, _2, _3]) } - public var Permissions_CellularDataText_v0: String { return self._s[2228]! } - public var Conversation_PinnedQuiz: String { return self._s[2230]! } - public var ShareMenu_SelectChats: String { return self._s[2232]! } - public var ChatList_Context_Unarchive: String { return self._s[2233]! } - public var MusicPlayer_VoiceNote: String { return self._s[2234]! } - public var Conversation_RestrictedText: String { return self._s[2235]! } - public var SettingsSearch_Synonyms_Privacy_Data_DeleteDrafts: String { return self._s[2236]! } - public var Wallet_Month_GenApril: String { return self._s[2237]! } - public var Wallet_Month_ShortMarch: String { return self._s[2238]! } - public var TwoStepAuth_DisableSuccess: String { return self._s[2239]! } - public var Cache_Videos: String { return self._s[2240]! } - public var PrivacySettings_PhoneNumber: String { return self._s[2241]! } - public var Wallet_Month_GenFebruary: String { return self._s[2242]! } - public var FeatureDisabled_Oops: String { return self._s[2244]! } - public var Passport_Address_PostcodePlaceholder: String { return self._s[2245]! } + public var Permissions_CellularDataText_v0: String { return self._s[2230]! } + public var Conversation_PinnedQuiz: String { return self._s[2232]! } + public var ShareMenu_SelectChats: String { return self._s[2234]! } + public var ChatList_Context_Unarchive: String { return self._s[2235]! } + public var MusicPlayer_VoiceNote: String { return self._s[2236]! } + public var Conversation_RestrictedText: String { return self._s[2237]! } + public var SettingsSearch_Synonyms_Privacy_Data_DeleteDrafts: String { return self._s[2238]! } + public var Wallet_Month_GenApril: String { return self._s[2239]! } + public var Wallet_Month_ShortMarch: String { return self._s[2240]! } + public var TwoStepAuth_DisableSuccess: String { return self._s[2241]! } + public var Cache_Videos: String { return self._s[2242]! } + public var PrivacySettings_PhoneNumber: String { return self._s[2243]! } + public var Wallet_Month_GenFebruary: String { return self._s[2244]! } + public var FeatureDisabled_Oops: String { return self._s[2246]! } + public var Passport_Address_PostcodePlaceholder: String { return self._s[2247]! } public func AddContact_StatusSuccess(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2246]!, self._r[2246]!, [_0]) + return formatWithArgumentRanges(self._s[2248]!, self._r[2248]!, [_0]) } - public var Stickers_GroupStickersHelp: String { return self._s[2247]! } - public var GroupPermission_NoSendPolls: String { return self._s[2248]! } - public var Wallet_Qr_ScanCode: String { return self._s[2249]! } - public var Message_VideoExpired: String { return self._s[2251]! } - public var GroupInfo_GroupHistoryVisible: String { return self._s[2252]! } - public var Notifications_Badge: String { return self._s[2253]! } - public var Wallet_Receive_AddressCopied: String { return self._s[2254]! } - public var CreatePoll_OptionPlaceholder: String { return self._s[2255]! } - public var Username_InvalidTooShort: String { return self._s[2256]! } - public var EnterPasscode_EnterNewPasscodeChange: String { return self._s[2257]! } - public var Channel_AdminLog_PinMessages: String { return self._s[2258]! } - public var ArchivedChats_IntroTitle3: String { return self._s[2259]! } + public var Stickers_GroupStickersHelp: String { return self._s[2249]! } + public var GroupPermission_NoSendPolls: String { return self._s[2250]! } + public var Wallet_Qr_ScanCode: String { return self._s[2251]! } + public var Message_VideoExpired: String { return self._s[2253]! } + public var GroupInfo_GroupHistoryVisible: String { return self._s[2254]! } + public var Notifications_Badge: String { return self._s[2255]! } + public var Wallet_Receive_AddressCopied: String { return self._s[2256]! } + public var CreatePoll_OptionPlaceholder: String { return self._s[2257]! } + public var Username_InvalidTooShort: String { return self._s[2258]! } + public var EnterPasscode_EnterNewPasscodeChange: String { return self._s[2259]! } + public var Channel_AdminLog_PinMessages: String { return self._s[2260]! } + public var ArchivedChats_IntroTitle3: String { return self._s[2261]! } public func Notification_MessageLifetimeRemoved(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2260]!, self._r[2260]!, [_1]) + return formatWithArgumentRanges(self._s[2262]!, self._r[2262]!, [_1]) } - public var Permissions_SiriAllowInSettings_v0: String { return self._s[2261]! } - public var Conversation_DefaultRestrictedText: String { return self._s[2262]! } - public var SharedMedia_CategoryDocs: String { return self._s[2265]! } + public var Permissions_SiriAllowInSettings_v0: String { return self._s[2263]! } + public var Conversation_DefaultRestrictedText: String { return self._s[2264]! } + public var SharedMedia_CategoryDocs: String { return self._s[2267]! } public func PUSH_MESSAGE_CONTACT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2266]!, self._r[2266]!, [_1]) + return formatWithArgumentRanges(self._s[2268]!, self._r[2268]!, [_1]) } - public var Wallet_Send_UninitializedTitle: String { return self._s[2267]! } - public var StickerPackActionInfo_ArchivedTitle: String { return self._s[2268]! } - public var Privacy_Forwards_NeverLink: String { return self._s[2270]! } + public var Wallet_Send_UninitializedTitle: String { return self._s[2269]! } + public var StickerPackActionInfo_ArchivedTitle: String { return self._s[2270]! } + public var Privacy_Forwards_NeverLink: String { return self._s[2272]! } public func Notification_MessageLifetimeChangedOutgoing(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2271]!, self._r[2271]!, [_1]) + return formatWithArgumentRanges(self._s[2273]!, self._r[2273]!, [_1]) } - public var CheckoutInfo_ErrorShippingNotAvailable: String { return self._s[2272]! } + public var CheckoutInfo_ErrorShippingNotAvailable: String { return self._s[2274]! } public func Time_MonthOfYear_m12(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2273]!, self._r[2273]!, [_0]) + return formatWithArgumentRanges(self._s[2275]!, self._r[2275]!, [_0]) } - public var ChatSettings_PrivateChats: String { return self._s[2274]! } - public var SettingsSearch_Synonyms_EditProfile_Logout: String { return self._s[2275]! } - public var Conversation_PrivateMessageLinkCopied: String { return self._s[2276]! } - public var Channel_UpdatePhotoItem: String { return self._s[2277]! } - public var GroupInfo_LeftStatus: String { return self._s[2278]! } - public var Watch_MessageView_Forward: String { return self._s[2280]! } - public var ReportPeer_ReasonChildAbuse: String { return self._s[2281]! } - public var Cache_ClearEmpty: String { return self._s[2283]! } - public var Localization_LanguageName: String { return self._s[2284]! } - public var Wallet_AccessDenied_Title: String { return self._s[2285]! } - public var WebSearch_GIFs: String { return self._s[2286]! } - public var Notifications_DisplayNamesOnLockScreenInfoWithLink: String { return self._s[2287]! } - public var Wallet_AccessDenied_Settings: String { return self._s[2288]! } - public var Username_InvalidStartsWithNumber: String { return self._s[2289]! } - public var Common_Back: String { return self._s[2290]! } - public var GroupInfo_Permissions_EditingDisabled: String { return self._s[2291]! } - public var Passport_Identity_DateOfBirthPlaceholder: String { return self._s[2292]! } - public var Wallet_Send_Send: String { return self._s[2293]! } + public var ChatSettings_PrivateChats: String { return self._s[2276]! } + public var SettingsSearch_Synonyms_EditProfile_Logout: String { return self._s[2277]! } + public var Conversation_PrivateMessageLinkCopied: String { return self._s[2278]! } + public var Channel_UpdatePhotoItem: String { return self._s[2279]! } + public var GroupInfo_LeftStatus: String { return self._s[2280]! } + public var Watch_MessageView_Forward: String { return self._s[2282]! } + public var ReportPeer_ReasonChildAbuse: String { return self._s[2283]! } + public var Cache_ClearEmpty: String { return self._s[2285]! } + public var Localization_LanguageName: String { return self._s[2286]! } + public var Wallet_AccessDenied_Title: String { return self._s[2287]! } + public var WebSearch_GIFs: String { return self._s[2288]! } + public var Notifications_DisplayNamesOnLockScreenInfoWithLink: String { return self._s[2289]! } + public var Wallet_AccessDenied_Settings: String { return self._s[2290]! } + public var Username_InvalidStartsWithNumber: String { return self._s[2291]! } + public var Common_Back: String { return self._s[2292]! } + public var GroupInfo_Permissions_EditingDisabled: String { return self._s[2293]! } + public var Passport_Identity_DateOfBirthPlaceholder: String { return self._s[2294]! } + public var Wallet_Send_Send: String { return self._s[2295]! } public func PUSH_CHANNEL_MESSAGE_STICKER(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2295]!, self._r[2295]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2297]!, self._r[2297]!, [_1, _2]) } - public var Wallet_Info_RefreshErrorTitle: String { return self._s[2296]! } - public var Wallet_Month_GenJune: String { return self._s[2297]! } - public var Passport_Email_Help: String { return self._s[2298]! } - public var Watch_Conversation_Reply: String { return self._s[2300]! } - public var Conversation_EditingMessageMediaChange: String { return self._s[2303]! } - public var Passport_Identity_IssueDatePlaceholder: String { return self._s[2304]! } - public var Channel_BanUser_Unban: String { return self._s[2306]! } - public var Channel_EditAdmin_PermissionPostMessages: String { return self._s[2307]! } - public var Group_Username_CreatePublicLinkHelp: String { return self._s[2308]! } - public var TwoStepAuth_ConfirmEmailCodePlaceholder: String { return self._s[2310]! } - public var Wallet_Send_AddressHeader: String { return self._s[2311]! } - public var Passport_Identity_Name: String { return self._s[2312]! } + public var Wallet_Info_RefreshErrorTitle: String { return self._s[2298]! } + public var Wallet_Month_GenJune: String { return self._s[2299]! } + public var Passport_Email_Help: String { return self._s[2300]! } + public var Watch_Conversation_Reply: String { return self._s[2302]! } + public var Conversation_EditingMessageMediaChange: String { return self._s[2305]! } + public var Passport_Identity_IssueDatePlaceholder: String { return self._s[2306]! } + public var Channel_BanUser_Unban: String { return self._s[2308]! } + public var Channel_EditAdmin_PermissionPostMessages: String { return self._s[2309]! } + public var Group_Username_CreatePublicLinkHelp: String { return self._s[2310]! } + public var TwoStepAuth_ConfirmEmailCodePlaceholder: String { return self._s[2312]! } + public var Wallet_Send_AddressHeader: String { return self._s[2313]! } + public var Passport_Identity_Name: String { return self._s[2314]! } public func Channel_DiscussionGroup_HeaderGroupSet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2313]!, self._r[2313]!, [_0]) + return formatWithArgumentRanges(self._s[2315]!, self._r[2315]!, [_0]) } - public var GroupRemoved_ViewUserInfo: String { return self._s[2314]! } - public var Conversation_BlockUser: String { return self._s[2315]! } - public var Month_GenJanuary: String { return self._s[2316]! } - public var ChatSettings_TextSize: String { return self._s[2317]! } - public var Notification_PassportValuePhone: String { return self._s[2318]! } - public var MediaPlayer_UnknownArtist: String { return self._s[2319]! } - public var Passport_Language_ne: String { return self._s[2320]! } - public var Notification_CallBack: String { return self._s[2321]! } - public var Wallet_SecureStorageReset_BiometryTouchId: String { return self._s[2322]! } - public var TwoStepAuth_EmailHelp: String { return self._s[2323]! } + public var GroupRemoved_ViewUserInfo: String { return self._s[2316]! } + public var Conversation_BlockUser: String { return self._s[2317]! } + public var Month_GenJanuary: String { return self._s[2318]! } + public var ChatSettings_TextSize: String { return self._s[2319]! } + public var Notification_PassportValuePhone: String { return self._s[2320]! } + public var MediaPlayer_UnknownArtist: String { return self._s[2321]! } + public var Passport_Language_ne: String { return self._s[2322]! } + public var Notification_CallBack: String { return self._s[2323]! } + public var Wallet_SecureStorageReset_BiometryTouchId: String { return self._s[2324]! } + public var TwoStepAuth_EmailHelp: String { return self._s[2325]! } public func Time_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2324]!, self._r[2324]!, [_0]) + return formatWithArgumentRanges(self._s[2326]!, self._r[2326]!, [_0]) } - public var Channel_Info_Management: String { return self._s[2325]! } - public var Passport_FieldIdentityUploadHelp: String { return self._s[2326]! } - public var Stickers_FrequentlyUsed: String { return self._s[2327]! } - public var Channel_BanUser_PermissionSendMessages: String { return self._s[2328]! } - public var Passport_Address_OneOfTypeUtilityBill: String { return self._s[2330]! } + public var Channel_Info_Management: String { return self._s[2327]! } + public var Passport_FieldIdentityUploadHelp: String { return self._s[2328]! } + public var Stickers_FrequentlyUsed: String { return self._s[2329]! } + public var Channel_BanUser_PermissionSendMessages: String { return self._s[2330]! } + public var Passport_Address_OneOfTypeUtilityBill: String { return self._s[2332]! } public func LOCAL_CHANNEL_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2331]!, self._r[2331]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[2333]!, self._r[2333]!, [_1, "\(_2)"]) } - public var TwoFactorSetup_Password_Title: String { return self._s[2332]! } - public var Passport_Address_EditResidentialAddress: String { return self._s[2333]! } - public var PrivacyPolicy_DeclineTitle: String { return self._s[2334]! } - public var CreatePoll_TextHeader: String { return self._s[2335]! } + public var TwoFactorSetup_Password_Title: String { return self._s[2334]! } + public var Passport_Address_EditResidentialAddress: String { return self._s[2335]! } + public var PrivacyPolicy_DeclineTitle: String { return self._s[2336]! } + public var CreatePoll_TextHeader: String { return self._s[2337]! } public func Checkout_SavePasswordTimeoutAndTouchId(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2336]!, self._r[2336]!, [_0]) + return formatWithArgumentRanges(self._s[2338]!, self._r[2338]!, [_0]) } - public var PhotoEditor_QualityMedium: String { return self._s[2337]! } - public var InfoPlist_NSMicrophoneUsageDescription: String { return self._s[2338]! } - public var Conversation_StatusKickedFromChannel: String { return self._s[2340]! } - public var CheckoutInfo_ReceiverInfoName: String { return self._s[2341]! } - public var Group_ErrorSendRestrictedStickers: String { return self._s[2342]! } + public var PhotoEditor_QualityMedium: String { return self._s[2339]! } + public var InfoPlist_NSMicrophoneUsageDescription: String { return self._s[2340]! } + public var Conversation_StatusKickedFromChannel: String { return self._s[2342]! } + public var CheckoutInfo_ReceiverInfoName: String { return self._s[2343]! } + public var Group_ErrorSendRestrictedStickers: String { return self._s[2344]! } public func Conversation_RestrictedInlineTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2343]!, self._r[2343]!, [_0]) + return formatWithArgumentRanges(self._s[2345]!, self._r[2345]!, [_0]) } public func Channel_AdminLog_MessageTransferedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2344]!, self._r[2344]!, [_1]) + return formatWithArgumentRanges(self._s[2346]!, self._r[2346]!, [_1]) } - public var LogoutOptions_LogOutWalletInfo: String { return self._s[2345]! } - public var TwoFactorSetup_Email_SkipConfirmationTitle: String { return self._s[2346]! } - public var Conversation_LinkDialogOpen: String { return self._s[2348]! } - public var TwoFactorSetup_Hint_Title: String { return self._s[2349]! } - public var VoiceOver_Chat_PollNoVotes: String { return self._s[2350]! } - public var Settings_Username: String { return self._s[2352]! } - public var Conversation_Block: String { return self._s[2354]! } - public var Wallpaper_Wallpaper: String { return self._s[2355]! } - public var SocksProxySetup_UseProxy: String { return self._s[2357]! } - public var Wallet_Send_Confirmation: String { return self._s[2358]! } - public var EditTheme_UploadEditedTheme: String { return self._s[2359]! } - public var UserInfo_ShareMyContactInfo: String { return self._s[2360]! } - public var MessageTimer_Forever: String { return self._s[2361]! } - public var Privacy_Calls_WhoCanCallMe: String { return self._s[2362]! } - public var PhotoEditor_DiscardChanges: String { return self._s[2363]! } - public var AuthSessions_TerminateOtherSessionsHelp: String { return self._s[2364]! } - public var Passport_Language_da: String { return self._s[2365]! } - public var SocksProxySetup_PortPlaceholder: String { return self._s[2366]! } + public var LogoutOptions_LogOutWalletInfo: String { return self._s[2347]! } + public var TwoFactorSetup_Email_SkipConfirmationTitle: String { return self._s[2348]! } + public var Conversation_LinkDialogOpen: String { return self._s[2350]! } + public var TwoFactorSetup_Hint_Title: String { return self._s[2351]! } + public var VoiceOver_Chat_PollNoVotes: String { return self._s[2352]! } + public var Settings_Username: String { return self._s[2354]! } + public var Conversation_Block: String { return self._s[2356]! } + public var Wallpaper_Wallpaper: String { return self._s[2357]! } + public var SocksProxySetup_UseProxy: String { return self._s[2359]! } + public var Wallet_Send_Confirmation: String { return self._s[2360]! } + public var EditTheme_UploadEditedTheme: String { return self._s[2361]! } + public var UserInfo_ShareMyContactInfo: String { return self._s[2362]! } + public var MessageTimer_Forever: String { return self._s[2363]! } + public var Privacy_Calls_WhoCanCallMe: String { return self._s[2364]! } + public var PhotoEditor_DiscardChanges: String { return self._s[2365]! } + public var AuthSessions_TerminateOtherSessionsHelp: String { return self._s[2366]! } + public var Passport_Language_da: String { return self._s[2367]! } + public var SocksProxySetup_PortPlaceholder: String { return self._s[2368]! } public func SecretGIF_NotViewedYet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2367]!, self._r[2367]!, [_0]) + return formatWithArgumentRanges(self._s[2369]!, self._r[2369]!, [_0]) } - public var Passport_Address_EditPassportRegistration: String { return self._s[2368]! } + public var Passport_Address_EditPassportRegistration: String { return self._s[2370]! } public func Channel_AdminLog_MessageChangedGroupAbout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2370]!, self._r[2370]!, [_0]) + return formatWithArgumentRanges(self._s[2372]!, self._r[2372]!, [_0]) } - public var Settings_AddDevice: String { return self._s[2371]! } - public var Passport_Identity_ResidenceCountryPlaceholder: String { return self._s[2373]! } - public var AuthSessions_AddDeviceIntro_Text1: String { return self._s[2374]! } - public var Conversation_SearchByName_Prefix: String { return self._s[2375]! } - public var Conversation_PinnedPoll: String { return self._s[2376]! } - public var AuthSessions_AddDeviceIntro_Text2: String { return self._s[2377]! } - public var Conversation_EmptyGifPanelPlaceholder: String { return self._s[2378]! } - public var AuthSessions_AddDeviceIntro_Text3: String { return self._s[2379]! } + public var Settings_AddDevice: String { return self._s[2373]! } + public var Passport_Identity_ResidenceCountryPlaceholder: String { return self._s[2375]! } + public var AuthSessions_AddDeviceIntro_Text1: String { return self._s[2376]! } + public var Conversation_SearchByName_Prefix: String { return self._s[2377]! } + public var Conversation_PinnedPoll: String { return self._s[2378]! } + public var AuthSessions_AddDeviceIntro_Text2: String { return self._s[2379]! } + public var Conversation_EmptyGifPanelPlaceholder: String { return self._s[2380]! } + public var AuthSessions_AddDeviceIntro_Text3: String { return self._s[2381]! } public func PUSH_ENCRYPTION_ACCEPT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2380]!, self._r[2380]!, [_1]) + return formatWithArgumentRanges(self._s[2382]!, self._r[2382]!, [_1]) } - public var WallpaperSearch_ColorPurple: String { return self._s[2381]! } - public var Cache_ByPeerHeader: String { return self._s[2382]! } + public var WallpaperSearch_ColorPurple: String { return self._s[2383]! } + public var Cache_ByPeerHeader: String { return self._s[2384]! } public func Conversation_EncryptedPlaceholderTitleIncoming(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2383]!, self._r[2383]!, [_0]) + return formatWithArgumentRanges(self._s[2385]!, self._r[2385]!, [_0]) } - public var ChatSettings_AutoDownloadDocuments: String { return self._s[2384]! } - public var Appearance_ThemePreview_Chat_3_Text: String { return self._s[2387]! } - public var Wallet_Completed_Title: String { return self._s[2388]! } - public var Notification_PinnedMessage: String { return self._s[2389]! } - public var TwoFactorSetup_EmailVerification_Placeholder: String { return self._s[2390]! } - public var VoiceOver_Chat_RecordModeVideoMessage: String { return self._s[2392]! } - public var Contacts_SortBy: String { return self._s[2393]! } + public var ChatSettings_AutoDownloadDocuments: String { return self._s[2386]! } + public var Appearance_ThemePreview_Chat_3_Text: String { return self._s[2389]! } + public var Wallet_Completed_Title: String { return self._s[2390]! } + public var Notification_PinnedMessage: String { return self._s[2391]! } + public var TwoFactorSetup_EmailVerification_Placeholder: String { return self._s[2392]! } + public var VoiceOver_Chat_RecordModeVideoMessage: String { return self._s[2394]! } + public var Contacts_SortBy: String { return self._s[2395]! } public func PUSH_CHANNEL_MESSAGE_NOTEXT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2394]!, self._r[2394]!, [_1]) + return formatWithArgumentRanges(self._s[2396]!, self._r[2396]!, [_1]) } - public var Appearance_ColorThemeNight: String { return self._s[2396]! } + public var Appearance_ColorThemeNight: String { return self._s[2398]! } public func PUSH_MESSAGE_GAME(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2397]!, self._r[2397]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2399]!, self._r[2399]!, [_1, _2]) } - public var Call_EncryptionKey_Title: String { return self._s[2398]! } - public var Watch_UserInfo_Service: String { return self._s[2399]! } - public var SettingsSearch_Synonyms_Data_SaveEditedPhotos: String { return self._s[2401]! } - public var Conversation_Unpin: String { return self._s[2403]! } - public var CancelResetAccount_Title: String { return self._s[2404]! } - public var Map_LiveLocationFor15Minutes: String { return self._s[2405]! } + public var Call_EncryptionKey_Title: String { return self._s[2400]! } + public var Watch_UserInfo_Service: String { return self._s[2401]! } + public var SettingsSearch_Synonyms_Data_SaveEditedPhotos: String { return self._s[2403]! } + public var Conversation_Unpin: String { return self._s[2405]! } + public var CancelResetAccount_Title: String { return self._s[2406]! } + public var Map_LiveLocationFor15Minutes: String { return self._s[2407]! } public func Time_PreciseDate_m8(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2407]!, self._r[2407]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2409]!, self._r[2409]!, [_1, _2, _3]) } - public var Group_Members_AddMemberBotErrorNotAllowed: String { return self._s[2408]! } - public var Appearance_BubbleCorners_Title: String { return self._s[2409]! } - public var CallSettings_Title: String { return self._s[2410]! } - public var SettingsSearch_Synonyms_Appearance_ChatBackground: String { return self._s[2411]! } - public var PasscodeSettings_EncryptDataHelp: String { return self._s[2413]! } - public var AutoDownloadSettings_Contacts: String { return self._s[2414]! } + public var Group_Members_AddMemberBotErrorNotAllowed: String { return self._s[2410]! } + public var Appearance_BubbleCorners_Title: String { return self._s[2411]! } + public var CallSettings_Title: String { return self._s[2412]! } + public var SettingsSearch_Synonyms_Appearance_ChatBackground: String { return self._s[2413]! } + public var PasscodeSettings_EncryptDataHelp: String { return self._s[2415]! } + public var AutoDownloadSettings_Contacts: String { return self._s[2416]! } public func Channel_AdminLog_MessageRankName(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2415]!, self._r[2415]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2417]!, self._r[2417]!, [_1, _2]) } - public var Passport_Identity_DocumentDetails: String { return self._s[2416]! } - public var LoginPassword_PasswordHelp: String { return self._s[2417]! } - public var SettingsSearch_Synonyms_Data_AutoDownloadUsingWifi: String { return self._s[2418]! } - public var PrivacyLastSeenSettings_CustomShareSettings_Delete: String { return self._s[2419]! } - public var ChatContextMenu_TextSelectionTip: String { return self._s[2420]! } - public var Checkout_TotalPaidAmount: String { return self._s[2421]! } + public var Passport_Identity_DocumentDetails: String { return self._s[2418]! } + public var LoginPassword_PasswordHelp: String { return self._s[2419]! } + public var SettingsSearch_Synonyms_Data_AutoDownloadUsingWifi: String { return self._s[2420]! } + public var PrivacyLastSeenSettings_CustomShareSettings_Delete: String { return self._s[2421]! } + public var ChatContextMenu_TextSelectionTip: String { return self._s[2422]! } + public var Checkout_TotalPaidAmount: String { return self._s[2423]! } public func FileSize_KB(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2422]!, self._r[2422]!, [_0]) + return formatWithArgumentRanges(self._s[2424]!, self._r[2424]!, [_0]) } - public var PasscodeSettings_ChangePasscode: String { return self._s[2423]! } - public var Conversation_SecretLinkPreviewAlert: String { return self._s[2425]! } - public var Privacy_SecretChatsLinkPreviews: String { return self._s[2426]! } + public var ChatState_Updating: String { return self._s[2425]! } + public var PasscodeSettings_ChangePasscode: String { return self._s[2426]! } + public var Conversation_SecretLinkPreviewAlert: String { return self._s[2428]! } + public var Privacy_SecretChatsLinkPreviews: String { return self._s[2429]! } public func PUSH_CHANNEL_MESSAGE_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2427]!, self._r[2427]!, [_1]) + return formatWithArgumentRanges(self._s[2430]!, self._r[2430]!, [_1]) } - public var VoiceOver_Chat_ReplyToYourMessage: String { return self._s[2428]! } - public var Contacts_InviteFriends: String { return self._s[2430]! } - public var Map_ChooseLocationTitle: String { return self._s[2431]! } - public var Conversation_StopPoll: String { return self._s[2433]! } + public var VoiceOver_Chat_ReplyToYourMessage: String { return self._s[2431]! } + public var Contacts_InviteFriends: String { return self._s[2433]! } + public var Map_ChooseLocationTitle: String { return self._s[2434]! } + public var Conversation_StopPoll: String { return self._s[2436]! } public func WebSearch_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2434]!, self._r[2434]!, [_0]) + return formatWithArgumentRanges(self._s[2437]!, self._r[2437]!, [_0]) } - public var Call_Camera: String { return self._s[2435]! } - public var LogoutOptions_ChangePhoneNumberTitle: String { return self._s[2436]! } - public var AppWallet_Intro_Text: String { return self._s[2437]! } - public var Appearance_BubbleCornersSetting: String { return self._s[2438]! } - public var Calls_RatingFeedback: String { return self._s[2439]! } - public var GroupInfo_BroadcastListNamePlaceholder: String { return self._s[2441]! } - public var Wallet_Alert_OK: String { return self._s[2442]! } - public var NotificationsSound_Pulse: String { return self._s[2443]! } - public var Watch_LastSeen_Lately: String { return self._s[2444]! } - public var ReportGroupLocation_Report: String { return self._s[2447]! } - public var Widget_NoUsers: String { return self._s[2448]! } - public var Conversation_UnvotePoll: String { return self._s[2449]! } - public var SettingsSearch_Synonyms_Privacy_ProfilePhoto: String { return self._s[2451]! } - public var Privacy_ProfilePhoto_WhoCanSeeMyPhoto: String { return self._s[2452]! } - public var NotificationsSound_Circles: String { return self._s[2453]! } - public var PrivacyLastSeenSettings_AlwaysShareWith_Title: String { return self._s[2456]! } - public var Wallet_Settings_DeleteWallet: String { return self._s[2457]! } - public var TwoStepAuth_RecoveryCodeExpired: String { return self._s[2458]! } - public var Proxy_TooltipUnavailable: String { return self._s[2459]! } - public var Passport_Identity_CountryPlaceholder: String { return self._s[2461]! } - public var GroupInfo_Permissions_SlowmodeInfo: String { return self._s[2463]! } - public var Conversation_FileDropbox: String { return self._s[2464]! } - public var Notifications_ExceptionsUnmuted: String { return self._s[2465]! } - public var Tour_Text3: String { return self._s[2467]! } - public var Login_ResetAccountProtected_Title: String { return self._s[2469]! } - public var GroupPermission_NoSendMessages: String { return self._s[2470]! } - public var WallpaperSearch_ColorTitle: String { return self._s[2471]! } - public var ChatAdmins_AllMembersAreAdminsOnHelp: String { return self._s[2472]! } + public var Call_Camera: String { return self._s[2438]! } + public var LogoutOptions_ChangePhoneNumberTitle: String { return self._s[2439]! } + public var AppWallet_Intro_Text: String { return self._s[2440]! } + public var Appearance_BubbleCornersSetting: String { return self._s[2441]! } + public var Calls_RatingFeedback: String { return self._s[2442]! } + public var GroupInfo_BroadcastListNamePlaceholder: String { return self._s[2444]! } + public var Wallet_Alert_OK: String { return self._s[2445]! } + public var NotificationsSound_Pulse: String { return self._s[2446]! } + public var Watch_LastSeen_Lately: String { return self._s[2447]! } + public var ReportGroupLocation_Report: String { return self._s[2450]! } + public var Widget_NoUsers: String { return self._s[2451]! } + public var Conversation_UnvotePoll: String { return self._s[2452]! } + public var SettingsSearch_Synonyms_Privacy_ProfilePhoto: String { return self._s[2454]! } + public var Privacy_ProfilePhoto_WhoCanSeeMyPhoto: String { return self._s[2455]! } + public var NotificationsSound_Circles: String { return self._s[2456]! } + public var PrivacyLastSeenSettings_AlwaysShareWith_Title: String { return self._s[2459]! } + public var Wallet_Settings_DeleteWallet: String { return self._s[2460]! } + public var TwoStepAuth_RecoveryCodeExpired: String { return self._s[2461]! } + public var Proxy_TooltipUnavailable: String { return self._s[2462]! } + public var Passport_Identity_CountryPlaceholder: String { return self._s[2464]! } + public var GroupInfo_Permissions_SlowmodeInfo: String { return self._s[2466]! } + public var Conversation_FileDropbox: String { return self._s[2467]! } + public var Notifications_ExceptionsUnmuted: String { return self._s[2468]! } + public var Tour_Text3: String { return self._s[2470]! } + public var Login_ResetAccountProtected_Title: String { return self._s[2472]! } + public var GroupPermission_NoSendMessages: String { return self._s[2473]! } + public var WallpaperSearch_ColorTitle: String { return self._s[2474]! } + public var ChatAdmins_AllMembersAreAdminsOnHelp: String { return self._s[2475]! } public func Conversation_LiveLocationYouAnd(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2474]!, self._r[2474]!, [_0]) + return formatWithArgumentRanges(self._s[2477]!, self._r[2477]!, [_0]) } - public var GroupInfo_AddParticipantTitle: String { return self._s[2475]! } - public var Checkout_ShippingOption_Title: String { return self._s[2476]! } - public var ChatSettings_AutoDownloadTitle: String { return self._s[2477]! } + public var GroupInfo_AddParticipantTitle: String { return self._s[2478]! } + public var Checkout_ShippingOption_Title: String { return self._s[2479]! } + public var ChatSettings_AutoDownloadTitle: String { return self._s[2480]! } public func DialogList_SingleTypingSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2478]!, self._r[2478]!, [_0]) + return formatWithArgumentRanges(self._s[2481]!, self._r[2481]!, [_0]) } public func ChatSettings_AutoDownloadSettings_TypeVideo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2479]!, self._r[2479]!, [_0]) + return formatWithArgumentRanges(self._s[2482]!, self._r[2482]!, [_0]) } - public var Channel_Management_LabelAdministrator: String { return self._s[2480]! } - public var EditTheme_FileReadError: String { return self._s[2481]! } - public var OwnershipTransfer_ComeBackLater: String { return self._s[2482]! } - public var PrivacyLastSeenSettings_NeverShareWith_Placeholder: String { return self._s[2483]! } - public var AutoDownloadSettings_Photos: String { return self._s[2485]! } - public var Appearance_PreviewIncomingText: String { return self._s[2486]! } - public var ChatList_Context_MarkAllAsRead: String { return self._s[2487]! } - public var ChannelInfo_ConfirmLeave: String { return self._s[2488]! } - public var MediaPicker_MomentsDateRangeSameMonthYearFormat: String { return self._s[2489]! } - public var Passport_Identity_DocumentNumberPlaceholder: String { return self._s[2490]! } - public var Channel_AdminLogFilter_EventsNewMembers: String { return self._s[2491]! } - public var PasscodeSettings_AutoLock_IfAwayFor_5minutes: String { return self._s[2492]! } - public var GroupInfo_SetGroupPhotoStop: String { return self._s[2493]! } - public var Notification_SecretChatScreenshot: String { return self._s[2494]! } - public var AccessDenied_Wallpapers: String { return self._s[2495]! } - public var ChatList_Context_Mute: String { return self._s[2497]! } - public var Passport_Address_City: String { return self._s[2498]! } - public var InfoPlist_NSPhotoLibraryAddUsageDescription: String { return self._s[2499]! } - public var Appearance_ThemeCarouselClassic: String { return self._s[2500]! } - public var SocksProxySetup_SecretPlaceholder: String { return self._s[2501]! } - public var AccessDenied_LocationDisabled: String { return self._s[2502]! } - public var Group_Location_Title: String { return self._s[2503]! } - public var SocksProxySetup_HostnamePlaceholder: String { return self._s[2505]! } - public var GroupInfo_Sound: String { return self._s[2506]! } - public var SettingsSearch_Synonyms_ChatSettings_OpenLinksIn: String { return self._s[2507]! } - public var ChannelInfo_ScamChannelWarning: String { return self._s[2508]! } - public var Stickers_RemoveFromFavorites: String { return self._s[2509]! } - public var Contacts_Title: String { return self._s[2510]! } - public var EditTheme_ThemeTemplateAlertText: String { return self._s[2511]! } - public var Passport_Language_fr: String { return self._s[2512]! } - public var TwoFactorSetup_EmailVerification_Action: String { return self._s[2513]! } - public var Notifications_ResetAllNotifications: String { return self._s[2514]! } - public var IntentsSettings_SuggestedChats: String { return self._s[2516]! } - public var PrivacySettings_SecurityTitle: String { return self._s[2518]! } - public var Checkout_NewCard_Title: String { return self._s[2519]! } - public var Login_HaveNotReceivedCodeInternal: String { return self._s[2520]! } - public var Conversation_ForwardChats: String { return self._s[2521]! } - public var Wallet_SecureStorageReset_PasscodeText: String { return self._s[2523]! } - public var PasscodeSettings_4DigitCode: String { return self._s[2524]! } - public var Settings_FAQ: String { return self._s[2526]! } - public var AutoDownloadSettings_DocumentsTitle: String { return self._s[2527]! } - public var Conversation_ContextMenuForward: String { return self._s[2528]! } - public var VoiceOver_Chat_YourPhoto: String { return self._s[2531]! } - public var PrivacyPolicy_Title: String { return self._s[2534]! } - public var Notifications_TextTone: String { return self._s[2535]! } - public var Profile_CreateNewContact: String { return self._s[2536]! } - public var PrivacyPhoneNumberSettings_WhoCanSeeMyPhoneNumber: String { return self._s[2537]! } - public var TwoFactorSetup_EmailVerification_Title: String { return self._s[2539]! } - public var Call_Speaker: String { return self._s[2540]! } - public var AutoNightTheme_AutomaticSection: String { return self._s[2541]! } - public var Channel_OwnershipTransfer_EnterPassword: String { return self._s[2543]! } - public var Channel_Username_InvalidCharacters: String { return self._s[2544]! } + public var Channel_Management_LabelAdministrator: String { return self._s[2483]! } + public var EditTheme_FileReadError: String { return self._s[2484]! } + public var OwnershipTransfer_ComeBackLater: String { return self._s[2485]! } + public var PrivacyLastSeenSettings_NeverShareWith_Placeholder: String { return self._s[2486]! } + public var AutoDownloadSettings_Photos: String { return self._s[2488]! } + public var Appearance_PreviewIncomingText: String { return self._s[2489]! } + public var ChatList_Context_MarkAllAsRead: String { return self._s[2490]! } + public var ChannelInfo_ConfirmLeave: String { return self._s[2491]! } + public var MediaPicker_MomentsDateRangeSameMonthYearFormat: String { return self._s[2492]! } + public var Passport_Identity_DocumentNumberPlaceholder: String { return self._s[2493]! } + public var Channel_AdminLogFilter_EventsNewMembers: String { return self._s[2494]! } + public var PasscodeSettings_AutoLock_IfAwayFor_5minutes: String { return self._s[2495]! } + public var GroupInfo_SetGroupPhotoStop: String { return self._s[2496]! } + public var Notification_SecretChatScreenshot: String { return self._s[2497]! } + public var AccessDenied_Wallpapers: String { return self._s[2498]! } + public var ChatList_Context_Mute: String { return self._s[2500]! } + public var Passport_Address_City: String { return self._s[2501]! } + public var InfoPlist_NSPhotoLibraryAddUsageDescription: String { return self._s[2502]! } + public var Appearance_ThemeCarouselClassic: String { return self._s[2503]! } + public var SocksProxySetup_SecretPlaceholder: String { return self._s[2504]! } + public var AccessDenied_LocationDisabled: String { return self._s[2505]! } + public var Group_Location_Title: String { return self._s[2506]! } + public var SocksProxySetup_HostnamePlaceholder: String { return self._s[2508]! } + public var GroupInfo_Sound: String { return self._s[2509]! } + public var SettingsSearch_Synonyms_ChatSettings_OpenLinksIn: String { return self._s[2510]! } + public var ChannelInfo_ScamChannelWarning: String { return self._s[2511]! } + public var Stickers_RemoveFromFavorites: String { return self._s[2512]! } + public var Contacts_Title: String { return self._s[2513]! } + public var EditTheme_ThemeTemplateAlertText: String { return self._s[2514]! } + public var Passport_Language_fr: String { return self._s[2515]! } + public var TwoFactorSetup_EmailVerification_Action: String { return self._s[2516]! } + public var Notifications_ResetAllNotifications: String { return self._s[2517]! } + public var IntentsSettings_SuggestedChats: String { return self._s[2519]! } + public var PrivacySettings_SecurityTitle: String { return self._s[2521]! } + public var Checkout_NewCard_Title: String { return self._s[2522]! } + public var Login_HaveNotReceivedCodeInternal: String { return self._s[2523]! } + public var Conversation_ForwardChats: String { return self._s[2524]! } + public var Wallet_SecureStorageReset_PasscodeText: String { return self._s[2526]! } + public var PasscodeSettings_4DigitCode: String { return self._s[2527]! } + public var Settings_FAQ: String { return self._s[2529]! } + public var AutoDownloadSettings_DocumentsTitle: String { return self._s[2530]! } + public var Conversation_ContextMenuForward: String { return self._s[2531]! } + public var VoiceOver_Chat_YourPhoto: String { return self._s[2534]! } + public var PrivacyPolicy_Title: String { return self._s[2537]! } + public var Notifications_TextTone: String { return self._s[2538]! } + public var Profile_CreateNewContact: String { return self._s[2539]! } + public var PrivacyPhoneNumberSettings_WhoCanSeeMyPhoneNumber: String { return self._s[2540]! } + public var TwoFactorSetup_EmailVerification_Title: String { return self._s[2542]! } + public var Call_Speaker: String { return self._s[2543]! } + public var AutoNightTheme_AutomaticSection: String { return self._s[2544]! } + public var Channel_OwnershipTransfer_EnterPassword: String { return self._s[2546]! } + public var Channel_Username_InvalidCharacters: String { return self._s[2547]! } public func Channel_AdminLog_MessageChangedChannelUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2545]!, self._r[2545]!, [_0]) + return formatWithArgumentRanges(self._s[2548]!, self._r[2548]!, [_0]) } - public var AutoDownloadSettings_AutodownloadFiles: String { return self._s[2546]! } - public var PrivacySettings_LastSeenTitle: String { return self._s[2547]! } - public var Channel_AdminLog_CanInviteUsers: String { return self._s[2548]! } - public var SettingsSearch_Synonyms_Privacy_Data_ClearPaymentsInfo: String { return self._s[2549]! } - public var OwnershipTransfer_SecurityCheck: String { return self._s[2550]! } - public var Conversation_MessageDeliveryFailed: String { return self._s[2551]! } - public var Watch_ChatList_NoConversationsText: String { return self._s[2552]! } - public var Bot_Unblock: String { return self._s[2553]! } - public var TextFormat_Italic: String { return self._s[2554]! } - public var WallpaperSearch_ColorPink: String { return self._s[2555]! } - public var Settings_About_Help: String { return self._s[2557]! } - public var SearchImages_Title: String { return self._s[2558]! } - public var Weekday_Wednesday: String { return self._s[2559]! } - public var Conversation_ClousStorageInfo_Description1: String { return self._s[2560]! } - public var ExplicitContent_AlertTitle: String { return self._s[2561]! } + public var AutoDownloadSettings_AutodownloadFiles: String { return self._s[2549]! } + public var PrivacySettings_LastSeenTitle: String { return self._s[2550]! } + public var Channel_AdminLog_CanInviteUsers: String { return self._s[2551]! } + public var SettingsSearch_Synonyms_Privacy_Data_ClearPaymentsInfo: String { return self._s[2552]! } + public var OwnershipTransfer_SecurityCheck: String { return self._s[2553]! } + public var Conversation_MessageDeliveryFailed: String { return self._s[2554]! } + public var Watch_ChatList_NoConversationsText: String { return self._s[2555]! } + public var Bot_Unblock: String { return self._s[2556]! } + public var TextFormat_Italic: String { return self._s[2557]! } + public var WallpaperSearch_ColorPink: String { return self._s[2558]! } + public var Settings_About_Help: String { return self._s[2560]! } + public var SearchImages_Title: String { return self._s[2561]! } + public var Weekday_Wednesday: String { return self._s[2562]! } + public var Conversation_ClousStorageInfo_Description1: String { return self._s[2563]! } + public var ExplicitContent_AlertTitle: String { return self._s[2564]! } public func Time_PreciseDate_m5(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2562]!, self._r[2562]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2565]!, self._r[2565]!, [_1, _2, _3]) } - public var Channel_DiscussionGroup_Create: String { return self._s[2563]! } - public var Weekday_Thursday: String { return self._s[2564]! } - public var Channel_BanUser_PermissionChangeGroupInfo: String { return self._s[2565]! } - public var Channel_Members_AddMembersHelp: String { return self._s[2566]! } + public var Channel_DiscussionGroup_Create: String { return self._s[2566]! } + public var Weekday_Thursday: String { return self._s[2567]! } + public var Channel_BanUser_PermissionChangeGroupInfo: String { return self._s[2568]! } + public var Channel_Members_AddMembersHelp: String { return self._s[2569]! } public func Checkout_SavePasswordTimeout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2567]!, self._r[2567]!, [_0]) + return formatWithArgumentRanges(self._s[2570]!, self._r[2570]!, [_0]) } - public var Channel_DiscussionGroup_LinkGroup: String { return self._s[2568]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsVibrate: String { return self._s[2569]! } - public var Passport_RequestedInformation: String { return self._s[2570]! } - public var Login_PhoneAndCountryHelp: String { return self._s[2571]! } - public var Conversation_EncryptionProcessing: String { return self._s[2573]! } - public var Notifications_PermissionsSuppressWarningTitle: String { return self._s[2574]! } - public var PhotoEditor_EnhanceTool: String { return self._s[2576]! } - public var Channel_Setup_Title: String { return self._s[2577]! } - public var Conversation_SearchPlaceholder: String { return self._s[2578]! } - public var OldChannels_GroupEmptyFormat: String { return self._s[2579]! } - public var AccessDenied_LocationAlwaysDenied: String { return self._s[2580]! } - public var Checkout_ErrorGeneric: String { return self._s[2581]! } - public var Passport_Language_hu: String { return self._s[2582]! } - public var GroupPermission_EditingDisabled: String { return self._s[2583]! } - public var Wallet_Month_ShortSeptember: String { return self._s[2585]! } + public var Channel_DiscussionGroup_LinkGroup: String { return self._s[2571]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsVibrate: String { return self._s[2572]! } + public var Passport_RequestedInformation: String { return self._s[2573]! } + public var Login_PhoneAndCountryHelp: String { return self._s[2574]! } + public var Conversation_EncryptionProcessing: String { return self._s[2576]! } + public var Notifications_PermissionsSuppressWarningTitle: String { return self._s[2577]! } + public var PhotoEditor_EnhanceTool: String { return self._s[2579]! } + public var Channel_Setup_Title: String { return self._s[2580]! } + public var Conversation_SearchPlaceholder: String { return self._s[2581]! } + public var OldChannels_GroupEmptyFormat: String { return self._s[2582]! } + public var AccessDenied_LocationAlwaysDenied: String { return self._s[2583]! } + public var Checkout_ErrorGeneric: String { return self._s[2584]! } + public var Passport_Language_hu: String { return self._s[2585]! } + public var GroupPermission_EditingDisabled: String { return self._s[2586]! } + public var Wallet_Month_ShortSeptember: String { return self._s[2588]! } public func Passport_Identity_UploadOneOfScan(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2586]!, self._r[2586]!, [_0]) + return formatWithArgumentRanges(self._s[2589]!, self._r[2589]!, [_0]) } public func PUSH_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2589]!, self._r[2589]!, [_1]) + return formatWithArgumentRanges(self._s[2592]!, self._r[2592]!, [_1]) } - public var ChatList_DeleteSavedMessagesConfirmationTitle: String { return self._s[2590]! } + public var ChatList_DeleteSavedMessagesConfirmationTitle: String { return self._s[2593]! } public func UserInfo_BlockConfirmationTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2591]!, self._r[2591]!, [_0]) + return formatWithArgumentRanges(self._s[2594]!, self._r[2594]!, [_0]) } - public var Conversation_CloudStorageInfo_Title: String { return self._s[2592]! } - public var Group_Location_Info: String { return self._s[2593]! } - public var PhotoEditor_CropAspectRatioSquare: String { return self._s[2594]! } - public var Permissions_PeopleNearbyAllow_v0: String { return self._s[2595]! } + public var Conversation_CloudStorageInfo_Title: String { return self._s[2595]! } + public var Group_Location_Info: String { return self._s[2596]! } + public var PhotoEditor_CropAspectRatioSquare: String { return self._s[2597]! } + public var Permissions_PeopleNearbyAllow_v0: String { return self._s[2598]! } public func Notification_Exceptions_MutedUntil(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2596]!, self._r[2596]!, [_0]) + return formatWithArgumentRanges(self._s[2599]!, self._r[2599]!, [_0]) } - public var Conversation_ClearPrivateHistory: String { return self._s[2597]! } - public var ContactInfo_PhoneLabelHome: String { return self._s[2598]! } - public var Appearance_RemoveThemeConfirmation: String { return self._s[2599]! } - public var PrivacySettings_LastSeenContacts: String { return self._s[2600]! } + public var Conversation_ClearPrivateHistory: String { return self._s[2600]! } + public var ContactInfo_PhoneLabelHome: String { return self._s[2601]! } + public var Appearance_RemoveThemeConfirmation: String { return self._s[2602]! } + public var PrivacySettings_LastSeenContacts: String { return self._s[2603]! } public func ChangePhone_ErrorOccupied(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2601]!, self._r[2601]!, [_0]) + return formatWithArgumentRanges(self._s[2604]!, self._r[2604]!, [_0]) } public func Notification_PinnedQuizMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2602]!, self._r[2602]!, [_0]) + return formatWithArgumentRanges(self._s[2605]!, self._r[2605]!, [_0]) } - public var Passport_Language_cs: String { return self._s[2603]! } - public var Message_PinnedAnimationMessage: String { return self._s[2605]! } - public var Passport_Identity_ReverseSideHelp: String { return self._s[2607]! } - public var SettingsSearch_Synonyms_Data_Storage_Title: String { return self._s[2608]! } - public var Wallet_Info_TransactionTo: String { return self._s[2610]! } - public var ChatList_DeleteForEveryoneConfirmationText: String { return self._s[2611]! } - public var SettingsSearch_Synonyms_Privacy_PasscodeAndTouchId: String { return self._s[2612]! } - public var Embed_PlayingInPIP: String { return self._s[2613]! } - public var Appearance_ThemePreview_Chat_3_TextWithLink: String { return self._s[2614]! } - public var AutoNightTheme_ScheduleSection: String { return self._s[2615]! } + public var Passport_Language_cs: String { return self._s[2606]! } + public var Message_PinnedAnimationMessage: String { return self._s[2608]! } + public var Passport_Identity_ReverseSideHelp: String { return self._s[2610]! } + public var SettingsSearch_Synonyms_Data_Storage_Title: String { return self._s[2611]! } + public var Wallet_Info_TransactionTo: String { return self._s[2613]! } + public var ChatList_DeleteForEveryoneConfirmationText: String { return self._s[2614]! } + public var SettingsSearch_Synonyms_Privacy_PasscodeAndTouchId: String { return self._s[2615]! } + public var Embed_PlayingInPIP: String { return self._s[2616]! } + public var Appearance_ThemePreview_Chat_3_TextWithLink: String { return self._s[2617]! } + public var AutoNightTheme_ScheduleSection: String { return self._s[2618]! } public func Call_EmojiDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2616]!, self._r[2616]!, [_0]) + return formatWithArgumentRanges(self._s[2619]!, self._r[2619]!, [_0]) } - public var MediaPicker_LivePhotoDescription: String { return self._s[2617]! } + public var MediaPicker_LivePhotoDescription: String { return self._s[2620]! } public func Channel_AdminLog_MessageRestrictedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2618]!, self._r[2618]!, [_1]) + return formatWithArgumentRanges(self._s[2621]!, self._r[2621]!, [_1]) } - public var Notification_PaymentSent: String { return self._s[2619]! } - public var PhotoEditor_CurvesGreen: String { return self._s[2620]! } - public var Notification_Exceptions_PreviewAlwaysOff: String { return self._s[2621]! } - public var AutoNightTheme_System: String { return self._s[2622]! } - public var SaveIncomingPhotosSettings_Title: String { return self._s[2623]! } - public var CreatePoll_QuizTitle: String { return self._s[2624]! } - public var NotificationSettings_ShowNotificationsAllAccounts: String { return self._s[2625]! } - public var VoiceOver_Chat_PagePreview: String { return self._s[2626]! } + public var Notification_PaymentSent: String { return self._s[2622]! } + public var PhotoEditor_CurvesGreen: String { return self._s[2623]! } + public var Notification_Exceptions_PreviewAlwaysOff: String { return self._s[2624]! } + public var AutoNightTheme_System: String { return self._s[2625]! } + public var SaveIncomingPhotosSettings_Title: String { return self._s[2626]! } + public var CreatePoll_QuizTitle: String { return self._s[2627]! } + public var NotificationSettings_ShowNotificationsAllAccounts: String { return self._s[2628]! } + public var VoiceOver_Chat_PagePreview: String { return self._s[2629]! } public func PUSH_MESSAGE_SCREENSHOT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2629]!, self._r[2629]!, [_1]) + return formatWithArgumentRanges(self._s[2632]!, self._r[2632]!, [_1]) } public func PUSH_MESSAGE_PHOTO_SECRET(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2630]!, self._r[2630]!, [_1]) + return formatWithArgumentRanges(self._s[2633]!, self._r[2633]!, [_1]) } public func ApplyLanguage_UnsufficientDataText(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2631]!, self._r[2631]!, [_1]) + return formatWithArgumentRanges(self._s[2634]!, self._r[2634]!, [_1]) } - public var NetworkUsageSettings_CallDataSection: String { return self._s[2633]! } - public var PasscodeSettings_HelpTop: String { return self._s[2634]! } - public var Conversation_WalletRequiredTitle: String { return self._s[2635]! } - public var Group_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[2636]! } - public var Passport_Address_TypeRentalAgreement: String { return self._s[2637]! } - public var EditTheme_ShortLink: String { return self._s[2638]! } - public var Theme_Colors_ColorWallpaperWarning: String { return self._s[2639]! } - public var ProxyServer_VoiceOver_Active: String { return self._s[2640]! } - public var ReportPeer_ReasonOther_Placeholder: String { return self._s[2641]! } - public var CheckoutInfo_ErrorPhoneInvalid: String { return self._s[2642]! } - public var Call_Accept: String { return self._s[2644]! } - public var GroupRemoved_RemoveInfo: String { return self._s[2645]! } - public var Month_GenMarch: String { return self._s[2647]! } - public var PhotoEditor_ShadowsTool: String { return self._s[2648]! } - public var LoginPassword_Title: String { return self._s[2649]! } - public var Call_End: String { return self._s[2650]! } - public var Watch_Conversation_GroupInfo: String { return self._s[2651]! } - public var VoiceOver_Chat_Contact: String { return self._s[2652]! } - public var EditTheme_Create_Preview_IncomingText: String { return self._s[2653]! } - public var CallSettings_Always: String { return self._s[2654]! } - public var CallFeedback_Success: String { return self._s[2655]! } - public var TwoStepAuth_SetupHint: String { return self._s[2656]! } + public var NetworkUsageSettings_CallDataSection: String { return self._s[2636]! } + public var PasscodeSettings_HelpTop: String { return self._s[2637]! } + public var Conversation_WalletRequiredTitle: String { return self._s[2638]! } + public var Group_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[2639]! } + public var Passport_Address_TypeRentalAgreement: String { return self._s[2640]! } + public var EditTheme_ShortLink: String { return self._s[2641]! } + public var Theme_Colors_ColorWallpaperWarning: String { return self._s[2642]! } + public var ProxyServer_VoiceOver_Active: String { return self._s[2643]! } + public var ReportPeer_ReasonOther_Placeholder: String { return self._s[2644]! } + public var CheckoutInfo_ErrorPhoneInvalid: String { return self._s[2645]! } + public var Call_Accept: String { return self._s[2647]! } + public var GroupRemoved_RemoveInfo: String { return self._s[2648]! } + public var Month_GenMarch: String { return self._s[2650]! } + public var PhotoEditor_ShadowsTool: String { return self._s[2651]! } + public var LoginPassword_Title: String { return self._s[2652]! } + public var Call_End: String { return self._s[2653]! } + public var Watch_Conversation_GroupInfo: String { return self._s[2654]! } + public var VoiceOver_Chat_Contact: String { return self._s[2655]! } + public var EditTheme_Create_Preview_IncomingText: String { return self._s[2656]! } + public var CallSettings_Always: String { return self._s[2657]! } + public var CallFeedback_Success: String { return self._s[2658]! } + public var TwoStepAuth_SetupHint: String { return self._s[2659]! } public func AddContact_ContactWillBeSharedAfterMutual(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2657]!, self._r[2657]!, [_1]) + return formatWithArgumentRanges(self._s[2660]!, self._r[2660]!, [_1]) } - public var ConversationProfile_UsersTooMuchError: String { return self._s[2658]! } - public var Login_PhoneTitle: String { return self._s[2659]! } - public var Passport_FieldPhoneHelp: String { return self._s[2660]! } - public var Weekday_ShortSunday: String { return self._s[2661]! } - public var Passport_InfoFAQ_URL: String { return self._s[2662]! } - public var ContactInfo_Job: String { return self._s[2664]! } - public var UserInfo_InviteBotToGroup: String { return self._s[2665]! } - public var Appearance_ThemeCarouselNightBlue: String { return self._s[2666]! } - public var CreatePoll_QuizTip: String { return self._s[2667]! } - public var TwoFactorSetup_Email_Text: String { return self._s[2668]! } - public var TwoStepAuth_PasswordRemovePassportConfirmation: String { return self._s[2669]! } - public var Invite_ChannelsTooMuch: String { return self._s[2670]! } - public var Wallet_Send_ConfirmationConfirm: String { return self._s[2671]! } - public var Wallet_TransactionInfo_OtherFeeInfo: String { return self._s[2672]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsPreview: String { return self._s[2673]! } - public var Wallet_Receive_AmountText: String { return self._s[2674]! } - public var Passport_DeletePersonalDetailsConfirmation: String { return self._s[2675]! } - public var CallFeedback_ReasonNoise: String { return self._s[2676]! } - public var Appearance_AppIconDefault: String { return self._s[2678]! } - public var Passport_Identity_AddInternalPassport: String { return self._s[2679]! } - public var MediaPicker_AddCaption: String { return self._s[2680]! } - public var CallSettings_TabIconDescription: String { return self._s[2681]! } + public var ConversationProfile_UsersTooMuchError: String { return self._s[2661]! } + public var Login_PhoneTitle: String { return self._s[2662]! } + public var Passport_FieldPhoneHelp: String { return self._s[2663]! } + public var Weekday_ShortSunday: String { return self._s[2664]! } + public var Passport_InfoFAQ_URL: String { return self._s[2665]! } + public var ContactInfo_Job: String { return self._s[2667]! } + public var UserInfo_InviteBotToGroup: String { return self._s[2668]! } + public var Appearance_ThemeCarouselNightBlue: String { return self._s[2669]! } + public var CreatePoll_QuizTip: String { return self._s[2670]! } + public var TwoFactorSetup_Email_Text: String { return self._s[2671]! } + public var TwoStepAuth_PasswordRemovePassportConfirmation: String { return self._s[2672]! } + public var Invite_ChannelsTooMuch: String { return self._s[2673]! } + public var Wallet_Send_ConfirmationConfirm: String { return self._s[2674]! } + public var Wallet_TransactionInfo_OtherFeeInfo: String { return self._s[2675]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsPreview: String { return self._s[2676]! } + public var Wallet_Receive_AmountText: String { return self._s[2677]! } + public var Passport_DeletePersonalDetailsConfirmation: String { return self._s[2678]! } + public var CallFeedback_ReasonNoise: String { return self._s[2679]! } + public var Appearance_AppIconDefault: String { return self._s[2681]! } + public var Passport_Identity_AddInternalPassport: String { return self._s[2682]! } + public var MediaPicker_AddCaption: String { return self._s[2683]! } + public var CallSettings_TabIconDescription: String { return self._s[2684]! } public func VoiceOver_Chat_Caption(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2682]!, self._r[2682]!, [_0]) + return formatWithArgumentRanges(self._s[2685]!, self._r[2685]!, [_0]) } - public var IntentsSettings_SuggestedChatsGroups: String { return self._s[2683]! } + public var IntentsSettings_SuggestedChatsGroups: String { return self._s[2686]! } public func Map_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2684]!, self._r[2684]!, [_0]) + return formatWithArgumentRanges(self._s[2687]!, self._r[2687]!, [_0]) } - public var ChatList_UndoArchiveHiddenTitle: String { return self._s[2685]! } - public var Privacy_GroupsAndChannels_AlwaysAllow: String { return self._s[2686]! } - public var Passport_Identity_TypePersonalDetails: String { return self._s[2687]! } - public var DialogList_SearchSectionRecent: String { return self._s[2688]! } - public var PrivacyPolicy_DeclineMessage: String { return self._s[2689]! } - public var CreatePoll_Anonymous: String { return self._s[2690]! } - public var LogoutOptions_ClearCacheText: String { return self._s[2693]! } - public var LastSeen_WithinAWeek: String { return self._s[2694]! } - public var ChannelMembers_GroupAdminsTitle: String { return self._s[2695]! } - public var Conversation_CloudStorage_ChatStatus: String { return self._s[2697]! } - public var VoiceOver_Media_PlaybackRateNormal: String { return self._s[2698]! } + public var ChatList_UndoArchiveHiddenTitle: String { return self._s[2688]! } + public var Privacy_GroupsAndChannels_AlwaysAllow: String { return self._s[2689]! } + public var Passport_Identity_TypePersonalDetails: String { return self._s[2690]! } + public var DialogList_SearchSectionRecent: String { return self._s[2691]! } + public var PrivacyPolicy_DeclineMessage: String { return self._s[2692]! } + public var CreatePoll_Anonymous: String { return self._s[2693]! } + public var LogoutOptions_ClearCacheText: String { return self._s[2696]! } + public var LastSeen_WithinAWeek: String { return self._s[2697]! } + public var ChannelMembers_GroupAdminsTitle: String { return self._s[2698]! } + public var Conversation_CloudStorage_ChatStatus: String { return self._s[2700]! } + public var VoiceOver_Media_PlaybackRateNormal: String { return self._s[2701]! } public func AddContact_SharedContactExceptionInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2699]!, self._r[2699]!, [_0]) + return formatWithArgumentRanges(self._s[2702]!, self._r[2702]!, [_0]) } - public var Passport_Address_TypeResidentialAddress: String { return self._s[2700]! } - public var Conversation_StatusLeftGroup: String { return self._s[2701]! } - public var SocksProxySetup_ProxyDetailsTitle: String { return self._s[2702]! } - public var SettingsSearch_Synonyms_Calls_Title: String { return self._s[2704]! } - public var GroupPermission_AddSuccess: String { return self._s[2705]! } - public var PhotoEditor_BlurToolRadial: String { return self._s[2707]! } - public var Conversation_ContextMenuCopy: String { return self._s[2708]! } - public var AccessDenied_CallMicrophone: String { return self._s[2709]! } + public var Passport_Address_TypeResidentialAddress: String { return self._s[2703]! } + public var Conversation_StatusLeftGroup: String { return self._s[2704]! } + public var SocksProxySetup_ProxyDetailsTitle: String { return self._s[2705]! } + public var SettingsSearch_Synonyms_Calls_Title: String { return self._s[2707]! } + public var GroupPermission_AddSuccess: String { return self._s[2708]! } + public var PhotoEditor_BlurToolRadial: String { return self._s[2710]! } + public var Conversation_ContextMenuCopy: String { return self._s[2711]! } + public var AccessDenied_CallMicrophone: String { return self._s[2712]! } public func Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2710]!, self._r[2710]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2713]!, self._r[2713]!, [_1, _2, _3]) } - public var Login_InvalidFirstNameError: String { return self._s[2711]! } - public var Notifications_Badge_CountUnreadMessages_InfoOn: String { return self._s[2712]! } - public var Checkout_PaymentMethod_New: String { return self._s[2713]! } - public var ShareMenu_CopyShareLinkGame: String { return self._s[2714]! } - public var PhotoEditor_QualityTool: String { return self._s[2715]! } - public var Login_SendCodeViaSms: String { return self._s[2716]! } - public var SettingsSearch_Synonyms_Privacy_DeleteAccountIfAwayFor: String { return self._s[2717]! } - public var Chat_SlowmodeAttachmentLimitReached: String { return self._s[2718]! } - public var Wallet_Receive_CopyAddress: String { return self._s[2719]! } - public var Login_EmailNotConfiguredError: String { return self._s[2720]! } - public var SocksProxySetup_Status: String { return self._s[2721]! } - public var Conversation_ScheduleMessage_SendWhenOnline: String { return self._s[2722]! } - public var PrivacyPolicy_Accept: String { return self._s[2723]! } - public var Notifications_ExceptionsMessagePlaceholder: String { return self._s[2724]! } - public var Appearance_AppIconClassicX: String { return self._s[2725]! } + public var Login_InvalidFirstNameError: String { return self._s[2714]! } + public var Notifications_Badge_CountUnreadMessages_InfoOn: String { return self._s[2715]! } + public var Checkout_PaymentMethod_New: String { return self._s[2716]! } + public var ShareMenu_CopyShareLinkGame: String { return self._s[2717]! } + public var PhotoEditor_QualityTool: String { return self._s[2718]! } + public var Login_SendCodeViaSms: String { return self._s[2719]! } + public var SettingsSearch_Synonyms_Privacy_DeleteAccountIfAwayFor: String { return self._s[2720]! } + public var Chat_SlowmodeAttachmentLimitReached: String { return self._s[2721]! } + public var Wallet_Receive_CopyAddress: String { return self._s[2722]! } + public var Login_EmailNotConfiguredError: String { return self._s[2723]! } + public var SocksProxySetup_Status: String { return self._s[2724]! } + public var Conversation_ScheduleMessage_SendWhenOnline: String { return self._s[2725]! } + public var PrivacyPolicy_Accept: String { return self._s[2726]! } + public var Notifications_ExceptionsMessagePlaceholder: String { return self._s[2727]! } + public var Appearance_AppIconClassicX: String { return self._s[2728]! } public func PUSH_CHAT_MESSAGE_TEXT(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2726]!, self._r[2726]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2729]!, self._r[2729]!, [_1, _2, _3]) } - public var OwnershipTransfer_SecurityRequirements: String { return self._s[2727]! } - public var InfoPlist_NSLocationAlwaysUsageDescription: String { return self._s[2729]! } - public var AutoNightTheme_Automatic: String { return self._s[2730]! } - public var Channel_Username_InvalidStartsWithNumber: String { return self._s[2731]! } - public var Privacy_ContactsSyncHelp: String { return self._s[2732]! } - public var Cache_Help: String { return self._s[2733]! } - public var Group_ErrorAccessDenied: String { return self._s[2734]! } - public var Passport_Language_fa: String { return self._s[2735]! } - public var Wallet_Intro_Text: String { return self._s[2736]! } - public var Login_ResetAccountProtected_TimerTitle: String { return self._s[2737]! } - public var VoiceOver_Chat_YourVideoMessage: String { return self._s[2738]! } - public var PrivacySettings_LastSeen: String { return self._s[2739]! } + public var OwnershipTransfer_SecurityRequirements: String { return self._s[2730]! } + public var InfoPlist_NSLocationAlwaysUsageDescription: String { return self._s[2732]! } + public var AutoNightTheme_Automatic: String { return self._s[2733]! } + public var Channel_Username_InvalidStartsWithNumber: String { return self._s[2734]! } + public var Privacy_ContactsSyncHelp: String { return self._s[2735]! } + public var Cache_Help: String { return self._s[2736]! } + public var Group_ErrorAccessDenied: String { return self._s[2737]! } + public var Passport_Language_fa: String { return self._s[2738]! } + public var Wallet_Intro_Text: String { return self._s[2739]! } + public var Login_ResetAccountProtected_TimerTitle: String { return self._s[2740]! } + public var VoiceOver_Chat_YourVideoMessage: String { return self._s[2741]! } + public var PrivacySettings_LastSeen: String { return self._s[2742]! } public func DialogList_MultipleTyping(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2740]!, self._r[2740]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2743]!, self._r[2743]!, [_0, _1]) } - public var Wallet_Configuration_Apply: String { return self._s[2744]! } - public var Preview_SaveGif: String { return self._s[2745]! } - public var SettingsSearch_Synonyms_Privacy_TwoStepAuth: String { return self._s[2746]! } - public var Profile_About: String { return self._s[2747]! } - public var Channel_About_Placeholder: String { return self._s[2748]! } - public var Login_InfoTitle: String { return self._s[2749]! } + public var Wallet_Configuration_Apply: String { return self._s[2747]! } + public var Preview_SaveGif: String { return self._s[2748]! } + public var SettingsSearch_Synonyms_Privacy_TwoStepAuth: String { return self._s[2749]! } + public var Profile_About: String { return self._s[2750]! } + public var Channel_About_Placeholder: String { return self._s[2751]! } + public var Login_InfoTitle: String { return self._s[2752]! } public func TwoStepAuth_SetupPendingEmail(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2750]!, self._r[2750]!, [_0]) + return formatWithArgumentRanges(self._s[2753]!, self._r[2753]!, [_0]) } - public var EditTheme_Expand_Preview_IncomingReplyText: String { return self._s[2751]! } - public var Watch_Suggestion_CantTalk: String { return self._s[2753]! } - public var ContactInfo_Title: String { return self._s[2754]! } - public var Media_ShareThisVideo: String { return self._s[2755]! } - public var Weekday_ShortFriday: String { return self._s[2756]! } - public var AccessDenied_Contacts: String { return self._s[2758]! } - public var Notification_CallIncomingShort: String { return self._s[2759]! } - public var Group_Setup_TypePublic: String { return self._s[2760]! } - public var Notifications_MessageNotificationsExceptions: String { return self._s[2761]! } - public var Notifications_Badge_IncludeChannels: String { return self._s[2762]! } - public var Notifications_MessageNotificationsPreview: String { return self._s[2765]! } - public var ConversationProfile_ErrorCreatingConversation: String { return self._s[2766]! } - public var Group_ErrorAddTooMuchBots: String { return self._s[2767]! } - public var Privacy_GroupsAndChannels_CustomShareHelp: String { return self._s[2768]! } - public var Permissions_CellularDataAllowInSettings_v0: String { return self._s[2769]! } + public var EditTheme_Expand_Preview_IncomingReplyText: String { return self._s[2754]! } + public var Watch_Suggestion_CantTalk: String { return self._s[2756]! } + public var ContactInfo_Title: String { return self._s[2757]! } + public var Media_ShareThisVideo: String { return self._s[2758]! } + public var Weekday_ShortFriday: String { return self._s[2759]! } + public var AccessDenied_Contacts: String { return self._s[2761]! } + public var Notification_CallIncomingShort: String { return self._s[2762]! } + public var Group_Setup_TypePublic: String { return self._s[2763]! } + public var Notifications_MessageNotificationsExceptions: String { return self._s[2764]! } + public var Notifications_Badge_IncludeChannels: String { return self._s[2765]! } + public var Notifications_MessageNotificationsPreview: String { return self._s[2768]! } + public var ConversationProfile_ErrorCreatingConversation: String { return self._s[2769]! } + public var Group_ErrorAddTooMuchBots: String { return self._s[2770]! } + public var Privacy_GroupsAndChannels_CustomShareHelp: String { return self._s[2771]! } + public var Permissions_CellularDataAllowInSettings_v0: String { return self._s[2772]! } public func Wallet_SecureStorageChanged_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2770]!, self._r[2770]!, [_0]) + return formatWithArgumentRanges(self._s[2773]!, self._r[2773]!, [_0]) } - public var DialogList_Typing: String { return self._s[2771]! } - public var CallFeedback_IncludeLogs: String { return self._s[2773]! } - public var Checkout_Phone: String { return self._s[2775]! } - public var Login_InfoFirstNamePlaceholder: String { return self._s[2778]! } - public var Privacy_Calls_Integration: String { return self._s[2779]! } - public var Notifications_PermissionsAllow: String { return self._s[2780]! } - public var TwoStepAuth_AddHintDescription: String { return self._s[2784]! } - public var Settings_ChatSettings: String { return self._s[2785]! } - public var Conversation_SendingOptionsTooltip: String { return self._s[2786]! } + public var DialogList_Typing: String { return self._s[2774]! } + public var CallFeedback_IncludeLogs: String { return self._s[2776]! } + public var Checkout_Phone: String { return self._s[2778]! } + public var Login_InfoFirstNamePlaceholder: String { return self._s[2781]! } + public var Privacy_Calls_Integration: String { return self._s[2782]! } + public var Notifications_PermissionsAllow: String { return self._s[2783]! } + public var TwoStepAuth_AddHintDescription: String { return self._s[2787]! } + public var Settings_ChatSettings: String { return self._s[2788]! } + public var Conversation_SendingOptionsTooltip: String { return self._s[2789]! } public func UserInfo_StartSecretChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2788]!, self._r[2788]!, [_0]) + return formatWithArgumentRanges(self._s[2791]!, self._r[2791]!, [_0]) } public func Channel_AdminLog_MessageInvitedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2789]!, self._r[2789]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2792]!, self._r[2792]!, [_1, _2]) } - public var GroupRemoved_DeleteUser: String { return self._s[2791]! } + public var GroupRemoved_DeleteUser: String { return self._s[2794]! } public func Channel_AdminLog_PollStopped(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2792]!, self._r[2792]!, [_0]) + return formatWithArgumentRanges(self._s[2795]!, self._r[2795]!, [_0]) } public func PUSH_MESSAGE_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2793]!, self._r[2793]!, [_1]) + return formatWithArgumentRanges(self._s[2796]!, self._r[2796]!, [_1]) } - public var Login_ContinueWithLocalization: String { return self._s[2794]! } - public var Watch_Message_ForwardedFrom: String { return self._s[2795]! } - public var TwoStepAuth_EnterEmailCode: String { return self._s[2797]! } - public var Conversation_Unblock: String { return self._s[2798]! } - public var PrivacySettings_DataSettings: String { return self._s[2799]! } - public var WallpaperPreview_PatternPaternApply: String { return self._s[2800]! } - public var Group_PublicLink_Info: String { return self._s[2801]! } + public var Login_ContinueWithLocalization: String { return self._s[2797]! } + public var Watch_Message_ForwardedFrom: String { return self._s[2798]! } + public var TwoStepAuth_EnterEmailCode: String { return self._s[2800]! } + public var Conversation_Unblock: String { return self._s[2801]! } + public var PrivacySettings_DataSettings: String { return self._s[2802]! } + public var WallpaperPreview_PatternPaternApply: String { return self._s[2803]! } + public var Group_PublicLink_Info: String { return self._s[2804]! } public func Wallet_Time_PreciseDate_m1(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2802]!, self._r[2802]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2805]!, self._r[2805]!, [_1, _2, _3]) } - public var Notifications_InAppNotificationsVibrate: String { return self._s[2803]! } + public var Notifications_InAppNotificationsVibrate: String { return self._s[2806]! } public func Privacy_GroupsAndChannels_InviteToChannelError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2804]!, self._r[2804]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2807]!, self._r[2807]!, [_0, _1]) } - public var OldChannels_ChannelsHeader: String { return self._s[2806]! } - public var Wallet_RestoreFailed_CreateWallet: String { return self._s[2807]! } - public var PrivacySettings_Passcode: String { return self._s[2809]! } - public var Call_Mute: String { return self._s[2810]! } - public var Wallet_Weekday_Yesterday: String { return self._s[2811]! } - public var Passport_Language_dz: String { return self._s[2812]! } - public var Wallet_Receive_AmountHeader: String { return self._s[2813]! } - public var Wallet_TransactionInfo_OtherFeeInfoUrl: String { return self._s[2814]! } - public var Passport_Language_tk: String { return self._s[2815]! } + public var OldChannels_ChannelsHeader: String { return self._s[2809]! } + public var Wallet_RestoreFailed_CreateWallet: String { return self._s[2810]! } + public var PrivacySettings_Passcode: String { return self._s[2812]! } + public var Call_Mute: String { return self._s[2813]! } + public var Wallet_Weekday_Yesterday: String { return self._s[2814]! } + public var Passport_Language_dz: String { return self._s[2815]! } + public var Wallet_Receive_AmountHeader: String { return self._s[2816]! } + public var Wallet_TransactionInfo_OtherFeeInfoUrl: String { return self._s[2817]! } + public var Passport_Language_tk: String { return self._s[2818]! } public func Login_EmailCodeSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2816]!, self._r[2816]!, [_0]) + return formatWithArgumentRanges(self._s[2819]!, self._r[2819]!, [_0]) } - public var Settings_Search: String { return self._s[2817]! } - public var Wallet_Month_ShortFebruary: String { return self._s[2818]! } - public var InfoPlist_NSPhotoLibraryUsageDescription: String { return self._s[2819]! } - public var Wallet_Configuration_SourceJSON: String { return self._s[2820]! } - public var Conversation_ContextMenuReply: String { return self._s[2821]! } - public var WallpaperSearch_ColorBrown: String { return self._s[2822]! } - public var Chat_AttachmentMultipleForwardDisabled: String { return self._s[2823]! } - public var Tour_Title1: String { return self._s[2824]! } - public var Wallet_Alert_Cancel: String { return self._s[2825]! } - public var Conversation_ClearGroupHistory: String { return self._s[2827]! } - public var Wallet_TransactionInfo_RecipientHeader: String { return self._s[2828]! } - public var WallpaperPreview_Motion: String { return self._s[2829]! } + public var Settings_Search: String { return self._s[2820]! } + public var Wallet_Month_ShortFebruary: String { return self._s[2821]! } + public var InfoPlist_NSPhotoLibraryUsageDescription: String { return self._s[2822]! } + public var Wallet_Configuration_SourceJSON: String { return self._s[2823]! } + public var Conversation_ContextMenuReply: String { return self._s[2824]! } + public var WallpaperSearch_ColorBrown: String { return self._s[2825]! } + public var Chat_AttachmentMultipleForwardDisabled: String { return self._s[2826]! } + public var Tour_Title1: String { return self._s[2827]! } + public var Wallet_Alert_Cancel: String { return self._s[2828]! } + public var Conversation_ClearGroupHistory: String { return self._s[2830]! } + public var Wallet_TransactionInfo_RecipientHeader: String { return self._s[2831]! } + public var WallpaperPreview_Motion: String { return self._s[2832]! } public func Checkout_PasswordEntry_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2830]!, self._r[2830]!, [_0]) + return formatWithArgumentRanges(self._s[2833]!, self._r[2833]!, [_0]) } - public var Wallet_Configuration_ApplyErrorTextJSONInvalidData: String { return self._s[2831]! } - public var Call_RateCall: String { return self._s[2832]! } - public var Channel_AdminLog_BanSendStickersAndGifs: String { return self._s[2833]! } - public var Passport_PasswordCompleteSetup: String { return self._s[2834]! } - public var Conversation_InputTextSilentBroadcastPlaceholder: String { return self._s[2835]! } - public var UserInfo_LastNamePlaceholder: String { return self._s[2837]! } + public var Wallet_Configuration_ApplyErrorTextJSONInvalidData: String { return self._s[2834]! } + public var Call_RateCall: String { return self._s[2835]! } + public var Channel_AdminLog_BanSendStickersAndGifs: String { return self._s[2836]! } + public var Passport_PasswordCompleteSetup: String { return self._s[2837]! } + public var Conversation_InputTextSilentBroadcastPlaceholder: String { return self._s[2838]! } + public var UserInfo_LastNamePlaceholder: String { return self._s[2840]! } public func Login_WillCallYou(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2839]!, self._r[2839]!, [_0]) + return formatWithArgumentRanges(self._s[2842]!, self._r[2842]!, [_0]) } - public var Compose_Create: String { return self._s[2840]! } - public var Contacts_InviteToTelegram: String { return self._s[2841]! } - public var GroupInfo_Notifications: String { return self._s[2842]! } - public var ChatList_DeleteSavedMessagesConfirmationAction: String { return self._s[2844]! } - public var Message_PinnedLiveLocationMessage: String { return self._s[2845]! } - public var Month_GenApril: String { return self._s[2846]! } - public var Appearance_AutoNightTheme: String { return self._s[2847]! } - public var ChatSettings_AutomaticAudioDownload: String { return self._s[2849]! } - public var Login_CodeSentSms: String { return self._s[2851]! } + public var Compose_Create: String { return self._s[2843]! } + public var Contacts_InviteToTelegram: String { return self._s[2844]! } + public var GroupInfo_Notifications: String { return self._s[2845]! } + public var ChatList_DeleteSavedMessagesConfirmationAction: String { return self._s[2847]! } + public var Message_PinnedLiveLocationMessage: String { return self._s[2848]! } + public var Month_GenApril: String { return self._s[2849]! } + public var Appearance_AutoNightTheme: String { return self._s[2850]! } + public var ChatSettings_AutomaticAudioDownload: String { return self._s[2852]! } + public var Login_CodeSentSms: String { return self._s[2854]! } public func UserInfo_UnblockConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2852]!, self._r[2852]!, [_0]) + return formatWithArgumentRanges(self._s[2855]!, self._r[2855]!, [_0]) } - public var EmptyGroupInfo_Line3: String { return self._s[2853]! } - public var LogoutOptions_ContactSupportText: String { return self._s[2854]! } - public var Passport_Language_hr: String { return self._s[2855]! } - public var Common_ActionNotAllowedError: String { return self._s[2856]! } + public var EmptyGroupInfo_Line3: String { return self._s[2856]! } + public var LogoutOptions_ContactSupportText: String { return self._s[2857]! } + public var Passport_Language_hr: String { return self._s[2858]! } + public var Common_ActionNotAllowedError: String { return self._s[2859]! } public func Channel_AdminLog_MessageRestrictedNewSetting(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2857]!, self._r[2857]!, [_0]) + return formatWithArgumentRanges(self._s[2860]!, self._r[2860]!, [_0]) } - public var GroupInfo_InviteLink_CopyLink: String { return self._s[2858]! } - public var Wallet_Info_TransactionFrom: String { return self._s[2859]! } - public var Wallet_Send_ErrorDecryptionFailed: String { return self._s[2860]! } - public var Conversation_InputTextBroadcastPlaceholder: String { return self._s[2861]! } - public var Privacy_SecretChatsTitle: String { return self._s[2862]! } - public var Notification_SecretChatMessageScreenshotSelf: String { return self._s[2864]! } - public var GroupInfo_AddUserLeftError: String { return self._s[2865]! } - public var AutoDownloadSettings_TypePrivateChats: String { return self._s[2866]! } - public var LogoutOptions_ContactSupportTitle: String { return self._s[2867]! } - public var Appearance_ThemePreview_Chat_7_Text: String { return self._s[2868]! } - public var Channel_AddBotErrorHaveRights: String { return self._s[2869]! } - public var Preview_DeleteGif: String { return self._s[2870]! } - public var GroupInfo_Permissions_Exceptions: String { return self._s[2871]! } - public var Group_ErrorNotMutualContact: String { return self._s[2872]! } - public var Notification_MessageLifetime5s: String { return self._s[2873]! } - public var Wallet_Send_OwnAddressAlertText: String { return self._s[2874]! } - public var OldChannels_ChannelFormat: String { return self._s[2875]! } + public var GroupInfo_InviteLink_CopyLink: String { return self._s[2861]! } + public var Wallet_Info_TransactionFrom: String { return self._s[2862]! } + public var Wallet_Send_ErrorDecryptionFailed: String { return self._s[2863]! } + public var Conversation_InputTextBroadcastPlaceholder: String { return self._s[2864]! } + public var Privacy_SecretChatsTitle: String { return self._s[2865]! } + public var Notification_SecretChatMessageScreenshotSelf: String { return self._s[2867]! } + public var GroupInfo_AddUserLeftError: String { return self._s[2868]! } + public var AutoDownloadSettings_TypePrivateChats: String { return self._s[2869]! } + public var LogoutOptions_ContactSupportTitle: String { return self._s[2870]! } + public var Appearance_ThemePreview_Chat_7_Text: String { return self._s[2871]! } + public var Channel_AddBotErrorHaveRights: String { return self._s[2872]! } + public var Preview_DeleteGif: String { return self._s[2873]! } + public var GroupInfo_Permissions_Exceptions: String { return self._s[2874]! } + public var Group_ErrorNotMutualContact: String { return self._s[2875]! } + public var Notification_MessageLifetime5s: String { return self._s[2876]! } + public var Wallet_Send_OwnAddressAlertText: String { return self._s[2877]! } + public var OldChannels_ChannelFormat: String { return self._s[2878]! } public func Watch_LastSeen_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2876]!, self._r[2876]!, [_0]) + return formatWithArgumentRanges(self._s[2879]!, self._r[2879]!, [_0]) } - public var VoiceOver_Chat_Video: String { return self._s[2877]! } - public var Channel_OwnershipTransfer_ErrorPublicChannelsTooMuch: String { return self._s[2879]! } - public var ReportSpam_DeleteThisChat: String { return self._s[2880]! } - public var Passport_Address_AddBankStatement: String { return self._s[2881]! } - public var Notification_CallIncoming: String { return self._s[2882]! } - public var Wallet_Words_NotDoneTitle: String { return self._s[2883]! } - public var Compose_NewGroupTitle: String { return self._s[2884]! } - public var TwoStepAuth_RecoveryCodeHelp: String { return self._s[2886]! } - public var Passport_Address_Postcode: String { return self._s[2888]! } + public var VoiceOver_Chat_Video: String { return self._s[2880]! } + public var Channel_OwnershipTransfer_ErrorPublicChannelsTooMuch: String { return self._s[2882]! } + public var ReportSpam_DeleteThisChat: String { return self._s[2883]! } + public var Passport_Address_AddBankStatement: String { return self._s[2884]! } + public var Notification_CallIncoming: String { return self._s[2885]! } + public var Wallet_Words_NotDoneTitle: String { return self._s[2886]! } + public var Compose_NewGroupTitle: String { return self._s[2887]! } + public var TwoStepAuth_RecoveryCodeHelp: String { return self._s[2889]! } + public var Passport_Address_Postcode: String { return self._s[2891]! } public func LastSeen_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2889]!, self._r[2889]!, [_0]) + return formatWithArgumentRanges(self._s[2892]!, self._r[2892]!, [_0]) } - public var Checkout_NewCard_SaveInfoHelp: String { return self._s[2890]! } - public var Wallet_Month_ShortOctober: String { return self._s[2891]! } - public var VoiceOver_Chat_YourMusic: String { return self._s[2892]! } - public var WallpaperColors_Title: String { return self._s[2893]! } - public var SocksProxySetup_ShareQRCodeInfo: String { return self._s[2894]! } - public var VoiceOver_MessageContextForward: String { return self._s[2895]! } - public var GroupPermission_Duration: String { return self._s[2896]! } + public var Checkout_NewCard_SaveInfoHelp: String { return self._s[2893]! } + public var Wallet_Month_ShortOctober: String { return self._s[2894]! } + public var VoiceOver_Chat_YourMusic: String { return self._s[2895]! } + public var WallpaperColors_Title: String { return self._s[2896]! } + public var SocksProxySetup_ShareQRCodeInfo: String { return self._s[2897]! } + public var VoiceOver_MessageContextForward: String { return self._s[2898]! } + public var GroupPermission_Duration: String { return self._s[2899]! } public func Cache_Clear(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2897]!, self._r[2897]!, [_0]) + return formatWithArgumentRanges(self._s[2900]!, self._r[2900]!, [_0]) } - public var Bot_GroupStatusDoesNotReadHistory: String { return self._s[2898]! } - public var Username_Placeholder: String { return self._s[2899]! } - public var CallFeedback_WhatWentWrong: String { return self._s[2900]! } - public var Passport_FieldAddressUploadHelp: String { return self._s[2901]! } - public var Permissions_NotificationsAllowInSettings_v0: String { return self._s[2902]! } + public var Bot_GroupStatusDoesNotReadHistory: String { return self._s[2901]! } + public var Username_Placeholder: String { return self._s[2902]! } + public var CallFeedback_WhatWentWrong: String { return self._s[2903]! } + public var Passport_FieldAddressUploadHelp: String { return self._s[2904]! } + public var Permissions_NotificationsAllowInSettings_v0: String { return self._s[2905]! } public func Channel_AdminLog_MessageChangedUnlinkedChannel(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2904]!, self._r[2904]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2907]!, self._r[2907]!, [_1, _2]) } - public var Passport_PasswordDescription: String { return self._s[2905]! } - public var Channel_MessagePhotoUpdated: String { return self._s[2906]! } - public var MediaPicker_TapToUngroupDescription: String { return self._s[2907]! } - public var SettingsSearch_Synonyms_Notifications_BadgeCountUnreadMessages: String { return self._s[2908]! } - public var AttachmentMenu_PhotoOrVideo: String { return self._s[2909]! } - public var Conversation_ContextMenuMore: String { return self._s[2910]! } - public var Privacy_PaymentsClearInfo: String { return self._s[2911]! } - public var CallSettings_TabIcon: String { return self._s[2912]! } - public var KeyCommand_Find: String { return self._s[2913]! } - public var ClearCache_FreeSpaceDescription: String { return self._s[2914]! } - public var Appearance_ThemePreview_ChatList_7_Text: String { return self._s[2915]! } - public var EditTheme_Edit_Preview_IncomingText: String { return self._s[2916]! } - public var Message_PinnedGame: String { return self._s[2917]! } - public var VoiceOver_Chat_ForwardedFromYou: String { return self._s[2918]! } - public var Notifications_Badge_CountUnreadMessages_InfoOff: String { return self._s[2920]! } - public var Login_CallRequestState2: String { return self._s[2922]! } - public var CheckoutInfo_ReceiverInfoNamePlaceholder: String { return self._s[2924]! } + public var Passport_PasswordDescription: String { return self._s[2908]! } + public var Channel_MessagePhotoUpdated: String { return self._s[2909]! } + public var MediaPicker_TapToUngroupDescription: String { return self._s[2910]! } + public var SettingsSearch_Synonyms_Notifications_BadgeCountUnreadMessages: String { return self._s[2911]! } + public var AttachmentMenu_PhotoOrVideo: String { return self._s[2912]! } + public var Conversation_ContextMenuMore: String { return self._s[2913]! } + public var Privacy_PaymentsClearInfo: String { return self._s[2914]! } + public var CallSettings_TabIcon: String { return self._s[2915]! } + public var KeyCommand_Find: String { return self._s[2916]! } + public var ClearCache_FreeSpaceDescription: String { return self._s[2917]! } + public var Appearance_ThemePreview_ChatList_7_Text: String { return self._s[2918]! } + public var EditTheme_Edit_Preview_IncomingText: String { return self._s[2919]! } + public var Message_PinnedGame: String { return self._s[2920]! } + public var VoiceOver_Chat_ForwardedFromYou: String { return self._s[2921]! } + public var Notifications_Badge_CountUnreadMessages_InfoOff: String { return self._s[2923]! } + public var Login_CallRequestState2: String { return self._s[2925]! } + public var CheckoutInfo_ReceiverInfoNamePlaceholder: String { return self._s[2927]! } public func VoiceOver_Chat_PhotoFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2925]!, self._r[2925]!, [_0]) + return formatWithArgumentRanges(self._s[2928]!, self._r[2928]!, [_0]) } public func Checkout_PayPrice(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2927]!, self._r[2927]!, [_0]) + return formatWithArgumentRanges(self._s[2930]!, self._r[2930]!, [_0]) } - public var AuthSessions_AddDevice: String { return self._s[2928]! } - public var WallpaperPreview_Blurred: String { return self._s[2929]! } - public var Conversation_InstantPagePreview: String { return self._s[2930]! } + public var AuthSessions_AddDevice: String { return self._s[2931]! } + public var WallpaperPreview_Blurred: String { return self._s[2932]! } + public var Conversation_InstantPagePreview: String { return self._s[2933]! } public func DialogList_SingleUploadingVideoSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2931]!, self._r[2931]!, [_0]) + return formatWithArgumentRanges(self._s[2934]!, self._r[2934]!, [_0]) } - public var SecretTimer_VideoDescription: String { return self._s[2934]! } - public var WallpaperSearch_ColorRed: String { return self._s[2935]! } - public var GroupPermission_NoPinMessages: String { return self._s[2936]! } - public var Passport_Language_es: String { return self._s[2937]! } - public var Permissions_ContactsAllow_v0: String { return self._s[2939]! } - public var Conversation_EditingMessageMediaEditCurrentVideo: String { return self._s[2940]! } + public var SecretTimer_VideoDescription: String { return self._s[2937]! } + public var WallpaperSearch_ColorRed: String { return self._s[2938]! } + public var GroupPermission_NoPinMessages: String { return self._s[2939]! } + public var Passport_Language_es: String { return self._s[2940]! } + public var Permissions_ContactsAllow_v0: String { return self._s[2942]! } + public var Conversation_EditingMessageMediaEditCurrentVideo: String { return self._s[2943]! } public func PUSH_CHAT_MESSAGE_CONTACT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2941]!, self._r[2941]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2944]!, self._r[2944]!, [_1, _2]) } - public var Privacy_Forwards_CustomHelp: String { return self._s[2942]! } - public var WebPreview_GettingLinkInfo: String { return self._s[2943]! } - public var Watch_UserInfo_Unmute: String { return self._s[2944]! } - public var GroupInfo_ChannelListNamePlaceholder: String { return self._s[2945]! } - public var AccessDenied_CameraRestricted: String { return self._s[2947]! } + public var Privacy_Forwards_CustomHelp: String { return self._s[2945]! } + public var WebPreview_GettingLinkInfo: String { return self._s[2946]! } + public var Watch_UserInfo_Unmute: String { return self._s[2947]! } + public var GroupInfo_ChannelListNamePlaceholder: String { return self._s[2948]! } + public var AccessDenied_CameraRestricted: String { return self._s[2950]! } public func Conversation_Kilobytes(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2948]!, self._r[2948]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[2951]!, self._r[2951]!, ["\(_0)"]) } - public var ChatList_ReadAll: String { return self._s[2950]! } - public var Settings_CopyUsername: String { return self._s[2951]! } - public var Contacts_SearchLabel: String { return self._s[2952]! } - public var Map_OpenInYandexNavigator: String { return self._s[2954]! } - public var PasscodeSettings_EncryptData: String { return self._s[2955]! } - public var Settings_Wallet: String { return self._s[2956]! } - public var Group_ErrorSupergroupConversionNotPossible: String { return self._s[2957]! } - public var WallpaperSearch_ColorPrefix: String { return self._s[2958]! } - public var Notifications_GroupNotificationsPreview: String { return self._s[2959]! } - public var DialogList_AdNoticeAlert: String { return self._s[2960]! } - public var Wallet_Month_GenMay: String { return self._s[2962]! } - public var CheckoutInfo_ShippingInfoAddress1: String { return self._s[2963]! } - public var CheckoutInfo_ShippingInfoAddress2: String { return self._s[2964]! } - public var Localization_LanguageCustom: String { return self._s[2965]! } - public var Passport_Identity_TypeDriversLicenseUploadScan: String { return self._s[2966]! } - public var CallFeedback_Title: String { return self._s[2967]! } - public var VoiceOver_Chat_RecordPreviewVoiceMessage: String { return self._s[2970]! } - public var Passport_Address_OneOfTypePassportRegistration: String { return self._s[2971]! } - public var Wallet_Intro_CreateErrorTitle: String { return self._s[2972]! } - public var Conversation_InfoGroup: String { return self._s[2973]! } - public var Compose_NewMessage: String { return self._s[2974]! } - public var FastTwoStepSetup_HintPlaceholder: String { return self._s[2975]! } - public var ChatSettings_AutoDownloadVideoMessages: String { return self._s[2976]! } - public var Wallet_SecureStorageReset_BiometryFaceId: String { return self._s[2977]! } - public var Channel_DiscussionGroup_UnlinkChannel: String { return self._s[2978]! } + public var ChatList_ReadAll: String { return self._s[2953]! } + public var Settings_CopyUsername: String { return self._s[2954]! } + public var Contacts_SearchLabel: String { return self._s[2955]! } + public var Map_OpenInYandexNavigator: String { return self._s[2957]! } + public var PasscodeSettings_EncryptData: String { return self._s[2958]! } + public var Settings_Wallet: String { return self._s[2959]! } + public var Group_ErrorSupergroupConversionNotPossible: String { return self._s[2960]! } + public var WallpaperSearch_ColorPrefix: String { return self._s[2961]! } + public var Notifications_GroupNotificationsPreview: String { return self._s[2962]! } + public var DialogList_AdNoticeAlert: String { return self._s[2963]! } + public var Wallet_Month_GenMay: String { return self._s[2965]! } + public var CheckoutInfo_ShippingInfoAddress1: String { return self._s[2966]! } + public var CheckoutInfo_ShippingInfoAddress2: String { return self._s[2967]! } + public var Localization_LanguageCustom: String { return self._s[2968]! } + public var Passport_Identity_TypeDriversLicenseUploadScan: String { return self._s[2969]! } + public var CallFeedback_Title: String { return self._s[2970]! } + public var VoiceOver_Chat_RecordPreviewVoiceMessage: String { return self._s[2973]! } + public var Passport_Address_OneOfTypePassportRegistration: String { return self._s[2974]! } + public var Wallet_Intro_CreateErrorTitle: String { return self._s[2975]! } + public var Conversation_InfoGroup: String { return self._s[2976]! } + public var Compose_NewMessage: String { return self._s[2977]! } + public var FastTwoStepSetup_HintPlaceholder: String { return self._s[2978]! } + public var ChatSettings_AutoDownloadVideoMessages: String { return self._s[2979]! } + public var Wallet_SecureStorageReset_BiometryFaceId: String { return self._s[2980]! } + public var Channel_DiscussionGroup_UnlinkChannel: String { return self._s[2981]! } public func Passport_Scans_ScanIndex(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2979]!, self._r[2979]!, [_0]) + return formatWithArgumentRanges(self._s[2982]!, self._r[2982]!, [_0]) } - public var Channel_AdminLog_CanDeleteMessages: String { return self._s[2980]! } - public var Login_CancelSignUpConfirmation: String { return self._s[2981]! } - public var ChangePhoneNumberCode_Help: String { return self._s[2982]! } - public var PrivacySettings_DeleteAccountHelp: String { return self._s[2983]! } - public var Channel_BlackList_Title: String { return self._s[2984]! } - public var UserInfo_PhoneCall: String { return self._s[2985]! } - public var Passport_Address_OneOfTypeBankStatement: String { return self._s[2987]! } - public var Wallet_Month_ShortJanuary: String { return self._s[2988]! } - public var State_connecting: String { return self._s[2989]! } - public var Appearance_ThemePreview_ChatList_6_Text: String { return self._s[2990]! } - public var Wallet_Month_GenMarch: String { return self._s[2991]! } - public var EditTheme_Expand_BottomInfo: String { return self._s[2992]! } - public var AuthSessions_AddedDeviceTerminate: String { return self._s[2993]! } + public var Channel_AdminLog_CanDeleteMessages: String { return self._s[2983]! } + public var Login_CancelSignUpConfirmation: String { return self._s[2984]! } + public var ChangePhoneNumberCode_Help: String { return self._s[2985]! } + public var PrivacySettings_DeleteAccountHelp: String { return self._s[2986]! } + public var Channel_BlackList_Title: String { return self._s[2987]! } + public var UserInfo_PhoneCall: String { return self._s[2988]! } + public var Passport_Address_OneOfTypeBankStatement: String { return self._s[2990]! } + public var Wallet_Month_ShortJanuary: String { return self._s[2991]! } + public var State_connecting: String { return self._s[2992]! } + public var Appearance_ThemePreview_ChatList_6_Text: String { return self._s[2993]! } + public var Wallet_Month_GenMarch: String { return self._s[2994]! } + public var EditTheme_Expand_BottomInfo: String { return self._s[2995]! } + public var AuthSessions_AddedDeviceTerminate: String { return self._s[2996]! } public func LastSeen_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2994]!, self._r[2994]!, [_0]) + return formatWithArgumentRanges(self._s[2997]!, self._r[2997]!, [_0]) } public func DialogList_SingleRecordingAudioSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2995]!, self._r[2995]!, [_0]) + return formatWithArgumentRanges(self._s[2998]!, self._r[2998]!, [_0]) } - public var Notifications_GroupNotifications: String { return self._s[2996]! } - public var Conversation_SendMessageErrorTooMuchScheduled: String { return self._s[2997]! } - public var Passport_Identity_EditPassport: String { return self._s[2998]! } - public var EnterPasscode_RepeatNewPasscode: String { return self._s[3000]! } - public var Localization_EnglishLanguageName: String { return self._s[3001]! } - public var Share_AuthDescription: String { return self._s[3002]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsAlert: String { return self._s[3003]! } - public var Passport_Identity_Surname: String { return self._s[3004]! } - public var Compose_TokenListPlaceholder: String { return self._s[3005]! } - public var Wallet_AccessDenied_Camera: String { return self._s[3006]! } - public var Passport_Identity_OneOfTypePassport: String { return self._s[3007]! } - public var Settings_AboutEmpty: String { return self._s[3008]! } - public var Conversation_Unmute: String { return self._s[3009]! } - public var CreateGroup_ChannelsTooMuch: String { return self._s[3011]! } - public var Wallet_Sending_Text: String { return self._s[3012]! } + public var Notifications_GroupNotifications: String { return self._s[2999]! } + public var Conversation_SendMessageErrorTooMuchScheduled: String { return self._s[3000]! } + public var Passport_Identity_EditPassport: String { return self._s[3001]! } + public var EnterPasscode_RepeatNewPasscode: String { return self._s[3003]! } + public var Localization_EnglishLanguageName: String { return self._s[3004]! } + public var Share_AuthDescription: String { return self._s[3005]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsAlert: String { return self._s[3006]! } + public var Passport_Identity_Surname: String { return self._s[3007]! } + public var Compose_TokenListPlaceholder: String { return self._s[3008]! } + public var Wallet_AccessDenied_Camera: String { return self._s[3009]! } + public var Passport_Identity_OneOfTypePassport: String { return self._s[3010]! } + public var Settings_AboutEmpty: String { return self._s[3011]! } + public var Conversation_Unmute: String { return self._s[3012]! } + public var CreateGroup_ChannelsTooMuch: String { return self._s[3014]! } + public var Wallet_Sending_Text: String { return self._s[3015]! } public func PUSH_CONTACT_JOINED(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3013]!, self._r[3013]!, [_1]) + return formatWithArgumentRanges(self._s[3016]!, self._r[3016]!, [_1]) } - public var Login_CodeSentCall: String { return self._s[3014]! } - public var ContactInfo_PhoneLabelHomeFax: String { return self._s[3016]! } - public var ChatSettings_Appearance: String { return self._s[3017]! } - public var ClearCache_StorageUsage: String { return self._s[3018]! } - public var Appearance_PickAccentColor: String { return self._s[3019]! } + public var Login_CodeSentCall: String { return self._s[3017]! } + public var ContactInfo_PhoneLabelHomeFax: String { return self._s[3019]! } + public var ChatSettings_Appearance: String { return self._s[3020]! } + public var ClearCache_StorageUsage: String { return self._s[3021]! } + public var Appearance_PickAccentColor: String { return self._s[3022]! } public func PUSH_CHAT_MESSAGE_NOTEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3020]!, self._r[3020]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3023]!, self._r[3023]!, [_1, _2]) } public func PUSH_MESSAGE_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3021]!, self._r[3021]!, [_1]) + return formatWithArgumentRanges(self._s[3024]!, self._r[3024]!, [_1]) } - public var Notification_CallMissed: String { return self._s[3022]! } - public var SettingsSearch_Synonyms_Appearance_ChatBackground_Custom: String { return self._s[3023]! } - public var Channel_AdminLogFilter_EventsInfo: String { return self._s[3024]! } - public var Wallet_Month_GenOctober: String { return self._s[3026]! } - public var ChatAdmins_AdminLabel: String { return self._s[3027]! } - public var KeyCommand_JumpToNextChat: String { return self._s[3028]! } - public var Conversation_StopPollConfirmationTitle: String { return self._s[3030]! } - public var ChangePhoneNumberCode_CodePlaceholder: String { return self._s[3031]! } - public var Month_GenJune: String { return self._s[3032]! } - public var IntentsSettings_MainAccountInfo: String { return self._s[3033]! } - public var Watch_Location_Current: String { return self._s[3034]! } - public var Wallet_Receive_CopyInvoiceUrl: String { return self._s[3035]! } - public var Conversation_TitleMute: String { return self._s[3036]! } - public var Map_PlacesInThisArea: String { return self._s[3037]! } + public var Notification_CallMissed: String { return self._s[3025]! } + public var SettingsSearch_Synonyms_Appearance_ChatBackground_Custom: String { return self._s[3026]! } + public var Channel_AdminLogFilter_EventsInfo: String { return self._s[3027]! } + public var Wallet_Month_GenOctober: String { return self._s[3029]! } + public var ChatAdmins_AdminLabel: String { return self._s[3030]! } + public var KeyCommand_JumpToNextChat: String { return self._s[3031]! } + public var Conversation_StopPollConfirmationTitle: String { return self._s[3033]! } + public var ChangePhoneNumberCode_CodePlaceholder: String { return self._s[3034]! } + public var Month_GenJune: String { return self._s[3035]! } + public var IntentsSettings_MainAccountInfo: String { return self._s[3036]! } + public var Watch_Location_Current: String { return self._s[3037]! } + public var Wallet_Receive_CopyInvoiceUrl: String { return self._s[3038]! } + public var Conversation_TitleMute: String { return self._s[3039]! } + public var Map_PlacesInThisArea: String { return self._s[3040]! } public func PUSH_CHANNEL_MESSAGE_ROUND(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3038]!, self._r[3038]!, [_1]) + return formatWithArgumentRanges(self._s[3041]!, self._r[3041]!, [_1]) } - public var GroupInfo_DeleteAndExit: String { return self._s[3039]! } + public var GroupInfo_DeleteAndExit: String { return self._s[3042]! } public func Conversation_Moderate_DeleteAllMessages(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3040]!, self._r[3040]!, [_0]) + return formatWithArgumentRanges(self._s[3043]!, self._r[3043]!, [_0]) } - public var Call_ReportPlaceholder: String { return self._s[3041]! } - public var Chat_SlowmodeSendError: String { return self._s[3042]! } - public var MaskStickerSettings_Info: String { return self._s[3043]! } - public var EditTheme_Expand_TopInfo: String { return self._s[3044]! } + public var Call_ReportPlaceholder: String { return self._s[3044]! } + public var Chat_SlowmodeSendError: String { return self._s[3045]! } + public var MaskStickerSettings_Info: String { return self._s[3046]! } + public var EditTheme_Expand_TopInfo: String { return self._s[3047]! } public func GroupInfo_AddParticipantConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3045]!, self._r[3045]!, [_0]) + return formatWithArgumentRanges(self._s[3048]!, self._r[3048]!, [_0]) } - public var Checkout_NewCard_PostcodeTitle: String { return self._s[3046]! } - public var Passport_Address_RegionPlaceholder: String { return self._s[3048]! } - public var Contacts_ShareTelegram: String { return self._s[3049]! } - public var EnterPasscode_EnterNewPasscodeNew: String { return self._s[3050]! } - public var Map_AddressOnMap: String { return self._s[3051]! } - public var Channel_ErrorAccessDenied: String { return self._s[3052]! } - public var UserInfo_ScamBotWarning: String { return self._s[3054]! } - public var Stickers_GroupChooseStickerPack: String { return self._s[3055]! } - public var Call_ConnectionErrorTitle: String { return self._s[3056]! } - public var UserInfo_NotificationsEnable: String { return self._s[3057]! } - public var ArchivedChats_IntroText1: String { return self._s[3058]! } - public var Tour_Text4: String { return self._s[3061]! } - public var WallpaperSearch_Recent: String { return self._s[3062]! } - public var GroupInfo_ScamGroupWarning: String { return self._s[3063]! } - public var Profile_MessageLifetime2s: String { return self._s[3065]! } - public var Appearance_ThemePreview_ChatList_5_Text: String { return self._s[3066]! } - public var Notification_MessageLifetime2s: String { return self._s[3067]! } + public var Checkout_NewCard_PostcodeTitle: String { return self._s[3049]! } + public var Passport_Address_RegionPlaceholder: String { return self._s[3051]! } + public var Contacts_ShareTelegram: String { return self._s[3052]! } + public var EnterPasscode_EnterNewPasscodeNew: String { return self._s[3053]! } + public var Map_AddressOnMap: String { return self._s[3054]! } + public var Channel_ErrorAccessDenied: String { return self._s[3055]! } + public var UserInfo_ScamBotWarning: String { return self._s[3057]! } + public var Stickers_GroupChooseStickerPack: String { return self._s[3058]! } + public var Call_ConnectionErrorTitle: String { return self._s[3059]! } + public var UserInfo_NotificationsEnable: String { return self._s[3060]! } + public var ArchivedChats_IntroText1: String { return self._s[3061]! } + public var Tour_Text4: String { return self._s[3064]! } + public var WallpaperSearch_Recent: String { return self._s[3065]! } + public var GroupInfo_ScamGroupWarning: String { return self._s[3066]! } + public var Profile_MessageLifetime2s: String { return self._s[3068]! } + public var Appearance_ThemePreview_ChatList_5_Text: String { return self._s[3069]! } + public var Notification_MessageLifetime2s: String { return self._s[3070]! } public func Time_PreciseDate_m10(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3068]!, self._r[3068]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3071]!, self._r[3071]!, [_1, _2, _3]) } - public var Cache_ClearCache: String { return self._s[3069]! } - public var AutoNightTheme_UpdateLocation: String { return self._s[3070]! } - public var Permissions_NotificationsUnreachableText_v0: String { return self._s[3071]! } + public var Cache_ClearCache: String { return self._s[3072]! } + public var AutoNightTheme_UpdateLocation: String { return self._s[3073]! } + public var Permissions_NotificationsUnreachableText_v0: String { return self._s[3074]! } public func Channel_AdminLog_MessageChangedGroupUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3075]!, self._r[3075]!, [_0]) + return formatWithArgumentRanges(self._s[3078]!, self._r[3078]!, [_0]) } public func Conversation_ShareMyPhoneNumber_StatusSuccess(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3077]!, self._r[3077]!, [_0]) + return formatWithArgumentRanges(self._s[3080]!, self._r[3080]!, [_0]) } - public var LocalGroup_Text: String { return self._s[3078]! } - public var Channel_AdminLog_EmptyFilterTitle: String { return self._s[3079]! } - public var SocksProxySetup_TypeSocks: String { return self._s[3080]! } - public var ChatList_UnarchiveAction: String { return self._s[3081]! } - public var AutoNightTheme_Title: String { return self._s[3082]! } - public var InstantPage_FeedbackButton: String { return self._s[3083]! } - public var Passport_FieldAddress: String { return self._s[3084]! } + public var LocalGroup_Text: String { return self._s[3081]! } + public var Channel_AdminLog_EmptyFilterTitle: String { return self._s[3082]! } + public var SocksProxySetup_TypeSocks: String { return self._s[3083]! } + public var ChatList_UnarchiveAction: String { return self._s[3084]! } + public var AutoNightTheme_Title: String { return self._s[3085]! } + public var InstantPage_FeedbackButton: String { return self._s[3086]! } + public var Passport_FieldAddress: String { return self._s[3087]! } public func Channel_AdminLog_SetSlowmode(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3085]!, self._r[3085]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3088]!, self._r[3088]!, [_1, _2]) } - public var Month_ShortMarch: String { return self._s[3086]! } + public var Month_ShortMarch: String { return self._s[3089]! } public func PUSH_MESSAGE_INVOICE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3087]!, self._r[3087]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3090]!, self._r[3090]!, [_1, _2]) } - public var SocksProxySetup_UsernamePlaceholder: String { return self._s[3088]! } - public var Conversation_ShareInlineBotLocationConfirmation: String { return self._s[3089]! } - public var Passport_FloodError: String { return self._s[3090]! } - public var SecretGif_Title: String { return self._s[3091]! } - public var NotificationSettings_ShowNotificationsAllAccountsInfoOn: String { return self._s[3092]! } - public var ChatList_Context_UnhideArchive: String { return self._s[3093]! } - public var Passport_Language_th: String { return self._s[3095]! } - public var Passport_Address_Address: String { return self._s[3096]! } - public var Login_InvalidLastNameError: String { return self._s[3097]! } - public var Notifications_InAppNotificationsPreview: String { return self._s[3098]! } - public var Notifications_PermissionsUnreachableTitle: String { return self._s[3099]! } - public var ChatList_Context_Archive: String { return self._s[3100]! } - public var SettingsSearch_FAQ: String { return self._s[3101]! } - public var ShareMenu_Send: String { return self._s[3102]! } - public var WallpaperSearch_ColorYellow: String { return self._s[3104]! } - public var Month_GenNovember: String { return self._s[3106]! } - public var SettingsSearch_Synonyms_Appearance_LargeEmoji: String { return self._s[3108]! } + public var SocksProxySetup_UsernamePlaceholder: String { return self._s[3091]! } + public var Conversation_ShareInlineBotLocationConfirmation: String { return self._s[3092]! } + public var Passport_FloodError: String { return self._s[3093]! } + public var SecretGif_Title: String { return self._s[3094]! } + public var NotificationSettings_ShowNotificationsAllAccountsInfoOn: String { return self._s[3095]! } + public var ChatList_Context_UnhideArchive: String { return self._s[3096]! } + public var Passport_Language_th: String { return self._s[3098]! } + public var Passport_Address_Address: String { return self._s[3099]! } + public var Login_InvalidLastNameError: String { return self._s[3100]! } + public var Notifications_InAppNotificationsPreview: String { return self._s[3101]! } + public var Notifications_PermissionsUnreachableTitle: String { return self._s[3102]! } + public var ChatList_Context_Archive: String { return self._s[3103]! } + public var SettingsSearch_FAQ: String { return self._s[3104]! } + public var ShareMenu_Send: String { return self._s[3105]! } + public var ChatState_Connecting: String { return self._s[3106]! } + public var WallpaperSearch_ColorYellow: String { return self._s[3108]! } + public var Month_GenNovember: String { return self._s[3110]! } + public var SettingsSearch_Synonyms_Appearance_LargeEmoji: String { return self._s[3112]! } public func Conversation_ShareMyPhoneNumberConfirmation(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3109]!, self._r[3109]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3113]!, self._r[3113]!, [_1, _2]) } - public var Conversation_SwipeToReplyHintText: String { return self._s[3110]! } - public var Checkout_Email: String { return self._s[3111]! } - public var NotificationsSound_Tritone: String { return self._s[3112]! } - public var StickerPacksSettings_ManagingHelp: String { return self._s[3114]! } - public var Wallet_ContextMenuCopy: String { return self._s[3116]! } + public var Conversation_SwipeToReplyHintText: String { return self._s[3114]! } + public var Checkout_Email: String { return self._s[3115]! } + public var NotificationsSound_Tritone: String { return self._s[3116]! } + public var StickerPacksSettings_ManagingHelp: String { return self._s[3118]! } + public var Wallet_ContextMenuCopy: String { return self._s[3120]! } public func Wallet_Time_PreciseDate_m6(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3118]!, self._r[3118]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3122]!, self._r[3122]!, [_1, _2, _3]) } - public var Appearance_TextSize_Automatic: String { return self._s[3119]! } + public var Appearance_TextSize_Automatic: String { return self._s[3123]! } public func PUSH_PINNED_ROUND(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3120]!, self._r[3120]!, [_1]) + return formatWithArgumentRanges(self._s[3124]!, self._r[3124]!, [_1]) } public func StickerPackActionInfo_AddedText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3121]!, self._r[3121]!, [_0]) + return formatWithArgumentRanges(self._s[3125]!, self._r[3125]!, [_0]) } - public var ChangePhoneNumberNumber_Help: String { return self._s[3122]! } + public var ChangePhoneNumberNumber_Help: String { return self._s[3126]! } public func Checkout_LiabilityAlert(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3123]!, self._r[3123]!, [_1, _1, _1, _2]) + return formatWithArgumentRanges(self._s[3127]!, self._r[3127]!, [_1, _1, _1, _2]) } - public var ChatList_UndoArchiveTitle: String { return self._s[3124]! } - public var Notification_Exceptions_Add: String { return self._s[3125]! } - public var DialogList_You: String { return self._s[3126]! } - public var MediaPicker_Send: String { return self._s[3129]! } - public var SettingsSearch_Synonyms_Stickers_Title: String { return self._s[3130]! } - public var Appearance_ThemePreview_ChatList_4_Text: String { return self._s[3131]! } - public var Call_AudioRouteSpeaker: String { return self._s[3132]! } - public var Watch_UserInfo_Title: String { return self._s[3133]! } - public var VoiceOver_Chat_PollFinalResults: String { return self._s[3134]! } - public var Appearance_AccentColor: String { return self._s[3136]! } + public var ChatList_UndoArchiveTitle: String { return self._s[3128]! } + public var Notification_Exceptions_Add: String { return self._s[3129]! } + public var DialogList_You: String { return self._s[3130]! } + public var MediaPicker_Send: String { return self._s[3133]! } + public var SettingsSearch_Synonyms_Stickers_Title: String { return self._s[3134]! } + public var Appearance_ThemePreview_ChatList_4_Text: String { return self._s[3135]! } + public var Call_AudioRouteSpeaker: String { return self._s[3136]! } + public var Watch_UserInfo_Title: String { return self._s[3137]! } + public var VoiceOver_Chat_PollFinalResults: String { return self._s[3138]! } + public var Appearance_AccentColor: String { return self._s[3140]! } public func Login_EmailPhoneSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3137]!, self._r[3137]!, [_0]) + return formatWithArgumentRanges(self._s[3141]!, self._r[3141]!, [_0]) } - public var Permissions_ContactsAllowInSettings_v0: String { return self._s[3138]! } + public var Permissions_ContactsAllowInSettings_v0: String { return self._s[3142]! } public func PUSH_CHANNEL_MESSAGE_GAME(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3139]!, self._r[3139]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3143]!, self._r[3143]!, [_1, _2]) } - public var Conversation_ClousStorageInfo_Description2: String { return self._s[3140]! } - public var WebSearch_RecentClearConfirmation: String { return self._s[3141]! } - public var Notification_CallOutgoing: String { return self._s[3142]! } - public var PrivacySettings_PasscodeAndFaceId: String { return self._s[3143]! } - public var Channel_DiscussionGroup_MakeHistoryPublic: String { return self._s[3144]! } - public var Call_RecordingDisabledMessage: String { return self._s[3145]! } - public var Message_Game: String { return self._s[3146]! } - public var Conversation_PressVolumeButtonForSound: String { return self._s[3147]! } - public var PrivacyLastSeenSettings_CustomHelp: String { return self._s[3148]! } - public var Channel_DiscussionGroup_PrivateGroup: String { return self._s[3149]! } - public var Channel_EditAdmin_PermissionAddAdmins: String { return self._s[3150]! } - public var Date_DialogDateFormat: String { return self._s[3152]! } - public var WallpaperColors_SetCustomColor: String { return self._s[3153]! } - public var Notifications_InAppNotifications: String { return self._s[3154]! } + public var Conversation_ClousStorageInfo_Description2: String { return self._s[3144]! } + public var WebSearch_RecentClearConfirmation: String { return self._s[3145]! } + public var Notification_CallOutgoing: String { return self._s[3146]! } + public var PrivacySettings_PasscodeAndFaceId: String { return self._s[3147]! } + public var Channel_DiscussionGroup_MakeHistoryPublic: String { return self._s[3148]! } + public var Call_RecordingDisabledMessage: String { return self._s[3149]! } + public var Message_Game: String { return self._s[3150]! } + public var Conversation_PressVolumeButtonForSound: String { return self._s[3151]! } + public var PrivacyLastSeenSettings_CustomHelp: String { return self._s[3152]! } + public var Channel_DiscussionGroup_PrivateGroup: String { return self._s[3153]! } + public var Channel_EditAdmin_PermissionAddAdmins: String { return self._s[3154]! } + public var Date_DialogDateFormat: String { return self._s[3156]! } + public var WallpaperColors_SetCustomColor: String { return self._s[3157]! } + public var Notifications_InAppNotifications: String { return self._s[3158]! } public func Channel_Management_RemovedBy(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3155]!, self._r[3155]!, [_0]) + return formatWithArgumentRanges(self._s[3159]!, self._r[3159]!, [_0]) } public func Settings_ApplyProxyAlert(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3156]!, self._r[3156]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3160]!, self._r[3160]!, [_1, _2]) } - public var NewContact_Title: String { return self._s[3157]! } + public var NewContact_Title: String { return self._s[3161]! } public func AutoDownloadSettings_UpToForAll(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3158]!, self._r[3158]!, [_0]) + return formatWithArgumentRanges(self._s[3162]!, self._r[3162]!, [_0]) } - public var Conversation_ViewContactDetails: String { return self._s[3159]! } + public var Conversation_ViewContactDetails: String { return self._s[3163]! } public func PUSH_CHANNEL_MESSAGE_CONTACT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3161]!, self._r[3161]!, [_1]) + return formatWithArgumentRanges(self._s[3165]!, self._r[3165]!, [_1]) } - public var Checkout_NewCard_CardholderNameTitle: String { return self._s[3162]! } - public var Passport_Identity_ExpiryDateNone: String { return self._s[3163]! } - public var PrivacySettings_Title: String { return self._s[3164]! } - public var Conversation_SilentBroadcastTooltipOff: String { return self._s[3167]! } - public var GroupRemoved_UsersSectionTitle: String { return self._s[3168]! } - public var VoiceOver_Chat_ContactEmail: String { return self._s[3169]! } - public var Contacts_PhoneNumber: String { return self._s[3170]! } - public var TwoFactorSetup_Password_PlaceholderConfirmPassword: String { return self._s[3172]! } - public var Map_ShowPlaces: String { return self._s[3173]! } - public var ChatAdmins_Title: String { return self._s[3174]! } - public var InstantPage_Reference: String { return self._s[3176]! } - public var Wallet_Info_Updating: String { return self._s[3177]! } - public var ReportGroupLocation_Text: String { return self._s[3178]! } + public var Checkout_NewCard_CardholderNameTitle: String { return self._s[3166]! } + public var Passport_Identity_ExpiryDateNone: String { return self._s[3167]! } + public var PrivacySettings_Title: String { return self._s[3168]! } + public var Conversation_SilentBroadcastTooltipOff: String { return self._s[3171]! } + public var GroupRemoved_UsersSectionTitle: String { return self._s[3172]! } + public var VoiceOver_Chat_ContactEmail: String { return self._s[3173]! } + public var Contacts_PhoneNumber: String { return self._s[3174]! } + public var TwoFactorSetup_Password_PlaceholderConfirmPassword: String { return self._s[3176]! } + public var Map_ShowPlaces: String { return self._s[3177]! } + public var ChatAdmins_Title: String { return self._s[3178]! } + public var InstantPage_Reference: String { return self._s[3180]! } + public var Wallet_Info_Updating: String { return self._s[3181]! } + public var ReportGroupLocation_Text: String { return self._s[3182]! } public func PUSH_CHAT_MESSAGE_FWD(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3179]!, self._r[3179]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3183]!, self._r[3183]!, [_1, _2]) } - public var Camera_FlashOff: String { return self._s[3180]! } - public var Watch_UserInfo_Block: String { return self._s[3181]! } - public var ChatSettings_Stickers: String { return self._s[3182]! } - public var ChatSettings_DownloadInBackground: String { return self._s[3183]! } - public var Appearance_ThemeCarouselTintedNight: String { return self._s[3184]! } + public var Camera_FlashOff: String { return self._s[3184]! } + public var Watch_UserInfo_Block: String { return self._s[3185]! } + public var ChatSettings_Stickers: String { return self._s[3186]! } + public var ChatSettings_DownloadInBackground: String { return self._s[3187]! } + public var Appearance_ThemeCarouselTintedNight: String { return self._s[3188]! } public func UserInfo_BlockConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3185]!, self._r[3185]!, [_0]) + return formatWithArgumentRanges(self._s[3189]!, self._r[3189]!, [_0]) } - public var Settings_ViewPhoto: String { return self._s[3186]! } - public var Login_CheckOtherSessionMessages: String { return self._s[3187]! } - public var AutoDownloadSettings_Cellular: String { return self._s[3188]! } - public var Wallet_Created_ExportErrorTitle: String { return self._s[3189]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsExceptions: String { return self._s[3190]! } - public var VoiceOver_MessageContextShare: String { return self._s[3191]! } + public var Settings_ViewPhoto: String { return self._s[3190]! } + public var Login_CheckOtherSessionMessages: String { return self._s[3191]! } + public var AutoDownloadSettings_Cellular: String { return self._s[3192]! } + public var Wallet_Created_ExportErrorTitle: String { return self._s[3193]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsExceptions: String { return self._s[3194]! } + public var VoiceOver_MessageContextShare: String { return self._s[3195]! } public func Target_InviteToGroupConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3193]!, self._r[3193]!, [_0]) + return formatWithArgumentRanges(self._s[3197]!, self._r[3197]!, [_0]) } - public var Privacy_DeleteDrafts: String { return self._s[3194]! } - public var Wallpaper_SetCustomBackgroundInfo: String { return self._s[3195]! } + public var Privacy_DeleteDrafts: String { return self._s[3198]! } + public var Wallpaper_SetCustomBackgroundInfo: String { return self._s[3199]! } public func LastSeen_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3196]!, self._r[3196]!, [_0]) + return formatWithArgumentRanges(self._s[3200]!, self._r[3200]!, [_0]) } - public var DialogList_SavedMessagesHelp: String { return self._s[3197]! } - public var Wallet_SecureStorageNotAvailable_Title: String { return self._s[3198]! } - public var DialogList_SavedMessages: String { return self._s[3199]! } - public var GroupInfo_UpgradeButton: String { return self._s[3200]! } - public var Appearance_ThemePreview_ChatList_3_Text: String { return self._s[3202]! } - public var DialogList_Pin: String { return self._s[3203]! } + public var DialogList_SavedMessagesHelp: String { return self._s[3201]! } + public var Wallet_SecureStorageNotAvailable_Title: String { return self._s[3202]! } + public var DialogList_SavedMessages: String { return self._s[3203]! } + public var GroupInfo_UpgradeButton: String { return self._s[3204]! } + public var Appearance_ThemePreview_ChatList_3_Text: String { return self._s[3206]! } + public var DialogList_Pin: String { return self._s[3207]! } public func ForwardedAuthors2(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3204]!, self._r[3204]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3208]!, self._r[3208]!, [_0, _1]) } public func Login_PhoneGenericEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3205]!, self._r[3205]!, [_0]) + return formatWithArgumentRanges(self._s[3209]!, self._r[3209]!, [_0]) } - public var Notification_Exceptions_AlwaysOn: String { return self._s[3206]! } - public var UserInfo_NotificationsDisable: String { return self._s[3207]! } - public var Conversation_ContextMenuCancelEditing: String { return self._s[3208]! } - public var Paint_Outlined: String { return self._s[3209]! } - public var Activity_PlayingGame: String { return self._s[3210]! } - public var SearchImages_NoImagesFound: String { return self._s[3211]! } - public var SocksProxySetup_ProxyType: String { return self._s[3212]! } - public var AppleWatch_ReplyPresetsHelp: String { return self._s[3214]! } - public var Conversation_ContextMenuCancelSending: String { return self._s[3215]! } - public var Settings_AppLanguage: String { return self._s[3216]! } - public var TwoStepAuth_ResetAccountHelp: String { return self._s[3217]! } - public var Common_ChoosePhoto: String { return self._s[3218]! } - public var AuthSessions_AddDevice_InvalidQRCode: String { return self._s[3219]! } - public var CallFeedback_ReasonEcho: String { return self._s[3220]! } + public var Notification_Exceptions_AlwaysOn: String { return self._s[3210]! } + public var UserInfo_NotificationsDisable: String { return self._s[3211]! } + public var Conversation_ContextMenuCancelEditing: String { return self._s[3212]! } + public var Paint_Outlined: String { return self._s[3213]! } + public var Activity_PlayingGame: String { return self._s[3214]! } + public var SearchImages_NoImagesFound: String { return self._s[3215]! } + public var SocksProxySetup_ProxyType: String { return self._s[3216]! } + public var AppleWatch_ReplyPresetsHelp: String { return self._s[3218]! } + public var Conversation_ContextMenuCancelSending: String { return self._s[3219]! } + public var Settings_AppLanguage: String { return self._s[3220]! } + public var TwoStepAuth_ResetAccountHelp: String { return self._s[3221]! } + public var Common_ChoosePhoto: String { return self._s[3222]! } + public var AuthSessions_AddDevice_InvalidQRCode: String { return self._s[3223]! } + public var CallFeedback_ReasonEcho: String { return self._s[3224]! } public func PUSH_PINNED_AUDIO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3221]!, self._r[3221]!, [_1]) + return formatWithArgumentRanges(self._s[3225]!, self._r[3225]!, [_1]) } - public var Privacy_Calls_AlwaysAllow: String { return self._s[3222]! } - public var PollResults_Collapse: String { return self._s[3223]! } - public var Activity_UploadingVideo: String { return self._s[3224]! } - public var Conversation_WalletRequiredNotNow: String { return self._s[3225]! } - public var ChannelInfo_DeleteChannelConfirmation: String { return self._s[3226]! } - public var NetworkUsageSettings_Wifi: String { return self._s[3227]! } - public var VoiceOver_Editing_ClearText: String { return self._s[3228]! } - public var PUSH_SENDER_YOU: String { return self._s[3229]! } - public var Channel_BanUser_PermissionReadMessages: String { return self._s[3230]! } - public var Checkout_PayWithTouchId: String { return self._s[3231]! } - public var Wallpaper_ResetWallpapersConfirmation: String { return self._s[3232]! } + public var Privacy_Calls_AlwaysAllow: String { return self._s[3226]! } + public var PollResults_Collapse: String { return self._s[3227]! } + public var Activity_UploadingVideo: String { return self._s[3228]! } + public var Conversation_WalletRequiredNotNow: String { return self._s[3229]! } + public var ChannelInfo_DeleteChannelConfirmation: String { return self._s[3230]! } + public var NetworkUsageSettings_Wifi: String { return self._s[3231]! } + public var VoiceOver_Editing_ClearText: String { return self._s[3232]! } + public var PUSH_SENDER_YOU: String { return self._s[3233]! } + public var Channel_BanUser_PermissionReadMessages: String { return self._s[3234]! } + public var Checkout_PayWithTouchId: String { return self._s[3235]! } + public var Wallpaper_ResetWallpapersConfirmation: String { return self._s[3236]! } public func PUSH_LOCKED_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3234]!, self._r[3234]!, [_1]) + return formatWithArgumentRanges(self._s[3238]!, self._r[3238]!, [_1]) } - public var Notifications_ExceptionsNone: String { return self._s[3235]! } + public var Notifications_ExceptionsNone: String { return self._s[3239]! } public func Message_ForwardedMessageShort(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3236]!, self._r[3236]!, [_0]) + return formatWithArgumentRanges(self._s[3240]!, self._r[3240]!, [_0]) } public func PUSH_PINNED_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3237]!, self._r[3237]!, [_1]) + return formatWithArgumentRanges(self._s[3241]!, self._r[3241]!, [_1]) } - public var AuthSessions_IncompleteAttempts: String { return self._s[3239]! } - public var Passport_Address_Region: String { return self._s[3242]! } - public var ChatList_DeleteChat: String { return self._s[3243]! } - public var LogoutOptions_ClearCacheTitle: String { return self._s[3244]! } - public var PhotoEditor_TiltShift: String { return self._s[3245]! } - public var Settings_FAQ_URL: String { return self._s[3246]! } - public var TwoFactorSetup_EmailVerification_ChangeAction: String { return self._s[3247]! } - public var Passport_Language_sl: String { return self._s[3248]! } - public var Settings_PrivacySettings: String { return self._s[3250]! } - public var SharedMedia_TitleLink: String { return self._s[3251]! } - public var Passport_Identity_TypePassportUploadScan: String { return self._s[3252]! } - public var Settings_SetProfilePhoto: String { return self._s[3253]! } - public var Channel_About_Help: String { return self._s[3254]! } - public var Contacts_PermissionsEnable: String { return self._s[3255]! } - public var Wallet_Sending_Title: String { return self._s[3256]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsAlert: String { return self._s[3257]! } - public var AttachmentMenu_SendAsFiles: String { return self._s[3258]! } - public var CallFeedback_ReasonInterruption: String { return self._s[3260]! } - public var Passport_Address_AddTemporaryRegistration: String { return self._s[3261]! } - public var AutoDownloadSettings_AutodownloadVideos: String { return self._s[3262]! } - public var ChatSettings_AutoDownloadSettings_Delimeter: String { return self._s[3263]! } - public var OldChannels_Title: String { return self._s[3264]! } - public var PrivacySettings_DeleteAccountTitle: String { return self._s[3265]! } - public var AccessDenied_VideoMessageCamera: String { return self._s[3267]! } - public var Map_OpenInYandexMaps: String { return self._s[3269]! } - public var CreateGroup_ErrorLocatedGroupsTooMuch: String { return self._s[3270]! } - public var VoiceOver_MessageContextReply: String { return self._s[3271]! } - public var PhotoEditor_SaturationTool: String { return self._s[3273]! } + public var AuthSessions_IncompleteAttempts: String { return self._s[3243]! } + public var Passport_Address_Region: String { return self._s[3246]! } + public var ChatList_DeleteChat: String { return self._s[3247]! } + public var LogoutOptions_ClearCacheTitle: String { return self._s[3248]! } + public var PhotoEditor_TiltShift: String { return self._s[3249]! } + public var Settings_FAQ_URL: String { return self._s[3250]! } + public var TwoFactorSetup_EmailVerification_ChangeAction: String { return self._s[3251]! } + public var Passport_Language_sl: String { return self._s[3252]! } + public var Settings_PrivacySettings: String { return self._s[3254]! } + public var SharedMedia_TitleLink: String { return self._s[3255]! } + public var Passport_Identity_TypePassportUploadScan: String { return self._s[3256]! } + public var Settings_SetProfilePhoto: String { return self._s[3257]! } + public var Channel_About_Help: String { return self._s[3258]! } + public var Contacts_PermissionsEnable: String { return self._s[3259]! } + public var Wallet_Sending_Title: String { return self._s[3260]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsAlert: String { return self._s[3261]! } + public var AttachmentMenu_SendAsFiles: String { return self._s[3262]! } + public var CallFeedback_ReasonInterruption: String { return self._s[3264]! } + public var Passport_Address_AddTemporaryRegistration: String { return self._s[3265]! } + public var AutoDownloadSettings_AutodownloadVideos: String { return self._s[3266]! } + public var ChatSettings_AutoDownloadSettings_Delimeter: String { return self._s[3267]! } + public var OldChannels_Title: String { return self._s[3268]! } + public var PrivacySettings_DeleteAccountTitle: String { return self._s[3269]! } + public var AccessDenied_VideoMessageCamera: String { return self._s[3271]! } + public var Map_OpenInYandexMaps: String { return self._s[3273]! } + public var CreateGroup_ErrorLocatedGroupsTooMuch: String { return self._s[3274]! } + public var VoiceOver_MessageContextReply: String { return self._s[3275]! } + public var PhotoEditor_SaturationTool: String { return self._s[3277]! } public func PUSH_MESSAGE_STICKER(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3274]!, self._r[3274]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3278]!, self._r[3278]!, [_1, _2]) } - public var PrivacyPhoneNumberSettings_CustomHelp: String { return self._s[3275]! } - public var Notification_Exceptions_NewException_NotificationHeader: String { return self._s[3276]! } - public var Group_OwnershipTransfer_ErrorLocatedGroupsTooMuch: String { return self._s[3277]! } + public var PrivacyPhoneNumberSettings_CustomHelp: String { return self._s[3279]! } + public var Notification_Exceptions_NewException_NotificationHeader: String { return self._s[3280]! } + public var Group_OwnershipTransfer_ErrorLocatedGroupsTooMuch: String { return self._s[3281]! } public func LOCAL_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3278]!, self._r[3278]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[3282]!, self._r[3282]!, [_1, "\(_2)"]) } - public var Appearance_ThemePreview_ChatList_2_Text: String { return self._s[3279]! } - public var Channel_Username_InvalidTooShort: String { return self._s[3281]! } - public var SettingsSearch_Synonyms_Wallet: String { return self._s[3282]! } + public var Appearance_ThemePreview_ChatList_2_Text: String { return self._s[3283]! } + public var Channel_Username_InvalidTooShort: String { return self._s[3285]! } + public var SettingsSearch_Synonyms_Wallet: String { return self._s[3286]! } public func Group_OwnershipTransfer_DescriptionInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3283]!, self._r[3283]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3287]!, self._r[3287]!, [_1, _2]) } - public var Forward_ErrorPublicPollDisabledInChannels: String { return self._s[3284]! } + public var Forward_ErrorPublicPollDisabledInChannels: String { return self._s[3288]! } public func PUSH_CHAT_MESSAGE_GAME(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3285]!, self._r[3285]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3289]!, self._r[3289]!, [_1, _2, _3]) } - public var WallpaperPreview_PatternTitle: String { return self._s[3286]! } - public var GroupInfo_PublicLinkAdd: String { return self._s[3287]! } - public var Passport_PassportInformation: String { return self._s[3290]! } - public var Theme_Unsupported: String { return self._s[3291]! } - public var WatchRemote_AlertTitle: String { return self._s[3292]! } - public var Privacy_GroupsAndChannels_NeverAllow: String { return self._s[3293]! } - public var ConvertToSupergroup_HelpText: String { return self._s[3295]! } + public var WallpaperPreview_PatternTitle: String { return self._s[3290]! } + public var GroupInfo_PublicLinkAdd: String { return self._s[3291]! } + public var Passport_PassportInformation: String { return self._s[3294]! } + public var Theme_Unsupported: String { return self._s[3295]! } + public var WatchRemote_AlertTitle: String { return self._s[3296]! } + public var Privacy_GroupsAndChannels_NeverAllow: String { return self._s[3297]! } + public var ConvertToSupergroup_HelpText: String { return self._s[3299]! } public func Time_MonthOfYear_m7(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3296]!, self._r[3296]!, [_0]) + return formatWithArgumentRanges(self._s[3300]!, self._r[3300]!, [_0]) } public func PUSH_PHONE_CALL_REQUEST(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3297]!, self._r[3297]!, [_1]) + return formatWithArgumentRanges(self._s[3301]!, self._r[3301]!, [_1]) } - public var Privacy_GroupsAndChannels_CustomHelp: String { return self._s[3298]! } - public var Wallet_Navigation_Done: String { return self._s[3300]! } - public var TwoStepAuth_RecoveryCodeInvalid: String { return self._s[3301]! } - public var AccessDenied_CameraDisabled: String { return self._s[3302]! } + public var Privacy_GroupsAndChannels_CustomHelp: String { return self._s[3302]! } + public var Wallet_Navigation_Done: String { return self._s[3304]! } + public var TwoStepAuth_RecoveryCodeInvalid: String { return self._s[3305]! } + public var AccessDenied_CameraDisabled: String { return self._s[3306]! } public func Channel_Username_UsernameIsAvailable(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3303]!, self._r[3303]!, [_0]) + return formatWithArgumentRanges(self._s[3307]!, self._r[3307]!, [_0]) } - public var ClearCache_Forever: String { return self._s[3304]! } - public var AuthSessions_AddDeviceIntro_Title: String { return self._s[3305]! } - public var CreatePoll_Quiz: String { return self._s[3306]! } - public var PhotoEditor_ContrastTool: String { return self._s[3309]! } + public var ClearCache_Forever: String { return self._s[3308]! } + public var AuthSessions_AddDeviceIntro_Title: String { return self._s[3309]! } + public var CreatePoll_Quiz: String { return self._s[3310]! } + public var PhotoEditor_ContrastTool: String { return self._s[3313]! } public func PUSH_PINNED_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3310]!, self._r[3310]!, [_1]) + return formatWithArgumentRanges(self._s[3314]!, self._r[3314]!, [_1]) } - public var DialogList_Draft: String { return self._s[3311]! } - public var Wallet_Configuration_BlockchainIdInfo: String { return self._s[3312]! } - public var Privacy_TopPeersDelete: String { return self._s[3314]! } - public var LoginPassword_PasswordPlaceholder: String { return self._s[3315]! } - public var Passport_Identity_TypeIdentityCardUploadScan: String { return self._s[3316]! } - public var WebSearch_RecentSectionClear: String { return self._s[3317]! } - public var EditTheme_ErrorInvalidCharacters: String { return self._s[3318]! } - public var Watch_ChatList_NoConversationsTitle: String { return self._s[3320]! } - public var Common_Done: String { return self._s[3322]! } - public var Shortcut_SwitchAccount: String { return self._s[3323]! } - public var AuthSessions_EmptyText: String { return self._s[3324]! } - public var Wallet_Configuration_BlockchainNameChangedTitle: String { return self._s[3325]! } - public var Conversation_ShareBotContactConfirmation: String { return self._s[3326]! } - public var Tour_Title5: String { return self._s[3327]! } - public var Wallet_Settings_Title: String { return self._s[3328]! } + public var DialogList_Draft: String { return self._s[3315]! } + public var Wallet_Configuration_BlockchainIdInfo: String { return self._s[3316]! } + public var Privacy_TopPeersDelete: String { return self._s[3318]! } + public var LoginPassword_PasswordPlaceholder: String { return self._s[3319]! } + public var Passport_Identity_TypeIdentityCardUploadScan: String { return self._s[3320]! } + public var WebSearch_RecentSectionClear: String { return self._s[3321]! } + public var EditTheme_ErrorInvalidCharacters: String { return self._s[3322]! } + public var Watch_ChatList_NoConversationsTitle: String { return self._s[3324]! } + public var Common_Done: String { return self._s[3326]! } + public var Shortcut_SwitchAccount: String { return self._s[3327]! } + public var AuthSessions_EmptyText: String { return self._s[3328]! } + public var Wallet_Configuration_BlockchainNameChangedTitle: String { return self._s[3329]! } + public var Conversation_ShareBotContactConfirmation: String { return self._s[3330]! } + public var Tour_Title5: String { return self._s[3331]! } + public var Wallet_Settings_Title: String { return self._s[3332]! } public func Map_DirectionsDriveEta(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3329]!, self._r[3329]!, [_0]) + return formatWithArgumentRanges(self._s[3333]!, self._r[3333]!, [_0]) } - public var ApplyLanguage_UnsufficientDataTitle: String { return self._s[3330]! } - public var Conversation_LinkDialogSave: String { return self._s[3331]! } - public var GroupInfo_ActionRestrict: String { return self._s[3332]! } - public var Checkout_Title: String { return self._s[3333]! } - public var Channel_DiscussionGroup_HeaderLabel: String { return self._s[3335]! } - public var Channel_AdminLog_CanChangeInfo: String { return self._s[3337]! } - public var Notification_RenamedGroup: String { return self._s[3338]! } - public var PeopleNearby_Groups: String { return self._s[3339]! } - public var Checkout_PayWithFaceId: String { return self._s[3340]! } - public var Channel_BanList_BlockedTitle: String { return self._s[3341]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsSound: String { return self._s[3343]! } - public var Checkout_WebConfirmation_Title: String { return self._s[3344]! } - public var Notifications_MessageNotificationsAlert: String { return self._s[3345]! } + public var ApplyLanguage_UnsufficientDataTitle: String { return self._s[3334]! } + public var Conversation_LinkDialogSave: String { return self._s[3335]! } + public var GroupInfo_ActionRestrict: String { return self._s[3336]! } + public var Checkout_Title: String { return self._s[3337]! } + public var Channel_DiscussionGroup_HeaderLabel: String { return self._s[3339]! } + public var Channel_AdminLog_CanChangeInfo: String { return self._s[3341]! } + public var Notification_RenamedGroup: String { return self._s[3342]! } + public var PeopleNearby_Groups: String { return self._s[3343]! } + public var Checkout_PayWithFaceId: String { return self._s[3344]! } + public var Channel_BanList_BlockedTitle: String { return self._s[3345]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsSound: String { return self._s[3347]! } + public var Checkout_WebConfirmation_Title: String { return self._s[3348]! } + public var Notifications_MessageNotificationsAlert: String { return self._s[3349]! } public func Activity_RemindAboutGroup(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3346]!, self._r[3346]!, [_0]) + return formatWithArgumentRanges(self._s[3350]!, self._r[3350]!, [_0]) } - public var Profile_AddToExisting: String { return self._s[3348]! } + public var Profile_AddToExisting: String { return self._s[3352]! } public func Profile_CreateEncryptedChatOutdatedError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3349]!, self._r[3349]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3353]!, self._r[3353]!, [_0, _1]) } - public var Cache_Files: String { return self._s[3351]! } - public var Permissions_PrivacyPolicy: String { return self._s[3352]! } - public var SocksProxySetup_ConnectAndSave: String { return self._s[3353]! } - public var UserInfo_NotificationsDefaultDisabled: String { return self._s[3354]! } - public var AutoDownloadSettings_TypeContacts: String { return self._s[3356]! } - public var Appearance_ThemePreview_ChatList_1_Text: String { return self._s[3358]! } - public var Calls_NoCallsPlaceholder: String { return self._s[3359]! } + public var Cache_Files: String { return self._s[3355]! } + public var Permissions_PrivacyPolicy: String { return self._s[3356]! } + public var SocksProxySetup_ConnectAndSave: String { return self._s[3357]! } + public var UserInfo_NotificationsDefaultDisabled: String { return self._s[3358]! } + public var AutoDownloadSettings_TypeContacts: String { return self._s[3360]! } + public var Appearance_ThemePreview_ChatList_1_Text: String { return self._s[3362]! } + public var Calls_NoCallsPlaceholder: String { return self._s[3363]! } public func Wallet_Receive_ShareInvoiceUrlInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3360]!, self._r[3360]!, [_0]) + return formatWithArgumentRanges(self._s[3364]!, self._r[3364]!, [_0]) } - public var Channel_Username_RevokeExistingUsernamesInfo: String { return self._s[3361]! } - public var VoiceOver_AttachMedia: String { return self._s[3364]! } - public var Notifications_ExceptionsGroupPlaceholder: String { return self._s[3365]! } + public var Channel_Username_RevokeExistingUsernamesInfo: String { return self._s[3365]! } + public var VoiceOver_AttachMedia: String { return self._s[3368]! } + public var Notifications_ExceptionsGroupPlaceholder: String { return self._s[3369]! } public func PUSH_CHAT_MESSAGE_INVOICE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3366]!, self._r[3366]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3370]!, self._r[3370]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsSound: String { return self._s[3367]! } - public var Conversation_SetReminder_Title: String { return self._s[3368]! } - public var Passport_FieldAddressHelp: String { return self._s[3369]! } - public var Privacy_GroupsAndChannels_InviteToChannelMultipleError: String { return self._s[3370]! } - public var PUSH_REMINDER_TITLE: String { return self._s[3371]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsSound: String { return self._s[3371]! } + public var Conversation_SetReminder_Title: String { return self._s[3372]! } + public var Passport_FieldAddressHelp: String { return self._s[3373]! } + public var Privacy_GroupsAndChannels_InviteToChannelMultipleError: String { return self._s[3374]! } + public var PUSH_REMINDER_TITLE: String { return self._s[3375]! } public func Login_TermsOfService_ProceedBot(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3372]!, self._r[3372]!, [_0]) + return formatWithArgumentRanges(self._s[3376]!, self._r[3376]!, [_0]) } - public var Channel_AdminLog_EmptyTitle: String { return self._s[3373]! } - public var Privacy_Calls_NeverAllow_Title: String { return self._s[3374]! } - public var Login_UnknownError: String { return self._s[3375]! } - public var Group_UpgradeNoticeText2: String { return self._s[3378]! } - public var Watch_Compose_AddContact: String { return self._s[3379]! } - public var ClearCache_StorageServiceFiles: String { return self._s[3380]! } - public var Web_Error: String { return self._s[3381]! } - public var Gif_Search: String { return self._s[3382]! } - public var Profile_MessageLifetime1h: String { return self._s[3383]! } - public var CheckoutInfo_ReceiverInfoEmailPlaceholder: String { return self._s[3384]! } - public var Channel_Username_CheckingUsername: String { return self._s[3385]! } - public var CallFeedback_ReasonSilentRemote: String { return self._s[3386]! } - public var AutoDownloadSettings_TypeChannels: String { return self._s[3387]! } - public var Channel_AboutItem: String { return self._s[3388]! } - public var Privacy_GroupsAndChannels_AlwaysAllow_Placeholder: String { return self._s[3390]! } - public var VoiceOver_Chat_VoiceMessage: String { return self._s[3391]! } - public var GroupInfo_SharedMedia: String { return self._s[3392]! } + public var Channel_AdminLog_EmptyTitle: String { return self._s[3377]! } + public var Privacy_Calls_NeverAllow_Title: String { return self._s[3378]! } + public var Login_UnknownError: String { return self._s[3379]! } + public var Group_UpgradeNoticeText2: String { return self._s[3382]! } + public var Watch_Compose_AddContact: String { return self._s[3383]! } + public var ClearCache_StorageServiceFiles: String { return self._s[3384]! } + public var Web_Error: String { return self._s[3385]! } + public var Gif_Search: String { return self._s[3386]! } + public var Profile_MessageLifetime1h: String { return self._s[3387]! } + public var CheckoutInfo_ReceiverInfoEmailPlaceholder: String { return self._s[3388]! } + public var Channel_Username_CheckingUsername: String { return self._s[3389]! } + public var CallFeedback_ReasonSilentRemote: String { return self._s[3390]! } + public var AutoDownloadSettings_TypeChannels: String { return self._s[3391]! } + public var Channel_AboutItem: String { return self._s[3392]! } + public var Privacy_GroupsAndChannels_AlwaysAllow_Placeholder: String { return self._s[3394]! } + public var VoiceOver_Chat_VoiceMessage: String { return self._s[3395]! } + public var GroupInfo_SharedMedia: String { return self._s[3396]! } public func Channel_AdminLog_MessagePromotedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3393]!, self._r[3393]!, [_1]) + return formatWithArgumentRanges(self._s[3397]!, self._r[3397]!, [_1]) } - public var Call_PhoneCallInProgressMessage: String { return self._s[3394]! } + public var Call_PhoneCallInProgressMessage: String { return self._s[3398]! } public func PUSH_CHANNEL_ALBUM(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3395]!, self._r[3395]!, [_1]) + return formatWithArgumentRanges(self._s[3399]!, self._r[3399]!, [_1]) } - public var ChatList_UndoArchiveRevealedText: String { return self._s[3396]! } - public var GroupInfo_InviteLink_RevokeAlert_Text: String { return self._s[3397]! } - public var Conversation_SearchByName_Placeholder: String { return self._s[3398]! } - public var CreatePoll_AddOption: String { return self._s[3399]! } - public var GroupInfo_Permissions_SearchPlaceholder: String { return self._s[3400]! } - public var Group_UpgradeNoticeHeader: String { return self._s[3401]! } - public var Channel_Management_AddModerator: String { return self._s[3402]! } - public var AutoDownloadSettings_MaxFileSize: String { return self._s[3403]! } - public var StickerPacksSettings_ShowStickersButton: String { return self._s[3404]! } - public var Wallet_Info_RefreshErrorNetworkText: String { return self._s[3405]! } - public var Theme_Colors_Background: String { return self._s[3406]! } - public var NotificationsSound_Hello: String { return self._s[3408]! } - public var SocksProxySetup_SavedProxies: String { return self._s[3409]! } - public var Channel_Stickers_Placeholder: String { return self._s[3411]! } + public var ChatList_UndoArchiveRevealedText: String { return self._s[3400]! } + public var GroupInfo_InviteLink_RevokeAlert_Text: String { return self._s[3401]! } + public var Conversation_SearchByName_Placeholder: String { return self._s[3402]! } + public var CreatePoll_AddOption: String { return self._s[3403]! } + public var GroupInfo_Permissions_SearchPlaceholder: String { return self._s[3404]! } + public var Group_UpgradeNoticeHeader: String { return self._s[3405]! } + public var Channel_Management_AddModerator: String { return self._s[3406]! } + public var AutoDownloadSettings_MaxFileSize: String { return self._s[3407]! } + public var StickerPacksSettings_ShowStickersButton: String { return self._s[3408]! } + public var Wallet_Info_RefreshErrorNetworkText: String { return self._s[3409]! } + public var Theme_Colors_Background: String { return self._s[3410]! } + public var NotificationsSound_Hello: String { return self._s[3412]! } + public var SocksProxySetup_SavedProxies: String { return self._s[3413]! } + public var Channel_Stickers_Placeholder: String { return self._s[3415]! } public func Login_EmailCodeBody(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3412]!, self._r[3412]!, [_0]) + return formatWithArgumentRanges(self._s[3416]!, self._r[3416]!, [_0]) } - public var PrivacyPolicy_DeclineDeclineAndDelete: String { return self._s[3413]! } - public var Channel_Management_AddModeratorHelp: String { return self._s[3414]! } - public var ContactInfo_BirthdayLabel: String { return self._s[3415]! } - public var ChangePhoneNumberCode_RequestingACall: String { return self._s[3416]! } - public var AutoDownloadSettings_Channels: String { return self._s[3417]! } - public var Passport_Language_mn: String { return self._s[3418]! } - public var Notifications_ResetAllNotificationsHelp: String { return self._s[3421]! } - public var GroupInfo_Permissions_SlowmodeValue_Off: String { return self._s[3422]! } - public var Passport_Language_ja: String { return self._s[3424]! } - public var Settings_About_Title: String { return self._s[3425]! } - public var Settings_NotificationsAndSounds: String { return self._s[3426]! } - public var ChannelInfo_DeleteGroup: String { return self._s[3427]! } - public var Settings_BlockedUsers: String { return self._s[3428]! } + public var PrivacyPolicy_DeclineDeclineAndDelete: String { return self._s[3417]! } + public var Channel_Management_AddModeratorHelp: String { return self._s[3418]! } + public var ContactInfo_BirthdayLabel: String { return self._s[3419]! } + public var ChangePhoneNumberCode_RequestingACall: String { return self._s[3420]! } + public var AutoDownloadSettings_Channels: String { return self._s[3421]! } + public var Passport_Language_mn: String { return self._s[3422]! } + public var Notifications_ResetAllNotificationsHelp: String { return self._s[3425]! } + public var GroupInfo_Permissions_SlowmodeValue_Off: String { return self._s[3426]! } + public var Passport_Language_ja: String { return self._s[3428]! } + public var Settings_About_Title: String { return self._s[3429]! } + public var Settings_NotificationsAndSounds: String { return self._s[3430]! } + public var ChannelInfo_DeleteGroup: String { return self._s[3431]! } + public var Settings_BlockedUsers: String { return self._s[3432]! } public func Time_MonthOfYear_m4(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3429]!, self._r[3429]!, [_0]) + return formatWithArgumentRanges(self._s[3433]!, self._r[3433]!, [_0]) } - public var EditTheme_Create_Preview_OutgoingText: String { return self._s[3430]! } - public var Wallet_Weekday_Today: String { return self._s[3431]! } - public var AutoDownloadSettings_PreloadVideo: String { return self._s[3432]! } - public var Widget_ApplicationLocked: String { return self._s[3433]! } - public var Passport_Address_AddResidentialAddress: String { return self._s[3434]! } - public var Channel_Username_Title: String { return self._s[3435]! } + public var EditTheme_Create_Preview_OutgoingText: String { return self._s[3434]! } + public var Wallet_Weekday_Today: String { return self._s[3435]! } + public var AutoDownloadSettings_PreloadVideo: String { return self._s[3436]! } + public var Widget_ApplicationLocked: String { return self._s[3437]! } + public var Passport_Address_AddResidentialAddress: String { return self._s[3438]! } + public var Channel_Username_Title: String { return self._s[3439]! } public func Notification_RemovedGroupPhoto(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3436]!, self._r[3436]!, [_0]) + return formatWithArgumentRanges(self._s[3440]!, self._r[3440]!, [_0]) } - public var AttachmentMenu_File: String { return self._s[3438]! } - public var AppleWatch_Title: String { return self._s[3439]! } - public var Activity_RecordingVideoMessage: String { return self._s[3440]! } + public var AttachmentMenu_File: String { return self._s[3442]! } + public var AppleWatch_Title: String { return self._s[3443]! } + public var Activity_RecordingVideoMessage: String { return self._s[3444]! } public func Channel_DiscussionGroup_PublicChannelLink(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3441]!, self._r[3441]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3445]!, self._r[3445]!, [_1, _2]) } - public var Theme_Colors_Messages: String { return self._s[3442]! } - public var Weekday_Saturday: String { return self._s[3443]! } - public var WallpaperPreview_SwipeColorsTopText: String { return self._s[3444]! } - public var Profile_CreateEncryptedChatError: String { return self._s[3445]! } - public var Common_Next: String { return self._s[3447]! } - public var Channel_Stickers_YourStickers: String { return self._s[3449]! } - public var Message_Theme: String { return self._s[3450]! } - public var Call_AudioRouteHeadphones: String { return self._s[3451]! } - public var TwoStepAuth_EnterPasswordForgot: String { return self._s[3453]! } - public var Watch_Contacts_NoResults: String { return self._s[3455]! } - public var PhotoEditor_TintTool: String { return self._s[3458]! } - public var LoginPassword_ResetAccount: String { return self._s[3460]! } - public var Settings_SavedMessages: String { return self._s[3461]! } - public var SettingsSearch_Synonyms_Appearance_Animations: String { return self._s[3462]! } - public var Bot_GenericSupportStatus: String { return self._s[3463]! } - public var StickerPack_Add: String { return self._s[3464]! } - public var Checkout_TotalAmount: String { return self._s[3465]! } - public var Your_cards_number_is_invalid: String { return self._s[3466]! } - public var SettingsSearch_Synonyms_Appearance_AutoNightTheme: String { return self._s[3467]! } - public var VoiceOver_Chat_VideoMessage: String { return self._s[3468]! } + public var Theme_Colors_Messages: String { return self._s[3446]! } + public var Weekday_Saturday: String { return self._s[3447]! } + public var WallpaperPreview_SwipeColorsTopText: String { return self._s[3448]! } + public var Profile_CreateEncryptedChatError: String { return self._s[3449]! } + public var Common_Next: String { return self._s[3451]! } + public var Channel_Stickers_YourStickers: String { return self._s[3453]! } + public var Message_Theme: String { return self._s[3454]! } + public var Call_AudioRouteHeadphones: String { return self._s[3455]! } + public var TwoStepAuth_EnterPasswordForgot: String { return self._s[3457]! } + public var Watch_Contacts_NoResults: String { return self._s[3459]! } + public var PhotoEditor_TintTool: String { return self._s[3462]! } + public var LoginPassword_ResetAccount: String { return self._s[3464]! } + public var Settings_SavedMessages: String { return self._s[3465]! } + public var SettingsSearch_Synonyms_Appearance_Animations: String { return self._s[3466]! } + public var Bot_GenericSupportStatus: String { return self._s[3467]! } + public var StickerPack_Add: String { return self._s[3468]! } + public var Checkout_TotalAmount: String { return self._s[3469]! } + public var Your_cards_number_is_invalid: String { return self._s[3470]! } + public var SettingsSearch_Synonyms_Appearance_AutoNightTheme: String { return self._s[3471]! } + public var VoiceOver_Chat_VideoMessage: String { return self._s[3472]! } public func ChangePhoneNumberCode_CallTimer(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3469]!, self._r[3469]!, [_0]) + return formatWithArgumentRanges(self._s[3473]!, self._r[3473]!, [_0]) } public func GroupPermission_AddedInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3470]!, self._r[3470]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3474]!, self._r[3474]!, [_1, _2]) } - public var ChatSettings_ConnectionType_UseSocks5: String { return self._s[3471]! } + public var ChatSettings_ConnectionType_UseSocks5: String { return self._s[3475]! } public func PUSH_CHAT_PHOTO_EDITED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3473]!, self._r[3473]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3477]!, self._r[3477]!, [_1, _2]) } public func Conversation_RestrictedTextTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3474]!, self._r[3474]!, [_0]) + return formatWithArgumentRanges(self._s[3478]!, self._r[3478]!, [_0]) } - public var GroupInfo_InviteLink_ShareLink: String { return self._s[3475]! } - public var StickerPack_Share: String { return self._s[3476]! } - public var Passport_DeleteAddress: String { return self._s[3477]! } - public var Settings_Passport: String { return self._s[3478]! } - public var SharedMedia_EmptyFilesText: String { return self._s[3479]! } - public var Conversation_DeleteMessagesForMe: String { return self._s[3480]! } - public var PasscodeSettings_AutoLock_IfAwayFor_1hour: String { return self._s[3481]! } - public var Contacts_PermissionsText: String { return self._s[3482]! } - public var Group_Setup_HistoryVisible: String { return self._s[3483]! } - public var Wallet_Month_ShortDecember: String { return self._s[3485]! } - public var Channel_EditAdmin_PermissionEnabledByDefault: String { return self._s[3486]! } - public var Passport_Address_AddRentalAgreement: String { return self._s[3487]! } - public var SocksProxySetup_Title: String { return self._s[3488]! } - public var Notification_Mute1h: String { return self._s[3489]! } + public var GroupInfo_InviteLink_ShareLink: String { return self._s[3479]! } + public var StickerPack_Share: String { return self._s[3480]! } + public var Passport_DeleteAddress: String { return self._s[3481]! } + public var Settings_Passport: String { return self._s[3482]! } + public var SharedMedia_EmptyFilesText: String { return self._s[3483]! } + public var Conversation_DeleteMessagesForMe: String { return self._s[3484]! } + public var PasscodeSettings_AutoLock_IfAwayFor_1hour: String { return self._s[3485]! } + public var Contacts_PermissionsText: String { return self._s[3486]! } + public var Group_Setup_HistoryVisible: String { return self._s[3487]! } + public var Wallet_Month_ShortDecember: String { return self._s[3489]! } + public var Channel_EditAdmin_PermissionEnabledByDefault: String { return self._s[3490]! } + public var Passport_Address_AddRentalAgreement: String { return self._s[3491]! } + public var SocksProxySetup_Title: String { return self._s[3492]! } + public var Notification_Mute1h: String { return self._s[3493]! } public func Passport_Email_CodeHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3490]!, self._r[3490]!, [_0]) + return formatWithArgumentRanges(self._s[3494]!, self._r[3494]!, [_0]) } - public var NotificationSettings_ShowNotificationsAllAccountsInfoOff: String { return self._s[3491]! } + public var NotificationSettings_ShowNotificationsAllAccountsInfoOff: String { return self._s[3495]! } public func PUSH_PINNED_GEOLIVE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3492]!, self._r[3492]!, [_1]) + return formatWithArgumentRanges(self._s[3496]!, self._r[3496]!, [_1]) } - public var FastTwoStepSetup_PasswordSection: String { return self._s[3493]! } - public var NetworkUsageSettings_ResetStatsConfirmation: String { return self._s[3496]! } - public var InfoPlist_NSFaceIDUsageDescription: String { return self._s[3498]! } - public var DialogList_NoMessagesText: String { return self._s[3499]! } - public var Privacy_ContactsResetConfirmation: String { return self._s[3500]! } - public var Privacy_Calls_P2PHelp: String { return self._s[3501]! } - public var Channel_DiscussionGroup_SearchPlaceholder: String { return self._s[3503]! } - public var Your_cards_expiration_year_is_invalid: String { return self._s[3504]! } - public var Common_TakePhotoOrVideo: String { return self._s[3505]! } - public var Wallet_Words_Text: String { return self._s[3506]! } - public var Call_StatusBusy: String { return self._s[3507]! } - public var Conversation_PinnedMessage: String { return self._s[3508]! } - public var AutoDownloadSettings_VoiceMessagesTitle: String { return self._s[3509]! } - public var Wallet_Configuration_BlockchainNameChangedProceed: String { return self._s[3510]! } - public var TwoStepAuth_SetupPasswordConfirmFailed: String { return self._s[3511]! } - public var Undo_ChatCleared: String { return self._s[3512]! } - public var AppleWatch_ReplyPresets: String { return self._s[3513]! } - public var Passport_DiscardMessageDescription: String { return self._s[3515]! } - public var Login_NetworkError: String { return self._s[3516]! } + public var FastTwoStepSetup_PasswordSection: String { return self._s[3497]! } + public var NetworkUsageSettings_ResetStatsConfirmation: String { return self._s[3500]! } + public var InfoPlist_NSFaceIDUsageDescription: String { return self._s[3502]! } + public var DialogList_NoMessagesText: String { return self._s[3503]! } + public var Privacy_ContactsResetConfirmation: String { return self._s[3504]! } + public var Privacy_Calls_P2PHelp: String { return self._s[3505]! } + public var Channel_DiscussionGroup_SearchPlaceholder: String { return self._s[3507]! } + public var Your_cards_expiration_year_is_invalid: String { return self._s[3508]! } + public var Common_TakePhotoOrVideo: String { return self._s[3509]! } + public var Wallet_Words_Text: String { return self._s[3510]! } + public var Call_StatusBusy: String { return self._s[3511]! } + public var Conversation_PinnedMessage: String { return self._s[3512]! } + public var AutoDownloadSettings_VoiceMessagesTitle: String { return self._s[3513]! } + public var Wallet_Configuration_BlockchainNameChangedProceed: String { return self._s[3514]! } + public var TwoStepAuth_SetupPasswordConfirmFailed: String { return self._s[3515]! } + public var Undo_ChatCleared: String { return self._s[3516]! } + public var AppleWatch_ReplyPresets: String { return self._s[3517]! } + public var Passport_DiscardMessageDescription: String { return self._s[3519]! } + public var Login_NetworkError: String { return self._s[3520]! } public func Notification_PinnedRoundMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3517]!, self._r[3517]!, [_0]) + return formatWithArgumentRanges(self._s[3521]!, self._r[3521]!, [_0]) } public func Channel_AdminLog_MessageRemovedChannelUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3518]!, self._r[3518]!, [_0]) + return formatWithArgumentRanges(self._s[3522]!, self._r[3522]!, [_0]) } - public var SocksProxySetup_PasswordPlaceholder: String { return self._s[3519]! } - public var Wallet_WordCheck_ViewWords: String { return self._s[3521]! } - public var Login_ResetAccountProtected_LimitExceeded: String { return self._s[3522]! } + public var SocksProxySetup_PasswordPlaceholder: String { return self._s[3523]! } + public var Wallet_WordCheck_ViewWords: String { return self._s[3525]! } + public var Login_ResetAccountProtected_LimitExceeded: String { return self._s[3526]! } public func Watch_LastSeen_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3524]!, self._r[3524]!, [_0]) + return formatWithArgumentRanges(self._s[3528]!, self._r[3528]!, [_0]) } - public var Call_ConnectionErrorMessage: String { return self._s[3525]! } - public var VoiceOver_Chat_Music: String { return self._s[3526]! } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsSound: String { return self._s[3527]! } - public var Compose_GroupTokenListPlaceholder: String { return self._s[3529]! } - public var ConversationMedia_Title: String { return self._s[3530]! } - public var EncryptionKey_Title: String { return self._s[3532]! } - public var TwoStepAuth_EnterPasswordTitle: String { return self._s[3533]! } - public var Notification_Exceptions_AddException: String { return self._s[3534]! } - public var PrivacySettings_BlockedPeersEmpty: String { return self._s[3535]! } - public var Profile_MessageLifetime1m: String { return self._s[3536]! } + public var Call_ConnectionErrorMessage: String { return self._s[3529]! } + public var VoiceOver_Chat_Music: String { return self._s[3530]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsSound: String { return self._s[3531]! } + public var Compose_GroupTokenListPlaceholder: String { return self._s[3533]! } + public var ConversationMedia_Title: String { return self._s[3534]! } + public var EncryptionKey_Title: String { return self._s[3536]! } + public var TwoStepAuth_EnterPasswordTitle: String { return self._s[3537]! } + public var Notification_Exceptions_AddException: String { return self._s[3538]! } + public var PrivacySettings_BlockedPeersEmpty: String { return self._s[3539]! } + public var Profile_MessageLifetime1m: String { return self._s[3540]! } public func Channel_AdminLog_MessageUnkickedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3537]!, self._r[3537]!, [_1]) + return formatWithArgumentRanges(self._s[3541]!, self._r[3541]!, [_1]) } - public var Month_GenMay: String { return self._s[3538]! } + public var Month_GenMay: String { return self._s[3542]! } public func LiveLocationUpdated_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3539]!, self._r[3539]!, [_0]) + return formatWithArgumentRanges(self._s[3543]!, self._r[3543]!, [_0]) } - public var PeopleNearby_Users: String { return self._s[3540]! } - public var Wallet_Send_AddressInfo: String { return self._s[3541]! } - public var ChannelMembers_WhoCanAddMembersAllHelp: String { return self._s[3542]! } - public var AutoDownloadSettings_ResetSettings: String { return self._s[3543]! } + public var PeopleNearby_Users: String { return self._s[3544]! } + public var Wallet_Send_AddressInfo: String { return self._s[3545]! } + public var ChannelMembers_WhoCanAddMembersAllHelp: String { return self._s[3546]! } + public var AutoDownloadSettings_ResetSettings: String { return self._s[3547]! } public func Wallet_Updated_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3545]!, self._r[3545]!, [_0]) + return formatWithArgumentRanges(self._s[3549]!, self._r[3549]!, [_0]) } - public var Conversation_EmptyPlaceholder: String { return self._s[3546]! } - public var Passport_Address_AddPassportRegistration: String { return self._s[3547]! } - public var Notifications_ChannelNotificationsAlert: String { return self._s[3548]! } - public var ChatSettings_AutoDownloadUsingCellular: String { return self._s[3549]! } - public var Camera_TapAndHoldForVideo: String { return self._s[3550]! } - public var Channel_JoinChannel: String { return self._s[3552]! } - public var Appearance_Animations: String { return self._s[3555]! } + public var Conversation_EmptyPlaceholder: String { return self._s[3550]! } + public var Passport_Address_AddPassportRegistration: String { return self._s[3551]! } + public var Notifications_ChannelNotificationsAlert: String { return self._s[3552]! } + public var ChatSettings_AutoDownloadUsingCellular: String { return self._s[3553]! } + public var Camera_TapAndHoldForVideo: String { return self._s[3554]! } + public var Channel_JoinChannel: String { return self._s[3556]! } + public var Appearance_Animations: String { return self._s[3559]! } public func Notification_MessageLifetimeChanged(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3556]!, self._r[3556]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3560]!, self._r[3560]!, [_1, _2]) } - public var Stickers_GroupStickers: String { return self._s[3558]! } - public var Appearance_ShareTheme: String { return self._s[3559]! } - public var TwoFactorSetup_Hint_Placeholder: String { return self._s[3560]! } - public var ConvertToSupergroup_HelpTitle: String { return self._s[3562]! } - public var StickerPackActionInfo_RemovedTitle: String { return self._s[3563]! } - public var Passport_Address_Street: String { return self._s[3564]! } - public var Conversation_AddContact: String { return self._s[3565]! } - public var Login_PhonePlaceholder: String { return self._s[3566]! } - public var Channel_Members_InviteLink: String { return self._s[3568]! } - public var Bot_Stop: String { return self._s[3569]! } - public var SettingsSearch_Synonyms_Proxy_UseForCalls: String { return self._s[3571]! } - public var Notification_PassportValueAddress: String { return self._s[3572]! } - public var Month_ShortJuly: String { return self._s[3573]! } - public var Passport_Address_TypeTemporaryRegistrationUploadScan: String { return self._s[3574]! } - public var Channel_AdminLog_BanSendMedia: String { return self._s[3575]! } - public var Passport_Identity_ReverseSide: String { return self._s[3576]! } - public var Watch_Stickers_Recents: String { return self._s[3579]! } - public var PrivacyLastSeenSettings_EmpryUsersPlaceholder: String { return self._s[3581]! } - public var Map_SendThisLocation: String { return self._s[3582]! } + public var Stickers_GroupStickers: String { return self._s[3562]! } + public var Appearance_ShareTheme: String { return self._s[3563]! } + public var TwoFactorSetup_Hint_Placeholder: String { return self._s[3564]! } + public var ConvertToSupergroup_HelpTitle: String { return self._s[3566]! } + public var StickerPackActionInfo_RemovedTitle: String { return self._s[3567]! } + public var Passport_Address_Street: String { return self._s[3568]! } + public var Conversation_AddContact: String { return self._s[3569]! } + public var Login_PhonePlaceholder: String { return self._s[3570]! } + public var Channel_Members_InviteLink: String { return self._s[3572]! } + public var Bot_Stop: String { return self._s[3573]! } + public var SettingsSearch_Synonyms_Proxy_UseForCalls: String { return self._s[3575]! } + public var Notification_PassportValueAddress: String { return self._s[3576]! } + public var Month_ShortJuly: String { return self._s[3577]! } + public var Passport_Address_TypeTemporaryRegistrationUploadScan: String { return self._s[3578]! } + public var Channel_AdminLog_BanSendMedia: String { return self._s[3579]! } + public var Passport_Identity_ReverseSide: String { return self._s[3580]! } + public var Watch_Stickers_Recents: String { return self._s[3583]! } + public var PrivacyLastSeenSettings_EmpryUsersPlaceholder: String { return self._s[3585]! } + public var Map_SendThisLocation: String { return self._s[3586]! } public func Time_MonthOfYear_m1(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3583]!, self._r[3583]!, [_0]) - } - public func InviteText_SingleContact(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3584]!, self._r[3584]!, [_0]) - } - public var ConvertToSupergroup_Note: String { return self._s[3585]! } - public var Wallet_Intro_NotNow: String { return self._s[3586]! } - public func FileSize_MB(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3587]!, self._r[3587]!, [_0]) } - public var NetworkUsageSettings_GeneralDataSection: String { return self._s[3588]! } + public func InviteText_SingleContact(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3588]!, self._r[3588]!, [_0]) + } + public var ConvertToSupergroup_Note: String { return self._s[3589]! } + public var Wallet_Intro_NotNow: String { return self._s[3590]! } + public func FileSize_MB(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3591]!, self._r[3591]!, [_0]) + } + public var NetworkUsageSettings_GeneralDataSection: String { return self._s[3592]! } public func Compatibility_SecretMediaVersionTooLow(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3589]!, self._r[3589]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3593]!, self._r[3593]!, [_0, _1]) } - public var Login_CallRequestState3: String { return self._s[3591]! } - public var Wallpaper_SearchShort: String { return self._s[3592]! } - public var SettingsSearch_Synonyms_Appearance_ColorTheme: String { return self._s[3594]! } - public var PasscodeSettings_UnlockWithFaceId: String { return self._s[3595]! } - public var Channel_BotDoesntSupportGroups: String { return self._s[3596]! } + public var Login_CallRequestState3: String { return self._s[3595]! } + public var Wallpaper_SearchShort: String { return self._s[3596]! } + public var SettingsSearch_Synonyms_Appearance_ColorTheme: String { return self._s[3598]! } + public var PasscodeSettings_UnlockWithFaceId: String { return self._s[3599]! } + public var Channel_BotDoesntSupportGroups: String { return self._s[3600]! } public func PUSH_CHAT_MESSAGE_GEOLIVE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3597]!, self._r[3597]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3601]!, self._r[3601]!, [_1, _2]) } - public var Channel_AdminLogFilter_Title: String { return self._s[3598]! } - public var Appearance_ThemePreview_Chat_4_Text: String { return self._s[3600]! } - public var Notifications_GroupNotificationsExceptions: String { return self._s[3603]! } + public var Channel_AdminLogFilter_Title: String { return self._s[3602]! } + public var Appearance_ThemePreview_Chat_4_Text: String { return self._s[3604]! } + public var Notifications_GroupNotificationsExceptions: String { return self._s[3607]! } public func FileSize_B(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3604]!, self._r[3604]!, [_0]) + return formatWithArgumentRanges(self._s[3608]!, self._r[3608]!, [_0]) } - public var Passport_CorrectErrors: String { return self._s[3605]! } - public var VoiceOver_Chat_YourAnonymousPoll: String { return self._s[3606]! } + public var Passport_CorrectErrors: String { return self._s[3609]! } + public var VoiceOver_Chat_YourAnonymousPoll: String { return self._s[3610]! } public func Channel_MessageTitleUpdated(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3607]!, self._r[3607]!, [_0]) + return formatWithArgumentRanges(self._s[3611]!, self._r[3611]!, [_0]) } - public var Map_SendMyCurrentLocation: String { return self._s[3608]! } - public var Channel_DiscussionGroup: String { return self._s[3609]! } - public var TwoFactorSetup_Email_SkipConfirmationSkip: String { return self._s[3610]! } + public var Map_SendMyCurrentLocation: String { return self._s[3612]! } + public var Channel_DiscussionGroup: String { return self._s[3613]! } + public var TwoFactorSetup_Email_SkipConfirmationSkip: String { return self._s[3614]! } public func PUSH_PINNED_CONTACT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3611]!, self._r[3611]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3615]!, self._r[3615]!, [_1, _2]) } - public var SharedMedia_SearchNoResults: String { return self._s[3612]! } - public var Permissions_NotificationsText_v0: String { return self._s[3613]! } - public var Channel_EditAdmin_PermissionDeleteMessagesOfOthers: String { return self._s[3614]! } - public var Appearance_AppIcon: String { return self._s[3615]! } - public var Appearance_ThemePreview_ChatList_3_AuthorName: String { return self._s[3616]! } - public var LoginPassword_FloodError: String { return self._s[3617]! } - public var Wallet_Send_OwnAddressAlertProceed: String { return self._s[3619]! } - public var Group_Setup_HistoryHiddenHelp: String { return self._s[3620]! } + public var SharedMedia_SearchNoResults: String { return self._s[3616]! } + public var Permissions_NotificationsText_v0: String { return self._s[3617]! } + public var Channel_EditAdmin_PermissionDeleteMessagesOfOthers: String { return self._s[3618]! } + public var Appearance_AppIcon: String { return self._s[3619]! } + public var Appearance_ThemePreview_ChatList_3_AuthorName: String { return self._s[3620]! } + public var LoginPassword_FloodError: String { return self._s[3621]! } + public var Wallet_Send_OwnAddressAlertProceed: String { return self._s[3623]! } + public var Group_Setup_HistoryHiddenHelp: String { return self._s[3624]! } public func TwoStepAuth_PendingEmailHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3621]!, self._r[3621]!, [_0]) - } - public var Passport_Language_bn: String { return self._s[3622]! } - public func DialogList_SingleUploadingPhotoSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3623]!, self._r[3623]!, [_0]) - } - public var ChatList_Context_Pin: String { return self._s[3624]! } - public func Notification_PinnedAudioMessage(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3625]!, self._r[3625]!, [_0]) } + public var Passport_Language_bn: String { return self._s[3626]! } + public func DialogList_SingleUploadingPhotoSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3627]!, self._r[3627]!, [_0]) + } + public var ChatList_Context_Pin: String { return self._s[3628]! } + public func Notification_PinnedAudioMessage(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3629]!, self._r[3629]!, [_0]) + } public func Channel_AdminLog_MessageChangedGroupStickerPack(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3626]!, self._r[3626]!, [_0]) + return formatWithArgumentRanges(self._s[3630]!, self._r[3630]!, [_0]) } - public var Wallet_Navigation_Close: String { return self._s[3627]! } - public var GroupInfo_InvitationLinkGroupFull: String { return self._s[3631]! } - public var Group_EditAdmin_PermissionChangeInfo: String { return self._s[3633]! } - public var Wallet_Month_GenDecember: String { return self._s[3634]! } - public var Contacts_PermissionsAllow: String { return self._s[3635]! } - public var ReportPeer_ReasonCopyright: String { return self._s[3636]! } - public var Channel_EditAdmin_PermissinAddAdminOn: String { return self._s[3637]! } - public var WallpaperPreview_Pattern: String { return self._s[3638]! } - public var Paint_Duplicate: String { return self._s[3639]! } - public var Passport_Address_Country: String { return self._s[3640]! } - public var Notification_RenamedChannel: String { return self._s[3642]! } - public var ChatList_Context_Unmute: String { return self._s[3643]! } - public var CheckoutInfo_ErrorPostcodeInvalid: String { return self._s[3644]! } - public var Group_MessagePhotoUpdated: String { return self._s[3645]! } - public var Channel_BanUser_PermissionSendMedia: String { return self._s[3646]! } - public var Conversation_ContextMenuBan: String { return self._s[3647]! } - public var TwoStepAuth_EmailSent: String { return self._s[3648]! } - public var MessagePoll_NoVotes: String { return self._s[3649]! } - public var Wallet_Send_ErrorNotEnoughFundsTitle: String { return self._s[3650]! } - public var Passport_Language_is: String { return self._s[3652]! } - public var PeopleNearby_UsersEmpty: String { return self._s[3654]! } - public var Tour_Text5: String { return self._s[3655]! } + public var Wallet_Navigation_Close: String { return self._s[3631]! } + public var GroupInfo_InvitationLinkGroupFull: String { return self._s[3635]! } + public var Group_EditAdmin_PermissionChangeInfo: String { return self._s[3637]! } + public var Wallet_Month_GenDecember: String { return self._s[3638]! } + public var Contacts_PermissionsAllow: String { return self._s[3639]! } + public var ReportPeer_ReasonCopyright: String { return self._s[3640]! } + public var Channel_EditAdmin_PermissinAddAdminOn: String { return self._s[3641]! } + public var WallpaperPreview_Pattern: String { return self._s[3642]! } + public var Paint_Duplicate: String { return self._s[3643]! } + public var Passport_Address_Country: String { return self._s[3644]! } + public var Notification_RenamedChannel: String { return self._s[3646]! } + public var ChatList_Context_Unmute: String { return self._s[3647]! } + public var CheckoutInfo_ErrorPostcodeInvalid: String { return self._s[3648]! } + public var Group_MessagePhotoUpdated: String { return self._s[3649]! } + public var Channel_BanUser_PermissionSendMedia: String { return self._s[3650]! } + public var Conversation_ContextMenuBan: String { return self._s[3651]! } + public var TwoStepAuth_EmailSent: String { return self._s[3652]! } + public var MessagePoll_NoVotes: String { return self._s[3653]! } + public var Wallet_Send_ErrorNotEnoughFundsTitle: String { return self._s[3654]! } + public var Passport_Language_is: String { return self._s[3656]! } + public var PeopleNearby_UsersEmpty: String { return self._s[3658]! } + public var Tour_Text5: String { return self._s[3659]! } public func Call_GroupFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3658]!, self._r[3658]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3662]!, self._r[3662]!, [_1, _2]) } - public var Undo_SecretChatDeleted: String { return self._s[3659]! } - public var SocksProxySetup_ShareQRCode: String { return self._s[3660]! } + public var Undo_SecretChatDeleted: String { return self._s[3663]! } + public var SocksProxySetup_ShareQRCode: String { return self._s[3664]! } public func VoiceOver_Chat_Size(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3661]!, self._r[3661]!, [_0]) + return formatWithArgumentRanges(self._s[3665]!, self._r[3665]!, [_0]) } - public var Forward_ErrorDisabledForChat: String { return self._s[3662]! } - public var LogoutOptions_ChangePhoneNumberText: String { return self._s[3663]! } - public var Paint_Edit: String { return self._s[3665]! } - public var ScheduledMessages_ReminderNotification: String { return self._s[3667]! } - public var Undo_DeletedGroup: String { return self._s[3669]! } - public var LoginPassword_ForgotPassword: String { return self._s[3670]! } - public var Wallet_WordImport_IncorrectTitle: String { return self._s[3671]! } - public var GroupInfo_GroupNamePlaceholder: String { return self._s[3672]! } + public var Forward_ErrorDisabledForChat: String { return self._s[3666]! } + public var LogoutOptions_ChangePhoneNumberText: String { return self._s[3667]! } + public var Paint_Edit: String { return self._s[3669]! } + public var ScheduledMessages_ReminderNotification: String { return self._s[3671]! } + public var Undo_DeletedGroup: String { return self._s[3673]! } + public var LoginPassword_ForgotPassword: String { return self._s[3674]! } + public var Wallet_WordImport_IncorrectTitle: String { return self._s[3675]! } + public var GroupInfo_GroupNamePlaceholder: String { return self._s[3676]! } public func Notification_Kicked(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3673]!, self._r[3673]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3677]!, self._r[3677]!, [_0, _1]) } - public var AppWallet_TransactionInfo_FeeInfoURL: String { return self._s[3674]! } - public var Conversation_InputTextCaptionPlaceholder: String { return self._s[3675]! } - public var AutoDownloadSettings_VideoMessagesTitle: String { return self._s[3676]! } - public var Passport_Language_uz: String { return self._s[3677]! } - public var Conversation_PinMessageAlertGroup: String { return self._s[3678]! } - public var SettingsSearch_Synonyms_Privacy_GroupsAndChannels: String { return self._s[3679]! } - public var Map_StopLiveLocation: String { return self._s[3681]! } - public var VoiceOver_MessageContextSend: String { return self._s[3683]! } - public var PasscodeSettings_Help: String { return self._s[3684]! } - public var NotificationsSound_Input: String { return self._s[3685]! } - public var Share_Title: String { return self._s[3688]! } - public var LogoutOptions_Title: String { return self._s[3689]! } - public var Wallet_Send_AddressText: String { return self._s[3690]! } - public var Login_TermsOfServiceAgree: String { return self._s[3691]! } - public var Compose_NewEncryptedChatTitle: String { return self._s[3692]! } - public var Channel_AdminLog_TitleSelectedEvents: String { return self._s[3693]! } - public var Channel_EditAdmin_PermissionEditMessages: String { return self._s[3694]! } - public var EnterPasscode_EnterTitle: String { return self._s[3695]! } + public var AppWallet_TransactionInfo_FeeInfoURL: String { return self._s[3678]! } + public var Conversation_InputTextCaptionPlaceholder: String { return self._s[3679]! } + public var AutoDownloadSettings_VideoMessagesTitle: String { return self._s[3680]! } + public var Passport_Language_uz: String { return self._s[3681]! } + public var Conversation_PinMessageAlertGroup: String { return self._s[3682]! } + public var SettingsSearch_Synonyms_Privacy_GroupsAndChannels: String { return self._s[3683]! } + public var Map_StopLiveLocation: String { return self._s[3685]! } + public var VoiceOver_MessageContextSend: String { return self._s[3687]! } + public var PasscodeSettings_Help: String { return self._s[3688]! } + public var NotificationsSound_Input: String { return self._s[3689]! } + public var Share_Title: String { return self._s[3692]! } + public var LogoutOptions_Title: String { return self._s[3693]! } + public var Wallet_Send_AddressText: String { return self._s[3694]! } + public var Login_TermsOfServiceAgree: String { return self._s[3695]! } + public var Compose_NewEncryptedChatTitle: String { return self._s[3696]! } + public var Channel_AdminLog_TitleSelectedEvents: String { return self._s[3697]! } + public var Channel_EditAdmin_PermissionEditMessages: String { return self._s[3698]! } + public var EnterPasscode_EnterTitle: String { return self._s[3699]! } public func Call_PrivacyErrorMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3696]!, self._r[3696]!, [_0]) + return formatWithArgumentRanges(self._s[3700]!, self._r[3700]!, [_0]) } - public var Settings_CopyPhoneNumber: String { return self._s[3697]! } - public var Conversation_AddToContacts: String { return self._s[3698]! } + public var Settings_CopyPhoneNumber: String { return self._s[3701]! } + public var Conversation_AddToContacts: String { return self._s[3702]! } public func VoiceOver_Chat_ReplyFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3699]!, self._r[3699]!, [_0]) + return formatWithArgumentRanges(self._s[3703]!, self._r[3703]!, [_0]) } - public var NotificationsSound_Keys: String { return self._s[3700]! } + public var NotificationsSound_Keys: String { return self._s[3704]! } public func Call_ParticipantVersionOutdatedError(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3701]!, self._r[3701]!, [_0]) + return formatWithArgumentRanges(self._s[3705]!, self._r[3705]!, [_0]) } - public var Notification_MessageLifetime1w: String { return self._s[3702]! } - public var Message_Video: String { return self._s[3703]! } - public var AutoDownloadSettings_CellularTitle: String { return self._s[3704]! } + public var Notification_MessageLifetime1w: String { return self._s[3706]! } + public var Message_Video: String { return self._s[3707]! } + public var AutoDownloadSettings_CellularTitle: String { return self._s[3708]! } public func PUSH_CHANNEL_MESSAGE_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3705]!, self._r[3705]!, [_1]) + return formatWithArgumentRanges(self._s[3709]!, self._r[3709]!, [_1]) } - public var Wallet_Receive_AmountInfo: String { return self._s[3708]! } + public var Wallet_Receive_AmountInfo: String { return self._s[3712]! } public func Notification_JoinedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3709]!, self._r[3709]!, [_0]) + return formatWithArgumentRanges(self._s[3713]!, self._r[3713]!, [_0]) } public func PrivacySettings_LastSeenContactsPlus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3710]!, self._r[3710]!, [_0]) + return formatWithArgumentRanges(self._s[3714]!, self._r[3714]!, [_0]) } - public var Passport_Language_mk: String { return self._s[3711]! } + public var Passport_Language_mk: String { return self._s[3715]! } public func Wallet_Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3712]!, self._r[3712]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3716]!, self._r[3716]!, [_1, _2, _3]) } - public var CreatePoll_CancelConfirmation: String { return self._s[3713]! } - public var MessagePoll_LabelAnonymousQuiz: String { return self._s[3714]! } - public var Conversation_SilentBroadcastTooltipOn: String { return self._s[3716]! } - public var PrivacyPolicy_Decline: String { return self._s[3717]! } - public var Passport_Identity_DoesNotExpire: String { return self._s[3718]! } - public var Channel_AdminLogFilter_EventsRestrictions: String { return self._s[3719]! } - public var AuthSessions_AddDeviceIntro_Action: String { return self._s[3720]! } - public var Permissions_SiriAllow_v0: String { return self._s[3722]! } - public var Wallet_Month_ShortAugust: String { return self._s[3723]! } - public var Appearance_ThemeCarouselNight: String { return self._s[3724]! } + public var CreatePoll_CancelConfirmation: String { return self._s[3717]! } + public var MessagePoll_LabelAnonymousQuiz: String { return self._s[3718]! } + public var Conversation_SilentBroadcastTooltipOn: String { return self._s[3720]! } + public var PrivacyPolicy_Decline: String { return self._s[3721]! } + public var Passport_Identity_DoesNotExpire: String { return self._s[3722]! } + public var Channel_AdminLogFilter_EventsRestrictions: String { return self._s[3723]! } + public var AuthSessions_AddDeviceIntro_Action: String { return self._s[3724]! } + public var Permissions_SiriAllow_v0: String { return self._s[3726]! } + public var Wallet_Month_ShortAugust: String { return self._s[3727]! } + public var Appearance_ThemeCarouselNight: String { return self._s[3728]! } public func LOCAL_CHAT_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3725]!, self._r[3725]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[3729]!, self._r[3729]!, [_1, "\(_2)"]) } public func Notification_RenamedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3726]!, self._r[3726]!, [_0]) + return formatWithArgumentRanges(self._s[3730]!, self._r[3730]!, [_0]) } - public var Paint_Regular: String { return self._s[3727]! } - public var ChatSettings_AutoDownloadReset: String { return self._s[3728]! } - public var SocksProxySetup_ShareLink: String { return self._s[3729]! } - public var Wallet_Qr_Title: String { return self._s[3730]! } - public var BlockedUsers_SelectUserTitle: String { return self._s[3731]! } - public var VoiceOver_Chat_RecordModeVoiceMessage: String { return self._s[3733]! } - public var Wallet_Settings_Configuration: String { return self._s[3734]! } - public var GroupInfo_InviteByLink: String { return self._s[3735]! } - public var MessageTimer_Custom: String { return self._s[3736]! } - public var UserInfo_NotificationsDefaultEnabled: String { return self._s[3737]! } - public var Conversation_StopQuizConfirmationTitle: String { return self._s[3738]! } - public var Passport_Address_TypeTemporaryRegistration: String { return self._s[3740]! } - public var Conversation_SendMessage_SetReminder: String { return self._s[3741]! } - public var VoiceOver_Chat_Selected: String { return self._s[3742]! } - public var ChatSettings_AutoDownloadUsingWiFi: String { return self._s[3743]! } - public var Channel_Username_InvalidTaken: String { return self._s[3744]! } - public var Conversation_ClousStorageInfo_Description3: String { return self._s[3745]! } - public var Wallet_WordCheck_TryAgain: String { return self._s[3746]! } - public var Wallet_Info_TransactionPendingHeader: String { return self._s[3747]! } - public var Settings_ChatBackground: String { return self._s[3748]! } - public var Channel_Subscribers_Title: String { return self._s[3749]! } - public var Wallet_Receive_InvoiceUrlHeader: String { return self._s[3750]! } - public var ApplyLanguage_ChangeLanguageTitle: String { return self._s[3751]! } - public var Watch_ConnectionDescription: String { return self._s[3752]! } - public var OldChannels_NoticeText: String { return self._s[3755]! } - public var Wallet_Configuration_ApplyErrorTitle: String { return self._s[3756]! } - public var IntentsSettings_SuggestBy: String { return self._s[3758]! } - public var Theme_ThemeChangedText: String { return self._s[3759]! } - public var ChatList_ArchivedChatsTitle: String { return self._s[3760]! } - public var Wallpaper_ResetWallpapers: String { return self._s[3761]! } - public var Wallet_Send_TransactionInProgress: String { return self._s[3762]! } - public var EditProfile_Title: String { return self._s[3763]! } - public var NotificationsSound_Bamboo: String { return self._s[3765]! } - public var Channel_AdminLog_MessagePreviousMessage: String { return self._s[3767]! } - public var Login_SmsRequestState2: String { return self._s[3768]! } - public var Passport_Language_ar: String { return self._s[3769]! } + public var Paint_Regular: String { return self._s[3731]! } + public var ChatSettings_AutoDownloadReset: String { return self._s[3732]! } + public var SocksProxySetup_ShareLink: String { return self._s[3733]! } + public var Wallet_Qr_Title: String { return self._s[3734]! } + public var BlockedUsers_SelectUserTitle: String { return self._s[3735]! } + public var VoiceOver_Chat_RecordModeVoiceMessage: String { return self._s[3737]! } + public var Wallet_Settings_Configuration: String { return self._s[3738]! } + public var GroupInfo_InviteByLink: String { return self._s[3739]! } + public var MessageTimer_Custom: String { return self._s[3740]! } + public var UserInfo_NotificationsDefaultEnabled: String { return self._s[3741]! } + public var Conversation_StopQuizConfirmationTitle: String { return self._s[3742]! } + public var Passport_Address_TypeTemporaryRegistration: String { return self._s[3744]! } + public var Conversation_SendMessage_SetReminder: String { return self._s[3745]! } + public var VoiceOver_Chat_Selected: String { return self._s[3746]! } + public var ChatSettings_AutoDownloadUsingWiFi: String { return self._s[3747]! } + public var Channel_Username_InvalidTaken: String { return self._s[3748]! } + public var Conversation_ClousStorageInfo_Description3: String { return self._s[3749]! } + public var Wallet_WordCheck_TryAgain: String { return self._s[3750]! } + public var Wallet_Info_TransactionPendingHeader: String { return self._s[3751]! } + public var Settings_ChatBackground: String { return self._s[3752]! } + public var Channel_Subscribers_Title: String { return self._s[3753]! } + public var Wallet_Receive_InvoiceUrlHeader: String { return self._s[3754]! } + public var ApplyLanguage_ChangeLanguageTitle: String { return self._s[3755]! } + public var Watch_ConnectionDescription: String { return self._s[3756]! } + public var OldChannels_NoticeText: String { return self._s[3759]! } + public var Wallet_Configuration_ApplyErrorTitle: String { return self._s[3760]! } + public var IntentsSettings_SuggestBy: String { return self._s[3762]! } + public var Theme_ThemeChangedText: String { return self._s[3763]! } + public var ChatList_ArchivedChatsTitle: String { return self._s[3764]! } + public var Wallpaper_ResetWallpapers: String { return self._s[3765]! } + public var Wallet_Send_TransactionInProgress: String { return self._s[3766]! } + public var EditProfile_Title: String { return self._s[3767]! } + public var NotificationsSound_Bamboo: String { return self._s[3769]! } + public var Channel_AdminLog_MessagePreviousMessage: String { return self._s[3771]! } + public var Login_SmsRequestState2: String { return self._s[3772]! } + public var Passport_Language_ar: String { return self._s[3773]! } public func Message_AuthorPinnedGame(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3770]!, self._r[3770]!, [_0]) + return formatWithArgumentRanges(self._s[3774]!, self._r[3774]!, [_0]) } - public var SettingsSearch_Synonyms_EditProfile_Title: String { return self._s[3771]! } - public var Wallet_Created_Text: String { return self._s[3772]! } - public var Conversation_MessageDialogEdit: String { return self._s[3774]! } - public var Wallet_Created_Proceed: String { return self._s[3775]! } - public var Wallet_Words_Done: String { return self._s[3776]! } - public var VoiceOver_Media_PlaybackPause: String { return self._s[3777]! } + public var SettingsSearch_Synonyms_EditProfile_Title: String { return self._s[3775]! } + public var Wallet_Created_Text: String { return self._s[3776]! } + public var Conversation_MessageDialogEdit: String { return self._s[3778]! } + public var Wallet_Created_Proceed: String { return self._s[3779]! } + public var Wallet_Words_Done: String { return self._s[3780]! } + public var VoiceOver_Media_PlaybackPause: String { return self._s[3781]! } public func PUSH_AUTH_UNKNOWN(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3778]!, self._r[3778]!, [_1]) + return formatWithArgumentRanges(self._s[3782]!, self._r[3782]!, [_1]) } - public var Common_Close: String { return self._s[3779]! } - public var GroupInfo_PublicLink: String { return self._s[3780]! } - public var Channel_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[3781]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsPreview: String { return self._s[3782]! } + public var Common_Close: String { return self._s[3783]! } + public var GroupInfo_PublicLink: String { return self._s[3784]! } + public var Channel_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[3785]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsPreview: String { return self._s[3786]! } public func Channel_AdminLog_MessageToggleInvitesOff(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3786]!, self._r[3786]!, [_0]) + return formatWithArgumentRanges(self._s[3790]!, self._r[3790]!, [_0]) } - public var UserInfo_About_Placeholder: String { return self._s[3787]! } + public var UserInfo_About_Placeholder: String { return self._s[3791]! } public func Conversation_FileHowToText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3788]!, self._r[3788]!, [_0]) - } - public var GroupInfo_Permissions_SectionTitle: String { return self._s[3789]! } - public var Channel_Info_Banned: String { return self._s[3791]! } - public func Time_MonthOfYear_m11(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3792]!, self._r[3792]!, [_0]) } - public var Appearance_Other: String { return self._s[3793]! } - public var Passport_Language_my: String { return self._s[3794]! } - public var Group_Setup_BasicHistoryHiddenHelp: String { return self._s[3795]! } + public var GroupInfo_Permissions_SectionTitle: String { return self._s[3793]! } + public var Channel_Info_Banned: String { return self._s[3795]! } + public func Time_MonthOfYear_m11(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3796]!, self._r[3796]!, [_0]) + } + public var Appearance_Other: String { return self._s[3797]! } + public var Passport_Language_my: String { return self._s[3798]! } + public var Group_Setup_BasicHistoryHiddenHelp: String { return self._s[3799]! } public func Time_PreciseDate_m9(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3796]!, self._r[3796]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3800]!, self._r[3800]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Privacy_PasscodeAndFaceId: String { return self._s[3797]! } - public var IntentsSettings_SuggestedAndSpotlightChatsInfo: String { return self._s[3798]! } - public var Preview_CopyAddress: String { return self._s[3799]! } + public var SettingsSearch_Synonyms_Privacy_PasscodeAndFaceId: String { return self._s[3801]! } + public var IntentsSettings_SuggestedAndSpotlightChatsInfo: String { return self._s[3802]! } + public var Preview_CopyAddress: String { return self._s[3803]! } public func DialogList_SinglePlayingGameSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3800]!, self._r[3800]!, [_0]) + return formatWithArgumentRanges(self._s[3804]!, self._r[3804]!, [_0]) } - public var KeyCommand_JumpToPreviousChat: String { return self._s[3801]! } - public var UserInfo_BotSettings: String { return self._s[3802]! } - public var LiveLocation_MenuStopAll: String { return self._s[3804]! } - public var Passport_PasswordCreate: String { return self._s[3805]! } - public var StickerSettings_MaskContextInfo: String { return self._s[3806]! } - public var Message_PinnedLocationMessage: String { return self._s[3807]! } - public var Map_Satellite: String { return self._s[3808]! } - public var Watch_Message_Unsupported: String { return self._s[3809]! } - public var Username_TooManyPublicUsernamesError: String { return self._s[3810]! } - public var TwoStepAuth_EnterPasswordInvalid: String { return self._s[3811]! } + public var KeyCommand_JumpToPreviousChat: String { return self._s[3805]! } + public var UserInfo_BotSettings: String { return self._s[3806]! } + public var LiveLocation_MenuStopAll: String { return self._s[3808]! } + public var Passport_PasswordCreate: String { return self._s[3809]! } + public var StickerSettings_MaskContextInfo: String { return self._s[3810]! } + public var Message_PinnedLocationMessage: String { return self._s[3811]! } + public var Map_Satellite: String { return self._s[3812]! } + public var Watch_Message_Unsupported: String { return self._s[3813]! } + public var Username_TooManyPublicUsernamesError: String { return self._s[3814]! } + public var TwoStepAuth_EnterPasswordInvalid: String { return self._s[3815]! } public func Notification_PinnedTextMessage(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3812]!, self._r[3812]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3816]!, self._r[3816]!, [_0, _1]) } public func Conversation_OpenBotLinkText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3813]!, self._r[3813]!, [_0]) + return formatWithArgumentRanges(self._s[3817]!, self._r[3817]!, [_0]) } - public var Wallet_WordImport_Continue: String { return self._s[3814]! } + public var Wallet_WordImport_Continue: String { return self._s[3818]! } public func TwoFactorSetup_EmailVerification_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3815]!, self._r[3815]!, [_0]) + return formatWithArgumentRanges(self._s[3819]!, self._r[3819]!, [_0]) } - public var Notifications_ChannelNotificationsHelp: String { return self._s[3816]! } - public var Privacy_Calls_P2PContacts: String { return self._s[3817]! } - public var NotificationsSound_None: String { return self._s[3818]! } - public var Wallet_TransactionInfo_StorageFeeHeader: String { return self._s[3819]! } - public var Channel_DiscussionGroup_UnlinkGroup: String { return self._s[3821]! } - public var AccessDenied_VoiceMicrophone: String { return self._s[3822]! } + public var Notifications_ChannelNotificationsHelp: String { return self._s[3820]! } + public var Privacy_Calls_P2PContacts: String { return self._s[3821]! } + public var NotificationsSound_None: String { return self._s[3822]! } + public var Wallet_TransactionInfo_StorageFeeHeader: String { return self._s[3823]! } + public var Channel_DiscussionGroup_UnlinkGroup: String { return self._s[3825]! } + public var AccessDenied_VoiceMicrophone: String { return self._s[3826]! } public func ApplyLanguage_ChangeLanguageAlreadyActive(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3823]!, self._r[3823]!, [_1]) + return formatWithArgumentRanges(self._s[3827]!, self._r[3827]!, [_1]) } - public var Cache_Indexing: String { return self._s[3824]! } - public var DialogList_RecentTitlePeople: String { return self._s[3826]! } - public var DialogList_EncryptionRejected: String { return self._s[3827]! } - public var GroupInfo_Administrators: String { return self._s[3828]! } - public var Passport_ScanPassportHelp: String { return self._s[3829]! } - public var Application_Name: String { return self._s[3830]! } - public var Channel_AdminLogFilter_ChannelEventsInfo: String { return self._s[3831]! } - public var Appearance_ThemeCarouselDay: String { return self._s[3833]! } - public var Passport_Identity_TranslationHelp: String { return self._s[3834]! } + public var Cache_Indexing: String { return self._s[3828]! } + public var DialogList_RecentTitlePeople: String { return self._s[3830]! } + public var DialogList_EncryptionRejected: String { return self._s[3831]! } + public var GroupInfo_Administrators: String { return self._s[3832]! } + public var Passport_ScanPassportHelp: String { return self._s[3833]! } + public var Application_Name: String { return self._s[3834]! } + public var Channel_AdminLogFilter_ChannelEventsInfo: String { return self._s[3835]! } + public var Appearance_ThemeCarouselDay: String { return self._s[3837]! } + public var Passport_Identity_TranslationHelp: String { return self._s[3838]! } public func VoiceOver_Chat_VideoMessageFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3835]!, self._r[3835]!, [_0]) + return formatWithArgumentRanges(self._s[3839]!, self._r[3839]!, [_0]) } public func Notification_JoinedGroupByLink(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3836]!, self._r[3836]!, [_0]) + return formatWithArgumentRanges(self._s[3840]!, self._r[3840]!, [_0]) } public func DialogList_EncryptedChatStartedOutgoing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3837]!, self._r[3837]!, [_0]) + return formatWithArgumentRanges(self._s[3841]!, self._r[3841]!, [_0]) } - public var Channel_EditAdmin_PermissionDeleteMessages: String { return self._s[3838]! } - public var Privacy_ChatsTitle: String { return self._s[3839]! } - public var DialogList_ClearHistoryConfirmation: String { return self._s[3840]! } - public var SettingsSearch_Synonyms_Data_Storage_ClearCache: String { return self._s[3841]! } - public var Watch_Suggestion_HoldOn: String { return self._s[3842]! } - public var Group_EditAdmin_TransferOwnership: String { return self._s[3843]! } - public var WebBrowser_Title: String { return self._s[3844]! } - public var Group_LinkedChannel: String { return self._s[3845]! } - public var VoiceOver_Chat_SeenByRecipient: String { return self._s[3846]! } - public var SocksProxySetup_RequiredCredentials: String { return self._s[3847]! } - public var Passport_Address_TypeRentalAgreementUploadScan: String { return self._s[3848]! } - public var Appearance_TextSize_UseSystem: String { return self._s[3849]! } - public var TwoStepAuth_EmailSkipAlert: String { return self._s[3850]! } - public var ScheduledMessages_RemindersTitle: String { return self._s[3852]! } - public var Channel_Setup_TypePublic: String { return self._s[3854]! } + public var Channel_EditAdmin_PermissionDeleteMessages: String { return self._s[3842]! } + public var Privacy_ChatsTitle: String { return self._s[3843]! } + public var DialogList_ClearHistoryConfirmation: String { return self._s[3844]! } + public var SettingsSearch_Synonyms_Data_Storage_ClearCache: String { return self._s[3845]! } + public var Watch_Suggestion_HoldOn: String { return self._s[3846]! } + public var Group_EditAdmin_TransferOwnership: String { return self._s[3847]! } + public var WebBrowser_Title: String { return self._s[3848]! } + public var Group_LinkedChannel: String { return self._s[3849]! } + public var VoiceOver_Chat_SeenByRecipient: String { return self._s[3850]! } + public var SocksProxySetup_RequiredCredentials: String { return self._s[3851]! } + public var Passport_Address_TypeRentalAgreementUploadScan: String { return self._s[3852]! } + public var Appearance_TextSize_UseSystem: String { return self._s[3853]! } + public var TwoStepAuth_EmailSkipAlert: String { return self._s[3854]! } + public var ScheduledMessages_RemindersTitle: String { return self._s[3856]! } + public var Channel_Setup_TypePublic: String { return self._s[3858]! } public func Channel_AdminLog_MessageToggleInvitesOn(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3855]!, self._r[3855]!, [_0]) + return formatWithArgumentRanges(self._s[3859]!, self._r[3859]!, [_0]) } - public var Channel_TypeSetup_Title: String { return self._s[3857]! } - public var MessagePoll_ViewResults: String { return self._s[3858]! } - public var Map_OpenInMaps: String { return self._s[3860]! } + public var Channel_TypeSetup_Title: String { return self._s[3861]! } + public var MessagePoll_ViewResults: String { return self._s[3862]! } + public var Map_OpenInMaps: String { return self._s[3864]! } public func PUSH_PINNED_NOTEXT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3861]!, self._r[3861]!, [_1]) + return formatWithArgumentRanges(self._s[3865]!, self._r[3865]!, [_1]) } - public var NotificationsSound_Tremolo: String { return self._s[3863]! } + public var NotificationsSound_Tremolo: String { return self._s[3867]! } public func Date_ChatDateHeaderYear(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3864]!, self._r[3864]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3868]!, self._r[3868]!, [_1, _2, _3]) } - public var ConversationProfile_UnknownAddMemberError: String { return self._s[3865]! } - public var Channel_OwnershipTransfer_PasswordPlaceholder: String { return self._s[3866]! } - public var Passport_PasswordHelp: String { return self._s[3867]! } - public var Login_CodeExpiredError: String { return self._s[3868]! } - public var Channel_EditAdmin_PermissionChangeInfo: String { return self._s[3869]! } - public var Conversation_TitleUnmute: String { return self._s[3870]! } - public var Passport_Identity_ScansHelp: String { return self._s[3871]! } - public var Passport_Language_lo: String { return self._s[3872]! } - public var Camera_FlashAuto: String { return self._s[3873]! } - public var Conversation_OpenBotLinkOpen: String { return self._s[3874]! } - public var Common_Cancel: String { return self._s[3875]! } - public var DialogList_SavedMessagesTooltip: String { return self._s[3876]! } - public var TwoStepAuth_SetupPasswordTitle: String { return self._s[3877]! } - public var Appearance_TintAllColors: String { return self._s[3878]! } + public var ConversationProfile_UnknownAddMemberError: String { return self._s[3869]! } + public var Channel_OwnershipTransfer_PasswordPlaceholder: String { return self._s[3870]! } + public var Passport_PasswordHelp: String { return self._s[3871]! } + public var Login_CodeExpiredError: String { return self._s[3872]! } + public var Channel_EditAdmin_PermissionChangeInfo: String { return self._s[3873]! } + public var Conversation_TitleUnmute: String { return self._s[3874]! } + public var Passport_Identity_ScansHelp: String { return self._s[3875]! } + public var Passport_Language_lo: String { return self._s[3876]! } + public var Camera_FlashAuto: String { return self._s[3877]! } + public var Conversation_OpenBotLinkOpen: String { return self._s[3878]! } + public var Common_Cancel: String { return self._s[3879]! } + public var DialogList_SavedMessagesTooltip: String { return self._s[3880]! } + public var TwoStepAuth_SetupPasswordTitle: String { return self._s[3881]! } + public var Appearance_TintAllColors: String { return self._s[3882]! } public func PUSH_MESSAGE_FWD(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3879]!, self._r[3879]!, [_1]) + return formatWithArgumentRanges(self._s[3883]!, self._r[3883]!, [_1]) } - public var Conversation_ReportSpamConfirmation: String { return self._s[3880]! } - public var ChatSettings_Title: String { return self._s[3882]! } - public var Passport_PasswordReset: String { return self._s[3883]! } - public var SocksProxySetup_TypeNone: String { return self._s[3884]! } - public var EditTheme_Title: String { return self._s[3887]! } - public var PhoneNumberHelp_Help: String { return self._s[3888]! } - public var Checkout_EnterPassword: String { return self._s[3889]! } - public var Activity_UploadingDocument: String { return self._s[3891]! } - public var Share_AuthTitle: String { return self._s[3892]! } - public var State_Connecting: String { return self._s[3893]! } - public var Profile_MessageLifetime1w: String { return self._s[3894]! } - public var Conversation_ContextMenuReport: String { return self._s[3895]! } - public var CheckoutInfo_ReceiverInfoPhone: String { return self._s[3896]! } - public var AutoNightTheme_ScheduledTo: String { return self._s[3897]! } + public var Conversation_ReportSpamConfirmation: String { return self._s[3884]! } + public var ChatSettings_Title: String { return self._s[3886]! } + public var Passport_PasswordReset: String { return self._s[3887]! } + public var SocksProxySetup_TypeNone: String { return self._s[3888]! } + public var EditTheme_Title: String { return self._s[3891]! } + public var PhoneNumberHelp_Help: String { return self._s[3892]! } + public var Checkout_EnterPassword: String { return self._s[3893]! } + public var Activity_UploadingDocument: String { return self._s[3895]! } + public var Share_AuthTitle: String { return self._s[3896]! } + public var State_Connecting: String { return self._s[3897]! } + public var Profile_MessageLifetime1w: String { return self._s[3898]! } + public var Conversation_ContextMenuReport: String { return self._s[3899]! } + public var CheckoutInfo_ReceiverInfoPhone: String { return self._s[3900]! } + public var AutoNightTheme_ScheduledTo: String { return self._s[3901]! } public func VoiceOver_Chat_AnonymousPollFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3898]!, self._r[3898]!, [_0]) + return formatWithArgumentRanges(self._s[3902]!, self._r[3902]!, [_0]) } - public var AuthSessions_Terminate: String { return self._s[3899]! } - public var Wallet_WordImport_CanNotRemember: String { return self._s[3900]! } - public var Checkout_NewCard_CardholderNamePlaceholder: String { return self._s[3902]! } - public var KeyCommand_JumpToPreviousUnreadChat: String { return self._s[3903]! } - public var PhotoEditor_Set: String { return self._s[3904]! } - public var EmptyGroupInfo_Title: String { return self._s[3905]! } - public var Login_PadPhoneHelp: String { return self._s[3906]! } - public var AutoDownloadSettings_TypeGroupChats: String { return self._s[3908]! } - public var PrivacyPolicy_DeclineLastWarning: String { return self._s[3910]! } - public var NotificationsSound_Complete: String { return self._s[3911]! } - public var SettingsSearch_Synonyms_Privacy_Data_Title: String { return self._s[3912]! } - public var Group_Info_AdminLog: String { return self._s[3913]! } - public var GroupPermission_NotAvailableInPublicGroups: String { return self._s[3914]! } + public var AuthSessions_Terminate: String { return self._s[3903]! } + public var Wallet_WordImport_CanNotRemember: String { return self._s[3904]! } + public var Checkout_NewCard_CardholderNamePlaceholder: String { return self._s[3906]! } + public var KeyCommand_JumpToPreviousUnreadChat: String { return self._s[3907]! } + public var PhotoEditor_Set: String { return self._s[3908]! } + public var EmptyGroupInfo_Title: String { return self._s[3909]! } + public var Login_PadPhoneHelp: String { return self._s[3910]! } + public var AutoDownloadSettings_TypeGroupChats: String { return self._s[3912]! } + public var PrivacyPolicy_DeclineLastWarning: String { return self._s[3914]! } + public var NotificationsSound_Complete: String { return self._s[3915]! } + public var SettingsSearch_Synonyms_Privacy_Data_Title: String { return self._s[3916]! } + public var Group_Info_AdminLog: String { return self._s[3917]! } + public var GroupPermission_NotAvailableInPublicGroups: String { return self._s[3918]! } public func Wallet_Time_PreciseDate_m11(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3915]!, self._r[3915]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3919]!, self._r[3919]!, [_1, _2, _3]) } - public var Channel_AdminLog_InfoPanelAlertText: String { return self._s[3916]! } - public var Group_Location_CreateInThisPlace: String { return self._s[3918]! } - public var Conversation_Admin: String { return self._s[3919]! } - public var Conversation_GifTooltip: String { return self._s[3920]! } - public var Passport_NotLoggedInMessage: String { return self._s[3921]! } + public var Channel_AdminLog_InfoPanelAlertText: String { return self._s[3920]! } + public var Group_Location_CreateInThisPlace: String { return self._s[3922]! } + public var Conversation_Admin: String { return self._s[3923]! } + public var Conversation_GifTooltip: String { return self._s[3924]! } + public var Passport_NotLoggedInMessage: String { return self._s[3925]! } public func AutoDownloadSettings_OnFor(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3923]!, self._r[3923]!, [_0]) + return formatWithArgumentRanges(self._s[3927]!, self._r[3927]!, [_0]) } - public var Profile_MessageLifetimeForever: String { return self._s[3924]! } - public var SharedMedia_EmptyTitle: String { return self._s[3926]! } - public var Channel_Edit_PrivatePublicLinkAlert: String { return self._s[3928]! } - public var Username_Help: String { return self._s[3929]! } - public var DialogList_LanguageTooltip: String { return self._s[3931]! } - public var Map_LoadError: String { return self._s[3932]! } - public var Login_PhoneNumberAlreadyAuthorized: String { return self._s[3933]! } - public var Channel_AdminLog_AddMembers: String { return self._s[3934]! } - public var ArchivedChats_IntroTitle2: String { return self._s[3935]! } - public var Notification_Exceptions_NewException: String { return self._s[3936]! } - public var TwoStepAuth_EmailTitle: String { return self._s[3937]! } - public var WatchRemote_AlertText: String { return self._s[3938]! } + public var Profile_MessageLifetimeForever: String { return self._s[3928]! } + public var SharedMedia_EmptyTitle: String { return self._s[3930]! } + public var Channel_Edit_PrivatePublicLinkAlert: String { return self._s[3932]! } + public var Username_Help: String { return self._s[3933]! } + public var DialogList_LanguageTooltip: String { return self._s[3935]! } + public var Map_LoadError: String { return self._s[3936]! } + public var Login_PhoneNumberAlreadyAuthorized: String { return self._s[3937]! } + public var Channel_AdminLog_AddMembers: String { return self._s[3938]! } + public var ArchivedChats_IntroTitle2: String { return self._s[3939]! } + public var Notification_Exceptions_NewException: String { return self._s[3940]! } + public var TwoStepAuth_EmailTitle: String { return self._s[3941]! } + public var WatchRemote_AlertText: String { return self._s[3942]! } public func Wallet_Send_ConfirmationText(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3939]!, self._r[3939]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3943]!, self._r[3943]!, [_1, _2, _3]) } - public var ChatSettings_ConnectionType_Title: String { return self._s[3943]! } + public var ChatSettings_ConnectionType_Title: String { return self._s[3947]! } public func PUSH_PINNED_QUIZ(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3944]!, self._r[3944]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3948]!, self._r[3948]!, [_1, _2]) } public func Settings_CheckPhoneNumberTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3945]!, self._r[3945]!, [_0]) - } - public var SettingsSearch_Synonyms_Calls_CallTab: String { return self._s[3946]! } - public var WebBrowser_DefaultBrowser: String { return self._s[3947]! } - public var Passport_Address_CountryPlaceholder: String { return self._s[3948]! } - public func DialogList_AwaitingEncryption(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3949]!, self._r[3949]!, [_0]) } + public var SettingsSearch_Synonyms_Calls_CallTab: String { return self._s[3950]! } + public var WebBrowser_DefaultBrowser: String { return self._s[3951]! } + public var Passport_Address_CountryPlaceholder: String { return self._s[3952]! } + public func DialogList_AwaitingEncryption(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3953]!, self._r[3953]!, [_0]) + } public func Time_PreciseDate_m6(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3950]!, self._r[3950]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3954]!, self._r[3954]!, [_1, _2, _3]) } - public var Group_AdminLog_EmptyText: String { return self._s[3951]! } - public var SettingsSearch_Synonyms_Appearance_Title: String { return self._s[3952]! } - public var Conversation_PrivateChannelTooltip: String { return self._s[3954]! } - public var Wallet_Created_ExportErrorText: String { return self._s[3955]! } - public var ChatList_UndoArchiveText1: String { return self._s[3956]! } - public var AccessDenied_VideoMicrophone: String { return self._s[3957]! } - public var Conversation_ContextMenuStickerPackAdd: String { return self._s[3958]! } - public var Cache_ClearNone: String { return self._s[3959]! } - public var SocksProxySetup_FailedToConnect: String { return self._s[3960]! } - public var Permissions_NotificationsTitle_v0: String { return self._s[3961]! } + public var Group_AdminLog_EmptyText: String { return self._s[3955]! } + public var SettingsSearch_Synonyms_Appearance_Title: String { return self._s[3956]! } + public var Conversation_PrivateChannelTooltip: String { return self._s[3958]! } + public var Wallet_Created_ExportErrorText: String { return self._s[3959]! } + public var ChatList_UndoArchiveText1: String { return self._s[3960]! } + public var AccessDenied_VideoMicrophone: String { return self._s[3961]! } + public var Conversation_ContextMenuStickerPackAdd: String { return self._s[3962]! } + public var Cache_ClearNone: String { return self._s[3963]! } + public var SocksProxySetup_FailedToConnect: String { return self._s[3964]! } + public var Permissions_NotificationsTitle_v0: String { return self._s[3965]! } public func Channel_AdminLog_MessageEdited(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3962]!, self._r[3962]!, [_0]) + return formatWithArgumentRanges(self._s[3966]!, self._r[3966]!, [_0]) } - public var Passport_Identity_Country: String { return self._s[3963]! } + public var Passport_Identity_Country: String { return self._s[3967]! } public func ChatSettings_AutoDownloadSettings_TypeFile(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3964]!, self._r[3964]!, [_0]) + return formatWithArgumentRanges(self._s[3968]!, self._r[3968]!, [_0]) } public func Notification_CreatedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3965]!, self._r[3965]!, [_0]) + return formatWithArgumentRanges(self._s[3969]!, self._r[3969]!, [_0]) } - public var Exceptions_AddToExceptions: String { return self._s[3966]! } - public var AccessDenied_Settings: String { return self._s[3967]! } - public var Passport_Address_TypeUtilityBillUploadScan: String { return self._s[3968]! } - public var Month_ShortMay: String { return self._s[3969]! } - public var Compose_NewGroup: String { return self._s[3971]! } - public var Group_Setup_TypePrivate: String { return self._s[3973]! } - public var Login_PadPhoneHelpTitle: String { return self._s[3975]! } - public var Appearance_ThemeDayClassic: String { return self._s[3976]! } - public var Channel_AdminLog_MessagePreviousCaption: String { return self._s[3977]! } - public var AutoDownloadSettings_OffForAll: String { return self._s[3978]! } - public var Privacy_GroupsAndChannels_WhoCanAddMe: String { return self._s[3979]! } - public var Conversation_typing: String { return self._s[3981]! } - public var Undo_ScheduledMessagesCleared: String { return self._s[3982]! } - public var Paint_Masks: String { return self._s[3983]! } - public var Contacts_DeselectAll: String { return self._s[3984]! } + public var Exceptions_AddToExceptions: String { return self._s[3970]! } + public var AccessDenied_Settings: String { return self._s[3971]! } + public var Passport_Address_TypeUtilityBillUploadScan: String { return self._s[3972]! } + public var Month_ShortMay: String { return self._s[3973]! } + public var Compose_NewGroup: String { return self._s[3975]! } + public var Group_Setup_TypePrivate: String { return self._s[3977]! } + public var Login_PadPhoneHelpTitle: String { return self._s[3979]! } + public var Appearance_ThemeDayClassic: String { return self._s[3980]! } + public var Channel_AdminLog_MessagePreviousCaption: String { return self._s[3981]! } + public var AutoDownloadSettings_OffForAll: String { return self._s[3982]! } + public var Privacy_GroupsAndChannels_WhoCanAddMe: String { return self._s[3983]! } + public var Conversation_typing: String { return self._s[3985]! } + public var Undo_ScheduledMessagesCleared: String { return self._s[3986]! } + public var Paint_Masks: String { return self._s[3987]! } + public var Contacts_DeselectAll: String { return self._s[3988]! } public func Wallet_Updated_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3985]!, self._r[3985]!, [_0]) + return formatWithArgumentRanges(self._s[3989]!, self._r[3989]!, [_0]) } - public var CreatePoll_MultipleChoiceQuizAlert: String { return self._s[3986]! } - public var Username_InvalidTaken: String { return self._s[3987]! } - public var Call_StatusNoAnswer: String { return self._s[3988]! } - public var TwoStepAuth_EmailAddSuccess: String { return self._s[3989]! } - public var SettingsSearch_Synonyms_Privacy_BlockedUsers: String { return self._s[3990]! } - public var Passport_Identity_Selfie: String { return self._s[3991]! } - public var Login_InfoLastNamePlaceholder: String { return self._s[3992]! } - public var Privacy_SecretChatsLinkPreviewsHelp: String { return self._s[3993]! } - public var Conversation_ClearSecretHistory: String { return self._s[3994]! } - public var PeopleNearby_Description: String { return self._s[3996]! } - public var NetworkUsageSettings_Title: String { return self._s[3997]! } - public var Your_cards_security_code_is_invalid: String { return self._s[3999]! } + public var CreatePoll_MultipleChoiceQuizAlert: String { return self._s[3990]! } + public var Username_InvalidTaken: String { return self._s[3991]! } + public var Call_StatusNoAnswer: String { return self._s[3992]! } + public var TwoStepAuth_EmailAddSuccess: String { return self._s[3993]! } + public var SettingsSearch_Synonyms_Privacy_BlockedUsers: String { return self._s[3994]! } + public var Passport_Identity_Selfie: String { return self._s[3995]! } + public var Login_InfoLastNamePlaceholder: String { return self._s[3996]! } + public var Privacy_SecretChatsLinkPreviewsHelp: String { return self._s[3997]! } + public var Conversation_ClearSecretHistory: String { return self._s[3998]! } + public var PeopleNearby_Description: String { return self._s[4000]! } + public var NetworkUsageSettings_Title: String { return self._s[4001]! } + public var Your_cards_security_code_is_invalid: String { return self._s[4003]! } public func Notification_LeftChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4001]!, self._r[4001]!, [_0]) + return formatWithArgumentRanges(self._s[4005]!, self._r[4005]!, [_0]) } public func Call_CallInProgressMessage(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4002]!, self._r[4002]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4006]!, self._r[4006]!, [_1, _2]) } - public var SaveIncomingPhotosSettings_From: String { return self._s[4004]! } - public var VoiceOver_Navigation_Search: String { return self._s[4005]! } - public var Map_LiveLocationTitle: String { return self._s[4006]! } - public var Login_InfoAvatarAdd: String { return self._s[4007]! } - public var Passport_Identity_FilesView: String { return self._s[4008]! } - public var UserInfo_GenericPhoneLabel: String { return self._s[4009]! } - public var Privacy_Calls_NeverAllow: String { return self._s[4010]! } - public var VoiceOver_Chat_File: String { return self._s[4011]! } - public var Wallet_Settings_DeleteWalletInfo: String { return self._s[4012]! } + public var SaveIncomingPhotosSettings_From: String { return self._s[4008]! } + public var VoiceOver_Navigation_Search: String { return self._s[4009]! } + public var Map_LiveLocationTitle: String { return self._s[4010]! } + public var Login_InfoAvatarAdd: String { return self._s[4011]! } + public var Passport_Identity_FilesView: String { return self._s[4012]! } + public var UserInfo_GenericPhoneLabel: String { return self._s[4013]! } + public var Privacy_Calls_NeverAllow: String { return self._s[4014]! } + public var VoiceOver_Chat_File: String { return self._s[4015]! } + public var Wallet_Settings_DeleteWalletInfo: String { return self._s[4016]! } public func Contacts_AddPhoneNumber(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4013]!, self._r[4013]!, [_0]) + return formatWithArgumentRanges(self._s[4017]!, self._r[4017]!, [_0]) } - public var ContactInfo_PhoneNumberHidden: String { return self._s[4014]! } - public var TwoStepAuth_ConfirmationText: String { return self._s[4015]! } - public var ChatSettings_AutomaticVideoMessageDownload: String { return self._s[4016]! } + public var ContactInfo_PhoneNumberHidden: String { return self._s[4018]! } + public var TwoStepAuth_ConfirmationText: String { return self._s[4019]! } + public var ChatSettings_AutomaticVideoMessageDownload: String { return self._s[4020]! } public func PUSH_CHAT_MESSAGE_VIDEOS(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4017]!, self._r[4017]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4021]!, self._r[4021]!, [_1, _2, _3]) } - public var Channel_AdminLogFilter_AdminsAll: String { return self._s[4018]! } - public var Wallet_Intro_CreateErrorText: String { return self._s[4019]! } - public var Tour_Title2: String { return self._s[4020]! } - public var Wallet_Sent_ViewWallet: String { return self._s[4021]! } - public var Conversation_FileOpenIn: String { return self._s[4022]! } - public var Checkout_ErrorPrecheckoutFailed: String { return self._s[4023]! } - public var Wallet_Send_ErrorInvalidAddress: String { return self._s[4024]! } - public var Wallpaper_Set: String { return self._s[4025]! } - public var Passport_Identity_Translations: String { return self._s[4027]! } + public var Channel_AdminLogFilter_AdminsAll: String { return self._s[4022]! } + public var Wallet_Intro_CreateErrorText: String { return self._s[4023]! } + public var Tour_Title2: String { return self._s[4024]! } + public var Wallet_Sent_ViewWallet: String { return self._s[4025]! } + public var Conversation_FileOpenIn: String { return self._s[4026]! } + public var Checkout_ErrorPrecheckoutFailed: String { return self._s[4027]! } + public var Wallet_Send_ErrorInvalidAddress: String { return self._s[4028]! } + public var Wallpaper_Set: String { return self._s[4029]! } + public var Passport_Identity_Translations: String { return self._s[4031]! } public func Channel_AdminLog_MessageChangedChannelAbout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4028]!, self._r[4028]!, [_0]) + return formatWithArgumentRanges(self._s[4032]!, self._r[4032]!, [_0]) } - public var Channel_LeaveChannel: String { return self._s[4029]! } + public var Channel_LeaveChannel: String { return self._s[4033]! } public func PINNED_INVOICE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4030]!, self._r[4030]!, [_1]) + return formatWithArgumentRanges(self._s[4034]!, self._r[4034]!, [_1]) } - public var SettingsSearch_Synonyms_Proxy_AddProxy: String { return self._s[4032]! } - public var PhotoEditor_HighlightsTint: String { return self._s[4033]! } - public var MessagePoll_LabelPoll: String { return self._s[4034]! } - public var Passport_Email_Delete: String { return self._s[4035]! } - public var Conversation_Mute: String { return self._s[4037]! } - public var Channel_AddBotAsAdmin: String { return self._s[4038]! } - public var Channel_AdminLog_CanSendMessages: String { return self._s[4040]! } - public var Wallet_Configuration_BlockchainNameChangedText: String { return self._s[4041]! } - public var ChatSettings_IntentsSettings: String { return self._s[4043]! } - public var Channel_Management_LabelOwner: String { return self._s[4044]! } + public var SettingsSearch_Synonyms_Proxy_AddProxy: String { return self._s[4036]! } + public var PhotoEditor_HighlightsTint: String { return self._s[4037]! } + public var MessagePoll_LabelPoll: String { return self._s[4038]! } + public var Passport_Email_Delete: String { return self._s[4039]! } + public var Conversation_Mute: String { return self._s[4041]! } + public var Channel_AddBotAsAdmin: String { return self._s[4042]! } + public var Channel_AdminLog_CanSendMessages: String { return self._s[4044]! } + public var Wallet_Configuration_BlockchainNameChangedText: String { return self._s[4045]! } + public var ChatSettings_IntentsSettings: String { return self._s[4047]! } + public var Channel_Management_LabelOwner: String { return self._s[4048]! } public func Notification_PassportValuesSentMessage(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4045]!, self._r[4045]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4049]!, self._r[4049]!, [_1, _2]) } - public var Calls_CallTabDescription: String { return self._s[4046]! } - public var Passport_Identity_NativeNameHelp: String { return self._s[4047]! } - public var Common_No: String { return self._s[4048]! } - public var Weekday_Sunday: String { return self._s[4049]! } - public var Notification_Reply: String { return self._s[4050]! } - public var Conversation_ViewMessage: String { return self._s[4051]! } + public var Calls_CallTabDescription: String { return self._s[4050]! } + public var Passport_Identity_NativeNameHelp: String { return self._s[4051]! } + public var Common_No: String { return self._s[4052]! } + public var Weekday_Sunday: String { return self._s[4053]! } + public var Notification_Reply: String { return self._s[4054]! } + public var Conversation_ViewMessage: String { return self._s[4055]! } public func Checkout_SavePasswordTimeoutAndFaceId(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4052]!, self._r[4052]!, [_0]) + return formatWithArgumentRanges(self._s[4056]!, self._r[4056]!, [_0]) } public func Map_LiveLocationPrivateDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4053]!, self._r[4053]!, [_0]) + return formatWithArgumentRanges(self._s[4057]!, self._r[4057]!, [_0]) } public func Wallet_Time_PreciseDate_m7(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4054]!, self._r[4054]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4058]!, self._r[4058]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_EditProfile_AddAccount: String { return self._s[4055]! } - public var Wallet_Send_Title: String { return self._s[4056]! } - public var Message_PinnedDocumentMessage: String { return self._s[4057]! } - public var Wallet_Info_RefreshErrorText: String { return self._s[4058]! } - public var DialogList_TabTitle: String { return self._s[4060]! } - public var ChatSettings_AutoPlayTitle: String { return self._s[4061]! } - public var Passport_FieldEmail: String { return self._s[4062]! } - public var Conversation_UnpinMessageAlert: String { return self._s[4063]! } - public var Passport_Address_TypeBankStatement: String { return self._s[4064]! } - public var Wallet_SecureStorageReset_Title: String { return self._s[4065]! } - public var Passport_Identity_ExpiryDate: String { return self._s[4066]! } - public var Privacy_Calls_P2P: String { return self._s[4067]! } + public var SettingsSearch_Synonyms_EditProfile_AddAccount: String { return self._s[4059]! } + public var Wallet_Send_Title: String { return self._s[4060]! } + public var Message_PinnedDocumentMessage: String { return self._s[4061]! } + public var Wallet_Info_RefreshErrorText: String { return self._s[4062]! } + public var DialogList_TabTitle: String { return self._s[4064]! } + public var ChatSettings_AutoPlayTitle: String { return self._s[4065]! } + public var Passport_FieldEmail: String { return self._s[4066]! } + public var Conversation_UnpinMessageAlert: String { return self._s[4067]! } + public var Passport_Address_TypeBankStatement: String { return self._s[4068]! } + public var Wallet_SecureStorageReset_Title: String { return self._s[4069]! } + public var Passport_Identity_ExpiryDate: String { return self._s[4070]! } + public var Privacy_Calls_P2P: String { return self._s[4071]! } public func CancelResetAccount_Success(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4069]!, self._r[4069]!, [_0]) + return formatWithArgumentRanges(self._s[4073]!, self._r[4073]!, [_0]) } - public var SocksProxySetup_UseForCallsHelp: String { return self._s[4070]! } + public var SocksProxySetup_UseForCallsHelp: String { return self._s[4074]! } public func PUSH_CHAT_ALBUM(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4071]!, self._r[4071]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4075]!, self._r[4075]!, [_1, _2]) } - public var Stickers_ClearRecent: String { return self._s[4072]! } - public var EnterPasscode_ChangeTitle: String { return self._s[4073]! } - public var TwoFactorSetup_Email_Title: String { return self._s[4074]! } - public var Passport_InfoText: String { return self._s[4075]! } - public var Checkout_NewCard_SaveInfoEnableHelp: String { return self._s[4076]! } + public var Stickers_ClearRecent: String { return self._s[4076]! } + public var EnterPasscode_ChangeTitle: String { return self._s[4077]! } + public var TwoFactorSetup_Email_Title: String { return self._s[4078]! } + public var Passport_InfoText: String { return self._s[4079]! } + public var Checkout_NewCard_SaveInfoEnableHelp: String { return self._s[4080]! } public func Login_InvalidPhoneEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4077]!, self._r[4077]!, [_0]) + return formatWithArgumentRanges(self._s[4081]!, self._r[4081]!, [_0]) } public func Time_PreciseDate_m3(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4078]!, self._r[4078]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4082]!, self._r[4082]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChannels: String { return self._s[4079]! } - public var ScheduledMessages_PollUnavailable: String { return self._s[4080]! } - public var VoiceOver_Navigation_Compose: String { return self._s[4081]! } - public var Passport_Identity_EditDriversLicense: String { return self._s[4082]! } - public var Conversation_TapAndHoldToRecord: String { return self._s[4084]! } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChats: String { return self._s[4085]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChannels: String { return self._s[4083]! } + public var ScheduledMessages_PollUnavailable: String { return self._s[4084]! } + public var VoiceOver_Navigation_Compose: String { return self._s[4085]! } + public var Passport_Identity_EditDriversLicense: String { return self._s[4086]! } + public var Conversation_TapAndHoldToRecord: String { return self._s[4088]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChats: String { return self._s[4089]! } public func Notification_CallTimeFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4086]!, self._r[4086]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4090]!, self._r[4090]!, [_1, _2]) } - public var Channel_EditAdmin_PermissionInviteViaLink: String { return self._s[4088]! } - public var ChatSettings_OpenLinksIn: String { return self._s[4089]! } - public var Map_HomeAndWorkTitle: String { return self._s[4090]! } + public var Channel_EditAdmin_PermissionInviteViaLink: String { return self._s[4092]! } + public var ChatSettings_OpenLinksIn: String { return self._s[4093]! } + public var Map_HomeAndWorkTitle: String { return self._s[4094]! } public func Generic_OpenHiddenLinkAlert(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4092]!, self._r[4092]!, [_0]) + return formatWithArgumentRanges(self._s[4096]!, self._r[4096]!, [_0]) } - public var DialogList_Unread: String { return self._s[4093]! } + public var DialogList_Unread: String { return self._s[4097]! } public func PUSH_CHAT_MESSAGE_GIF(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4094]!, self._r[4094]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4098]!, self._r[4098]!, [_1, _2]) } - public var User_DeletedAccount: String { return self._s[4095]! } - public var OwnershipTransfer_SetupTwoStepAuth: String { return self._s[4096]! } + public var User_DeletedAccount: String { return self._s[4099]! } + public var OwnershipTransfer_SetupTwoStepAuth: String { return self._s[4100]! } public func Watch_Time_ShortYesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4097]!, self._r[4097]!, [_0]) + return formatWithArgumentRanges(self._s[4101]!, self._r[4101]!, [_0]) } - public var UserInfo_NotificationsDefault: String { return self._s[4098]! } - public var SharedMedia_CategoryMedia: String { return self._s[4099]! } - public var SocksProxySetup_ProxyStatusUnavailable: String { return self._s[4100]! } - public var Channel_AdminLog_MessageRestrictedForever: String { return self._s[4101]! } - public var Watch_ChatList_Compose: String { return self._s[4102]! } - public var Notifications_MessageNotificationsExceptionsHelp: String { return self._s[4103]! } - public var AutoDownloadSettings_Delimeter: String { return self._s[4104]! } - public var Watch_Microphone_Access: String { return self._s[4105]! } - public var Group_Setup_HistoryHeader: String { return self._s[4106]! } - public var Map_SetThisLocation: String { return self._s[4107]! } - public var Appearance_ThemePreview_Chat_2_ReplyName: String { return self._s[4108]! } - public var Activity_UploadingPhoto: String { return self._s[4109]! } - public var Conversation_Edit: String { return self._s[4111]! } - public var Group_ErrorSendRestrictedMedia: String { return self._s[4112]! } - public var Login_TermsOfServiceDecline: String { return self._s[4113]! } - public var Message_PinnedContactMessage: String { return self._s[4114]! } + public var UserInfo_NotificationsDefault: String { return self._s[4102]! } + public var SharedMedia_CategoryMedia: String { return self._s[4103]! } + public var SocksProxySetup_ProxyStatusUnavailable: String { return self._s[4104]! } + public var Channel_AdminLog_MessageRestrictedForever: String { return self._s[4105]! } + public var Watch_ChatList_Compose: String { return self._s[4106]! } + public var Notifications_MessageNotificationsExceptionsHelp: String { return self._s[4107]! } + public var AutoDownloadSettings_Delimeter: String { return self._s[4108]! } + public var Watch_Microphone_Access: String { return self._s[4109]! } + public var Group_Setup_HistoryHeader: String { return self._s[4110]! } + public var Map_SetThisLocation: String { return self._s[4111]! } + public var Appearance_ThemePreview_Chat_2_ReplyName: String { return self._s[4112]! } + public var Activity_UploadingPhoto: String { return self._s[4113]! } + public var Conversation_Edit: String { return self._s[4115]! } + public var Group_ErrorSendRestrictedMedia: String { return self._s[4116]! } + public var Login_TermsOfServiceDecline: String { return self._s[4117]! } + public var Message_PinnedContactMessage: String { return self._s[4118]! } public func Channel_AdminLog_MessageRestrictedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4115]!, self._r[4115]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4119]!, self._r[4119]!, [_1, _2]) } public func Login_PhoneBannedEmailBody(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4116]!, self._r[4116]!, [_1, _2, _3, _4, _5]) + return formatWithArgumentRanges(self._s[4120]!, self._r[4120]!, [_1, _2, _3, _4, _5]) } - public var Appearance_LargeEmoji: String { return self._s[4117]! } - public var TwoStepAuth_AdditionalPassword: String { return self._s[4119]! } - public var EditTheme_Edit_Preview_IncomingReplyText: String { return self._s[4120]! } + public var Appearance_LargeEmoji: String { return self._s[4121]! } + public var TwoStepAuth_AdditionalPassword: String { return self._s[4123]! } + public var EditTheme_Edit_Preview_IncomingReplyText: String { return self._s[4124]! } public func PUSH_CHAT_DELETE_YOU(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4121]!, self._r[4121]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4125]!, self._r[4125]!, [_1, _2]) } - public var Passport_Phone_EnterOtherNumber: String { return self._s[4122]! } - public var Message_PinnedPhotoMessage: String { return self._s[4123]! } - public var Passport_FieldPhone: String { return self._s[4124]! } - public var TwoStepAuth_RecoveryEmailAddDescription: String { return self._s[4125]! } - public var ChatSettings_AutoPlayGifs: String { return self._s[4126]! } - public var InfoPlist_NSCameraUsageDescription: String { return self._s[4128]! } - public var Conversation_Call: String { return self._s[4129]! } - public var Common_TakePhoto: String { return self._s[4131]! } - public var Group_EditAdmin_RankTitle: String { return self._s[4132]! } - public var Wallet_Receive_CommentHeader: String { return self._s[4133]! } - public var Channel_NotificationLoading: String { return self._s[4134]! } + public var Passport_Phone_EnterOtherNumber: String { return self._s[4126]! } + public var Message_PinnedPhotoMessage: String { return self._s[4127]! } + public var Passport_FieldPhone: String { return self._s[4128]! } + public var TwoStepAuth_RecoveryEmailAddDescription: String { return self._s[4129]! } + public var ChatSettings_AutoPlayGifs: String { return self._s[4130]! } + public var InfoPlist_NSCameraUsageDescription: String { return self._s[4132]! } + public var Conversation_Call: String { return self._s[4133]! } + public var Common_TakePhoto: String { return self._s[4135]! } + public var Group_EditAdmin_RankTitle: String { return self._s[4136]! } + public var Wallet_Receive_CommentHeader: String { return self._s[4137]! } + public var Channel_NotificationLoading: String { return self._s[4138]! } public func Notification_Exceptions_Sound(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4135]!, self._r[4135]!, [_0]) - } - public func ScheduledMessages_ScheduledDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4136]!, self._r[4136]!, [_0]) - } - public func PUSH_CHANNEL_MESSAGE_VIDEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4137]!, self._r[4137]!, [_1]) - } - public var Permissions_SiriTitle_v0: String { return self._s[4138]! } - public func VoiceOver_Chat_VoiceMessageFrom(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[4139]!, self._r[4139]!, [_0]) } - public func Login_ResetAccountProtected_Text(_ _0: String) -> (String, [(Int, NSRange)]) { + public func ScheduledMessages_ScheduledDate(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[4140]!, self._r[4140]!, [_0]) } - public var Channel_MessagePhotoRemoved: String { return self._s[4141]! } - public var Wallet_Info_ReceiveGrams: String { return self._s[4142]! } - public var ClearCache_FreeSpace: String { return self._s[4143]! } - public var Appearance_BubbleCorners_Apply: String { return self._s[4144]! } - public var Common_edit: String { return self._s[4145]! } - public var PrivacySettings_AuthSessions: String { return self._s[4146]! } - public var Month_ShortJune: String { return self._s[4147]! } - public var PrivacyLastSeenSettings_AlwaysShareWith_Placeholder: String { return self._s[4148]! } - public var Call_ReportSend: String { return self._s[4149]! } - public var Watch_LastSeen_JustNow: String { return self._s[4150]! } - public var Notifications_MessageNotifications: String { return self._s[4151]! } - public var WallpaperSearch_ColorGreen: String { return self._s[4152]! } - public var BroadcastListInfo_AddRecipient: String { return self._s[4154]! } - public var Group_Status: String { return self._s[4155]! } + public func PUSH_CHANNEL_MESSAGE_VIDEO(_ _1: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[4141]!, self._r[4141]!, [_1]) + } + public var Permissions_SiriTitle_v0: String { return self._s[4142]! } + public func VoiceOver_Chat_VoiceMessageFrom(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[4143]!, self._r[4143]!, [_0]) + } + public func Login_ResetAccountProtected_Text(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[4144]!, self._r[4144]!, [_0]) + } + public var Channel_MessagePhotoRemoved: String { return self._s[4145]! } + public var Wallet_Info_ReceiveGrams: String { return self._s[4146]! } + public var ClearCache_FreeSpace: String { return self._s[4147]! } + public var Appearance_BubbleCorners_Apply: String { return self._s[4148]! } + public var Common_edit: String { return self._s[4149]! } + public var PrivacySettings_AuthSessions: String { return self._s[4150]! } + public var Month_ShortJune: String { return self._s[4151]! } + public var PrivacyLastSeenSettings_AlwaysShareWith_Placeholder: String { return self._s[4152]! } + public var Call_ReportSend: String { return self._s[4153]! } + public var Watch_LastSeen_JustNow: String { return self._s[4154]! } + public var Notifications_MessageNotifications: String { return self._s[4155]! } + public var WallpaperSearch_ColorGreen: String { return self._s[4156]! } + public var BroadcastListInfo_AddRecipient: String { return self._s[4158]! } + public var Group_Status: String { return self._s[4159]! } public func AutoNightTheme_LocationHelp(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4156]!, self._r[4156]!, [_0, _1]) + return formatWithArgumentRanges(self._s[4160]!, self._r[4160]!, [_0, _1]) } - public var TextFormat_AddLinkTitle: String { return self._s[4157]! } - public var ShareMenu_ShareTo: String { return self._s[4158]! } - public var Conversation_Moderate_Ban: String { return self._s[4159]! } + public var TextFormat_AddLinkTitle: String { return self._s[4161]! } + public var ShareMenu_ShareTo: String { return self._s[4162]! } + public var Conversation_Moderate_Ban: String { return self._s[4163]! } public func Conversation_DeleteMessagesFor(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4160]!, self._r[4160]!, [_0]) + return formatWithArgumentRanges(self._s[4164]!, self._r[4164]!, [_0]) } - public var SharedMedia_ViewInChat: String { return self._s[4161]! } - public var Map_LiveLocationFor8Hours: String { return self._s[4162]! } + public var SharedMedia_ViewInChat: String { return self._s[4165]! } + public var Map_LiveLocationFor8Hours: String { return self._s[4166]! } public func PUSH_PINNED_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4163]!, self._r[4163]!, [_1]) + return formatWithArgumentRanges(self._s[4167]!, self._r[4167]!, [_1]) } public func PUSH_PINNED_POLL(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4164]!, self._r[4164]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4168]!, self._r[4168]!, [_1, _2]) } public func Map_AccurateTo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4166]!, self._r[4166]!, [_0]) + return formatWithArgumentRanges(self._s[4170]!, self._r[4170]!, [_0]) } - public var Map_OpenInHereMaps: String { return self._s[4167]! } - public var Appearance_ReduceMotion: String { return self._s[4168]! } + public var Map_OpenInHereMaps: String { return self._s[4171]! } + public var Appearance_ReduceMotion: String { return self._s[4172]! } public func PUSH_MESSAGE_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4169]!, self._r[4169]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4173]!, self._r[4173]!, [_1, _2]) } - public var Channel_Setup_TypePublicHelp: String { return self._s[4170]! } - public var Passport_Identity_EditInternalPassport: String { return self._s[4171]! } - public var PhotoEditor_Skip: String { return self._s[4172]! } - public func LiveLocationUpdated_MinutesAgo(_ value: Int32) -> String { + public var Channel_Setup_TypePublicHelp: String { return self._s[4174]! } + public var Passport_Identity_EditInternalPassport: String { return self._s[4175]! } + public var PhotoEditor_Skip: String { return self._s[4176]! } + public func ChatList_DeleteConfirmation(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue) } - public func LastSeen_MinutesAgo(_ value: Int32) -> String { + public func Wallpaper_DeleteConfirmation(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue) } - public func CreatePoll_AddMoreOptions(_ value: Int32) -> String { + public func AttachmentMenu_SendPhoto(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[2 * 6 + Int(form.rawValue)]!, stringValue) } - public func ForwardedLocations(_ value: Int32) -> String { + public func ForwardedVideos(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[3 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessageTimer_Weeks(_ value: Int32) -> String { + public func SharedMedia_Video(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[4 * 6 + Int(form.rawValue)]!, stringValue) } - public func AttachmentMenu_SendVideo(_ value: Int32) -> String { + public func Theme_UsersCount(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[5 * 6 + Int(form.rawValue)]!, stringValue) } - public func SharedMedia_Photo(_ value: Int32) -> String { + public func SharedMedia_Link(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[6 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_CHANNEL_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[7 * 6 + Int(form.rawValue)]!, _1, _2) + public func Notifications_ExceptionMuteExpires_Days(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[7 * 6 + Int(form.rawValue)]!, stringValue) } - public func Notification_GameScoreExtended(_ value: Int32) -> String { + public func SharedMedia_DeleteItemsConfirmation(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[8 * 6 + Int(form.rawValue)]!, stringValue) } - public func MuteFor_Days(_ value: Int32) -> String { + public func ChatList_DeletedChats(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[9 * 6 + Int(form.rawValue)]!, stringValue) } - public func Wallpaper_DeleteConfirmation(_ value: Int32) -> String { + public func MuteFor_Days(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[10 * 6 + Int(form.rawValue)]!, stringValue) } - public func Conversation_LiveLocationMembersCount(_ value: Int32) -> String { + public func ServiceMessage_GameScoreSelfExtended(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[11 * 6 + Int(form.rawValue)]!, stringValue) } - public func ForwardedVideoMessages(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[12 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Contacts_ImportersCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[13 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedMessages(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[14 * 6 + Int(form.rawValue)]!, stringValue) - } public func PUSH_CHANNEL_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[15 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func AttachmentMenu_SendItem(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[16 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreSelfExtended(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[17 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Forward_ConfirmMultipleFiles(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[18 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PollResults_ShowMore(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[19 * 6 + Int(form.rawValue)]!, stringValue) - } - public func DialogList_LiveLocationChatsCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[20 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_Minutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[21 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Conversation_SelectedMessages(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[22 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Media_SharePhoto(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[23 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[12 * 6 + Int(form.rawValue)]!, _1, _2) } public func OldChannels_InactiveWeek(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[24 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGE_VIDEOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[25 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func MuteFor_Hours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[26 * 6 + Int(form.rawValue)]!, stringValue) - } - public func OldChannels_GroupFormat(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[27 * 6 + Int(form.rawValue)]!, stringValue) - } - public func UserCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[28 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notification_GameScoreSelfExtended(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[29 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Watch_UserInfo_Mute(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[30 * 6 + Int(form.rawValue)]!, stringValue) - } - public func AttachmentMenu_SendGif(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[31 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteExpires_Days(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[32 * 6 + Int(form.rawValue)]!, stringValue) - } - public func InviteText_ContactsCountText(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[33 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_StickerCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[34 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[35 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func ForwardedGifs(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[36 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Map_ETAHours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[37 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ChatList_SelectedChats(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[38 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_ShortMinutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[39 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Media_ShareItem(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[40 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Media_ShareVideo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[41 * 6 + Int(form.rawValue)]!, stringValue) - } - public func OldChannels_InactiveYear(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[42 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_PollOptionCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[43 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessagePoll_VotedCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[44 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[45 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func PUSH_CHAT_MESSAGES(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[46 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func MessageTimer_ShortSeconds(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[47 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreSimple(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[48 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_Generic(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[49 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[13 * 6 + Int(form.rawValue)]!, stringValue) } public func MessageTimer_Days(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[14 * 6 + Int(form.rawValue)]!, stringValue) + } + public func OldChannels_InactiveMonth(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[15 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Minutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[16 * 6 + Int(form.rawValue)]!, stringValue) + } + public func DialogList_LiveLocationChatsCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[17 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[18 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func Call_ShortMinutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[19 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreSelfExtended(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[20 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_LiveLocationMembersCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[21 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notifications_Exceptions(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[22 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Months(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[23 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_StatusSubscribers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[24 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_PollVotes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[25 * 6 + Int(form.rawValue)]!, stringValue) + } + public func QuickSend_Photos(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[26 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[27 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func OldChannels_Leave(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[28 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Map_ETAMinutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[29 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PollResults_ShowMore(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[30 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Hours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[31 * 6 + Int(form.rawValue)]!, stringValue) + } + public func LiveLocation_MenuChatsCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[32 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Map_ETAHours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[33 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_RemoveStickerCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[34 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PrivacyLastSeenSettings_AddUsers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[35 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteExpires_Days(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[36 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessagePoll_VotedCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[37 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedFiles(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[38 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreSimple(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[39 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_ContactEmailCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[40 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Media_ShareItem(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[41 * 6 + Int(form.rawValue)]!, stringValue) + } + public func OldChannels_GroupFormat(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[42 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_File(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[43 * 6 + Int(form.rawValue)]!, stringValue) + } + public func InviteText_ContactsCountText(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[44 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Watch_UserInfo_Mute(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[45 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedPhotos(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[46 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreSelfSimple(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[47 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedContacts(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[48 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_Seconds(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[49 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Media_SharePhoto(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[50 * 6 + Int(form.rawValue)]!, stringValue) } - public func Conversation_StatusMembers(_ value: Int32) -> String { + public func VoiceOver_Chat_PollOptionCount(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[51 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessageTimer_ShortMinutes(_ value: Int32) -> String { + public func Invitation_Members(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[52 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessageTimer_Seconds(_ value: Int32) -> String { + public func ForwardedLocations(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[53 * 6 + Int(form.rawValue)]!, stringValue) } - public func GroupInfo_ShowMoreMembers(_ value: Int32) -> String { + public func ForwardedVideoMessages(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[54 * 6 + Int(form.rawValue)]!, stringValue) @@ -4981,345 +4988,342 @@ public final class PresentationStrings: Equatable { let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[55 * 6 + Int(form.rawValue)]!, stringValue) } - public func OldChannels_Leave(_ value: Int32) -> String { + public func UserCount(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[56 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_CHAT_MESSAGE_PHOTOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[57 * 6 + Int(form.rawValue)]!, _2, _1, _3) + public func ForwardedMessages(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[57 * 6 + Int(form.rawValue)]!, stringValue) } - public func VoiceOver_Chat_ContactEmailCount(_ value: Int32) -> String { + public func SharedMedia_Photo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[58 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessageTimer_Years(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[59 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessagePoll_QuizCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[60 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[61 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func SharedMedia_Link(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[62 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_RemoveMaskCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[63 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_ExceptionMuteExpires_Hours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[64 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Theme_UsersCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[65 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedAuthorsOthers(_ selector: Int32, _ _0: String, _ _1: String) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[66 * 6 + Int(form.rawValue)]!, _0, _1) - } - public func Watch_LastSeen_MinutesAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[67 * 6 + Int(form.rawValue)]!, stringValue) - } - public func QuickSend_Photos(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[68 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortDays(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[69 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortWeeks(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[70 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Watch_LastSeen_HoursAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[71 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Chat_DeleteMessagesConfirmation(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[72 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PasscodeSettings_FailedAttempts(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[73 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_Seconds(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[74 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteExpires_Hours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[75 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Contacts_InviteContacts(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[76 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedFiles(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[77 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[78 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func Notifications_ExceptionMuteExpires_Days(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[79 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Wallet_Updated_HoursAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[80 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_AddStickerCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[81 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedContacts(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[82 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedAudios(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[83 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notification_GameScoreSelfSimple(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[84 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreExtended(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[85 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreSelfSimple(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[86 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PrivacyLastSeenSettings_AddUsers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[87 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_PollVotes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[88 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedStickers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[89 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedPolls(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[90 * 6 + Int(form.rawValue)]!, stringValue) - } - public func AttachmentMenu_SendPhoto(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[91 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortHours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[92 * 6 + Int(form.rawValue)]!, stringValue) - } - public func LiveLocation_MenuChatsCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[93 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_ContactPhoneNumberCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[94 * 6 + Int(form.rawValue)]!, stringValue) - } - public func LastSeen_HoursAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[95 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ChatList_DeleteConfirmation(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[96 * 6 + Int(form.rawValue)]!, stringValue) - } - public func OldChannels_InactiveMonth(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[97 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedVideos(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[98 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_Video(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[99 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_AddMaskCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[100 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Map_ETAMinutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[101 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_File(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[102 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Minutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[103 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Invitation_Members(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[104 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_RemoveStickerCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[105 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ChatList_DeletedChats(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[106 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGE_ROUNDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[107 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func MessageTimer_Hours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[108 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_ExceptionMuteExpires_Minutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[109 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_DeleteItemsConfirmation(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[110 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[111 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func Passport_Scans(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[112 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[113 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func MessageTimer_Months(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[114 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGE_FWDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[115 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func MuteExpires_Minutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[116 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[117 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_Exceptions(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[118 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_ShortSeconds(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[119 * 6 + Int(form.rawValue)]!, stringValue) - } - public func GroupInfo_ParticipantCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[120 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Conversation_StatusSubscribers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[121 * 6 + Int(form.rawValue)]!, stringValue) - } public func PUSH_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[122 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func PUSH_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[123 * 6 + Int(form.rawValue)]!, _1, _2) + return String(format: self._ps[59 * 6 + Int(form.rawValue)]!, _1, _2) } public func Conversation_StatusOnline(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[124 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[60 * 6 + Int(form.rawValue)]!, stringValue) } - public func ForwardedPhotos(_ value: Int32) -> String { + public func ServiceMessage_GameScoreExtended(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[125 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[61 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[62 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func Call_ShortSeconds(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[63 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Watch_LastSeen_HoursAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[64 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHAT_MESSAGE_FWDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[65 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func LastSeen_HoursAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[66 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreSelfSimple(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[67 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Wallet_Updated_HoursAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[68 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Watch_LastSeen_MinutesAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[69 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHAT_MESSAGE_VIDEOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[70 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func PUSH_CHAT_MESSAGE_ROUNDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[71 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func OldChannels_InactiveYear(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[72 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notifications_ExceptionMuteExpires_Minutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[73 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_Minutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[74 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedAudios(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[75 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortHours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[76 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortSeconds(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[77 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Weeks(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[78 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[79 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedPolls(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[80 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Media_ShareVideo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[81 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Forward_ConfirmMultipleFiles(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[82 * 6 + Int(form.rawValue)]!, stringValue) + } + public func GroupInfo_ParticipantCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[83 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteExpires_Minutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[84 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_ContactPhoneNumberCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[85 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ChatList_SelectedChats(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[86 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_AddStickerCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[87 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[88 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func PasscodeSettings_FailedAttempts(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[89 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notifications_ExceptionMuteExpires_Hours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[90 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_SelectedMessages(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[91 * 6 + Int(form.rawValue)]!, stringValue) + } + public func AttachmentMenu_SendItem(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[92 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_AddMaskCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[93 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_RemoveMaskCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[94 * 6 + Int(form.rawValue)]!, stringValue) + } + public func CreatePoll_AddMoreOptions(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[95 * 6 + Int(form.rawValue)]!, stringValue) + } + public func GroupInfo_ShowMoreMembers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[96 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteExpires_Hours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[97 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Contacts_ImportersCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[98 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedGifs(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[99 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[100 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func AttachmentMenu_SendGif(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[101 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreExtended(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[102 * 6 + Int(form.rawValue)]!, stringValue) + } + public func LiveLocationUpdated_MinutesAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[103 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Years(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[104 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_StickerCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[105 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortMinutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[106 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedAuthorsOthers(_ selector: Int32, _ _0: String, _ _1: String) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[107 * 6 + Int(form.rawValue)]!, _0, _1) + } + public func AttachmentMenu_SendVideo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[108 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedStickers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[109 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHAT_MESSAGE_PHOTOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[110 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func Chat_DeleteMessagesConfirmation(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[111 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortDays(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[112 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortWeeks(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[113 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_StatusMembers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[114 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Contacts_InviteContacts(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[115 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[116 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func MessageTimer_Seconds(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[117 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Passport_Scans(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[118 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_Generic(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[119 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteFor_Hours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[120 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessagePoll_QuizCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[121 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[122 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func PUSH_CHAT_MESSAGES(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[123 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func LastSeen_MinutesAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[124 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[125 * 6 + Int(form.rawValue)]!, _1, _2) } public init(primaryComponent: PresentationStringsComponent, secondaryComponent: PresentationStringsComponent?, groupingSeparator: String) { diff --git a/submodules/TelegramUI/TelegramUI/ChatController.swift b/submodules/TelegramUI/TelegramUI/ChatController.swift index ee1d46ff01..09d4a6ebdb 100644 --- a/submodules/TelegramUI/TelegramUI/ChatController.swift +++ b/submodules/TelegramUI/TelegramUI/ChatController.swift @@ -1892,7 +1892,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G strongSelf.presentInGlobalOverlay(contextController) } avatarNode.tapped = { [weak self] in - self?.navigationButtonAction(.openChatInfo(expandAvatar: true)) + guard let strongSelf = self else { + return + } + var expandAvatar = false + if let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer, peer.smallProfileImage != nil { + expandAvatar = true + } + strongSelf.navigationButtonAction(.openChatInfo(expandAvatar: expandAvatar)) } } self.navigationItem.titleView = self.chatTitleView diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageInteractiveMediaBadge.swift b/submodules/TelegramUI/TelegramUI/ChatMessageInteractiveMediaBadge.swift index d71b6f4a6f..b713b25614 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageInteractiveMediaBadge.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageInteractiveMediaBadge.swift @@ -87,7 +87,7 @@ final class ChatMessageInteractiveMediaBadge: ASDisplayNode { return self.measureNode.measure(CGSize(width: 240.0, height: 160.0)).width } - func update(theme: PresentationTheme, content: ChatMessageInteractiveMediaBadgeContent?, mediaDownloadState: ChatMessageInteractiveMediaDownloadState?, alignment: NSTextAlignment = .left, animated: Bool, badgeAnimated: Bool = true) { + func update(theme: PresentationTheme?, content: ChatMessageInteractiveMediaBadgeContent?, mediaDownloadState: ChatMessageInteractiveMediaDownloadState?, alignment: NSTextAlignment = .left, animated: Bool, badgeAnimated: Bool = true) { var transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.2, curve: .easeInOut) : .immediate let previousContentSize = self.previousContentSize @@ -263,7 +263,7 @@ final class ChatMessageInteractiveMediaBadge: ASDisplayNode { var originY: CGFloat = 5.0 switch mediaDownloadState { case .remote: - if let image = PresentationResourcesChat.chatBubbleFileCloudFetchMediaIcon(theme) { + if let theme = theme, let image = PresentationResourcesChat.chatBubbleFileCloudFetchMediaIcon(theme) { state = .customIcon(image) } else { state = .none diff --git a/submodules/TelegramUI/TelegramUI/ChatTitleView.swift b/submodules/TelegramUI/TelegramUI/ChatTitleView.swift index bc988e496b..27802c7185 100644 --- a/submodules/TelegramUI/TelegramUI/ChatTitleView.swift +++ b/submodules/TelegramUI/TelegramUI/ChatTitleView.swift @@ -60,7 +60,7 @@ private final class ChatTitleNetworkStatusNode: ASDisplayNode { func updateTheme(theme: PresentationTheme) { self.theme = theme - self.titleNode.attributedText = NSAttributedString(string: self.title, font: Font.bold(17.0), textColor: self.theme.rootController.navigationBar.primaryTextColor) + self.titleNode.attributedText = NSAttributedString(string: self.title, font: Font.medium(24.0), textColor: self.theme.rootController.navigationBar.primaryTextColor) self.activityIndicator.type = .custom(self.theme.rootController.navigationBar.primaryTextColor, 22.0, 1.5, false) } @@ -109,7 +109,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { private var titleRightIcon: ChatTitleIcon = .none private var titleScamIcon = false - private var networkStatusNode: ChatTitleNetworkStatusNode? + //private var networkStatusNode: ChatTitleNetworkStatusNode? private var presenceManager: PeerPresenceStatusManager? @@ -125,7 +125,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { isOnline = true } - if isOnline || layout?.metrics.widthClass == .regular { + /*if isOnline || layout?.metrics.widthClass == .regular { self.contentContainer.isHidden = false if let networkStatusNode = self.networkStatusNode { self.networkStatusNode = nil @@ -155,7 +155,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { case .online: break } - } + }*/ self.setNeedsLayout() } @@ -164,6 +164,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { didSet { if self.networkState != oldValue { updateNetworkStatusNode(networkState: self.networkState, layout: self.layout) + self.updateStatus() } } } @@ -277,175 +278,191 @@ final class ChatTitleView: UIView, NavigationBarTitleView { } var state = ChatTitleActivityNodeState.none - if let (peerId, inputActivities) = self.inputActivities, !inputActivities.isEmpty, inputActivitiesAllowed { - var stringValue = "" - var first = true - var mergedActivity = inputActivities[0].1 - for (_, activity) in inputActivities { - if activity != mergedActivity { - mergedActivity = .typingText - break - } + switch self.networkState { + case .waitingForNetwork, .connecting, .updating: + var infoText: String + switch self.networkState { + case .waitingForNetwork: + infoText = self.strings.ChatState_WaitingForNetwork + case let .connecting(proxy): + infoText = self.strings.ChatState_Connecting + case .updating: + infoText = self.strings.ChatState_Updating + case .online: + infoText = "" } - if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.SecretChat { - switch mergedActivity { - case .typingText: - stringValue = strings.Conversation_typing - case .uploadingFile: - stringValue = strings.Activity_UploadingDocument - case .recordingVoice: - stringValue = strings.Activity_RecordingAudio - case .uploadingPhoto: - stringValue = strings.Activity_UploadingPhoto - case .uploadingVideo: - stringValue = strings.Activity_UploadingVideo - case .playingGame: - stringValue = strings.Activity_PlayingGame - case .recordingInstantVideo: - stringValue = strings.Activity_RecordingVideoMessage - case .uploadingInstantVideo: - stringValue = strings.Activity_UploadingVideoMessage - } - } else { - for (peer, _) in inputActivities { - let title = peer.compactDisplayTitle - if !title.isEmpty { - if first { - first = false - } else { - stringValue += ", " - } - stringValue += title + state = .info(NSAttributedString(string: infoText, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor), .generic) + case .online: + if let (peerId, inputActivities) = self.inputActivities, !inputActivities.isEmpty, inputActivitiesAllowed { + var stringValue = "" + var first = true + var mergedActivity = inputActivities[0].1 + for (_, activity) in inputActivities { + if activity != mergedActivity { + mergedActivity = .typingText + break } } - } - let color = self.theme.rootController.navigationBar.accentTextColor - let string = NSAttributedString(string: stringValue, font: Font.regular(13.0), textColor: color) - switch mergedActivity { - case .typingText: - state = .typingText(string, color) - case .recordingVoice: - state = .recordingVoice(string, color) - case .recordingInstantVideo: - state = .recordingVideo(string, color) - case .uploadingFile, .uploadingInstantVideo, .uploadingPhoto, .uploadingVideo: - state = .uploading(string, color) - case .playingGame: - state = .playingGame(string, color) - } - } else { - if let titleContent = self.titleContent { - switch titleContent { - case let .peer(peerView, onlineMemberCount, isScheduledMessages): - if let peer = peerViewMainPeer(peerView) { - let servicePeer = isServicePeer(peer) - if peer.id == self.account.peerId || isScheduledMessages { - let string = NSAttributedString(string: "", font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) - state = .info(string, .generic) - } else if let user = peer as? TelegramUser { - if servicePeer { + if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.SecretChat { + switch mergedActivity { + case .typingText: + stringValue = strings.Conversation_typing + case .uploadingFile: + stringValue = strings.Activity_UploadingDocument + case .recordingVoice: + stringValue = strings.Activity_RecordingAudio + case .uploadingPhoto: + stringValue = strings.Activity_UploadingPhoto + case .uploadingVideo: + stringValue = strings.Activity_UploadingVideo + case .playingGame: + stringValue = strings.Activity_PlayingGame + case .recordingInstantVideo: + stringValue = strings.Activity_RecordingVideoMessage + case .uploadingInstantVideo: + stringValue = strings.Activity_UploadingVideoMessage + } + } else { + for (peer, _) in inputActivities { + let title = peer.compactDisplayTitle + if !title.isEmpty { + if first { + first = false + } else { + stringValue += ", " + } + stringValue += title + } + } + } + let color = self.theme.rootController.navigationBar.accentTextColor + let string = NSAttributedString(string: stringValue, font: Font.regular(13.0), textColor: color) + switch mergedActivity { + case .typingText: + state = .typingText(string, color) + case .recordingVoice: + state = .recordingVoice(string, color) + case .recordingInstantVideo: + state = .recordingVideo(string, color) + case .uploadingFile, .uploadingInstantVideo, .uploadingPhoto, .uploadingVideo: + state = .uploading(string, color) + case .playingGame: + state = .playingGame(string, color) + } + } else { + if let titleContent = self.titleContent { + switch titleContent { + case let .peer(peerView, onlineMemberCount, isScheduledMessages): + if let peer = peerViewMainPeer(peerView) { + let servicePeer = isServicePeer(peer) + if peer.id == self.account.peerId || isScheduledMessages { let string = NSAttributedString(string: "", font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) state = .info(string, .generic) - } else if user.flags.contains(.isSupport) { - let statusText = self.strings.Bot_GenericSupportStatus - - let string = NSAttributedString(string: statusText, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) - state = .info(string, .generic) - } else if let _ = user.botInfo { - let statusText = self.strings.Bot_GenericBotStatus - - let string = NSAttributedString(string: statusText, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) - state = .info(string, .generic) - } else if let peer = peerViewMainPeer(peerView) { - let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 - let userPresence: TelegramUserPresence - if let presence = peerView.peerPresences[peer.id] as? TelegramUserPresence { - userPresence = presence - self.presenceManager?.reset(presence: presence) + } else if let user = peer as? TelegramUser { + if servicePeer { + let string = NSAttributedString(string: "", font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) + state = .info(string, .generic) + } else if user.flags.contains(.isSupport) { + let statusText = self.strings.Bot_GenericSupportStatus + + let string = NSAttributedString(string: statusText, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) + state = .info(string, .generic) + } else if let _ = user.botInfo { + let statusText = self.strings.Bot_GenericBotStatus + + let string = NSAttributedString(string: statusText, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) + state = .info(string, .generic) + } else if let peer = peerViewMainPeer(peerView) { + let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + let userPresence: TelegramUserPresence + if let presence = peerView.peerPresences[peer.id] as? TelegramUserPresence { + userPresence = presence + self.presenceManager?.reset(presence: presence) + } else { + userPresence = TelegramUserPresence(status: .none, lastActivity: 0) + } + let (string, activity) = stringAndActivityForUserPresence(strings: self.strings, dateTimeFormat: self.dateTimeFormat, presence: userPresence, relativeTo: Int32(timestamp)) + let attributedString = NSAttributedString(string: string, font: Font.regular(13.0), textColor: activity ? self.theme.rootController.navigationBar.accentTextColor : self.theme.rootController.navigationBar.secondaryTextColor) + state = .info(attributedString, activity ? .online : .lastSeenTime) } else { - userPresence = TelegramUserPresence(status: .none, lastActivity: 0) + let string = NSAttributedString(string: "", font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) + state = .info(string, .generic) } - let (string, activity) = stringAndActivityForUserPresence(strings: self.strings, dateTimeFormat: self.dateTimeFormat, presence: userPresence, relativeTo: Int32(timestamp)) - let attributedString = NSAttributedString(string: string, font: Font.regular(13.0), textColor: activity ? self.theme.rootController.navigationBar.accentTextColor : self.theme.rootController.navigationBar.secondaryTextColor) - state = .info(attributedString, activity ? .online : .lastSeenTime) - } else { - let string = NSAttributedString(string: "", font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) - state = .info(string, .generic) - } - } else if let group = peer as? TelegramGroup { - var onlineCount = 0 - if let cachedGroupData = peerView.cachedData as? CachedGroupData, let participants = cachedGroupData.participants { - let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 - for participant in participants.participants { - if let presence = peerView.peerPresences[participant.peerId] as? TelegramUserPresence { - let relativeStatus = relativeUserPresenceStatus(presence, relativeTo: Int32(timestamp)) - switch relativeStatus { - case .online: - onlineCount += 1 - default: - break + } else if let group = peer as? TelegramGroup { + var onlineCount = 0 + if let cachedGroupData = peerView.cachedData as? CachedGroupData, let participants = cachedGroupData.participants { + let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + for participant in participants.participants { + if let presence = peerView.peerPresences[participant.peerId] as? TelegramUserPresence { + let relativeStatus = relativeUserPresenceStatus(presence, relativeTo: Int32(timestamp)) + switch relativeStatus { + case .online: + onlineCount += 1 + default: + break + } } } } - } - if onlineCount > 1 { - let string = NSMutableAttributedString() - - string.append(NSAttributedString(string: "\(strings.Conversation_StatusMembers(Int32(group.participantCount))), ", font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)) - string.append(NSAttributedString(string: strings.Conversation_StatusOnline(Int32(onlineCount)), font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)) - state = .info(string, .generic) - } else { - let string = NSAttributedString(string: strings.Conversation_StatusMembers(Int32(group.participantCount)), font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) - state = .info(string, .generic) - } - } else if let channel = peer as? TelegramChannel { - if let cachedChannelData = peerView.cachedData as? CachedChannelData, let memberCount = cachedChannelData.participantsSummary.memberCount { - if memberCount == 0 { - let string: NSAttributedString - if case .group = channel.info { - string = NSAttributedString(string: strings.Group_Status, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) - } else { - string = NSAttributedString(string: strings.Channel_Status, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) - } + if onlineCount > 1 { + let string = NSMutableAttributedString() + + string.append(NSAttributedString(string: "\(strings.Conversation_StatusMembers(Int32(group.participantCount))), ", font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)) + string.append(NSAttributedString(string: strings.Conversation_StatusOnline(Int32(onlineCount)), font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)) state = .info(string, .generic) } else { - if case .group = channel.info, let onlineMemberCount = onlineMemberCount, onlineMemberCount > 1 { - let string = NSMutableAttributedString() - - string.append(NSAttributedString(string: "\(strings.Conversation_StatusMembers(Int32(memberCount))), ", font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)) - string.append(NSAttributedString(string: strings.Conversation_StatusOnline(Int32(onlineMemberCount)), font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)) + let string = NSAttributedString(string: strings.Conversation_StatusMembers(Int32(group.participantCount)), font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) + state = .info(string, .generic) + } + } else if let channel = peer as? TelegramChannel { + if let cachedChannelData = peerView.cachedData as? CachedChannelData, let memberCount = cachedChannelData.participantsSummary.memberCount { + if memberCount == 0 { + let string: NSAttributedString + if case .group = channel.info { + string = NSAttributedString(string: strings.Group_Status, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) + } else { + string = NSAttributedString(string: strings.Channel_Status, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) + } state = .info(string, .generic) } else { - let membersString: String - if case .group = channel.info { - membersString = strings.Conversation_StatusMembers(memberCount) + if case .group = channel.info, let onlineMemberCount = onlineMemberCount, onlineMemberCount > 1 { + let string = NSMutableAttributedString() + + string.append(NSAttributedString(string: "\(strings.Conversation_StatusMembers(Int32(memberCount))), ", font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)) + string.append(NSAttributedString(string: strings.Conversation_StatusOnline(Int32(onlineMemberCount)), font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)) + state = .info(string, .generic) } else { - membersString = strings.Conversation_StatusSubscribers(memberCount) + let membersString: String + if case .group = channel.info { + membersString = strings.Conversation_StatusMembers(memberCount) + } else { + membersString = strings.Conversation_StatusSubscribers(memberCount) + } + let string = NSAttributedString(string: membersString, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) + state = .info(string, .generic) } - let string = NSAttributedString(string: membersString, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) - state = .info(string, .generic) } - } - } else { - switch channel.info { - case .group: - let string = NSAttributedString(string: strings.Group_Status, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) - state = .info(string, .generic) - case .broadcast: - let string = NSAttributedString(string: strings.Channel_Status, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) - state = .info(string, .generic) + } else { + switch channel.info { + case .group: + let string = NSAttributedString(string: strings.Group_Status, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) + state = .info(string, .generic) + case .broadcast: + let string = NSAttributedString(string: strings.Channel_Status, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) + state = .info(string, .generic) + } } } } - } - default: - break + default: + break + } + + self.accessibilityLabel = self.titleNode.attributedText?.string + self.accessibilityValue = state.string + } else { + self.accessibilityLabel = nil } - - self.accessibilityLabel = self.titleNode.attributedText?.string - self.accessibilityValue = state.string - } else { - self.accessibilityLabel = nil } } @@ -552,7 +569,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { self.theme = theme self.strings = strings - self.networkStatusNode?.updateTheme(theme: theme) + //self.networkStatusNode?.updateTheme(theme: theme) let titleContent = self.titleContent self.titleContent = titleContent self.updateStatus() @@ -612,7 +629,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { let titleSideInset: CGFloat = 3.0 if size.height > 40.0 { - var titleSize = self.titleNode.updateLayout(CGSize(width: clearBounds.width - leftIconWidth - credibilityIconWidth - rightIconWidth - titleSideInset * 2.0, height: size.height)) + var titleSize = self.titleNode.updateLayout(CGSize(width: clearBounds.width - leftIconWidth - credibilityIconWidth - rightIconWidth - titleSideInset * 2.0 - leftInset, height: size.height)) titleSize.width += credibilityIconWidth let activitySize = self.activityNode.updateLayout(clearBounds.size, alignment: .left) let titleInfoSpacing: CGFloat = 0.0 @@ -663,10 +680,10 @@ final class ChatTitleView: UIView, NavigationBarTitleView { } } - if let networkStatusNode = self.networkStatusNode { + /*if let networkStatusNode = self.networkStatusNode { transition.updateFrame(node: networkStatusNode, frame: CGRect(origin: CGPoint(), size: size)) networkStatusNode.updateLayout(size: size, transition: transition) - } + }*/ } @objc func buttonPressed() { diff --git a/submodules/TelegramUI/TelegramUI/FileMediaResourceStatus.swift b/submodules/TelegramUI/TelegramUI/FileMediaResourceStatus.swift index df635fa8b4..03980fc8e1 100644 --- a/submodules/TelegramUI/TelegramUI/FileMediaResourceStatus.swift +++ b/submodules/TelegramUI/TelegramUI/FileMediaResourceStatus.swift @@ -33,7 +33,7 @@ func messageFileMediaPlaybackStatus(context: AccountContext, file: TelegramMedia } } -func messageFileMediaResourceStatus(context: AccountContext, file: TelegramMediaFile, message: Message, isRecentActions: Bool) -> Signal { +func messageFileMediaResourceStatus(context: AccountContext, file: TelegramMediaFile, message: Message, isRecentActions: Bool, isSharedMedia: Bool = false) -> Signal { let playbackStatus = internalMessageFileMediaPlaybackStatus(context: context, file: file, message: message, isRecentActions: isRecentActions) |> map { status -> MediaPlayerPlaybackStatus? in return status?.status } diff --git a/submodules/TelegramUI/TelegramUI/ListMessageFileItemNode.swift b/submodules/TelegramUI/TelegramUI/ListMessageFileItemNode.swift index b6e759f72f..57daa968c1 100644 --- a/submodules/TelegramUI/TelegramUI/ListMessageFileItemNode.swift +++ b/submodules/TelegramUI/TelegramUI/ListMessageFileItemNode.swift @@ -15,6 +15,7 @@ import AccountContext import RadialStatusNode import PhotoResources import MusicAlbumArtResources +import UniversalMediaPlayer private let extensionImageCache = Atomic<[UInt32: UIImage]>(value: [:]) @@ -124,6 +125,7 @@ private struct FetchControls { private enum FileIconImage: Equatable { case imageRepresentation(TelegramMediaFile, TelegramMediaImageRepresentation) case albumArt(TelegramMediaFile, SharedMediaPlaybackAlbumArt) + case roundVideo(TelegramMediaFile) static func ==(lhs: FileIconImage, rhs: FileIconImage) -> Bool { switch lhs { @@ -139,6 +141,12 @@ private enum FileIconImage: Equatable { } else { return false } + case let .roundVideo(file): + if case .roundVideo(file) = rhs { + return true + } else { + return false + } } } } @@ -159,6 +167,10 @@ final class ListMessageFileItemNode: ListMessageNode { private let statusButtonNode: HighlightTrackingButtonNode private let statusNode: RadialStatusNode + private var waveformNode: AudioWaveformNode? + private var waveformForegroundNode: AudioWaveformNode? + private var waveformScrubbingNode: MediaPlayerScrubbingNode? + private var currentIconImage: FileIconImage? private var currentMedia: Media? @@ -167,6 +179,8 @@ final class ListMessageFileItemNode: ListMessageNode { private var fetchStatus: MediaResourceStatus? private var resourceStatus: FileMediaResourceMediaStatus? private let fetchDisposable = MetaDisposable() + private let playbackStatusDisposable = MetaDisposable() + private let playbackStatus = Promise() private var downloadStatusIconNode: ASImageNode private var linearProgressNode: ASDisplayNode @@ -226,7 +240,7 @@ final class ListMessageFileItemNode: ListMessageNode { self.downloadStatusIconNode.displayWithoutProcessing = true self.progressNode = RadialProgressNode(theme: RadialProgressTheme(backgroundColor: .black, foregroundColor: .white, icon: nil)) - self.progressNode.isLayerBacked = true + //self.progressNode.isLayerBacked = true self.linearProgressNode = ASDisplayNode() self.linearProgressNode.isLayerBacked = true @@ -235,6 +249,7 @@ final class ListMessageFileItemNode: ListMessageNode { self.addSubnode(self.separatorNode) self.addSubnode(self.titleNode) + self.addSubnode(self.progressNode) self.addSubnode(self.descriptionNode) self.addSubnode(self.descriptionProgressNode) self.addSubnode(self.extensionIconNode) @@ -335,9 +350,13 @@ final class ListMessageFileItemNode: ListMessageNode { var iconImage: FileIconImage? var updateIconImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>? var updatedStatusSignal: Signal? + var updatedPlaybackStatusSignal: Signal? var updatedFetchControls: FetchControls? + var waveform: AudioWaveform? var isAudio = false + var isVoice = false + var isInstantVideo = false let message = item.message @@ -346,9 +365,12 @@ final class ListMessageFileItemNode: ListMessageNode { if let file = media as? TelegramMediaFile { selectedMedia = file + isInstantVideo = file.isInstantVideo + for attribute in file.attributes { - if case let .Audio(voice, _, title, performer, _) = attribute { + if case let .Audio(voice, _, title, performer, waveformValue) = attribute { isAudio = true + isVoice = voice titleText = NSAttributedString(string: title ?? (file.fileName ?? "Unknown Track"), font: audioTitleFont, textColor: item.theme.list.itemPrimaryTextColor) @@ -365,11 +387,21 @@ final class ListMessageFileItemNode: ListMessageNode { if !voice { iconImage = .albumArt(file, SharedMediaPlaybackAlbumArt(thumbnailResource: ExternalMusicAlbumArtResource(title: title ?? "", performer: performer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(title: title ?? "", performer: performer ?? "", isThumbnail: false))) + } else { + titleText = NSAttributedString(string: " ", font: audioTitleFont, textColor: item.theme.list.itemPrimaryTextColor) + descriptionText = NSAttributedString(string: item.message.author?.displayTitle(strings: item.strings, displayOrder: .firstLast) ?? " ", font: descriptionFont, textColor: item.theme.list.itemSecondaryTextColor) + waveformValue?.withDataNoCopy { data in + waveform = AudioWaveform(bitstream: data, bitsPerSample: 5) + } } } } - if !isAudio { + if isInstantVideo { + titleText = NSAttributedString(string: item.strings.Message_VideoMessage, font: audioTitleFont, textColor: item.theme.list.itemPrimaryTextColor) + descriptionText = NSAttributedString(string: item.message.author?.displayTitle(strings: item.strings, displayOrder: .firstLast) ?? " ", font: descriptionFont, textColor: item.theme.list.itemSecondaryTextColor) + iconImage = .roundVideo(file) + } else if !isAudio { let fileName: String = file.fileName ?? "" titleText = NSAttributedString(string: fileName, font: titleFont, textColor: item.theme.list.itemPrimaryTextColor) @@ -402,7 +434,7 @@ final class ListMessageFileItemNode: ListMessageNode { } } - if isAudio { + if isAudio && !isVoice { leftInset += 14.0 } @@ -435,9 +467,9 @@ final class ListMessageFileItemNode: ListMessageNode { } if statusUpdated { - updatedStatusSignal = messageFileMediaResourceStatus(context: item.context, file: selectedMedia, message: message, isRecentActions: false) + updatedStatusSignal = messageFileMediaResourceStatus(context: item.context, file: selectedMedia, message: message, isRecentActions: false, isSharedMedia: true) - if isAudio { + if isAudio || isInstantVideo { if let currentUpdatedStatusSignal = updatedStatusSignal { updatedStatusSignal = currentUpdatedStatusSignal |> map { status in @@ -450,6 +482,9 @@ final class ListMessageFileItemNode: ListMessageNode { } } } + if isVoice { + updatedPlaybackStatusSignal = messageFileMediaPlaybackStatus(context: item.context, file: selectedMedia, message: message, isRecentActions: false) + } } } @@ -472,6 +507,11 @@ final class ListMessageFileItemNode: ListMessageNode { let imageCorners = ImageCorners(topLeft: .Corner(4.0), topRight: .Corner(4.0), bottomLeft: .Corner(4.0), bottomRight: .Corner(4.0)) let arguments = TransformImageArguments(corners: imageCorners, imageSize: iconSize, boundingSize: iconSize, intrinsicInsets: UIEdgeInsets(), emptyColor: item.theme.list.mediaPlaceholderColor) iconImageApply = iconImageLayout(arguments) + case let .roundVideo(file): + let iconSize = CGSize(width: 42.0, height: 42.0) + let imageCorners = ImageCorners(topLeft: .Corner(iconSize.width / 2.0), topRight: .Corner(iconSize.width / 2.0), bottomLeft: .Corner(iconSize.width / 2.0), bottomRight: .Corner(iconSize.width / 2.0)) + let arguments = TransformImageArguments(corners: imageCorners, imageSize: (file.dimensions ?? PixelDimensions(width: 320, height: 320)).cgSize.aspectFilled(iconSize), boundingSize: iconSize, intrinsicInsets: UIEdgeInsets(), emptyColor: item.theme.list.mediaPlaceholderColor) + iconImageApply = iconImageLayout(arguments) } } @@ -482,7 +522,8 @@ final class ListMessageFileItemNode: ListMessageNode { updateIconImageSignal = chatWebpageSnippetFile(account: item.context.account, fileReference: .message(message: MessageReference(message), media: file), representation: representation) case let .albumArt(file, albumArt): updateIconImageSignal = playerAlbumArt(postbox: item.context.account.postbox, fileReference: .message(message: MessageReference(message), media: file), albumArt: albumArt, thumbnail: true) - + case let .roundVideo(file): + updateIconImageSignal = mediaGridMessageVideo(postbox: item.context.account.postbox, videoReference: FileMediaReference.message(message: MessageReference(message), media: file), autoFetchFullSizeThumbnail: true) } } else { updateIconImageSignal = .complete() @@ -581,6 +622,48 @@ final class ListMessageFileItemNode: ListMessageNode { strongSelf.currentIconImage = iconImage + if isVoice { + let waveformNode: AudioWaveformNode + let waveformForegroundNode: AudioWaveformNode + let waveformScrubbingNode: MediaPlayerScrubbingNode + if let current = strongSelf.waveformNode { + waveformNode = current + } else { + waveformNode = AudioWaveformNode() + waveformNode.isLayerBacked = true + strongSelf.waveformNode = waveformNode + strongSelf.addSubnode(waveformNode) + } + if let current = strongSelf.waveformForegroundNode { + waveformForegroundNode = current + } else { + waveformForegroundNode = AudioWaveformNode() + waveformForegroundNode.isLayerBacked = true + strongSelf.waveformForegroundNode = waveformForegroundNode + strongSelf.addSubnode(waveformForegroundNode) + } + if let current = strongSelf.waveformScrubbingNode { + waveformScrubbingNode = current + } else { + waveformScrubbingNode = MediaPlayerScrubbingNode(content: .custom(backgroundNode: waveformNode, foregroundContentNode: waveformForegroundNode)) + waveformScrubbingNode.hitTestSlop = UIEdgeInsets(top: -10.0, left: 0.0, bottom: -10.0, right: 0.0) + waveformScrubbingNode.seek = { timestamp in + if let strongSelf = self, let context = strongSelf.context, let message = strongSelf.message, let type = peerMessageMediaPlayerType(message) { + context.sharedContext.mediaManager.playlistControl(.seek(timestamp), type: type) + } + } + waveformScrubbingNode.enableScrubbing = false + waveformScrubbingNode.status = strongSelf.playbackStatus.get() + strongSelf.waveformScrubbingNode = waveformScrubbingNode + strongSelf.addSubnode(waveformScrubbingNode) + } + + strongSelf.waveformScrubbingNode?.frame = CGRect(origin: CGPoint(x: leftOffset + leftInset, y: 10.0), size: CGSize(width: params.width - (leftOffset + leftInset) - 16.0, height: 12.0)) + + waveformNode.setup(color: item.theme.list.controlSecondaryColor, waveform: waveform) + waveformForegroundNode.setup(color: item.theme.list.itemAccentColor, waveform: waveform) + } + if let iconImageApply = iconImageApply { if let updateImageSignal = updateIconImageSignal { strongSelf.iconImageNode.setSignal(updateImageSignal) @@ -632,10 +715,24 @@ final class ListMessageFileItemNode: ListMessageNode { transition.updateFrame(node: strongSelf.downloadStatusIconNode, frame: CGRect(origin: CGPoint(x: leftOffset + leftInset, y: strongSelf.descriptionNode.frame.minY + floor((strongSelf.descriptionNode.frame.height - 11.0) / 2.0)), size: CGSize(width: 11.0, height: 11.0))) + let progressSize: CGFloat = 40.0 + transition.updateFrame(node: strongSelf.progressNode, frame: CGRect(origin: CGPoint(x: leftOffset + params.leftInset + floor((leftInset - params.leftInset - progressSize) / 2.0), y: floor((nodeLayout.contentSize.height - progressSize) / 2.0)), size: CGSize(width: progressSize, height: progressSize))) + if let updatedFetchControls = updatedFetchControls { let _ = strongSelf.fetchControls.swap(updatedFetchControls) } + if let updatedPlaybackStatusSignal = updatedPlaybackStatusSignal { + strongSelf.playbackStatus.set(updatedPlaybackStatusSignal) + /*strongSelf.playbackStatusDisposable.set((updatedPlaybackStatusSignal |> deliverOnMainQueue).start(next: { [weak strongSelf] status in + displayLinkDispatcher.dispatch { + if let strongSelf = strongSelf { + strongSelf.playerStatus = status + } + } + }))*/ + } + strongSelf.updateStatus(transition: transition) } }) @@ -648,25 +745,34 @@ final class ListMessageFileItemNode: ListMessageNode { } var isAudio = false + var isVoice = false + var isInstantVideo = false if let file = media as? TelegramMediaFile { isAudio = file.isMusic || file.isVoice + isVoice = file.isVoice + isInstantVideo = file.isInstantVideo } + self.progressNode.isHidden = !isVoice + + var enableScrubbing = false var musicIsPlaying: Bool? var statusState: RadialStatusNodeState = .none - if !isAudio { + if !isAudio && !isInstantVideo { self.updateProgressFrame(size: contentSize, leftInset: layoutParams.leftInset, rightInset: layoutParams.rightInset, transition: .immediate) } else { - switch fetchStatus { - case let .Fetching(_, progress): - let adjustedProgress = max(progress, 0.027) - statusState = .cloudProgress(color: item.theme.list.itemAccentColor, strokeBackgroundColor: item.theme.list.itemAccentColor.withAlphaComponent(0.5), lineWidth: 2.0, value: CGFloat(adjustedProgress)) - case .Local: - break - case .Remote: - if let image = PresentationResourcesItemList.cloudFetchIcon(item.theme) { - statusState = .customIcon(image) - } + if !isVoice && !isInstantVideo { + switch fetchStatus { + case let .Fetching(_, progress): + let adjustedProgress = max(progress, 0.027) + statusState = .cloudProgress(color: item.theme.list.itemAccentColor, strokeBackgroundColor: item.theme.list.itemAccentColor.withAlphaComponent(0.5), lineWidth: 2.0, value: CGFloat(adjustedProgress)) + case .Local: + break + case .Remote: + if let image = PresentationResourcesItemList.cloudFetchIcon(item.theme) { + statusState = .customIcon(image) + } + } } self.statusNode.transitionToState(statusState, completion: {}) self.statusButtonNode.isUserInteractionEnabled = statusState != .none @@ -691,6 +797,7 @@ final class ListMessageFileItemNode: ListMessageNode { } } case let .playbackStatus(playbackStatus): + enableScrubbing = true switch playbackStatus { case .playing: musicIsPlaying = true @@ -701,7 +808,8 @@ final class ListMessageFileItemNode: ListMessageNode { } } } - if let musicIsPlaying = musicIsPlaying { + self.waveformScrubbingNode?.enableScrubbing = enableScrubbing + if let musicIsPlaying = musicIsPlaying, !isVoice { if self.playbackOverlayNode == nil { let playbackOverlayNode = ListMessagePlaybackOverlayNode() playbackOverlayNode.frame = self.iconImageNode.frame diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoFilesPane.swift b/submodules/TelegramUI/TelegramUI/PeerInfoFilesPane.swift index 112682fe33..e5b8b0bc22 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfoFilesPane.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfoFilesPane.swift @@ -13,6 +13,8 @@ import TelegramUIPreferences final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode { private let context: AccountContext private let peerId: PeerId + private let paneInteraction: PeerInfoPaneInteraction + private let controllerInteraction: ChatControllerInteraction private let listNode: ChatHistoryListNode @@ -24,14 +26,25 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode { return self.ready.get() } + private let selectedMessagesPromise = Promise?>(nil) + private var selectedMessages: Set? { + didSet { + if self.selectedMessages != oldValue { + self.selectedMessagesPromise.set(.single(self.selectedMessages)) + } + } + } + private var hiddenMediaDisposable: Disposable? - init(context: AccountContext, openMessage: @escaping (MessageId) -> Bool, peerId: PeerId, tagMask: MessageTags) { + init(context: AccountContext, openMessage: @escaping (MessageId) -> Bool, peerId: PeerId, tagMask: MessageTags, interaction: PeerInfoPaneInteraction) { self.context = context self.peerId = peerId + self.paneInteraction = interaction var openMessageImpl: ((MessageId) -> Bool)? - let controllerInteraction = ChatControllerInteraction(openMessage: { message, _ in + var toggleMessageSelectionImpl: (([MessageId]) -> Void)? + self.controllerInteraction = ChatControllerInteraction(openMessage: { message, _ in return openMessageImpl?(message.id) ?? false }, openPeer: { _, _, _ in }, openPeerMention: { _ in @@ -39,7 +52,8 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode { }, openMessageContextActions: { _, _, _, _ in }, navigateToMessage: { _, _ in }, tapMessage: nil, clickThroughMessage: { - }, toggleMessagesSelection: { _, _ in + }, toggleMessagesSelection: { ids, _ in + toggleMessageSelectionImpl?(ids) }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _ in @@ -97,8 +111,13 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode { }, requestMessageUpdate: { _ in }, cancelInteractiveKeyboardGestures: { }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false)) + self.controllerInteraction.selectionState = self.paneInteraction.selectedMessageIds.flatMap { ids in + return ChatInterfaceSelectionState(selectedIds: ids) + } + self.selectedMessages = self.paneInteraction.selectedMessageIds + self.selectedMessagesPromise.set(.single(self.selectedMessages)) - self.listNode = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), tagMask: tagMask, subject: nil, controllerInteraction: controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: false)) + self.listNode = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), tagMask: tagMask, subject: nil, controllerInteraction: controllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), mode: .list(search: false, reversed: false)) super.init() @@ -106,6 +125,12 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode { return openMessage(id) } + toggleMessageSelectionImpl = { [weak self] ids in + for id in ids { + self?.paneInteraction.toggleMessageSelected(id) + } + } + self.hiddenMediaDisposable = context.sharedContext.mediaManager.galleryHiddenMediaManager.hiddenIds().start(next: { [weak self] ids in guard let strongSelf = self else { return @@ -116,7 +141,7 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode { hiddenMedia[messageId] = [media] } } - controllerInteraction.hiddenMedia = hiddenMedia + strongSelf.controllerInteraction.hiddenMedia = hiddenMedia strongSelf.listNode.forEachItemNode { itemNode in if let itemNode = itemNode as? ListMessageNode { itemNode.updateHiddenMedia() @@ -171,4 +196,16 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode { } return transitionNode } + + func updateSelectedMessages(animated: Bool) { + self.controllerInteraction.selectionState = self.paneInteraction.selectedMessageIds.flatMap { ids in + return ChatInterfaceSelectionState(selectedIds: ids) + } + self.listNode.forEachItemNode { itemNode in + if let itemNode = itemNode as? ChatMessageItemView { + itemNode.updateSelectionState(animated: animated) + } + } + self.selectedMessages = self.paneInteraction.selectedMessageIds + } } diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoGroupsInCommonPaneNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfoGroupsInCommonPaneNode.swift new file mode 100644 index 0000000000..82c1c0b91f --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/PeerInfoGroupsInCommonPaneNode.swift @@ -0,0 +1,165 @@ +import AsyncDisplayKit +import Display +import TelegramCore +import SyncCore +import SwiftSignalKit +import Postbox +import TelegramPresentationData +import AccountContext +import ContextUI +import PhotoResources +import TelegramUIPreferences +import ItemListPeerItem +import MergeLists +import ItemListUI + +private struct GroupsInCommonListTransaction { + let deletions: [ListViewDeleteItem] + let insertions: [ListViewInsertItem] + let updates: [ListViewUpdateItem] +} + +private struct GroupsInCommonListEntry: Comparable, Identifiable { + var index: Int + var peer: Peer + + var stableId: PeerId { + return self.peer.id + } + + static func ==(lhs: GroupsInCommonListEntry, rhs: GroupsInCommonListEntry) -> Bool { + return lhs.peer.isEqual(rhs.peer) + } + + static func <(lhs: GroupsInCommonListEntry, rhs: GroupsInCommonListEntry) -> Bool { + return lhs.index < rhs.index + } + + func item(context: AccountContext, presentationData: PresentationData, openPeer: @escaping (Peer) -> Void) -> ListViewItem { + let peer = self.peer + return ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: context, peer: self.peer, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: nil, enabled: true, selectable: true, sectionId: 0, action: { + openPeer(peer) + }, setPeerIdWithRevealedOptions: { _, _ in + }, removePeer: { _ in + }, contextAction: { node, gesture in + //arguments.contextAction(peer, node, gesture) + }, hasTopStripe: false, noInsets: true) + } +} + +private func preparedTransition(from fromEntries: [GroupsInCommonListEntry], to toEntries: [GroupsInCommonListEntry], context: AccountContext, presentationData: PresentationData, openPeer: @escaping (Peer) -> Void) -> GroupsInCommonListTransaction { + 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(context: context, presentationData: presentationData, openPeer: openPeer), directionHint: nil) } + let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, openPeer: openPeer), directionHint: nil) } + + return GroupsInCommonListTransaction(deletions: deletions, insertions: insertions, updates: updates) +} + +final class PeerInfoGroupsInCommonPaneNode: ASDisplayNode, PeerInfoPaneNode { + private let context: AccountContext + private let peerId: PeerId + private let paneInteraction: PeerInfoPaneInteraction + + private let listNode: ListView + private var peers: [Peer] = [] + private var currentEntries: [GroupsInCommonListEntry] = [] + private var enqueuedTransactions: [GroupsInCommonListTransaction] = [] + + private var currentParams: (size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData)? + + private let ready = Promise() + private var didSetReady: Bool = false + var isReady: Signal { + return self.ready.get() + } + + init(context: AccountContext, peerId: PeerId, interaction: PeerInfoPaneInteraction, peers: [Peer]) { + self.context = context + self.peerId = peerId + self.paneInteraction = interaction + + self.listNode = ListView() + + super.init() + + self.listNode.preloadPages = true + self.addSubnode(self.listNode) + + self.peers = peers + } + + deinit { + } + + func scrollToTop() -> Bool { + if !self.listNode.scrollToOffsetFromTop(0.0) { + self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Spring(duration: 0.4), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) + return true + } else { + return false + } + } + + func update(size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { + let isFirstLayout = self.currentParams == nil + self.currentParams = (size, isScrollingLockedAtTop, presentationData) + + transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(), size: size)) + let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition) + + self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: size, insets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0), headerInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0), scrollIndicatorInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0), duration: duration, curve: curve), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) + + self.listNode.scrollEnabled = !isScrollingLockedAtTop + + if isFirstLayout { + self.updatePeers(peers: self.peers, presentationData: presentationData) + } + } + + private func updatePeers(peers: [Peer], presentationData: PresentationData) { + var entries: [GroupsInCommonListEntry] = [] + for peer in peers { + entries.append(GroupsInCommonListEntry(index: entries.count, peer: peer)) + } + let transaction = preparedTransition(from: self.currentEntries, to: entries, context: self.context, presentationData: presentationData, openPeer: { [weak self] peer in + self?.paneInteraction.openPeer(peer) + }) + self.currentEntries = entries + self.enqueuedTransactions.append(transaction) + self.dequeueTransaction() + } + + private func dequeueTransaction() { + guard let (layout, _, _) = self.currentParams, let transaction = self.enqueuedTransactions.first else { + return + } + + self.enqueuedTransactions.remove(at: 0) + + var options = ListViewDeleteAndInsertOptions() + options.insert(.Synchronous) + + self.listNode.transaction(deleteIndices: transaction.deletions, insertIndicesAndItems: transaction.insertions, updateIndicesAndItems: transaction.updates, options: options, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { [weak self] _ in + guard let strongSelf = self else { + return + } + if !strongSelf.didSetReady { + strongSelf.didSetReady = true + strongSelf.ready.set(.single(true)) + } + }) + } + + func findLoadedMessage(id: MessageId) -> Message? { + return nil + } + + func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { + return nil + } + + func updateSelectedMessages(animated: Bool) { + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift b/submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift index 06811f13db..fe64232ab7 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift @@ -20,8 +20,10 @@ import OverlayStatusController import ShareController import PhotoResources import PeerAvatarGalleryUI - -private let avatarFont = avatarPlaceholderFont(size: 28.0) +import TelegramIntents +import PeerInfoUI +import SearchBarNode +import SearchUI private enum PeerInfoHeaderButtonKey: Hashable { case message @@ -196,16 +198,21 @@ private final class PeerInfoAvatarListItemNode: ASDisplayNode { } func update(size: CGSize, transition: ContainedViewLayoutTransition) { + let imageSize = CGSize(width: min(size.width, size.height), height: min(size.width, size.height)) let makeLayout = self.imageNode.asyncLayout() - let applyLayout = makeLayout(TransformImageArguments(corners: ImageCorners(), imageSize: size, boundingSize: size, intrinsicInsets: UIEdgeInsets())) + let applyLayout = makeLayout(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets())) let _ = applyLayout() - transition.updateFrame(node: self.imageNode, frame: CGRect(origin: CGPoint(), size: size)) + transition.updateFrame(node: self.imageNode, frame: CGRect(origin: CGPoint(x: floor((size.width - imageSize.width) / 2.0), y: floor((size.height - imageSize.height) / 2.0)), size: imageSize)) } } private final class PeerInfoAvatarListContainerNode: ASDisplayNode { private let context: AccountContext + let controlsContainerNode: ASDisplayNode + let controlsContainerTransformNode: ASDisplayNode + let shadowNode: ASDisplayNode + let contentNode: ASDisplayNode private var items: [PeerInfoAvatarListItem] = [] private var itemNodes: [WrappedMediaResourceId: PeerInfoAvatarListItemNode] = [:] @@ -225,12 +232,25 @@ private final class PeerInfoAvatarListContainerNode: ASDisplayNode { self.contentNode = ASDisplayNode() + self.controlsContainerNode = ASDisplayNode() + self.controlsContainerNode.isUserInteractionEnabled = false + + self.controlsContainerTransformNode = ASDisplayNode() + self.controlsContainerTransformNode.isUserInteractionEnabled = false + + self.shadowNode = ASDisplayNode() + //self.shadowNode.backgroundColor = .green + super.init() self.backgroundColor = .black self.addSubnode(self.contentNode) + self.controlsContainerNode.addSubnode(self.shadowNode) + self.controlsContainerTransformNode.addSubnode(self.controlsContainerNode) + self.addSubnode(self.controlsContainerTransformNode) + self.view.disablesInteractiveTransitionGestureRecognizer = true self.view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))) } @@ -381,6 +401,7 @@ private final class PeerInfoAvatarTransformContainerNode: ASDisplayNode { init(context: AccountContext) { self.context = context + let avatarFont = avatarPlaceholderFont(size: floor(100.0 * 16.0 / 37.0)) self.avatarNode = AvatarNode(font: avatarFont) super.init() @@ -405,6 +426,38 @@ private final class PeerInfoAvatarTransformContainerNode: ASDisplayNode { } } +private final class PeerInfoEditingAvatarNode: ASDisplayNode { + let context: AccountContext + let avatarNode: AvatarNode + + var tapped: (() -> Void)? + + init(context: AccountContext) { + self.context = context + let avatarFont = avatarPlaceholderFont(size: floor(100.0 * 16.0 / 37.0)) + self.avatarNode = AvatarNode(font: avatarFont) + + super.init() + + self.addSubnode(self.avatarNode) + self.avatarNode.frame = CGRect(origin: CGPoint(x: -50.0, y: -50.0), size: CGSize(width: 100.0, height: 100.0)) + + self.avatarNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))) + } + + @objc private func tapGesture(_ recognizer: UITapGestureRecognizer) { + if case .ended = recognizer.state { + self.tapped?() + } + } + + func update(peer: Peer?, theme: PresentationTheme) { + if let peer = peer { + self.avatarNode.setPeer(context: self.context, theme: theme, peer: peer, synchronousLoad: false, displayDimensions: CGSize(width: 100.0, height: 100.0)) + } + } +} + private final class PeerInfoAvatarListNode: ASDisplayNode { let avatarContainerNode: PeerInfoAvatarTransformContainerNode let listContainerTransformNode: ASDisplayNode @@ -472,6 +525,379 @@ private final class PeerInfoAvatarListNode: ASDisplayNode { } } +private final class PeerInfoHeaderNavigationButton: HighlightableButtonNode { + private let regularTextNode: ImmediateTextNode + private let whiteTextNode: ImmediateTextNode + private let iconNode: ASImageNode + + private var key: PeerInfoHeaderNavigationButtonKey? + private var theme: PresentationTheme? + + var isWhite: Bool = false { + didSet { + if self.isWhite != oldValue { + self.regularTextNode.isHidden = self.isWhite + self.whiteTextNode.isHidden = !self.isWhite + } + } + } + + var action: (() -> Void)? + + override init() { + self.regularTextNode = ImmediateTextNode() + self.whiteTextNode = ImmediateTextNode() + self.whiteTextNode.isHidden = true + + self.iconNode = ASImageNode() + self.iconNode.displaysAsynchronously = false + self.iconNode.displayWithoutProcessing = true + + super.init() + + self.addSubnode(self.regularTextNode) + self.addSubnode(self.whiteTextNode) + self.addSubnode(self.iconNode) + + self.addTarget(self, action: #selector(self.pressed), forControlEvents: .touchUpInside) + } + + @objc private func pressed() { + self.action?() + } + + func update(key: PeerInfoHeaderNavigationButtonKey, presentationData: PresentationData) -> CGSize { + let textSize: CGSize + if self.key != key || self.theme !== presentationData.theme { + self.key = key + self.theme = presentationData.theme + + let text: String + var icon: UIImage? + var isBold = false + switch key { + case .edit: + text = presentationData.strings.Common_Edit + case .done, .cancel, .selectionDone: + text = presentationData.strings.Common_Done + isBold = true + case .select: + text = presentationData.strings.Common_Select + case .search: + text = "" + icon = PresentationResourcesRootController.navigationCompactSearchIcon(presentationData.theme) + } + + let font: UIFont = isBold ? Font.semibold(17.0) : Font.regular(17.0) + + self.regularTextNode.attributedText = NSAttributedString(string: text, font: font, textColor: presentationData.theme.rootController.navigationBar.accentTextColor) + self.whiteTextNode.attributedText = NSAttributedString(string: text, font: font, textColor: .white) + self.iconNode.image = icon + + textSize = self.regularTextNode.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude)) + let _ = self.whiteTextNode.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude)) + } else { + textSize = self.regularTextNode.bounds.size + } + + let inset: CGFloat = 0.0 + let height: CGFloat = 44.0 + + let textFrame = CGRect(origin: CGPoint(x: inset, y: floor((height - textSize.height) / 2.0)), size: textSize) + self.regularTextNode.frame = textFrame + self.whiteTextNode.frame = textFrame + + if let image = self.iconNode.image { + self.iconNode.frame = CGRect(origin: CGPoint(x: inset, y: floor((height - image.size.height) / 2.0)), size: image.size) + + return CGSize(width: image.size.width + inset * 2.0, height: height) + } else { + return CGSize(width: textSize.width + inset * 2.0, height: height) + } + } +} + +private enum PeerInfoHeaderNavigationButtonKey { + case edit + case done + case cancel + case select + case selectionDone + case search +} + +private struct PeerInfoHeaderNavigationButtonSpec: Equatable { + let key: PeerInfoHeaderNavigationButtonKey + let isForExpandedView: Bool +} + +private final class PeerInfoHeaderNavigationButtonContainerNode: ASDisplayNode { + private var buttonNodes: [PeerInfoHeaderNavigationButtonKey: PeerInfoHeaderNavigationButton] = [:] + + private var currentButtons: [PeerInfoHeaderNavigationButtonSpec] = [] + + var isWhite: Bool = false { + didSet { + if self.isWhite != oldValue { + for (_, buttonNode) in self.buttonNodes { + buttonNode.isWhite = self.isWhite + } + } + } + } + + var performAction: ((PeerInfoHeaderNavigationButtonKey) -> Void)? + + override init() { + super.init() + } + + func update(size: CGSize, presentationData: PresentationData, buttons: [PeerInfoHeaderNavigationButtonSpec], expandFraction: CGFloat, transition: ContainedViewLayoutTransition) { + let maximumExpandOffset: CGFloat = 14.0 + let expandOffset: CGFloat = -expandFraction * maximumExpandOffset + if self.currentButtons != buttons { + self.currentButtons = buttons + + var nextRegularButtonOrigin = size.width - 16.0 + var nextExpandedButtonOrigin = size.width - 16.0 + for spec in buttons.reversed() { + let buttonNode: PeerInfoHeaderNavigationButton + var wasAdded = false + if let current = self.buttonNodes[spec.key] { + buttonNode = current + } else { + wasAdded = true + buttonNode = PeerInfoHeaderNavigationButton() + self.buttonNodes[spec.key] = buttonNode + self.addSubnode(buttonNode) + buttonNode.isWhite = self.isWhite + buttonNode.action = { [weak self] in + self?.performAction?(spec.key) + } + } + let buttonSize = buttonNode.update(key: spec.key, presentationData: presentationData) + var nextButtonOrigin = spec.isForExpandedView ? nextExpandedButtonOrigin : nextRegularButtonOrigin + let buttonFrame = CGRect(origin: CGPoint(x: nextButtonOrigin - buttonSize.width, y: expandOffset + (spec.isForExpandedView ? maximumExpandOffset : 0.0)), size: buttonSize) + nextButtonOrigin -= buttonSize.width + 4.0 + if spec.isForExpandedView { + nextExpandedButtonOrigin = nextButtonOrigin + } else { + nextRegularButtonOrigin = nextButtonOrigin + } + if wasAdded { + buttonNode.frame = buttonFrame + } else { + transition.updateFrameAdditiveToCenter(node: buttonNode, frame: buttonFrame) + } + let alphaFactor: CGFloat = spec.isForExpandedView ? expandFraction : (1.0 - expandFraction) + transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor) + } + var removeKeys: [PeerInfoHeaderNavigationButtonKey] = [] + for (key, _) in self.buttonNodes { + if !buttons.contains(where: { $0.key == key }) { + removeKeys.append(key) + } + } + for key in removeKeys { + if let buttonNode = self.buttonNodes.removeValue(forKey: key) { + buttonNode.removeFromSupernode() + } + } + } else { + var nextRegularButtonOrigin = size.width - 16.0 + var nextExpandedButtonOrigin = size.width - 16.0 + for spec in buttons.reversed() { + if let buttonNode = self.buttonNodes[spec.key] { + let buttonSize = buttonNode.bounds.size + var nextButtonOrigin = spec.isForExpandedView ? nextExpandedButtonOrigin : nextRegularButtonOrigin + let buttonFrame = CGRect(origin: CGPoint(x: nextButtonOrigin - buttonSize.width, y: expandOffset + (spec.isForExpandedView ? maximumExpandOffset : 0.0)), size: buttonSize) + nextButtonOrigin -= buttonSize.width + 4.0 + if spec.isForExpandedView { + nextExpandedButtonOrigin = nextButtonOrigin + } else { + nextRegularButtonOrigin = nextButtonOrigin + } + transition.updateFrameAdditiveToCenter(node: buttonNode, frame: buttonFrame) + let alphaFactor: CGFloat = spec.isForExpandedView ? expandFraction : (1.0 - expandFraction) + transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor) + } + } + } + } +} + +private final class PeerInfoHeaderRegularContentNode: ASDisplayNode { + +} + +private enum PeerInfoHeaderTextFieldNodeKey { + case firstName + case lastName + case title + case description +} + +private protocol PeerInfoHeaderTextFieldNode: ASDisplayNode { + var text: String { get } + + func update(width: CGFloat, safeInset: CGFloat, hasPrevious: Bool, placeholder: String, isEnabled: Bool, presentationData: PresentationData, updateText: String?) -> CGFloat +} + +private final class PeerInfoHeaderSingleLineTextFieldNode: ASDisplayNode, PeerInfoHeaderTextFieldNode { + private let textNode: TextFieldNode + private let topSeparator: ASDisplayNode + + private var theme: PresentationTheme? + + var text: String { + return self.textNode.textField.text ?? "" + } + + override init() { + self.textNode = TextFieldNode() + self.topSeparator = ASDisplayNode() + + super.init() + + self.addSubnode(self.textNode) + self.addSubnode(self.topSeparator) + } + + func update(width: CGFloat, safeInset: CGFloat, hasPrevious: Bool, placeholder: String, isEnabled: Bool, presentationData: PresentationData, updateText: String?) -> CGFloat { + if self.theme !== presentationData.theme { + self.theme = presentationData.theme + self.textNode.textField.textColor = presentationData.theme.list.itemPrimaryTextColor + //self.textNode.textField.keyboardAppearance = presentationData.theme.keyboardAppearance + self.textNode.textField.tintColor = presentationData.theme.list.itemAccentColor + } + + let attributedPlaceholderText = NSAttributedString(string: placeholder, font: Font.regular(17.0), textColor: presentationData.theme.list.itemPlaceholderTextColor) + if self.textNode.textField.attributedPlaceholder == nil || !self.textNode.textField.attributedPlaceholder!.isEqual(to: attributedPlaceholderText) { + self.textNode.textField.attributedPlaceholder = attributedPlaceholderText + self.textNode.textField.accessibilityHint = attributedPlaceholderText.string + } + + if let updateText = updateText { + self.textNode.textField.text = updateText + } + + self.topSeparator.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + self.topSeparator.frame = CGRect(origin: CGPoint(x: safeInset + (hasPrevious ? 16.0 : 0.0), y: 0.0), size: CGSize(width: width, height: UIScreenPixel)) + + let height: CGFloat = 44.0 + + self.textNode.frame = CGRect(origin: CGPoint(x: safeInset + 16.0, y: floor((height - 40.0) / 2.0)), size: CGSize(width: max(1.0, width - 16.0 * 2.0), height: 40.0)) + + self.textNode.isUserInteractionEnabled = isEnabled + self.textNode.alpha = isEnabled ? 1.0 : 0.6 + + return height + } +} + +/*private final class PeerInfoHeaderMultiLineTextFieldNode: ASDisplayNode, PeerInfoHeaderTextFieldNode { + private let textNode: TextFieldNode + private let topSeparator: ASDisplayNode + + override init() { + self.textNode = TextFieldNode() + self.topSeparator = ASDisplayNode() + + super.init() + } + + func update(width: CGFloat, safeInset: CGFloat) -> CGFloat { + return 44.0 + } +}*/ + +private final class PeerInfoHeaderEditingContentNode: ASDisplayNode { + private let context: AccountContext + let avatarNode: PeerInfoEditingAvatarNode + + var itemNodes: [PeerInfoHeaderTextFieldNodeKey: PeerInfoHeaderTextFieldNode] = [:] + + init(context: AccountContext) { + self.context = context + self.avatarNode = PeerInfoEditingAvatarNode(context: context) + + super.init() + + self.addSubnode(self.avatarNode) + } + + func editingTextForKey(_ key: PeerInfoHeaderTextFieldNodeKey) -> String? { + return self.itemNodes[key]?.text + } + + func update(width: CGFloat, safeInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, peer: Peer?, isContact: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) -> CGFloat { + let avatarSize: CGFloat = 100.0 + let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 10.0), size: CGSize(width: avatarSize, height: avatarSize)) + transition.updateFrameAdditiveToCenter(node: self.avatarNode, frame: CGRect(origin: avatarFrame.center, size: CGSize())) + + var contentHeight: CGFloat = statusBarHeight + 10.0 + 100.0 + 20.0 + + var fieldKeys: [PeerInfoHeaderTextFieldNodeKey] = [] + if let _ = peer as? TelegramUser { + fieldKeys.append(.firstName) + fieldKeys.append(.lastName) + } + var hasPrevious = false + for key in fieldKeys { + let itemNode: PeerInfoHeaderTextFieldNode + var updateText: String? + if let current = self.itemNodes[key] { + itemNode = current + } else { + switch key { + case .firstName: + updateText = (peer as? TelegramUser)?.firstName ?? "" + case .lastName: + updateText = (peer as? TelegramUser)?.lastName ?? "" + case .title: + updateText = (peer as? TelegramUser)?.debugDisplayTitle ?? "" + case .description: + break + } + itemNode = PeerInfoHeaderSingleLineTextFieldNode() + self.itemNodes[key] = itemNode + self.addSubnode(itemNode) + } + let placeholder: String + var isEnabled = true + switch key { + case .firstName: + placeholder = "First Name" + isEnabled = isContact + case .lastName: + placeholder = "Last Name" + isEnabled = isContact + case .title: + placeholder = "Title" + case .description: + placeholder = "Description" + } + let itemHeight = itemNode.update(width: width, safeInset: safeInset, hasPrevious: hasPrevious, placeholder: placeholder, isEnabled: isEnabled, presentationData: presentationData, updateText: updateText) + transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: itemHeight))) + contentHeight += itemHeight + hasPrevious = true + } + var removeKeys: [PeerInfoHeaderTextFieldNodeKey] = [] + for (key, _) in self.itemNodes { + if !fieldKeys.contains(key) { + removeKeys.append(key) + } + } + for key in removeKeys { + if let itemNode = self.itemNodes.removeValue(forKey: key) { + itemNode.removeFromSupernode() + } + } + + return contentHeight + } +} + private final class PeerInfoHeaderNode: ASDisplayNode { private var context: AccountContext private var presentationData: PresentationData? @@ -479,6 +905,9 @@ private final class PeerInfoHeaderNode: ASDisplayNode { private(set) var isAvatarExpanded: Bool private let avatarListNode: PeerInfoAvatarListNode + + let regularContentNode: PeerInfoHeaderRegularContentNode + let editingContentNode: PeerInfoHeaderEditingContentNode let titleNodeContainer: ASDisplayNode let titleNodeRawContainer: ASDisplayNode let titleNode: ImmediateTextNode @@ -487,7 +916,9 @@ private final class PeerInfoHeaderNode: ASDisplayNode { let subtitleNode: ImmediateTextNode private var buttonNodes: [PeerInfoHeaderButtonKey: PeerInfoHeaderButtonNode] = [:] private let backgroundNode: ASDisplayNode + private let expandedBackgroundNode: ASDisplayNode let separatorNode: ASDisplayNode + let navigationButtonContainer: PeerInfoHeaderNavigationButtonContainerNode var performButtonAction: ((PeerInfoHeaderButtonKey) -> Void)? var requestAvatarExpansion: (() -> Void)? @@ -510,8 +941,16 @@ private final class PeerInfoHeaderNode: ASDisplayNode { self.subtitleNode = ImmediateTextNode() self.subtitleNode.displaysAsynchronously = false + self.regularContentNode = PeerInfoHeaderRegularContentNode() + self.editingContentNode = PeerInfoHeaderEditingContentNode(context: context) + self.editingContentNode.alpha = 0.0 + + self.navigationButtonContainer = PeerInfoHeaderNavigationButtonContainerNode() + self.backgroundNode = ASDisplayNode() self.backgroundNode.isLayerBacked = true + self.expandedBackgroundNode = ASDisplayNode() + self.expandedBackgroundNode.isLayerBacked = true self.separatorNode = ASDisplayNode() self.separatorNode.isLayerBacked = true @@ -519,12 +958,16 @@ private final class PeerInfoHeaderNode: ASDisplayNode { super.init() self.addSubnode(self.backgroundNode) + self.addSubnode(self.expandedBackgroundNode) self.addSubnode(self.separatorNode) - self.addSubnode(self.avatarListNode) self.titleNodeContainer.addSubnode(self.titleNode) - self.addSubnode(self.titleNodeContainer) + self.regularContentNode.addSubnode(self.titleNodeContainer) self.subtitleNodeContainer.addSubnode(self.subtitleNode) - self.addSubnode(self.subtitleNodeContainer) + self.regularContentNode.addSubnode(self.subtitleNodeContainer) + self.regularContentNode.addSubnode(self.avatarListNode) + self.addSubnode(self.regularContentNode) + self.addSubnode(self.editingContentNode) + self.addSubnode(self.navigationButtonContainer) self.avatarListNode.avatarContainerNode.tapped = { [weak self] in guard let strongSelf = self else { @@ -536,14 +979,24 @@ private final class PeerInfoHeaderNode: ASDisplayNode { } } - func update(width: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, contentOffset: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, notificationSettings: TelegramPeerNotificationSettings?, presence: TelegramUserPresence?, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat { + func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, contentOffset: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, notificationSettings: TelegramPeerNotificationSettings?, presence: TelegramUserPresence?, isContact: Bool, state: PeerInfoState, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat { self.presentationData = presentationData + self.regularContentNode.alpha = state.isEditing ? 0.0 : 1.0 + self.editingContentNode.alpha = state.isEditing ? 1.0 : 0.0 + + let editingContentHeight = self.editingContentNode.update(width: width, safeInset: containerInset, statusBarHeight: statusBarHeight, navigationHeight: navigationHeight, peer: state.isEditing ? peer : nil, isContact: isContact, presentationData: presentationData, transition: transition) + transition.updateFrame(node: self.editingContentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -contentOffset), size: CGSize(width: width, height: editingContentHeight))) + var transitionSourceHeight: CGFloat = 0.0 var transitionFraction: CGFloat = 0.0 var transitionSourceAvatarFrame = CGRect() var transitionSourceTitleFrame = CGRect() var transitionSourceSubtitleFrame = CGRect() + + self.backgroundNode.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor + self.expandedBackgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.backgroundColor + if let navigationTransition = self.navigationTransition, let sourceAvatarNode = navigationTransition.sourceTitleView.avatarNode?.avatarNode { transitionSourceHeight = navigationTransition.sourceNavigationBar.bounds.height transitionFraction = navigationTransition.fraction @@ -551,18 +1004,20 @@ private final class PeerInfoHeaderNode: ASDisplayNode { transitionSourceTitleFrame = navigationTransition.sourceTitleFrame transitionSourceSubtitleFrame = navigationTransition.sourceSubtitleFrame - transition.updateBackgroundColor(node: self.backgroundNode, color: presentationData.theme.list.itemBlocksBackgroundColor.interpolateTo(presentationData.theme.rootController.navigationBar.backgroundColor, fraction: transitionFraction)!) + //transition.updateBackgroundColor(node: self.backgroundNode, color: presentationData.theme.list.itemBlocksBackgroundColor.interpolateTo(presentationData.theme.rootController.navigationBar.backgroundColor, fraction: transitionFraction)!) + transition.updateAlpha(node: self.expandedBackgroundNode, alpha: transitionFraction) } else { - self.backgroundNode.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor - let backgroundTransitionFraction: CGFloat = max(0.0, min(1.0, contentOffset / (212.0))) - transition.updateBackgroundColor(node: self.backgroundNode, color: presentationData.theme.list.itemBlocksBackgroundColor.interpolateTo(presentationData.theme.rootController.navigationBar.backgroundColor, fraction: backgroundTransitionFraction)!) + transition.updateAlpha(node: self.expandedBackgroundNode, alpha: backgroundTransitionFraction) + //transition.updateBackgroundColor(node: self.backgroundNode, color: presentationData.theme.list.itemBlocksBackgroundColor.interpolateTo(presentationData.theme.rootController.navigationBar.backgroundColor, fraction: backgroundTransitionFraction)!) } self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor let defaultButtonSize: CGFloat = 40.0 let defaultMaxButtonSpacing: CGFloat = 40.0 + let expandedAvatarListHeight = min(width, containerHeight - 64.0) + let expandedAvatarListSize = CGSize(width: width, height: expandedAvatarListHeight) var buttonKeys: [PeerInfoHeaderButtonKey] = [] @@ -572,7 +1027,7 @@ private final class PeerInfoHeaderNode: ASDisplayNode { buttonKeys.append(.mute) buttonKeys.append(.more) - self.titleNode.attributedText = NSAttributedString(string: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.semibold(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor) + self.titleNode.attributedText = NSAttributedString(string: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.medium(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor) let presence = presence ?? TelegramUserPresence(status: .none, lastActivity: 0) let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 @@ -588,7 +1043,7 @@ private final class PeerInfoHeaderNode: ASDisplayNode { let textSideInset: CGFloat = 16.0 let expandedAvatarControlsHeight: CGFloat = 64.0 - let expandedAvatarHeight: CGFloat = width + expandedAvatarControlsHeight + let expandedAvatarHeight: CGFloat = expandedAvatarListSize.height + expandedAvatarControlsHeight let avatarSize: CGFloat = 100.0 let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 10.0), size: CGSize(width: avatarSize, height: avatarSize)) @@ -628,7 +1083,7 @@ private final class PeerInfoHeaderNode: ASDisplayNode { avatarScale = 1.0 * (1.0 - titleCollapseFraction) + avatarMinScale * titleCollapseFraction avatarOffset = apparentTitleLockOffset + 0.0 * (1.0 - titleCollapseFraction) + 10.0 * titleCollapseFraction } - let avatarListFrame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: width)) + let avatarListFrame = CGRect(origin: CGPoint(), size: expandedAvatarListSize) if self.isAvatarExpanded { self.avatarListNode.listContainerNode.isHidden = false @@ -647,6 +1102,7 @@ private final class PeerInfoHeaderNode: ASDisplayNode { } self.avatarListNode.update(size: CGSize(), isExpanded: self.isAvatarExpanded, peer: peer, theme: presentationData.theme, transition: transition) + self.editingContentNode.avatarNode.update(peer: peer, theme: presentationData.theme) if additive { transition.updateSublayerTransformScaleAdditive(node: self.avatarListNode.avatarContainerNode, scale: avatarScale) } else { @@ -654,12 +1110,12 @@ private final class PeerInfoHeaderNode: ASDisplayNode { } let apparentAvatarFrame: CGRect if self.isAvatarExpanded { - let expandedAvatarCenter = CGPoint(x: width / 2.0, y: width / 2.0 - contentOffset / 2.0) + let expandedAvatarCenter = CGPoint(x: expandedAvatarListSize.width / 2.0, y: expandedAvatarListSize.height / 2.0 - contentOffset / 2.0) apparentAvatarFrame = CGRect(origin: CGPoint(x: expandedAvatarCenter.x * (1.0 - transitionFraction) + transitionFraction * avatarCenter.x, y: expandedAvatarCenter.y * (1.0 - transitionFraction) + transitionFraction * avatarCenter.y), size: CGSize()) } else { apparentAvatarFrame = CGRect(origin: CGPoint(x: avatarCenter.x - avatarFrame.width / 2.0, y: -contentOffset + avatarOffset + avatarCenter.y - avatarFrame.height / 2.0), size: avatarFrame.size) } - if case let .animated(duration, curve) = transition, !transitionSourceAvatarFrame.width.isZero { + if case let .animated(duration, curve) = transition, !transitionSourceAvatarFrame.width.isZero, false { let previousFrame = self.avatarListNode.frame self.avatarListNode.frame = CGRect(origin: apparentAvatarFrame.center, size: CGSize()) let horizontalTransition: ContainedViewLayoutTransition @@ -681,22 +1137,28 @@ private final class PeerInfoHeaderNode: ASDisplayNode { let avatarListContainerScale: CGFloat if self.isAvatarExpanded { if !transitionSourceAvatarFrame.width.isZero { - let neutralAvatarListContainerSize = CGSize(width: width, height: width) + let neutralAvatarListContainerSize = expandedAvatarListSize let avatarListContainerSize = CGSize(width: neutralAvatarListContainerSize.width * (1.0 - transitionFraction) + transitionSourceAvatarFrame.width * transitionFraction, height: neutralAvatarListContainerSize.height * (1.0 - transitionFraction) + transitionSourceAvatarFrame.height * transitionFraction) avatarListContainerFrame = CGRect(origin: CGPoint(x: -avatarListContainerSize.width / 2.0, y: -avatarListContainerSize.height / 2.0), size: avatarListContainerSize) } else { - avatarListContainerFrame = CGRect(origin: CGPoint(x: -width / 2.0, y: -width / 2.0), size: CGSize(width: width, height: width)) + avatarListContainerFrame = CGRect(origin: CGPoint(x: -expandedAvatarListSize.width / 2.0, y: -expandedAvatarListSize.height / 2.0), size: expandedAvatarListSize) } - avatarListContainerScale = 1.0 + max(0.0, -contentOffset / avatarListContainerFrame.width) + avatarListContainerScale = 1.0 + max(0.0, -contentOffset / avatarListContainerFrame.height) } else { avatarListContainerFrame = CGRect(origin: CGPoint(x: -apparentAvatarFrame.width / 2.0, y: -apparentAvatarFrame.height / 2.0), size: apparentAvatarFrame.size) avatarListContainerScale = avatarScale } transition.updateFrame(node: self.avatarListNode.listContainerNode, frame: avatarListContainerFrame) - let innerScale = avatarListContainerFrame.width / width - let innerDelta = (avatarListContainerFrame.width - width) / 2.0 + let innerScale = avatarListContainerFrame.height / expandedAvatarListSize.height + let innerDeltaX = (avatarListContainerFrame.width - expandedAvatarListSize.width) / 2.0 + let innerDeltaY = (avatarListContainerFrame.height - expandedAvatarListSize.height) / 2.0 transition.updateSublayerTransformScale(node: self.avatarListNode.listContainerNode, scale: innerScale) - transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.contentNode, frame: CGRect(origin: CGPoint(x: innerDelta + width / 2.0, y: innerDelta + width / 2.0), size: CGSize())) + transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.contentNode, frame: CGRect(origin: CGPoint(x: innerDeltaX + expandedAvatarListSize.width / 2.0, y: innerDeltaY + expandedAvatarListSize.height / 2.0), size: CGSize())) + + transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.controlsContainerTransformNode, frame: CGRect(origin: CGPoint(x: expandedAvatarListSize.width / 2.0, y: expandedAvatarListSize.height / 2.0 - innerDeltaY), size: CGSize())) + transition.updateSublayerTransformScale(node: self.avatarListNode.listContainerNode.controlsContainerNode, scale: 1.0 / innerScale) + transition.updateSublayerTransformScaleAdditive(node: self.avatarListNode.listContainerNode.controlsContainerTransformNode, scale: 1.0 / avatarListContainerScale) + transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.shadowNode, frame: CGRect(origin: CGPoint(x: -apparentAvatarFrame.minX, y: -apparentAvatarFrame.minY), size: CGSize(width: expandedAvatarListSize.width, height: navigationHeight))) if additive { transition.updateSublayerTransformScaleAdditive(node: self.avatarListNode.listContainerTransformNode, scale: avatarListContainerScale) @@ -704,7 +1166,7 @@ private final class PeerInfoHeaderNode: ASDisplayNode { transition.updateSublayerTransformScale(node: self.avatarListNode.listContainerTransformNode, scale: avatarListContainerScale) } - self.avatarListNode.listContainerNode.update(size: CGSize(width: width, height: width), peer: peer, transition: transition) + self.avatarListNode.listContainerNode.update(size: expandedAvatarListSize, peer: peer, transition: transition) let buttonsCollapseStart = titleCollapseOffset let buttonsCollapseEnd = 212.0 - (navigationHeight - statusBarHeight) + 10.0 @@ -837,7 +1299,7 @@ private final class PeerInfoHeaderNode: ASDisplayNode { self?.buttonPressed(buttonNode) }) self.buttonNodes[buttonKey] = buttonNode - self.addSubnode(buttonNode) + self.regularContentNode.addSubnode(buttonNode) } let buttonFrame = CGRect(origin: CGPoint(x: buttonRightOrigin.x - defaultButtonSize + buttonsScaledOffset, y: buttonRightOrigin.y), size: CGSize(width: defaultButtonSize, height: defaultButtonSize)) @@ -877,7 +1339,16 @@ private final class PeerInfoHeaderNode: ASDisplayNode { transition.updateSublayerTransformScaleAdditive(node: buttonNode, scale: buttonsScale) transition.updateAlpha(node: buttonNode, alpha: buttonsAlpha) - if self.isAvatarExpanded, case .mute = buttonKey { + + let hiddenWhileExpanded: Bool + switch buttonKey { + case .more: + hiddenWhileExpanded = false + default: + hiddenWhileExpanded = true + } + + if self.isAvatarExpanded, hiddenWhileExpanded { if case let .animated(duration, curve) = transition { ContainedViewLayoutTransition.animated(duration: duration * 0.3, curve: curve).updateAlpha(node: buttonNode.containerNode, alpha: 0.0) } else { @@ -906,21 +1377,40 @@ private final class PeerInfoHeaderNode: ASDisplayNode { } } - let backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -2000.0 + apparentHeight), size: CGSize(width: width, height: 2000.0)) - let separatorFrame = CGRect(origin: CGPoint(x: 0.0, y: apparentHeight), size: CGSize(width: width, height: UIScreenPixel)) + let resolvedRegularHeight: CGFloat + if self.isAvatarExpanded { + resolvedRegularHeight = expandedAvatarListSize.height + expandedAvatarControlsHeight + } else { + resolvedRegularHeight = 212.0 + navigationHeight + } + + let backgroundFrame: CGRect + let separatorFrame: CGRect + + let resolvedHeight: CGFloat + if state.isEditing { + resolvedHeight = editingContentHeight + backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -2000.0 + resolvedHeight - contentOffset), size: CGSize(width: width, height: 2000.0)) + separatorFrame = CGRect(origin: CGPoint(x: 0.0, y: resolvedHeight - contentOffset), size: CGSize(width: width, height: UIScreenPixel)) + } else { + resolvedHeight = resolvedRegularHeight + backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -2000.0 + apparentHeight), size: CGSize(width: width, height: 2000.0)) + separatorFrame = CGRect(origin: CGPoint(x: 0.0, y: apparentHeight), size: CGSize(width: width, height: UIScreenPixel)) + } + + transition.updateFrame(node: self.regularContentNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: resolvedHeight))) + if additive { transition.updateFrameAdditive(node: self.backgroundNode, frame: backgroundFrame) + transition.updateFrameAdditive(node: self.expandedBackgroundNode, frame: backgroundFrame) transition.updateFrameAdditive(node: self.separatorNode, frame: separatorFrame) } else { transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame) + transition.updateFrame(node: self.expandedBackgroundNode, frame: backgroundFrame) transition.updateFrame(node: self.separatorNode, frame: separatorFrame) } - if self.isAvatarExpanded { - return width + expandedAvatarControlsHeight - } else { - return 212.0 + navigationHeight - } + return resolvedHeight } private func buttonPressed(_ buttonNode: PeerInfoHeaderButtonNode) { @@ -928,13 +1418,16 @@ private final class PeerInfoHeaderNode: ASDisplayNode { } override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { - if !self.backgroundNode.frame.contains(point) { - return nil - } guard let result = super.hitTest(point, with: event) else { return nil } - if result == self.view { + if result.isDescendant(of: self.navigationButtonContainer.view) { + return result + } + if !self.backgroundNode.frame.contains(point) { + return nil + } + if result == self.view || result == self.regularContentNode.view || result == self.editingContentNode.view { return nil } return result @@ -952,6 +1445,22 @@ protocol PeerInfoPaneNode: ASDisplayNode { func scrollToTop() -> Bool func findLoadedMessage(id: MessageId) -> Message? func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? + func updateSelectedMessages(animated: Bool) +} + +final class PeerInfoPaneInteraction { + var selectedMessageIds: Set? + + let toggleMessageSelected: (MessageId) -> Void + let openPeer: (Peer) -> Void + + init( + toggleMessageSelected: @escaping (MessageId) -> Void, + openPeer: @escaping (Peer) -> Void + ) { + self.toggleMessageSelected = toggleMessageSelected + self.openPeer = openPeer + } } private final class PeerInfoPaneWrapper { @@ -979,7 +1488,9 @@ private enum PeerInfoPaneKey { case media case files case links + case voice case music + case groupsInCommon } private final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode { @@ -1057,6 +1568,7 @@ private final class PeerInfoPaneTabsContainerNode: ASDisplayNode { super.init() + self.scrollNode.view.disablesInteractiveTransitionGestureRecognizer = true self.scrollNode.view.showsHorizontalScrollIndicator = false self.scrollNode.view.scrollsToTop = false if #available(iOS 11.0, *) { @@ -1183,15 +1695,24 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { let isReady = Promise() var didSetIsReady = false - private var currentParams: (size: CGSize, expansionFraction: CGFloat, presentationData: PresentationData)? - - private var availablePanes: [PeerInfoPaneKey] = [] - private var currentPaneKey: PeerInfoPaneKey? + private var currentParams: (size: CGSize, expansionFraction: CGFloat, presentationData: PresentationData, data: PeerInfoScreenData?)? + private(set) var currentPaneKey: PeerInfoPaneKey? private var currentPane: PeerInfoPaneWrapper? - private var candidatePane: (PeerInfoPaneWrapper, Disposable)? + private var currentCandidatePaneKey: PeerInfoPaneKey? + private var candidatePane: (PeerInfoPaneWrapper, Disposable, Bool)? + + var selectionPanelNode: PeerInfoSelectionPanelNode? + + var _paneInteraction: PeerInfoPaneInteraction? + var paneInteraction: PeerInfoPaneInteraction { + return self._paneInteraction! + } var openMessage: ((MessageId) -> Bool)? + var toggleMessageSelected: ((MessageId) -> Void)? + var openPeer: ((Peer) -> Void)? + var currentPaneUpdated: (() -> Void)? init(context: AccountContext, peerId: PeerId) { self.context = context @@ -1210,14 +1731,26 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { super.init() + self._paneInteraction = PeerInfoPaneInteraction( + toggleMessageSelected: { [weak self] id in + guard let strongSelf = self else { + return + } + strongSelf.toggleMessageSelected?(id) + }, + openPeer: { [weak self] peer in + guard let strongSelf = self else { + return + } + strongSelf.openPeer?(peer) + } + ) + self.addSubnode(self.separatorNode) self.addSubnode(self.coveringBackgroundNode) self.addSubnode(self.tabsContainerNode) self.addSubnode(self.tapsSeparatorNode) - self.availablePanes = [.media, .files, .links, .music] - self.currentPaneKey = .media - self.tabsContainerNode.requestSelectPane = { [weak self] key in guard let strongSelf = self else { return @@ -1225,75 +1758,14 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { if strongSelf.currentPaneKey == key { return } - - let paneNode: PeerInfoPaneNode - switch key { - case .media: - paneNode = PeerInfoVisualMediaPaneNode(context: strongSelf.context, openMessage: { id in - return self?.openMessage?(id) ?? false - }, peerId: strongSelf.peerId) - case .files: - paneNode = PeerInfoListPaneNode(context: strongSelf.context, openMessage: { id in - return self?.openMessage?(id) ?? false - }, peerId: strongSelf.peerId, tagMask: .file) - case .links: - paneNode = PeerInfoListPaneNode(context: strongSelf.context, openMessage: { id in - return self?.openMessage?(id) ?? false - }, peerId: strongSelf.peerId, tagMask: .webPage) - case .music: - paneNode = PeerInfoListPaneNode(context: strongSelf.context, openMessage: { id in - return self?.openMessage?(id) ?? false - }, peerId: strongSelf.peerId, tagMask: .music) + if strongSelf.currentCandidatePaneKey == key { + return } + strongSelf.currentCandidatePaneKey = key - if let (_, disposable) = strongSelf.candidatePane { - disposable.dispose() + if let (size, expansionFraction, presentationData, data) = strongSelf.currentParams { + strongSelf.update(size: size, expansionFraction: expansionFraction, presentationData: presentationData, data: data, transition: .immediate) } - - let disposable = MetaDisposable() - strongSelf.candidatePane = (PeerInfoPaneWrapper(key: key, node: paneNode), disposable) - - if let (size, expansionFraction, presentationData) = strongSelf.currentParams { - strongSelf.update(size: size, expansionFraction: expansionFraction, presentationData: presentationData, transition: .immediate) - } - - disposable.set((paneNode.isReady - |> take(1) - |> deliverOnMainQueue).start(next: { _ in - guard let strongSelf = self else { - return - } - if let (candidatePane, _) = strongSelf.candidatePane { - let previousPane = strongSelf.currentPane - strongSelf.candidatePane = nil - strongSelf.currentPaneKey = candidatePane.key - strongSelf.currentPane = candidatePane - - if let (size, expansionFraction, presentationData) = strongSelf.currentParams { - strongSelf.update(size: size, expansionFraction: expansionFraction, presentationData: presentationData, transition: .animated(duration: 0.35, curve: .spring)) - - if let previousPane = previousPane { - let directionToRight: Bool - if let previousIndex = strongSelf.availablePanes.index(of: previousPane.key), let updatedIndex = strongSelf.availablePanes.index(of: candidatePane.key) { - directionToRight = previousIndex < updatedIndex - } else { - directionToRight = false - } - - let offset: CGFloat = directionToRight ? previousPane.node.bounds.width : -previousPane.node.bounds.width - candidatePane.node.layer.animatePosition(from: CGPoint(x: offset, y: 0.0), to: CGPoint(), duration: 0.35, timingFunction: kCAMediaTimingFunctionSpring, additive: true) - let previousNode = previousPane.node - previousNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: -offset, y: 0.0), duration: 0.35, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true, completion: { [weak previousNode] _ in - previousNode?.removeFromSupernode() - }) - } - } else { - if let previousPane = previousPane { - previousPane.node.removeFromSupernode() - } - } - } - })) } } @@ -1313,8 +1785,34 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { return self.currentPane?.node.transitionNodeForGallery(messageId: messageId, media: media) } - func update(size: CGSize, expansionFraction: CGFloat, presentationData: PresentationData, transition: ContainedViewLayoutTransition) { - self.currentParams = (size, expansionFraction, presentationData) + func updateSelectedMessageIds(_ selectedMessageIds: Set?, animated: Bool) { + if self.paneInteraction.selectedMessageIds != selectedMessageIds { + self.paneInteraction.selectedMessageIds = selectedMessageIds + self.currentPane?.node.updateSelectedMessages(animated: animated) + self.candidatePane?.0.node.updateSelectedMessages(animated: animated) + } + } + + func update(size: CGSize, expansionFraction: CGFloat, presentationData: PresentationData, data: PeerInfoScreenData?, transition: ContainedViewLayoutTransition) { + let availablePanes = data?.availablePanes ?? [] + + let previousCurrentPaneKey = self.currentPaneKey + if availablePanes.isEmpty { + self.currentPaneKey = nil + self.currentCandidatePaneKey = nil + if let (_, disposable, _) = self.candidatePane { + disposable.dispose() + self.candidatePane = nil + } + if let currentPane = self.currentPane { + self.currentPane = nil + currentPane.node.removeFromSupernode() + } + } else if (self.currentParams?.data?.availablePanes ?? []).isEmpty { + self.currentCandidatePaneKey = availablePanes.first + } + + self.currentParams = (size, expansionFraction, presentationData, data) transition.updateAlpha(node: self.coveringBackgroundNode, alpha: expansionFraction) @@ -1330,55 +1828,94 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { transition.updateFrame(node: self.tapsSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: tabsHeight - UIScreenPixel), size: CGSize(width: size.width, height: UIScreenPixel))) - transition.updateFrame(node: self.tabsContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: tabsHeight))) - self.tabsContainerNode.update(size: CGSize(width: size.width, height: tabsHeight), presentationData: presentationData, paneList: self.availablePanes.map { key in - let title: String - switch key { - case .media: - title = "Media" - case .files: - title = "Files" - case .links: - title = "Links" - case .music: - title = "Audio" - } - return PeerInfoPaneSpecifier(key: key, title: title) - }, selectedPane: self.currentPaneKey, transition: transition) - let paneFrame = CGRect(origin: CGPoint(x: 0.0, y: tabsHeight), size: CGSize(width: size.width, height: size.height - tabsHeight)) - if self.currentPane?.key != self.currentPaneKey { - if let currentPane = self.currentPane { - currentPane.node.removeFromSupernode() - self.currentPane = nil - } - - if let currentPaneKey = self.currentPaneKey { + if let currentCandidatePaneKey = self.currentCandidatePaneKey { + if self.candidatePane?.0.key != currentCandidatePaneKey { + self.candidatePane?.1.dispose() + let paneNode: PeerInfoPaneNode - switch currentPaneKey { + switch currentCandidatePaneKey { case .media: paneNode = PeerInfoVisualMediaPaneNode(context: self.context, openMessage: { [weak self] id in return self?.openMessage?(id) ?? false - }, peerId: self.peerId) + }, peerId: self.peerId, interaction: self.paneInteraction) case .files: paneNode = PeerInfoListPaneNode(context: self.context, openMessage: { [weak self] id in return self?.openMessage?(id) ?? false - }, peerId: self.peerId, tagMask: .file) + }, peerId: self.peerId, tagMask: .file, interaction: self.paneInteraction) case .links: - paneNode = PeerInfoListPaneNode(context: self.context, openMessage: { [weak self] id in + paneNode = PeerInfoListPaneNode(context: self.context, openMessage: { [weak self] id in return self?.openMessage?(id) ?? false - }, peerId: self.peerId, tagMask: .webPage) + }, peerId: self.peerId, tagMask: .webPage, interaction: self.paneInteraction) + case .voice: + paneNode = PeerInfoListPaneNode(context: self.context, openMessage: { [weak self] id in + return self?.openMessage?(id) ?? false + }, peerId: self.peerId, tagMask: .voiceOrInstantVideo, interaction: self.paneInteraction) case .music: - paneNode = PeerInfoListPaneNode(context: self.context, openMessage: { [weak self] id in + paneNode = PeerInfoListPaneNode(context: self.context, openMessage: { [weak self] id in return self?.openMessage?(id) ?? false - }, peerId: self.peerId, tagMask: .music) + }, peerId: self.peerId, tagMask: .music, interaction: self.paneInteraction) + case .groupsInCommon: + paneNode = PeerInfoGroupsInCommonPaneNode(context: self.context, peerId: peerId, interaction: self.paneInteraction, peers: data?.groupsInCommon ?? []) } - self.currentPane = PeerInfoPaneWrapper(key: currentPaneKey, node: paneNode) + + let disposable = MetaDisposable() + self.candidatePane = (PeerInfoPaneWrapper(key: currentCandidatePaneKey, node: paneNode), disposable, false) + + var shouldReLayout = false + disposable.set((paneNode.isReady + |> take(1) + |> deliverOnMainQueue).start(next: { [weak self] _ in + guard let strongSelf = self else { + return + } + if let (candidatePane, disposable, _) = strongSelf.candidatePane { + strongSelf.candidatePane = (candidatePane, disposable, true) + + if shouldReLayout { + if let (size, expansionFraction, presentationData, data) = strongSelf.currentParams { + strongSelf.update(size: size, expansionFraction: expansionFraction, presentationData: presentationData, data: data, transition: strongSelf.currentPane != nil ? .animated(duration: 0.35, curve: .spring) : .immediate) + } + } + } + })) + shouldReLayout = true } } - if let currentPane = self.currentPane { + if let (candidatePane, _, isReady) = self.candidatePane, isReady { + let previousPane = self.currentPane + self.candidatePane = nil + self.currentPaneKey = candidatePane.key + self.currentCandidatePaneKey = nil + self.currentPane = candidatePane + + if let selectionPanelNode = self.selectionPanelNode { + self.insertSubnode(candidatePane.node, belowSubnode: selectionPanelNode) + } else { + self.addSubnode(candidatePane.node) + } + candidatePane.node.frame = paneFrame + candidatePane.update(size: paneFrame.size, isScrollingLockedAtTop: expansionFraction < 1.0 - CGFloat.ulpOfOne, presentationData: presentationData, synchronous: true, transition: .immediate) + + if let previousPane = previousPane { + let directionToRight: Bool + if let previousIndex = availablePanes.index(of: previousPane.key), let updatedIndex = availablePanes.index(of: candidatePane.key) { + directionToRight = previousIndex < updatedIndex + } else { + directionToRight = false + } + + let offset: CGFloat = directionToRight ? previousPane.node.bounds.width : -previousPane.node.bounds.width + + transition.animatePositionAdditive(node: candidatePane.node, offset: CGPoint(x: offset, y: 0.0)) + let previousNode = previousPane.node + transition.updateFrame(node: previousNode, frame: paneFrame.offsetBy(dx: -offset, dy: 0.0), completion: { [weak previousNode] _ in + previousNode?.removeFromSupernode() + }) + } + } else if let currentPane = self.currentPane { let paneWasAdded = currentPane.node.supernode == nil if paneWasAdded { self.addSubnode(currentPane.node) @@ -1388,7 +1925,28 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { paneTransition.updateFrame(node: currentPane.node, frame: paneFrame) currentPane.update(size: paneFrame.size, isScrollingLockedAtTop: expansionFraction < 1.0 - CGFloat.ulpOfOne, presentationData: presentationData, synchronous: paneWasAdded, transition: paneTransition) } - if let (candidatePane, _) = self.candidatePane { + + transition.updateFrame(node: self.tabsContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: tabsHeight))) + self.tabsContainerNode.update(size: CGSize(width: size.width, height: tabsHeight), presentationData: presentationData, paneList: availablePanes.map { key in + let title: String + switch key { + case .media: + title = "Media" + case .files: + title = "Files" + case .links: + title = "Links" + case .voice: + title = "Voice Messages" + case .music: + title = "Audio" + case .groupsInCommon: + title = "Groups" + } + return PeerInfoPaneSpecifier(key: key, title: title) + }, selectedPane: self.currentPaneKey, transition: transition) + + if let (candidatePane, _, _) = self.candidatePane { let paneTransition: ContainedViewLayoutTransition = .immediate paneTransition.updateFrame(node: candidatePane.node, frame: paneFrame) candidatePane.update(size: paneFrame.size, isScrollingLockedAtTop: expansionFraction < 1.0 - CGFloat.ulpOfOne, presentationData: presentationData, synchronous: true, transition: paneTransition) @@ -1401,6 +1959,9 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { self.isReady.set(.single(true)) } } + if let previousCurrentPaneKey = previousCurrentPaneKey, self.currentPaneKey != previousCurrentPaneKey { + self.currentPaneUpdated?() + } } } @@ -1492,7 +2053,7 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { } } for id in removeIds { - if let itemNode = self.itemNodes[id] { + if let itemNode = self.itemNodes.removeValue(forKey: id) { transition.updateAlpha(node: itemNode, alpha: 0.0, completion: { [weak itemNode] _ in itemNode?.removeFromSupernode() }) @@ -1503,26 +2064,209 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { transition.updateFrame(node: self.topSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel))) transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: UIScreenPixel))) + if contentHeight.isZero { + transition.updateAlpha(node: self.topSeparatorNode, alpha: 0.0) + transition.updateAlpha(node: self.bottomSeparatorNode, alpha: 0.0) + } else { + transition.updateAlpha(node: self.topSeparatorNode, alpha: 1.0) + transition.updateAlpha(node: self.bottomSeparatorNode, alpha: 1.0) + } + return contentHeight } } +private final class PeerInfoSelectionPanelNode: ASDisplayNode { + private let context: AccountContext + private let peerId: PeerId + + private let deleteMessages: () -> Void + private let shareMessages: () -> Void + private let forwardMessages: () -> Void + private let reportMessages: () -> Void + + let selectionPanel: ChatMessageSelectionInputPanelNode + let separatorNode: ASDisplayNode + let backgroundNode: ASDisplayNode + + init(context: AccountContext, peerId: PeerId, deleteMessages: @escaping () -> Void, shareMessages: @escaping () -> Void, forwardMessages: @escaping () -> Void, reportMessages: @escaping () -> Void) { + self.context = context + self.peerId = peerId + self.deleteMessages = deleteMessages + self.shareMessages = shareMessages + self.forwardMessages = forwardMessages + self.reportMessages = reportMessages + + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + + self.separatorNode = ASDisplayNode() + self.backgroundNode = ASDisplayNode() + + self.selectionPanel = ChatMessageSelectionInputPanelNode(theme: presentationData.theme, strings: presentationData.strings, peerMedia: true) + self.selectionPanel.context = context + self.selectionPanel.backgroundColor = presentationData.theme.chat.inputPanel.panelBackgroundColor + + let interfaceInteraction = ChatPanelInterfaceInteraction(setupReplyMessage: { _, _ in + }, setupEditMessage: { _, _ in + }, beginMessageSelection: { _, _ in + }, deleteSelectedMessages: { + deleteMessages() + }, reportSelectedMessages: { + reportMessages() + }, reportMessages: { _, _ in + }, deleteMessages: { _, _, f in + f(.default) + }, forwardSelectedMessages: { + forwardMessages() + }, forwardCurrentForwardMessages: { + }, forwardMessages: { _ in + }, shareSelectedMessages: { + shareMessages() + }, updateTextInputStateAndMode: { _ in + }, updateInputModeAndDismissedButtonKeyboardMessageId: { _ in + }, openStickers: { + }, editMessage: { + }, beginMessageSearch: { _, _ in + }, dismissMessageSearch: { + }, updateMessageSearch: { _ in + }, openSearchResults: { + }, navigateMessageSearch: { _ in + }, openCalendarSearch: { + }, toggleMembersSearch: { _ in + }, navigateToMessage: { _ in + }, navigateToChat: { _ in + }, openPeerInfo: { + }, togglePeerNotifications: { + }, sendContextResult: { _, _, _, _ in + return false + }, sendBotCommand: { _, _ in + }, sendBotStart: { _ in + }, botSwitchChatWithPayload: { _, _ in + }, beginMediaRecording: { _ in + }, finishMediaRecording: { _ in + }, stopMediaRecording: { + }, lockMediaRecording: { + }, deleteRecordedMedia: { + }, sendRecordedMedia: { + }, displayRestrictedInfo: { _, _ in + }, displayVideoUnmuteTip: { _ in + }, switchMediaRecordingMode: { + }, setupMessageAutoremoveTimeout: { + }, sendSticker: { _, _, _ in + return false + }, unblockPeer: { + }, pinMessage: { _ in + }, unpinMessage: { + }, shareAccountContact: { + }, reportPeer: { + }, presentPeerContact: { + }, dismissReportPeer: { + }, deleteChat: { + }, beginCall: { + }, toggleMessageStickerStarred: { _ in + }, presentController: { _, _ in + }, getNavigationController: { + return nil + }, presentGlobalOverlayController: { _, _ in + }, navigateFeed: { + }, openGrouping: { + }, toggleSilentPost: { + }, requestUnvoteInMessage: { _ in + }, requestStopPollInMessage: { _ in + }, updateInputLanguage: { _ in + }, unarchiveChat: { + }, openLinkEditing: { + }, reportPeerIrrelevantGeoLocation: { + }, displaySlowmodeTooltip: { _, _ in + }, displaySendMessageOptions: { _, _ in + }, openScheduledMessages: { + }, displaySearchResultsTooltip: { _, _ in + }, statuses: nil) + + selectionPanel.interfaceInteraction = interfaceInteraction + + super.init() + + self.addSubnode(self.backgroundNode) + self.addSubnode(self.separatorNode) + self.addSubnode(self.selectionPanel) + } + + func update(width: CGFloat, safeInset: CGFloat, metrics: LayoutMetrics, presentationData: PresentationData, transition: ContainedViewLayoutTransition) -> CGFloat { + self.backgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.backgroundColor + self.separatorNode.backgroundColor = presentationData.theme.rootController.navigationBar.separatorColor + + let interfaceState = ChatPresentationInterfaceState(chatWallpaper: .color(0), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, limitsConfiguration: .defaultValue, fontSize: .regular, bubbleCorners: PresentationChatBubbleCorners(mainRadius: 16.0, auxiliaryRadius: 8.0, mergeBubbleCorners: true), accountPeerId: self.context.account.peerId, mode: .standard(previewing: false), chatLocation: .peer(self.peerId), isScheduledMessages: false) + let panelHeight = self.selectionPanel.updateLayout(width: width, leftInset: safeInset, rightInset: safeInset, maxHeight: 0.0, isSecondary: false, transition: transition, interfaceState: interfaceState, metrics: metrics) + + transition.updateFrame(node: self.selectionPanel, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))) + transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))) + transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel))) + + return panelHeight + } +} + +private final class PeerInfoState { + let isEditing: Bool + let isSearching: Bool + let selectedMessageIds: Set? + + init( + isEditing: Bool, + isSearching: Bool, + selectedMessageIds: Set? + ) { + self.isEditing = isEditing + self.isSearching = isSearching + self.selectedMessageIds = selectedMessageIds + } + + func withIsEditing(_ isEditing: Bool) -> PeerInfoState { + return PeerInfoState( + isEditing: isEditing, + isSearching: self.isSearching, + selectedMessageIds: self.selectedMessageIds + ) + } + + func withSelectedMessageIds(_ selectedMessageIds: Set?) -> PeerInfoState { + return PeerInfoState( + isEditing: self.isEditing, + isSearching: self.isSearching, + selectedMessageIds: selectedMessageIds + ) + } +} + private final class PeerInfoScreenData { let peer: Peer? let cachedData: CachedPeerData? let presence: TelegramUserPresence? let notificationSettings: TelegramPeerNotificationSettings? + let globalNotificationSettings: GlobalNotificationSettings? + let isContact: Bool + let availablePanes: [PeerInfoPaneKey] + let groupsInCommon: [Peer]? init( peer: Peer?, cachedData: CachedPeerData?, presence: TelegramUserPresence?, - notificationSettings: TelegramPeerNotificationSettings? + notificationSettings: TelegramPeerNotificationSettings?, + globalNotificationSettings: GlobalNotificationSettings?, + isContact: Bool, + availablePanes: [PeerInfoPaneKey], + groupsInCommon: [Peer]? ) { self.peer = peer self.cachedData = cachedData self.presence = presence self.notificationSettings = notificationSettings + self.globalNotificationSettings = globalNotificationSettings + self.isContact = isContact + self.availablePanes = availablePanes + self.groupsInCommon = groupsInCommon } } @@ -1531,6 +2275,44 @@ private enum PeerInfoScreenInputData: Equatable { case user } +private func peerInfoAvailableMediaPanes(context: AccountContext, peerId: PeerId) -> Signal<[PeerInfoPaneKey], NoError> { + let tags: [(MessageTags, PeerInfoPaneKey)] = [ + (.photoOrVideo, .media), + (.file, .files), + (.music, .music), + (.voiceOrInstantVideo, .voice), + (.webPage, .links) + ] + return combineLatest(tags.map { tagAndKey -> Signal in + let (tag, key) = tagAndKey + return context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId), index: .upperBound, anchorIndex: .upperBound, count: 2, clipHoles: false, fixedCombinedReadStates: nil, tagMask: tag) + |> map { (view, _, _) -> PeerInfoPaneKey? in + if view.entries.isEmpty { + return nil + } else { + return key + } + } + }) + |> map { keys -> [PeerInfoPaneKey] in + return keys.compactMap { $0 } + } + |> distinctUntilChanged + /*return context.account.postbox.combinedView(keys: tags.map { (tag, _) -> PostboxViewKey in + return .historyTagInfo(peerId: peerId, tag: tag) + }) + |> map { view -> [PeerInfoPaneKey] in + return tags.compactMap { (tag, key) -> PeerInfoPaneKey? in + if let info = view.views[.historyTagInfo(peerId: peerId, tag: tag)] as? HistoryTagInfoView, !info.isEmpty { + return key + } else { + return nil + } + } + } + |> distinctUntilChanged*/ +} + private func peerInfoScreenData(context: AccountContext, peerId: PeerId) -> Signal { return context.account.postbox.combinedView(keys: [.basicPeer(peerId)]) |> map { view -> PeerInfoScreenInputData in @@ -1551,16 +2333,47 @@ private func peerInfoScreenData(context: AccountContext, peerId: PeerId) -> Sign peer: nil, cachedData: nil, presence: nil, - notificationSettings: nil + notificationSettings: nil, + globalNotificationSettings: nil, + isContact: false, + availablePanes: [], + groupsInCommon: nil )) case .user: - return context.account.viewTracker.peerView(peerId, updateData: true) - |> map { view -> PeerInfoScreenData in + let groupsInCommonSignal: Signal<[Peer]?, NoError> = .single(nil) + |> then( + groupsInCommon(account: context.account, peerId: peerId) + |> map(Optional.init) + ) + let globalNotificationsKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.globalNotifications])) + return combineLatest( + context.account.viewTracker.peerView(peerId, updateData: true), + peerInfoAvailableMediaPanes(context: context, peerId: peerId), + context.account.postbox.combinedView(keys: [.peerChatState(peerId: peerId), globalNotificationsKey]), + groupsInCommonSignal + ) + |> map { peerView, availablePanes, combinedView, groupsInCommon -> PeerInfoScreenData in + var globalNotificationSettings: GlobalNotificationSettings = .defaultSettings + if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView { + if let settings = preferencesView.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings { + globalNotificationSettings = settings + } + } + + var availablePanes = availablePanes + if let groupsInCommon = groupsInCommon, !groupsInCommon.isEmpty { + availablePanes.append(.groupsInCommon) + } + return PeerInfoScreenData( - peer: view.peers[peerId], - cachedData: view.cachedData, - presence: view.peerPresences[peerId] as? TelegramUserPresence, - notificationSettings: view.notificationSettings as? TelegramPeerNotificationSettings + peer: peerView.peers[peerId], + cachedData: peerView.cachedData, + presence: peerView.peerPresences[peerId] as? TelegramUserPresence, + notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings, + globalNotificationSettings: globalNotificationSettings, + isContact: peerView.peerIsContact, + availablePanes: availablePanes, + groupsInCommon: groupsInCommon ) } } @@ -1570,32 +2383,123 @@ private func peerInfoScreenData(context: AccountContext, peerId: PeerId) -> Sign private final class PeerInfoInteraction { let openUsername: (String) -> Void let openPhone: (String) -> Void + let editingOpenNotificationSettings: () -> Void + let editingOpenSoundSettings: () -> Void + let editingToggleShowMessageText: (Bool) -> Void + let requestDeleteContact: () -> Void + let openAddContact: () -> Void + let updateBlocked: (Bool) -> Void init( openUsername: @escaping (String) -> Void, - openPhone: @escaping (String) -> Void + openPhone: @escaping (String) -> Void, + editingOpenNotificationSettings: @escaping () -> Void, + editingOpenSoundSettings: @escaping () -> Void, + editingToggleShowMessageText: @escaping (Bool) -> Void, + requestDeleteContact: @escaping () -> Void, + openAddContact: @escaping () -> Void, + updateBlocked: @escaping (Bool) -> Void ) { self.openUsername = openUsername self.openPhone = openPhone + self.editingOpenNotificationSettings = editingOpenNotificationSettings + self.editingOpenSoundSettings = editingOpenSoundSettings + self.editingToggleShowMessageText = editingToggleShowMessageText + self.requestDeleteContact = requestDeleteContact + self.openAddContact = openAddContact + self.updateBlocked = updateBlocked } } private func peerInfoSectionItems(data: PeerInfoScreenData?, presentationData: PresentationData, interaction: PeerInfoInteraction) -> [PeerInfoScreenItem] { + guard let data = data else { + return [] + } var items: [PeerInfoScreenItem] = [] - if let user = data?.peer as? TelegramUser { - if let cachedData = data?.cachedData as? CachedUserData { - if let about = cachedData.about { - items.append(PeerInfoScreenLabeledValueItem(id: 0, label: "bio", text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) - } + if let user = data.peer as? TelegramUser { + if let phone = user.phone { + items.append(PeerInfoScreenLabeledValueItem(id: 2, label: "mobile", text: "\(formatPhoneNumber(phone))", textColor: .accent, action: { + interaction.openPhone(phone) + })) } if let username = user.username { items.append(PeerInfoScreenLabeledValueItem(id: 1, label: "username", text: "@\(username)", textColor: .accent, action: { interaction.openUsername(username) })) } - if let phone = user.phone { - items.append(PeerInfoScreenLabeledValueItem(id: 2, label: "mobile", text: "\(formatPhoneNumber(phone))", textColor: .accent, action: { - interaction.openPhone(phone) + if let cachedData = data.cachedData as? CachedUserData { + if let about = cachedData.about { + items.append(PeerInfoScreenLabeledValueItem(id: 0, label: "bio", text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) + } + } + if !data.isContact { + items.append(PeerInfoScreenActionItem(id: 3, text: "Add Contact", action: { + interaction.openAddContact() + })) + if let cachedData = data.cachedData as? CachedUserData { + if cachedData.isBlocked { + items.append(PeerInfoScreenActionItem(id: 4, text: "Unblock", action: { + interaction.updateBlocked(false) + })) + } else { + if user.flags.contains(.isSupport) { + } else { + items.append(PeerInfoScreenActionItem(id: 4, text: "Block User", color: .destructive, action: { + interaction.updateBlocked(true) + })) + } + } + } + } + } + return items +} + +private func editingInfoSectionItems(data: PeerInfoScreenData?, presentationData: PresentationData, interaction: PeerInfoInteraction) -> [PeerInfoScreenItem] { + guard let data = data else { + return [] + } + var items: [PeerInfoScreenItem] = [] + + if let _ = data.peer as? TelegramUser { + if let notificationSettings = data.notificationSettings { + let notificationsLabel: String + let soundLabel: String + let notificationSettings = notificationSettings as? TelegramPeerNotificationSettings ?? TelegramPeerNotificationSettings.defaultSettings + if case let .muted(until) = notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) { + if until < Int32.max - 1 { + notificationsLabel = stringForRemainingMuteInterval(strings: presentationData.strings, muteInterval: until) + } else { + notificationsLabel = presentationData.strings.UserInfo_NotificationsDisabled + } + } else { + notificationsLabel = presentationData.strings.UserInfo_NotificationsEnabled + } + + let globalNotificationSettings: GlobalNotificationSettings = data.globalNotificationSettings ?? GlobalNotificationSettings.defaultSettings + soundLabel = localizedPeerNotificationSoundString(strings: presentationData.strings, sound: notificationSettings.messageSound, default: globalNotificationSettings.effective.privateChats.sound) + + items.append(PeerInfoScreenDisclosureItem(id: 0, label: notificationsLabel, text: "Notifications", action: { + interaction.editingOpenNotificationSettings() + })) + items.append(PeerInfoScreenDisclosureItem(id: 1, label: soundLabel, text: "Sound", action: { + interaction.editingOpenSoundSettings() + })) + items.append(PeerInfoScreenSwitchItem(id: 2, text: "Show Message Text", value: notificationSettings.displayPreviews != .hide, toggled: { value in + interaction.editingToggleShowMessageText(value) + })) + } + } + + return items +} + +private func editingActionsSectionItems(data: PeerInfoScreenData?, presentationData: PresentationData, interaction: PeerInfoInteraction) -> [PeerInfoScreenItem] { + var items: [PeerInfoScreenItem] = [] + if let data = data { + if data.isContact { + items.append(PeerInfoScreenActionItem(id: 0, text: "Delete Contact", color: .destructive, action: { + interaction.requestDeleteContact() })) } } @@ -1612,19 +2516,35 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD let headerNode: PeerInfoHeaderNode private let infoSection: PeerInfoScreenItemSectionContainerNode + private let editingInfoSection: PeerInfoScreenItemSectionContainerNode + private let editingActionsSection: PeerInfoScreenItemSectionContainerNode private let paneContainerNode: PeerInfoPaneContainerNode private var ignoreScrolling: Bool = false private var hapticFeedback: HapticFeedback? + private var searchDisplayController: SearchDisplayController? + private var _interaction: PeerInfoInteraction? private var interaction: PeerInfoInteraction { return self._interaction! } + private var _chatInterfaceInteraction: ChatControllerInteraction? + private var chatInterfaceInteraction: ChatControllerInteraction { + return self._chatInterfaceInteraction! + } + private(set) var validLayout: (ContainerViewLayout, CGFloat)? private(set) var data: PeerInfoScreenData? + private(set) var state = PeerInfoState( + isEditing: false, + isSearching: false, + selectedMessageIds: nil + ) private var dataDisposable: Disposable? + private let activeActionDisposable = MetaDisposable() + private let _ready = Promise() var ready: Promise { return self._ready @@ -1641,6 +2561,8 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self.headerNode = PeerInfoHeaderNode(context: context, avatarInitiallyExpanded: avatarInitiallyExpanded) self.infoSection = PeerInfoScreenItemSectionContainerNode(id: 0) + self.editingInfoSection = PeerInfoScreenItemSectionContainerNode(id: 1) + self.editingActionsSection = PeerInfoScreenItemSectionContainerNode(id: 2) self.paneContainerNode = PeerInfoPaneContainerNode(context: context, peerId: peerId) super.init() @@ -1651,19 +2573,367 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }, openPhone: { [weak self] value in self?.openPhone(value: value) + }, + editingOpenNotificationSettings: { [weak self] in + self?.editingOpenNotificationSettings() + }, + editingOpenSoundSettings: { [weak self] in + self?.editingOpenSoundSettings() + }, + editingToggleShowMessageText: { [weak self] value in + self?.editingToggleShowMessageText(value: value) + }, + requestDeleteContact: { [weak self] in + self?.requestDeleteContact() + }, + openAddContact: { [weak self] in + self?.openAddContact() + }, + updateBlocked: { [weak self] block in + self?.updateBlocked(block: block) } ) + self._chatInterfaceInteraction = ChatControllerInteraction(openMessage: { message, mode in + /*if let strongSelf = self, strongSelf.isNodeLoaded, let galleryMessage = strongSelf.mediaCollectionDisplayNode.messageForGallery(message.id) { + guard let navigationController = strongSelf.navigationController as? NavigationController else { + return false + } + strongSelf.mediaCollectionDisplayNode.view.endEditing(true) + return context.sharedContext.openChatMessage(OpenChatMessageParams(context: context, message: galleryMessage.message, standalone: false, reverseMessageGalleryOrder: true, navigationController: navigationController, dismissInput: { + self?.mediaCollectionDisplayNode.view.endEditing(true) + }, present: { c, a in + self?.present(c, in: .window(.root), with: a, blockInteraction: true) + }, transitionNode: { messageId, media in + if let strongSelf = self { + return strongSelf.mediaCollectionDisplayNode.transitionNodeForGallery(messageId: messageId, media: media) + } + return nil + }, addToTransitionSurface: { view in + if let strongSelf = self { + var belowSubview: UIView? + if let historyNode = strongSelf.mediaCollectionDisplayNode.historyNode as? ChatHistoryGridNode { + if let lowestSectionNode = historyNode.lowestSectionNode() { + belowSubview = lowestSectionNode.view + } + } + strongSelf.mediaCollectionDisplayNode.historyNode + if let belowSubview = belowSubview { + strongSelf.mediaCollectionDisplayNode.historyNode.view.insertSubview(view, belowSubview: belowSubview) + } else { + strongSelf.mediaCollectionDisplayNode.historyNode.view.addSubview(view) + } + } + }, openUrl: { url in + self?.openUrl(url) + }, openPeer: { peer, navigation in + self?.controllerInteraction?.openPeer(peer.id, navigation, nil) + }, callPeer: { peerId in + self?.controllerInteraction?.callPeer(peerId) + }, enqueueMessage: { _ in + }, sendSticker: nil, setupTemporaryHiddenMedia: { _, _, _ in }, chatAvatarHiddenMedia: { _, _ in })) + }*/ + return false + }, openPeer: { id, navigation, _ in + /*if let strongSelf = self, let id = id, let navigationController = strongSelf.navigationController as? NavigationController { + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id))) + }*/ + }, openPeerMention: { _ in + }, openMessageContextMenu: { message, _, _, _, _ in + /*guard let strongSelf = self else { + return + } + let items = (chatAvailableMessageActionsImpl(postbox: strongSelf.context.account.postbox, accountPeerId: strongSelf.context.account.peerId, messageIds: [message.id]) + |> deliverOnMainQueue).start(next: { actions in + var messageIds = Set() + messageIds.insert(message.id) + + if let strongSelf = self, strongSelf.isNodeLoaded { + if let message = strongSelf.mediaCollectionDisplayNode.messageForGallery(message.id)?.message { + let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData) + var items: [ActionSheetButtonItem] = [] + + items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.SharedMedia_ViewInChat, color: .accent, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController { + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(strongSelf.peerId), subject: .message(message.id))) + } + })) + items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_ContextMenuForward, color: .accent, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + if let strongSelf = self { + strongSelf.forwardMessages(messageIds) + } + })) + if actions.options.contains(.deleteLocally) || actions.options.contains(.deleteGlobally) { + items.append( ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_ContextMenuDelete, color: .destructive, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + if let strongSelf = self { + strongSelf.deleteMessages(messageIds) + } + })) + } + actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [ + ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + }) + ])]) + strongSelf.mediaCollectionDisplayNode.view.endEditing(true) + strongSelf.present(actionSheet, in: .window(.root)) + } + } + })*/ + }, openMessageContextActions: { message, node, rect, gesture in + /*guard let strongSelf = self else { + gesture?.cancel() + return + } + + let _ = (chatMediaListPreviewControllerData(context: strongSelf.context, message: message, standalone: false, reverseMessageGalleryOrder: false, navigationController: strongSelf.navigationController as? NavigationController) + |> deliverOnMainQueue).start(next: { previewData in + guard let strongSelf = self else { + gesture?.cancel() + return + } + if let previewData = previewData { + let context = strongSelf.context + let strings = strongSelf.presentationData.strings + let items = chatAvailableMessageActionsImpl(postbox: strongSelf.context.account.postbox, accountPeerId: strongSelf.context.account.peerId, messageIds: [message.id]) + |> map { actions -> [ContextMenuItem] in + var items: [ContextMenuItem] = [] + + items.append(.action(ContextMenuActionItem(text: strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { c, f in + c.dismiss(completion: { + if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController { + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(strongSelf.peerId), subject: .message(message.id))) + } + }) + }))) + + items.append(.action(ContextMenuActionItem(text: strings.Conversation_ContextMenuForward, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { c, f in + c.dismiss(completion: { + if let strongSelf = self { + strongSelf.forwardMessages([message.id]) + } + }) + }))) + + if actions.options.contains(.deleteLocally) || actions.options.contains(.deleteGlobally) { + items.append(.action(ContextMenuActionItem(text: strings.Conversation_ContextMenuDelete, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { c, f in + c.setItems(context.account.postbox.transaction { transaction -> [ContextMenuItem] in + var items: [ContextMenuItem] = [] + let messageIds = [message.id] + + if let peer = transaction.getPeer(message.id.peerId) { + var personalPeerName: String? + var isChannel = false + if let user = peer as? TelegramUser { + personalPeerName = user.compactDisplayTitle + } else if let channel = peer as? TelegramChannel, case .broadcast = channel.info { + isChannel = true + } + + if actions.options.contains(.deleteGlobally) { + let globalTitle: String + if isChannel { + globalTitle = strongSelf.presentationData.strings.Conversation_DeleteMessagesForMe + } else if let personalPeerName = personalPeerName { + globalTitle = strongSelf.presentationData.strings.Conversation_DeleteMessagesFor(personalPeerName).0 + } else { + globalTitle = strongSelf.presentationData.strings.Conversation_DeleteMessagesForEveryone + } + items.append(.action(ContextMenuActionItem(text: globalTitle, textColor: .destructive, icon: { _ in nil }, action: { c, f in + c.dismiss(completion: { + if let strongSelf = self { + strongSelf.updateInterfaceState(animated: true, { $0.withoutSelectionState() }) + let _ = deleteMessagesInteractively(account: strongSelf.context.account, messageIds: Array(messageIds), type: .forEveryone).start() + } + }) + }))) + } + + if actions.options.contains(.deleteLocally) { + var localOptionText = strongSelf.presentationData.strings.Conversation_DeleteMessagesForMe + if strongSelf.context.account.peerId == strongSelf.peerId { + if messageIds.count == 1 { + localOptionText = strongSelf.presentationData.strings.Conversation_Moderate_Delete + } else { + localOptionText = strongSelf.presentationData.strings.Conversation_DeleteManyMessages + } + } + items.append(.action(ContextMenuActionItem(text: localOptionText, textColor: .destructive, icon: { _ in nil }, action: { c, f in + c.dismiss(completion: { + if let strongSelf = self { + strongSelf.updateInterfaceState(animated: true, { $0.withoutSelectionState() }) + let _ = deleteMessagesInteractively(account: strongSelf.context.account, messageIds: Array(messageIds), type: .forLocalPeer).start() + } + }) + }))) + } + } + + return items + }) + }))) + } + + return items + } + + switch previewData { + case let .gallery(gallery): + gallery.setHintWillBePresentedInPreviewingContext(true) + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: gallery, sourceNode: node)), items: items, reactionItems: [], gesture: gesture) + strongSelf.presentInGlobalOverlay(contextController) + case .instantPage: + break + } + } + })*/ + }, navigateToMessage: { fromId, id in + /*if let strongSelf = self, strongSelf.isNodeLoaded { + if id.peerId == strongSelf.peerId { + var fromIndex: MessageIndex? + + if let message = strongSelf.mediaCollectionDisplayNode.historyNode.messageInCurrentHistoryView(fromId) { + fromIndex = message.index + } + } else { + (strongSelf.navigationController as? NavigationController)?.pushViewController(ChatControllerImpl(context: strongSelf.context, chatLocation: .peer(id.peerId), subject: .message(id))) + } + }*/ + }, tapMessage: nil, clickThroughMessage: { + //self?.view.endEditing(true) + }, toggleMessagesSelection: { ids, value in + /*if let strongSelf = self, strongSelf.isNodeLoaded { + strongSelf.updateInterfaceState(animated: true, { $0.withToggledSelectedMessages(ids, value: value) }) + }*/ + }, sendCurrentMessage: { _ in + }, sendMessage: { _ in + }, sendSticker: { _, _, _, _ in + return false + }, sendGif: { _, _, _ in + return false + }, requestMessageActionCallback: { _, _, _ in + }, requestMessageActionUrlAuth: { _, _, _ in + }, activateSwitchInline: { _, _ in + }, openUrl: { url, _, external, _ in + //self?.openUrl(url, external: external ?? false) + }, shareCurrentLocation: { + }, shareAccountContact: { + }, sendBotCommand: { _, _ in + }, openInstantPage: { message, associatedData in + /*if let strongSelf = self, strongSelf.isNodeLoaded, let navigationController = strongSelf.navigationController as? NavigationController, let message = strongSelf.mediaCollectionDisplayNode.messageForGallery(message.id)?.message { + openChatInstantPage(context: strongSelf.context, message: message, sourcePeerType: associatedData?.automaticDownloadPeerType, navigationController: navigationController) + }*/ + }, openWallpaper: { message in + /*if let strongSelf = self, strongSelf.isNodeLoaded, let message = strongSelf.mediaCollectionDisplayNode.messageForGallery(message.id)?.message { + openChatWallpaper(context: strongSelf.context, message: message, present: { [weak self] c, a in + self?.present(c, in: .window(.root), with: a, blockInteraction: true) + }) + }*/ + }, openTheme: { _ in + }, openHashtag: { _, _ in + }, updateInputState: { _ in + }, updateInputMode: { _ in + }, openMessageShareMenu: { _ in + }, presentController: { _, _ in + }, navigationController: { + return nil + }, chatControllerNode: { + return nil + }, reactionContainerNode: { + return nil + }, presentGlobalOverlayController: { _, _ in }, callPeer: { _ in + }, longTap: { content, _ in + /*if let strongSelf = self { + strongSelf.view.endEditing(true) + switch content { + case let .url(url): + let canOpenIn = availableOpenInOptions(context: strongSelf.context, item: .url(url: url)).count > 1 + let openText = canOpenIn ? strongSelf.presentationData.strings.Conversation_FileOpenIn : strongSelf.presentationData.strings.Conversation_LinkDialogOpen + let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData) + actionSheet.setItemGroups([ActionSheetItemGroup(items: [ + ActionSheetTextItem(title: url), + ActionSheetButtonItem(title: openText, color: .accent, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + if let strongSelf = self { + if canOpenIn { + let actionSheet = OpenInActionSheetController(context: strongSelf.context, item: .url(url: url), openUrl: { [weak self] url in + if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController { + strongSelf.context.sharedContext.openExternalUrl(context: strongSelf.context, urlContext: .generic, url: url, forceExternal: true, presentationData: strongSelf.presentationData, navigationController: navigationController, dismissInput: { + }) + } + }) + strongSelf.present(actionSheet, in: .window(.root)) + } else { + strongSelf.context.sharedContext.applicationBindings.openUrl(url) + } + } + }), + ActionSheetButtonItem(title: strongSelf.presentationData.strings.ShareMenu_CopyShareLink, color: .accent, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + UIPasteboard.general.string = url + }), + ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_AddToReadingList, color: .accent, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + if let link = URL(string: url) { + let _ = try? SSReadingList.default()?.addItem(with: link, title: nil, previewText: nil) + } + }) + ]), ActionSheetItemGroup(items: [ + ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + }) + ])]) + strongSelf.present(actionSheet, in: .window(.root)) + default: + break + } + }*/ + }, openCheckoutOrReceipt: { _ in + }, openSearch: { + //self?.activateSearch() + }, setupReply: { _ in + }, canSetupReply: { _ in + return false + }, navigateToFirstDateMessage: { _ in + }, requestRedeliveryOfFailedMessages: { _ in + }, addContact: { _ in + }, rateCall: { _, _ in + }, requestSelectMessagePollOptions: { _, _ in + }, requestOpenMessagePollResults: { _, _ in + }, openAppStorePage: { + }, displayMessageTooltip: { _, _, _, _ in + }, seekToTimecode: { _, _, _ in + }, scheduleCurrentMessage: { + }, sendScheduledMessagesNow: { _ in + }, editScheduledMessagesTime: { _ in + }, performTextSelectionAction: { _, _, _ in + }, updateMessageReaction: { _, _ in + }, openMessageReactions: { _ in + }, displaySwipeToReplyHint: { + }, dismissReplyMarkupMessage: { _ in + }, openMessagePollResults: { _, _ in + }, openPollCreation: { _ in + }, requestMessageUpdate: { _ in + }, cancelInteractiveKeyboardGestures: { + }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, + pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false)) + self.backgroundColor = self.presentationData.theme.list.blocksBackgroundColor self.scrollNode.view.showsVerticalScrollIndicator = false if #available(iOS 11.0, *) { self.scrollNode.view.contentInsetAdjustmentBehavior = .never } + self.scrollNode.view.alwaysBounceVertical = true self.scrollNode.view.scrollsToTop = false self.scrollNode.view.delegate = self self.addSubnode(self.scrollNode) self.scrollNode.addSubnode(self.infoSection) + self.scrollNode.addSubnode(self.editingInfoSection) + self.scrollNode.addSubnode(self.editingActionsSection) self.scrollNode.addSubnode(self.paneContainerNode) self.addSubnode(self.headerNode) @@ -1671,14 +2941,52 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD return self?.openMessage(id: id) ?? false } + self.paneContainerNode.toggleMessageSelected = { [weak self] id in + guard let strongSelf = self else { + return + } + if var selectedMessageIds = strongSelf.state.selectedMessageIds { + if selectedMessageIds.contains(id) { + selectedMessageIds.remove(id) + } else { + selectedMessageIds.insert(id) + } + strongSelf.state = strongSelf.state.withSelectedMessageIds(selectedMessageIds) + strongSelf.paneContainerNode.updateSelectedMessageIds(strongSelf.state.selectedMessageIds, animated: true) + if let (layout, navigationHeight) = strongSelf.validLayout { + strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.4, curve: .spring), additive: false) + } + } + } + + self.paneContainerNode.openPeer = { [weak self] peer in + guard let strongSelf = self else { + return + } + if let navigationController = strongSelf.controller?.navigationController as? NavigationController { + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id), keepStack: .always)) + } + } + + self.paneContainerNode.currentPaneUpdated = { [weak self] in + guard let strongSelf = self else { + return + } + if let (layout, navigationHeight) = strongSelf.validLayout { + strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false) + strongSelf.scrollNode.view.setContentOffset(CGPoint(x: 0.0, y: strongSelf.paneContainerNode.frame.minY - navigationHeight), animated: true) + } + } + self.headerNode.performButtonAction = { [weak self] key in self?.performButtonAction(key: key) } self.headerNode.requestAvatarExpansion = { [weak self] in - guard let strongSelf = self else { + guard let strongSelf = self, let peer = strongSelf.data?.peer, peer.smallProfileImage != nil else { return } + let transition: ContainedViewLayoutTransition = .animated(duration: 0.35, curve: .spring) strongSelf.headerNode.updateIsAvatarExpanded(true) @@ -1689,6 +2997,99 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } } + self.headerNode.navigationButtonContainer.performAction = { [weak self] key in + guard let strongSelf = self else { + return + } + switch key { + case .edit: + strongSelf.state = strongSelf.state.withIsEditing(true) + if strongSelf.headerNode.isAvatarExpanded { + strongSelf.headerNode.updateIsAvatarExpanded(false) + strongSelf.updateNavigationExpansionPresentation(isExpanded: false, animated: true) + } + if let (layout, navigationHeight) = strongSelf.validLayout { + strongSelf.scrollNode.view.setContentOffset(CGPoint(), animated: false) + strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false) + } + UIView.transition(with: strongSelf.view, duration: 0.3, options: [.transitionCrossDissolve], animations: { + }, completion: nil) + strongSelf.controller?.navigationItem.setLeftBarButton(UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, style: .plain, target: strongSelf, action: #selector(strongSelf.editingCancelPressed)), animated: true) + case .done, .cancel: + if case .done = key { + if let data = strongSelf.data, data.isContact { + if let peer = data.peer as? TelegramUser { + let firstName = strongSelf.headerNode.editingContentNode.editingTextForKey(.firstName) ?? "" + let lastName = strongSelf.headerNode.editingContentNode.editingTextForKey(.lastName) ?? "" + + if peer.firstName != firstName || peer.lastName != lastName { + strongSelf.activeActionDisposable.set((updateContactName(account: context.account, peerId: peer.id, firstName: firstName, lastName: lastName) + |> deliverOnMainQueue).start(error: { _ in + guard let strongSelf = self else { + return + } + strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel) + }, completed: { + guard let strongSelf = self else { + return + } + let context = strongSelf.context + let _ = (getUserPeer(postbox: strongSelf.context.account.postbox, peerId: peer.id) + |> mapToSignal { peer, _ -> Signal in + guard let peer = peer as? TelegramUser, let phone = peer.phone, !phone.isEmpty else { + return .complete() + } + return (context.sharedContext.contactDataManager?.basicDataForNormalizedPhoneNumber(DeviceContactNormalizedPhoneNumber(rawValue: formatPhoneNumber(phone))) ?? .single([])) + |> take(1) + |> mapToSignal { records -> Signal in + var signals: [Signal] = [] + if let contactDataManager = context.sharedContext.contactDataManager { + for (id, basicData) in records { + signals.append(contactDataManager.appendContactData(DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: firstName, lastName: lastName, phoneNumbers: basicData.phoneNumbers), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: ""), to: id)) + } + } + return combineLatest(signals) + |> mapToSignal { _ -> Signal in + return .complete() + } + } + }).start() + strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel) + })) + } else { + strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel) + } + } + } else { + strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel) + } + } else { + strongSelf.state = strongSelf.state.withIsEditing(false) + if let (layout, navigationHeight) = strongSelf.validLayout { + strongSelf.scrollNode.view.setContentOffset(CGPoint(), animated: false) + strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false) + } + UIView.transition(with: strongSelf.view, duration: 0.3, options: [.transitionCrossDissolve], animations: { + }, completion: nil) + strongSelf.controller?.navigationItem.setLeftBarButton(nil, animated: true) + } + case .select: + strongSelf.state = strongSelf.state.withSelectedMessageIds(Set()) + if let (layout, navigationHeight) = strongSelf.validLayout { + strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.4, curve: .spring), additive: false) + } + strongSelf.paneContainerNode.updateSelectedMessageIds(strongSelf.state.selectedMessageIds, animated: true) + case .selectionDone: + strongSelf.state = strongSelf.state.withSelectedMessageIds(nil) + if let (layout, navigationHeight) = strongSelf.validLayout { + strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.4, curve: .spring), additive: false) + } + strongSelf.paneContainerNode.updateSelectedMessageIds(strongSelf.state.selectedMessageIds, animated: true) + case .search: + strongSelf.activateSearch() + } + } + self.dataDisposable = (peerInfoScreenData(context: context, peerId: peerId) |> deliverOnMainQueue).start(next: { [weak self] data in guard let strongSelf = self else { @@ -1700,6 +3101,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD deinit { self.dataDisposable?.dispose() + self.activeActionDisposable.dispose() } override func didLoad() { @@ -1717,6 +3119,10 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self.scrollNode.view.setContentOffset(CGPoint(), animated: true) } + @objc private func editingCancelPressed() { + self.headerNode.navigationButtonContainer.performAction?(.cancel) + } + private func openMessage(id: MessageId) -> Bool { guard let galleryMessage = self.paneContainerNode.findLoadedMessage(id: id), let controller = self.controller, let navigationController = controller.navigationController as? NavigationController else { return false @@ -1801,13 +3207,27 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } var reportSpam = false var deleteChat = false + var items: [ActionSheetItem] = [] + if self.headerNode.isAvatarExpanded { + items.append(ActionSheetButtonItem(title: "Message", color: .accent, action: { [weak self] in + dismissAction() + self?.performButtonAction(key: .message) + })) + items.append(ActionSheetButtonItem(title: "Call", color: .accent, action: { [weak self] in + dismissAction() + self?.performButtonAction(key: .call) + })) + items.append(ActionSheetButtonItem(title: "Mute", color: .accent, action: { [weak self] in + dismissAction() + self?.performButtonAction(key: .mute) + })) + } + items.append(ActionSheetButtonItem(title: presentationData.strings.UserInfo_StartSecretChat, color: .accent, action: { [weak self] in + dismissAction() + self?.openStartSecretChat() + })) actionSheet.setItemGroups([ - ActionSheetItemGroup(items: [ - ActionSheetButtonItem(title: presentationData.strings.UserInfo_StartSecretChat, color: .accent, action: { [weak self] in - dismissAction() - self?.openStartSecretChat() - }) - ]), + ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [ActionSheetButtonItem(title: self.presentationData.strings.Common_Cancel, action: { dismissAction() })]) ]) controller.present(actionSheet, in: .window(.root)) @@ -1980,9 +3400,430 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }) } + private func editingOpenNotificationSettings() { + let peerId = self.peerId + let _ = (self.context.account.postbox.transaction { transaction -> (TelegramPeerNotificationSettings, GlobalNotificationSettings) in + let peerSettings: TelegramPeerNotificationSettings = (transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings) ?? TelegramPeerNotificationSettings.defaultSettings + let globalSettings: GlobalNotificationSettings = (transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications) as? GlobalNotificationSettings) ?? GlobalNotificationSettings.defaultSettings + return (peerSettings, globalSettings) + } + |> deliverOnMainQueue).start(next: { [weak self] peerSettings, globalSettings in + guard let strongSelf = self else { + return + } + let soundSettings: NotificationSoundSettings? + if case .default = peerSettings.messageSound { + soundSettings = NotificationSoundSettings(value: nil) + } else { + soundSettings = NotificationSoundSettings(value: peerSettings.messageSound) + } + let muteSettingsController = notificationMuteSettingsController(presentationData: strongSelf.presentationData, notificationSettings: globalSettings.effective.groupChats, soundSettings: nil, openSoundSettings: { + guard let strongSelf = self else { + return + } + let soundController = notificationSoundSelectionController(context: strongSelf.context, isModal: true, currentSound: peerSettings.messageSound, defaultSound: globalSettings.effective.groupChats.sound, completion: { sound in + guard let strongSelf = self else { + return + } + let _ = updatePeerNotificationSoundInteractive(account: strongSelf.context.account, peerId: strongSelf.peerId, sound: sound).start() + }) + strongSelf.controller?.push(soundController) + }, updateSettings: { value in + guard let strongSelf = self else { + return + } + let _ = updatePeerMuteSetting(account: strongSelf.context.account, peerId: strongSelf.peerId, muteInterval: value).start() + }) + strongSelf.controller?.present(muteSettingsController, in: .window(.root)) + }) + } + + private func editingOpenSoundSettings() { + let peerId = self.peerId + let _ = (self.context.account.postbox.transaction { transaction -> (TelegramPeerNotificationSettings, GlobalNotificationSettings) in + let peerSettings: TelegramPeerNotificationSettings = (transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings) ?? TelegramPeerNotificationSettings.defaultSettings + let globalSettings: GlobalNotificationSettings = (transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications) as? GlobalNotificationSettings) ?? GlobalNotificationSettings.defaultSettings + return (peerSettings, globalSettings) + } + |> deliverOnMainQueue).start(next: { [weak self] peerSettings, globalSettings in + guard let strongSelf = self else { + return + } + let soundSettings: NotificationSoundSettings? + if case .default = peerSettings.messageSound { + soundSettings = NotificationSoundSettings(value: nil) + } else { + soundSettings = NotificationSoundSettings(value: peerSettings.messageSound) + } + + let soundController = notificationSoundSelectionController(context: strongSelf.context, isModal: true, currentSound: peerSettings.messageSound, defaultSound: globalSettings.effective.groupChats.sound, completion: { sound in + guard let strongSelf = self else { + return + } + let _ = updatePeerNotificationSoundInteractive(account: strongSelf.context.account, peerId: strongSelf.peerId, sound: sound).start() + }) + strongSelf.controller?.push(soundController) + }) + } + + private func editingToggleShowMessageText(value: Bool) { + let _ = (getUserPeer(postbox: self.context.account.postbox, peerId: self.peerId) + |> deliverOnMainQueue).start(next: { [weak self] peer, _ in + guard let strongSelf = self, let peer = peer else { + return + } + let _ = updatePeerDisplayPreviewsSetting(account: strongSelf.context.account, peerId: peer.id, displayPreviews: value ? .show : .hide).start() + }) + } + + private func requestDeleteContact() { + let actionSheet = ActionSheetController(presentationData: self.presentationData) + let dismissAction: () -> Void = { [weak actionSheet] in + actionSheet?.dismissAnimated() + } + actionSheet.setItemGroups([ + ActionSheetItemGroup(items: [ + ActionSheetButtonItem(title: self.presentationData.strings.UserInfo_DeleteContact, color: .destructive, action: { [weak self] in + dismissAction() + guard let strongSelf = self else { + return + } + let _ = (getUserPeer(postbox: strongSelf.context.account.postbox, peerId: strongSelf.peerId) + |> deliverOnMainQueue).start(next: { peer, _ in + guard let peer = peer, let strongSelf = self else { + return + } + let deleteContactFromDevice: Signal + if let contactDataManager = strongSelf.context.sharedContext.contactDataManager { + deleteContactFromDevice = contactDataManager.deleteContactWithAppSpecificReference(peerId: peer.id) + } else { + deleteContactFromDevice = .complete() + } + + var deleteSignal = deleteContactPeerInteractively(account: strongSelf.context.account, peerId: peer.id) + |> then(deleteContactFromDevice) + + let progressSignal = Signal { subscriber in + guard let strongSelf = self else { + return EmptyDisposable + } + let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } + let statusController = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil)) + strongSelf.controller?.present(statusController, in: .window(.root)) + return ActionDisposable { [weak statusController] in + Queue.mainQueue().async() { + statusController?.dismiss() + } + } + } + |> runOn(Queue.mainQueue()) + |> delay(0.15, queue: Queue.mainQueue()) + let progressDisposable = progressSignal.start() + + deleteSignal = deleteSignal + |> afterDisposed { + Queue.mainQueue().async { + progressDisposable.dispose() + } + } + + strongSelf.activeActionDisposable.set((deleteSignal + |> deliverOnMainQueue).start(completed: { + self?.controller?.dismiss() + })) + + deleteSendMessageIntents(peerId: strongSelf.peerId) + }) + }) + ]), + ActionSheetItemGroup(items: [ActionSheetButtonItem(title: self.presentationData.strings.Common_Cancel, action: { dismissAction() })]) + ]) + self.controller?.present(actionSheet, in: .window(.root)) + } + + private func openAddContact() { + let _ = (getUserPeer(postbox: self.context.account.postbox, peerId: self.peerId) + |> deliverOnMainQueue).start(next: { [weak self] peer, _ in + guard let strongSelf = self, let peer = peer else { + return + } + openAddPersonContactImpl(context: strongSelf.context, peerId: peer.id, pushController: { c in + self?.controller?.push(c) + }, present: { c, a in + self?.controller?.present(c, in: .window(.root), with: a) + }) + }) + } + + private func updateBlocked(block: Bool) { + let _ = (getUserPeer(postbox: self.context.account.postbox, peerId: self.peerId) + |> take(1) + |> deliverOnMainQueue).start(next: { [weak self] peer, _ in + guard let strongSelf = self, let peer = peer else { + return + } + + let presentationData = strongSelf.presentationData + if let peer = peer as? TelegramUser, let _ = peer.botInfo { + strongSelf.activeActionDisposable.set(requestUpdatePeerIsBlocked(account: strongSelf.context.account, peerId: peer.id, isBlocked: block).start()) + if !block { + let _ = enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: [.message(text: "/start", attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)]).start() + if let navigationController = strongSelf.controller?.navigationController as? NavigationController { + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id))) + } + } + } else { + if block { + let presentationData = strongSelf.presentationData + let actionSheet = ActionSheetController(presentationData: presentationData) + let dismissAction: () -> Void = { [weak actionSheet] in + actionSheet?.dismissAnimated() + } + var reportSpam = false + var deleteChat = false + actionSheet.setItemGroups([ + ActionSheetItemGroup(items: [ + ActionSheetTextItem(title: presentationData.strings.UserInfo_BlockConfirmationTitle(peer.compactDisplayTitle).0), + ActionSheetButtonItem(title: presentationData.strings.UserInfo_BlockActionTitle(peer.compactDisplayTitle).0, color: .destructive, action: { + dismissAction() + guard let strongSelf = self else { + return + } + + strongSelf.activeActionDisposable.set(requestUpdatePeerIsBlocked(account: strongSelf.context.account, peerId: peer.id, isBlocked: true).start()) + if deleteChat { + let _ = removePeerChat(account: strongSelf.context.account, peerId: strongSelf.peerId, reportChatSpam: reportSpam).start() + (strongSelf.controller?.navigationController as? NavigationController)?.popToRoot(animated: true) + } else if reportSpam { + let _ = reportPeer(account: strongSelf.context.account, peerId: strongSelf.peerId, reason: .spam).start() + } + + deleteSendMessageIntents(peerId: strongSelf.peerId) + }) + ]), + ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })]) + ]) + strongSelf.controller?.present(actionSheet, in: .window(.root)) + } else { + let text: String + if block { + text = presentationData.strings.UserInfo_BlockConfirmation(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).0 + } else { + text = presentationData.strings.UserInfo_UnblockConfirmation(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).0 + } + strongSelf.controller?.present(textAlertController(context: strongSelf.context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_No, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Yes, action: { + guard let strongSelf = self else { + return + } + strongSelf.activeActionDisposable.set(requestUpdatePeerIsBlocked(account: strongSelf.context.account, peerId: peer.id, isBlocked: block).start()) + })]), in: .window(.root)) + } + } + }) + } + + func deleteMessages() { + if let messageIds = self.state.selectedMessageIds, !messageIds.isEmpty { + self.activeActionDisposable.set((self.context.sharedContext.chatAvailableMessageActions(postbox: self.context.account.postbox, accountPeerId: self.context.account.peerId, messageIds: messageIds) + |> deliverOnMainQueue).start(next: { [weak self] actions in + if let strongSelf = self, let peer = strongSelf.data?.peer, !actions.options.isEmpty { + let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData) + var items: [ActionSheetItem] = [] + var personalPeerName: String? + var isChannel = false + if let user = peer as? TelegramUser { + personalPeerName = user.compactDisplayTitle + } else if let channel = peer as? TelegramChannel, case .broadcast = channel.info { + isChannel = true + } + + if actions.options.contains(.deleteGlobally) { + let globalTitle: String + if isChannel { + globalTitle = strongSelf.presentationData.strings.Conversation_DeleteMessagesForMe + } else if let personalPeerName = personalPeerName { + globalTitle = strongSelf.presentationData.strings.Conversation_DeleteMessagesFor(personalPeerName).0 + } else { + globalTitle = strongSelf.presentationData.strings.Conversation_DeleteMessagesForEveryone + } + items.append(ActionSheetButtonItem(title: globalTitle, color: .destructive, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + if let strongSelf = self { + strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone) + let _ = deleteMessagesInteractively(account: strongSelf.context.account, messageIds: Array(messageIds), type: .forEveryone).start() + } + })) + } + if actions.options.contains(.deleteLocally) { + var localOptionText = strongSelf.presentationData.strings.Conversation_DeleteMessagesForMe + if strongSelf.context.account.peerId == strongSelf.peerId { + if messageIds.count == 1 { + localOptionText = strongSelf.presentationData.strings.Conversation_Moderate_Delete + } else { + localOptionText = strongSelf.presentationData.strings.Conversation_DeleteManyMessages + } + } + items.append(ActionSheetButtonItem(title: localOptionText, color: .destructive, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + if let strongSelf = self { + strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone) + let _ = deleteMessagesInteractively(account: strongSelf.context.account, messageIds: Array(messageIds), type: .forLocalPeer).start() + } + })) + } + actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [ + ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + }) + ])]) + strongSelf.controller?.present(actionSheet, in: .window(.root)) + } + })) + } + } + + func forwardMessages() { + if let messageIds = self.state.selectedMessageIds, !messageIds.isEmpty { + let peerSelectionController = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context, filter: [.onlyWriteable, .excludeDisabled])) + peerSelectionController.peerSelected = { [weak self, weak peerSelectionController] peerId in + if let strongSelf = self, let _ = peerSelectionController { + if peerId == strongSelf.context.account.peerId { + strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone) + + let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: messageIds.map { id -> EnqueueMessage in + return .forward(source: id, grouping: .auto, attributes: []) + }) + |> deliverOnMainQueue).start(next: { [weak self] messageIds in + if let strongSelf = self { + let signals: [Signal] = messageIds.compactMap({ id -> Signal? in + guard let id = id else { + return nil + } + return strongSelf.context.account.pendingMessageManager.pendingMessageStatus(id) + |> mapToSignal { status, _ -> Signal in + if status != nil { + return .never() + } else { + return .single(true) + } + } + |> take(1) + }) + strongSelf.activeActionDisposable.set((combineLatest(signals) + |> deliverOnMainQueue).start(completed: { + guard let strongSelf = self else { + return + } + strongSelf.controller?.present(OverlayStatusController(theme: strongSelf.presentationData.theme, type: .success), in: .window(.root)) + })) + } + }) + if let peerSelectionController = peerSelectionController { + peerSelectionController.dismiss() + } + } else { + let _ = (strongSelf.context.account.postbox.transaction({ transaction -> Void in + transaction.updatePeerChatInterfaceState(peerId, update: { currentState in + if let currentState = currentState as? ChatInterfaceState { + return currentState.withUpdatedForwardMessageIds(Array(messageIds)) + } else { + return ChatInterfaceState().withUpdatedForwardMessageIds(Array(messageIds)) + } + }) + }) |> deliverOnMainQueue).start(completed: { + if let strongSelf = self { + strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone) + + let ready = ValuePromise() + strongSelf.activeActionDisposable.set((ready.get() |> take(1) |> deliverOnMainQueue).start(next: { _ in + if let peerSelectionController = peerSelectionController { + peerSelectionController.dismiss() + } + })) + + (strongSelf.controller?.navigationController as? NavigationController)?.replaceTopController(ChatControllerImpl(context: strongSelf.context, chatLocation: .peer(peerId)), animated: false, ready: ready) + } + }) + } + } + } + self.controller?.push(peerSelectionController) + } + } + + private func activateSearch() { + guard let (layout, navigationBarHeight) = self.validLayout else { + return + } + + var maybePlaceholderNode: SearchBarPlaceholderNode? + /*if let listNode = historyNode as? ListView { + listNode.forEachItemNode { node in + if let node = node as? ChatListSearchItemNode { + maybePlaceholderNode = node.searchBarNode + } + } + }*/ + + if let _ = self.searchDisplayController { + return + } + + var tagMask: MessageTags = .file + if let currentPaneKey = self.paneContainerNode.currentPaneKey { + switch currentPaneKey { + case .links: + tagMask = .webPage + case .music: + tagMask = .music + default: + break + } + } + + self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, contentNode: ChatHistorySearchContainerNode(context: self.context, peerId: self.peerId, tagMask: tagMask, interfaceInteraction: self.chatInterfaceInteraction), cancel: { [weak self] in + self?.deactivateSearch() + }) + let transition: ContainedViewLayoutTransition = .animated(duration: 0.2, curve: .easeInOut) + if let navigationBar = self.controller?.navigationBar { + transition.updateAlpha(node: navigationBar, alpha: 0.0) + } + + self.searchDisplayController?.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate) + self.searchDisplayController?.activate(insertSubnode: { [weak self] subnode, isSearchBar in + if let strongSelf = self, let navigationBar = strongSelf.controller?.navigationBar { + strongSelf.insertSubnode(subnode, belowSubnode: navigationBar) + } + }, placeholder: nil) + + if let (layout, navigationHeight) = self.validLayout { + self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate) + } + } + + private func deactivateSearch() { + guard let searchDisplayController = self.searchDisplayController else { + return + } + self.searchDisplayController = nil + searchDisplayController.deactivate(placeholder: nil) + + let transition: ContainedViewLayoutTransition = .animated(duration: 0.35, curve: .easeInOut) + if let navigationBar = self.controller?.navigationBar { + transition.updateAlpha(node: navigationBar, alpha: 1.0) + } + } + func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition, additive: Bool = false) { self.validLayout = (layout, navigationHeight) + if let searchDisplayController = self.searchDisplayController { + searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: navigationHeight, transition: transition) + if !searchDisplayController.isDeactivating { + //vanillaInsets.top += (layout.statusBarHeight ?? 0.0) - navigationBarHeightDelta + } + } + self.ignoreScrolling = true transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: layout.size)) @@ -1991,7 +3832,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD var contentHeight: CGFloat = 0.0 - let headerHeight = self.headerNode.update(width: layout.size.width, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, contentOffset: self.scrollNode.view.contentOffset.y, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, presence: self.data?.presence, transition: transition, additive: additive) + let headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: layout.safeInsets.left, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, contentOffset: self.scrollNode.view.contentOffset.y, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, presence: self.data?.presence, isContact: self.data?.isContact ?? false, state: self.state, transition: transition, additive: additive) let headerFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: headerHeight)) if additive { transition.updateFrameAdditive(node: self.headerNode, frame: headerFrame) @@ -2008,31 +3849,141 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } else { transition.updateFrame(node: self.infoSection, frame: infoSectionFrame) } - contentHeight += infoSectionHeight - contentHeight += sectionSpacing + + let editingInfoSectionHeight = self.editingInfoSection.update(width: layout.size.width, presentationData: self.presentationData, items: editingInfoSectionItems(data: self.data, presentationData: self.presentationData, interaction: self.interaction), transition: transition) + let editingInfoSectionFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: infoSectionHeight)) + if additive { + transition.updateFrameAdditive(node: self.editingInfoSection, frame: editingInfoSectionFrame) + } else { + transition.updateFrame(node: self.editingInfoSection, frame: editingInfoSectionFrame) + } + + if self.state.isEditing { + transition.updateAlpha(node: self.infoSection, alpha: 0.0) + transition.updateAlpha(node: self.editingInfoSection, alpha: 1.0) + transition.updateAlpha(node: self.editingActionsSection, alpha: 1.0) + if !editingInfoSectionHeight.isZero { + contentHeight += editingInfoSectionHeight + contentHeight += sectionSpacing + } + } else { + transition.updateAlpha(node: self.infoSection, alpha: 1.0) + transition.updateAlpha(node: self.editingInfoSection, alpha: 0.0) + transition.updateAlpha(node: self.editingActionsSection, alpha: 0.0) + if !infoSectionHeight.isZero { + contentHeight += infoSectionHeight + contentHeight += sectionSpacing + } + } + + let editingActionsSectionHeight = self.editingActionsSection.update(width: layout.size.width, presentationData: self.presentationData, items: editingActionsSectionItems(data: self.data, presentationData: self.presentationData, interaction: self.interaction), transition: transition) + let editingActionsSectionFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: editingActionsSectionHeight)) + if additive { + transition.updateFrameAdditive(node: self.editingActionsSection, frame: editingActionsSectionFrame) + } else { + transition.updateFrame(node: self.editingActionsSection, frame: editingActionsSectionFrame) + } + + if self.state.isEditing { + if !editingActionsSectionHeight.isZero { + contentHeight += editingActionsSectionHeight + contentHeight += sectionSpacing + } + } let paneContainerSize = CGSize(width: layout.size.width, height: layout.size.height - navigationHeight) var restoreContentOffset: CGPoint? if additive { restoreContentOffset = self.scrollNode.view.contentOffset } - self.scrollNode.view.contentSize = CGSize(width: layout.size.width, height: contentHeight + paneContainerSize.height) + + let paneContainerFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: paneContainerSize) + if self.state.isEditing || (self.data?.availablePanes ?? []).isEmpty { + transition.updateAlpha(node: self.paneContainerNode, alpha: 0.0) + } else { + contentHeight += layout.size.height - navigationHeight + transition.updateAlpha(node: self.paneContainerNode, alpha: 1.0) + } + + if let selectedMessageIds = self.state.selectedMessageIds { + var wasAdded = false + let selectionPanelNode: PeerInfoSelectionPanelNode + if let current = self.paneContainerNode.selectionPanelNode { + selectionPanelNode = current + } else { + wasAdded = true + selectionPanelNode = PeerInfoSelectionPanelNode(context: self.context, peerId: self.peerId, deleteMessages: { [weak self] in + guard let strongSelf = self else { + return + } + strongSelf.deleteMessages() + }, shareMessages: { [weak self] in + guard let strongSelf = self, let messageIds = strongSelf.state.selectedMessageIds, !messageIds.isEmpty else { + return + } + let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Message] in + var messages: [Message] = [] + for id in messageIds { + if let message = transaction.getMessage(id) { + messages.append(message) + } + } + return messages + } + |> deliverOnMainQueue).start(next: { messages in + if let strongSelf = self, !messages.isEmpty { + strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone) + + let shareController = ShareController(context: strongSelf.context, subject: .messages(messages.sorted(by: { lhs, rhs in + return lhs.index < rhs.index + })), externalShare: true, immediateExternalShare: true) + strongSelf.controller?.present(shareController, in: .window(.root)) + } + }) + }, forwardMessages: { [weak self] in + guard let strongSelf = self else { + return + } + strongSelf.forwardMessages() + }, reportMessages: { [weak self] in + guard let strongSelf = self, let messageIds = strongSelf.state.selectedMessageIds, !messageIds.isEmpty else { + return + } + strongSelf.controller?.present(peerReportOptionsController(context: strongSelf.context, subject: .messages(Array(messageIds).sorted()), present: { c, a in + self?.controller?.present(c, in: .window(.root), with: a) + }, push: { c in + self?.controller?.push(c) + }, completion: { _ in }), in: .window(.root)) + }) + self.paneContainerNode.selectionPanelNode = selectionPanelNode + self.paneContainerNode.addSubnode(selectionPanelNode) + } + selectionPanelNode.selectionPanel.selectedMessages = selectedMessageIds + let panelHeight = selectionPanelNode.update(width: layout.size.width, safeInset: layout.safeInsets.left, metrics: layout.metrics, presentationData: self.presentationData, transition: wasAdded ? .immediate : transition) + let panelFrame = CGRect(origin: CGPoint(x: 0.0, y: paneContainerSize.height - panelHeight), size: CGSize(width: layout.size.width, height: panelHeight)) + if wasAdded { + selectionPanelNode.frame = panelFrame + transition.animatePositionAdditive(node: selectionPanelNode, offset: CGPoint(x: 0.0, y: panelHeight)) + } else { + transition.updateFrame(node: selectionPanelNode, frame: panelFrame) + } + } else if let selectionPanelNode = self.paneContainerNode.selectionPanelNode { + self.paneContainerNode.selectionPanelNode = nil + transition.updateFrame(node: selectionPanelNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height), size: selectionPanelNode.bounds.size), completion: { [weak selectionPanelNode] _ in + selectionPanelNode?.removeFromSupernode() + }) + } + + self.scrollNode.view.contentSize = CGSize(width: layout.size.width, height: contentHeight) if let restoreContentOffset = restoreContentOffset { self.scrollNode.view.contentOffset = restoreContentOffset } - let paneAreaExpansionDistance: CGFloat = 32.0 - var paneAreaExpansionDelta = (contentHeight - navigationHeight) - self.scrollNode.view.contentOffset.y - paneAreaExpansionDelta = max(0.0, min(paneAreaExpansionDelta, paneAreaExpansionDistance)) - let paneAreaExpansionFraction: CGFloat = 1.0 - paneAreaExpansionDelta / paneAreaExpansionDistance - - let paneContainerFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: paneContainerSize) if additive { transition.updateFrameAdditive(node: self.paneContainerNode, frame: paneContainerFrame) } else { transition.updateFrame(node: self.paneContainerNode, frame: paneContainerFrame) } - contentHeight += layout.size.height - navigationHeight self.ignoreScrolling = false self.updateNavigation(transition: transition, additive: additive) @@ -2046,25 +3997,58 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD private func updateNavigation(transition: ContainedViewLayoutTransition, additive: Bool) { let offsetY = self.scrollNode.view.contentOffset.y - if offsetY <= 50.0 { + if self.state.isEditing || offsetY <= 50.0 { self.scrollNode.view.bounces = true + self.scrollNode.view.alwaysBounceVertical = true } else { self.scrollNode.view.bounces = false + self.scrollNode.view.alwaysBounceVertical = false } if let (layout, navigationHeight) = self.validLayout { if !additive { - self.headerNode.update(width: layout.size.width, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, contentOffset: offsetY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, presence: self.data?.presence, transition: transition, additive: additive) + self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: layout.safeInsets.left, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, contentOffset: offsetY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, presence: self.data?.presence, isContact: self.data?.isContact ?? false, state: self.state, transition: transition, additive: additive) } let paneAreaExpansionDistance: CGFloat = 32.0 var paneAreaExpansionDelta = (self.paneContainerNode.frame.minY - navigationHeight) - self.scrollNode.view.contentOffset.y paneAreaExpansionDelta = max(0.0, min(paneAreaExpansionDelta, paneAreaExpansionDistance)) + let paneAreaExpansionFraction: CGFloat = 1.0 - paneAreaExpansionDelta / paneAreaExpansionDistance - transition.updateAlpha(node: self.headerNode.separatorNode, alpha: 1.0 - paneAreaExpansionFraction) + let effectiveAreaExpansionFraction: CGFloat + if self.state.isEditing { + effectiveAreaExpansionFraction = 0.0 + } else { + effectiveAreaExpansionFraction = paneAreaExpansionFraction + } - self.paneContainerNode.update(size: self.paneContainerNode.bounds.size, expansionFraction: paneAreaExpansionFraction, presentationData: self.presentationData, transition: transition) + transition.updateAlpha(node: self.headerNode.separatorNode, alpha: 1.0 - effectiveAreaExpansionFraction) + + self.paneContainerNode.update(size: self.paneContainerNode.bounds.size, expansionFraction: paneAreaExpansionFraction, presentationData: self.presentationData, data: self.data, transition: transition) + self.headerNode.navigationButtonContainer.frame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: layout.statusBarHeight ?? 0.0), size: CGSize(width: layout.size.width - layout.safeInsets.left * 2.0, height: 44.0)) + self.headerNode.navigationButtonContainer.isWhite = self.headerNode.isAvatarExpanded + + var navigationButtons: [PeerInfoHeaderNavigationButtonSpec] = [] + if self.state.isEditing { + navigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .done, isForExpandedView: false)) + } else { + navigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .edit, isForExpandedView: false)) + if self.state.selectedMessageIds == nil { + if let currentPaneKey = self.paneContainerNode.currentPaneKey { + switch currentPaneKey { + case .files, .music, .links: + navigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .search, isForExpandedView: true)) + default: + break + } + } + navigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .select, isForExpandedView: true)) + } else { + navigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .selectionDone, isForExpandedView: true)) + } + } + self.headerNode.navigationButtonContainer.update(size: CGSize(width: layout.size.width - layout.safeInsets.left * 2.0, height: 44.0), presentationData: self.presentationData, buttons: navigationButtons, expandFraction: effectiveAreaExpansionFraction, transition: transition) } } @@ -2080,12 +4064,14 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } self.updateNavigation(transition: .immediate, additive: false) - if scrollView.isDragging && scrollView.isTracking { + if !self.state.isEditing { let offsetY = self.scrollNode.view.contentOffset.y var shouldBeExpanded: Bool? - if offsetY <= -32.0 { - shouldBeExpanded = true - } else if offsetY >= 4.0 { + if offsetY <= -32.0 && scrollView.isDragging && scrollView.isTracking { + if let peer = self.data?.peer, peer.smallProfileImage != nil { + shouldBeExpanded = true + } + } else if offsetY >= 1.0 { shouldBeExpanded = false } if let shouldBeExpanded = shouldBeExpanded, self.canUpdateAvatarExpansion, shouldBeExpanded != self.headerNode.isAvatarExpanded { @@ -2106,10 +4092,6 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD if let (layout, navigationHeight) = self.validLayout { self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: transition, additive: true) } - - if !shouldBeExpanded { - //scrollView.setContentOffset(CGPoint(), animated: true) - } } } } @@ -2118,6 +4100,11 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD if let controller = self.controller { controller.statusBar.updateStatusBarStyle(isExpanded ? .White : self.presentationData.theme.rootController.statusBarStyle.style, animated: animated) + if animated { + UIView.transition(with: controller.controllerNode.headerNode.navigationButtonContainer.view, duration: 0.3, options: [.transitionCrossDissolve], animations: { + }, completion: nil) + } + let baseNavigationBarPresentationData = NavigationBarPresentationData(presentationData: self.presentationData) let navigationBarPresentationData = NavigationBarPresentationData( theme: NavigationBarTheme( @@ -2145,11 +4132,18 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD guard let (_, navigationHeight) = self.validLayout else { return } - if targetContentOffset.pointee.y < 212.0 { - if targetContentOffset.pointee.y < 212.0 / 2.0 { - targetContentOffset.pointee.y = 0.0 - } else { - targetContentOffset.pointee.y = 212.0 + if !self.state.isEditing { + if targetContentOffset.pointee.y < 212.0 { + if targetContentOffset.pointee.y < 212.0 / 2.0 { + targetContentOffset.pointee.y = 0.0 + } else { + targetContentOffset.pointee.y = 212.0 + } + } + let paneAreaExpansionDistance: CGFloat = 32.0 + let paneAreaExpansionFinalPoint: CGFloat = self.paneContainerNode.frame.minY - navigationHeight + if targetContentOffset.pointee.y > paneAreaExpansionFinalPoint - paneAreaExpansionDistance && targetContentOffset.pointee.y < paneAreaExpansionFinalPoint { + targetContentOffset.pointee.y = paneAreaExpansionFinalPoint } } } @@ -2189,7 +4183,7 @@ public final class PeerInfoScreen: ViewController { private var presentationData: PresentationData - private var controllerNode: PeerInfoScreenNode { + fileprivate var controllerNode: PeerInfoScreenNode { return self.displayNode as! PeerInfoScreenNode } @@ -2221,6 +4215,9 @@ public final class PeerInfoScreen: ViewController { guard let strongSelf = self else { return nil } + if strongSelf.navigationItem.leftBarButtonItem != nil { + return nil + } if strongSelf.controllerNode.scrollNode.view.contentOffset.y > .ulpOfOne { return nil } @@ -2289,6 +4286,7 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig private var topNavigationBar: NavigationBar? private var bottomNavigationBar: NavigationBar? + private var reverseFraction: Bool = false private let headerNode: PeerInfoHeaderNode @@ -2314,44 +4312,52 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig } func setup(topNavigationBar: NavigationBar, bottomNavigationBar: NavigationBar) { - self.topNavigationBar = topNavigationBar - self.bottomNavigationBar = bottomNavigationBar + if let _ = bottomNavigationBar.userInfo as? PeerInfoNavigationSourceTag { + self.topNavigationBar = topNavigationBar + self.bottomNavigationBar = bottomNavigationBar + } else { + self.topNavigationBar = bottomNavigationBar + self.bottomNavigationBar = topNavigationBar + self.reverseFraction = true + } topNavigationBar.isHidden = true bottomNavigationBar.isHidden = true - if let previousBackButtonArrow = bottomNavigationBar.makeTransitionBackArrowNode(accentColor: self.presentationData.theme.rootController.navigationBar.accentTextColor) { - self.previousBackButtonArrow = previousBackButtonArrow - self.addSubnode(previousBackButtonArrow) - } - if self.screenNode.headerNode.isAvatarExpanded, let currentBackButtonArrow = topNavigationBar.makeTransitionBackArrowNode(accentColor: self.screenNode.headerNode.isAvatarExpanded ? .white : self.presentationData.theme.rootController.navigationBar.accentTextColor) { - self.currentBackButtonArrow = currentBackButtonArrow - self.addSubnode(currentBackButtonArrow) - } - if let previousBackButtonBadge = bottomNavigationBar.makeTransitionBadgeNode() { - self.previousBackButtonBadge = previousBackButtonBadge - self.addSubnode(previousBackButtonBadge) - } - if let previousRightButton = bottomNavigationBar.makeTransitionRightButtonNode(accentColor: self.presentationData.theme.rootController.navigationBar.accentTextColor) { - self.previousRightButton = previousRightButton - self.addSubnode(previousRightButton) - } - if let currentBackButton = topNavigationBar.makeTransitionBackButtonNode(accentColor: self.screenNode.headerNode.isAvatarExpanded ? .white : self.presentationData.theme.rootController.navigationBar.accentTextColor) { - self.currentBackButton = currentBackButton - self.addSubnode(currentBackButton) - } - if let previousTitleView = bottomNavigationBar.titleView as? ChatTitleView { - let previousTitleNode = previousTitleView.titleNode.makeCopy() - let previousTitleContainerNode = ASDisplayNode() - previousTitleContainerNode.addSubnode(previousTitleNode) - self.previousTitleNode = (previousTitleContainerNode, previousTitleNode) - self.addSubnode(previousTitleContainerNode) - - let previousStatusNode = previousTitleView.activityNode.makeCopy() - let previousStatusContainerNode = ASDisplayNode() - previousStatusContainerNode.addSubnode(previousStatusNode) - self.previousStatusNode = (previousStatusContainerNode, previousStatusNode) - self.addSubnode(previousStatusContainerNode) + if let topNavigationBar = self.topNavigationBar, let bottomNavigationBar = self.bottomNavigationBar { + if let previousBackButtonArrow = bottomNavigationBar.makeTransitionBackArrowNode(accentColor: self.presentationData.theme.rootController.navigationBar.accentTextColor) { + self.previousBackButtonArrow = previousBackButtonArrow + self.addSubnode(previousBackButtonArrow) + } + if self.screenNode.headerNode.isAvatarExpanded, let currentBackButtonArrow = topNavigationBar.makeTransitionBackArrowNode(accentColor: self.screenNode.headerNode.isAvatarExpanded ? .white : self.presentationData.theme.rootController.navigationBar.accentTextColor) { + self.currentBackButtonArrow = currentBackButtonArrow + self.addSubnode(currentBackButtonArrow) + } + if let previousBackButtonBadge = bottomNavigationBar.makeTransitionBadgeNode() { + self.previousBackButtonBadge = previousBackButtonBadge + self.addSubnode(previousBackButtonBadge) + } + if let previousRightButton = bottomNavigationBar.makeTransitionRightButtonNode(accentColor: self.presentationData.theme.rootController.navigationBar.accentTextColor) { + self.previousRightButton = previousRightButton + self.addSubnode(previousRightButton) + } + if let currentBackButton = topNavigationBar.makeTransitionBackButtonNode(accentColor: self.screenNode.headerNode.isAvatarExpanded ? .white : self.presentationData.theme.rootController.navigationBar.accentTextColor) { + self.currentBackButton = currentBackButton + self.addSubnode(currentBackButton) + } + if let previousTitleView = bottomNavigationBar.titleView as? ChatTitleView { + let previousTitleNode = previousTitleView.titleNode.makeCopy() + let previousTitleContainerNode = ASDisplayNode() + previousTitleContainerNode.addSubnode(previousTitleNode) + self.previousTitleNode = (previousTitleContainerNode, previousTitleNode) + self.addSubnode(previousTitleContainerNode) + + let previousStatusNode = previousTitleView.activityNode.makeCopy() + let previousStatusContainerNode = ASDisplayNode() + previousStatusContainerNode.addSubnode(previousStatusNode) + self.previousStatusNode = (previousStatusContainerNode, previousStatusNode) + self.addSubnode(previousStatusContainerNode) + } } } @@ -2360,6 +4366,8 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig return } + let fraction = self.reverseFraction ? (1.0 - fraction) : fraction + if let previousBackButtonArrow = self.previousBackButtonArrow { let previousBackButtonArrowFrame = bottomNavigationBar.backButtonArrow.view.convert(bottomNavigationBar.backButtonArrow.view.bounds, to: bottomNavigationBar.view) previousBackButtonArrow.frame = previousBackButtonArrowFrame @@ -2401,7 +4409,7 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig self.headerNode.navigationTransition = PeerInfoHeaderNavigationTransition(sourceNavigationBar: bottomNavigationBar, sourceTitleView: previousTitleView, sourceTitleFrame: previousTitleFrame, sourceSubtitleFrame: previousStatusFrame, fraction: fraction) if let (layout, navigationHeight) = self.screenNode.validLayout { - self.headerNode.update(width: layout.size.width, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, contentOffset: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, notificationSettings: self.screenNode.data?.notificationSettings, presence: self.screenNode.data?.presence, transition: transition, additive: false) + self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: layout.safeInsets.left, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, contentOffset: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, notificationSettings: self.screenNode.data?.notificationSettings, presence: self.screenNode.data?.presence, isContact: self.screenNode.data?.isContact ?? false, state: self.screenNode.state, transition: transition, additive: false) } let titleScale = (fraction * previousTitleNode.bounds.height + (1.0 - fraction) * self.headerNode.titleNode.bounds.height) / previousTitleNode.bounds.height @@ -2419,6 +4427,8 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig transition.updateAlpha(node: previousTitleNode, alpha: fraction) transition.updateAlpha(node: self.headerNode.subtitleNode, alpha: (1.0 - fraction)) transition.updateAlpha(node: previousStatusNode, alpha: fraction) + + transition.updateAlpha(node: self.headerNode.navigationButtonContainer, alpha: (1.0 - fraction)) } } diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoScreenActionItem.swift b/submodules/TelegramUI/TelegramUI/PeerInfoScreenActionItem.swift new file mode 100644 index 0000000000..c7b9fb361f --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/PeerInfoScreenActionItem.swift @@ -0,0 +1,98 @@ +import AsyncDisplayKit +import Display +import TelegramPresentationData + +enum PeerInfoScreenActionColor { + case accent + case destructive +} + +final class PeerInfoScreenActionItem: PeerInfoScreenItem { + let id: AnyHashable + let text: String + let color: PeerInfoScreenActionColor + let action: (() -> Void)? + + init(id: AnyHashable, text: String, color: PeerInfoScreenActionColor = .accent, action: (() -> Void)?) { + self.id = id + self.text = text + self.color = color + self.action = action + } + + func node() -> PeerInfoScreenItemNode { + return PeerInfoScreenActionItemNode() + } +} + +private final class PeerInfoScreenActionItemNode: PeerInfoScreenItemNode { + private let selectionNode: PeerInfoScreenSelectableBackgroundNode + private let textNode: ImmediateTextNode + private let bottomSeparatorNode: ASDisplayNode + + private var item: PeerInfoScreenActionItem? + + override init() { + var bringToFrontForHighlightImpl: (() -> Void)? + self.selectionNode = PeerInfoScreenSelectableBackgroundNode(bringToFrontForHighlight: { bringToFrontForHighlightImpl?() }) + + self.textNode = ImmediateTextNode() + self.textNode.displaysAsynchronously = false + self.textNode.isUserInteractionEnabled = false + + self.bottomSeparatorNode = ASDisplayNode() + self.bottomSeparatorNode.isLayerBacked = true + + super.init() + + bringToFrontForHighlightImpl = { [weak self] in + self?.bringToFrontForHighlight?() + } + + self.addSubnode(self.bottomSeparatorNode) + self.addSubnode(self.selectionNode) + self.addSubnode(self.textNode) + } + + override func update(width: CGFloat, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + guard let item = item as? PeerInfoScreenActionItem else { + return 10.0 + } + + self.item = item + + self.selectionNode.pressed = item.action + + let sideInset: CGFloat = 16.0 + + self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + + let textColorValue: UIColor + switch item.color { + case .accent: + textColorValue = presentationData.theme.list.itemAccentColor + case .destructive: + textColorValue = presentationData.theme.list.itemDestructiveColor + } + + self.textNode.maximumNumberOfLines = 1 + self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(17.0), textColor: textColorValue) + + let textSize = self.textNode.updateLayout(CGSize(width: width - sideInset * 2.0, height: .greatestFiniteMagnitude)) + + let textFrame = CGRect(origin: CGPoint(x: sideInset, y: 11.0), size: textSize) + + let height = textSize.height + 22.0 + + transition.updateFrame(node: self.textNode, frame: textFrame) + + let highlightNodeOffset: CGFloat = topItem == nil ? 0.0 : UIScreenPixel + self.selectionNode.update(size: CGSize(width: width, height: height + highlightNodeOffset), theme: presentationData.theme, transition: transition) + transition.updateFrame(node: self.selectionNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -highlightNodeOffset), size: CGSize(width: width, height: height + highlightNodeOffset))) + + transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: sideInset, y: height - UIScreenPixel), size: CGSize(width: width - sideInset, height: UIScreenPixel))) + transition.updateAlpha(node: self.bottomSeparatorNode, alpha: bottomItem == nil ? 0.0 : 1.0) + + return height + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoScreenDisclosureItem.swift b/submodules/TelegramUI/TelegramUI/PeerInfoScreenDisclosureItem.swift new file mode 100644 index 0000000000..ca27a09e75 --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/PeerInfoScreenDisclosureItem.swift @@ -0,0 +1,115 @@ +import AsyncDisplayKit +import Display +import TelegramPresentationData + +final class PeerInfoScreenDisclosureItem: PeerInfoScreenItem { + let id: AnyHashable + let label: String + let text: String + let action: (() -> Void)? + + init(id: AnyHashable, label: String, text: String, action: (() -> Void)?) { + self.id = id + self.label = label + self.text = text + self.action = action + } + + func node() -> PeerInfoScreenItemNode { + return PeerInfoScreenDisclosureItemNode() + } +} + +private final class PeerInfoScreenDisclosureItemNode: PeerInfoScreenItemNode { + private let selectionNode: PeerInfoScreenSelectableBackgroundNode + private let labelNode: ImmediateTextNode + private let textNode: ImmediateTextNode + private let arrowNode: ASImageNode + private let bottomSeparatorNode: ASDisplayNode + + private var item: PeerInfoScreenDisclosureItem? + + override init() { + var bringToFrontForHighlightImpl: (() -> Void)? + self.selectionNode = PeerInfoScreenSelectableBackgroundNode(bringToFrontForHighlight: { bringToFrontForHighlightImpl?() }) + + self.labelNode = ImmediateTextNode() + self.labelNode.displaysAsynchronously = false + self.labelNode.isUserInteractionEnabled = false + + self.textNode = ImmediateTextNode() + self.textNode.displaysAsynchronously = false + self.textNode.isUserInteractionEnabled = false + + self.arrowNode = ASImageNode() + self.arrowNode.isLayerBacked = true + self.arrowNode.displaysAsynchronously = false + self.arrowNode.displayWithoutProcessing = true + self.arrowNode.isUserInteractionEnabled = false + + self.bottomSeparatorNode = ASDisplayNode() + self.bottomSeparatorNode.isLayerBacked = true + + super.init() + + bringToFrontForHighlightImpl = { [weak self] in + self?.bringToFrontForHighlight?() + } + + self.addSubnode(self.bottomSeparatorNode) + self.addSubnode(self.selectionNode) + self.addSubnode(self.labelNode) + self.addSubnode(self.textNode) + self.addSubnode(self.arrowNode) + } + + override func update(width: CGFloat, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + guard let item = item as? PeerInfoScreenDisclosureItem else { + return 10.0 + } + + self.item = item + + self.selectionNode.pressed = item.action + + let sideInset: CGFloat = 16.0 + + self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + + let textColorValue: UIColor = presentationData.theme.list.itemPrimaryTextColor + let labelColorValue: UIColor = presentationData.theme.list.itemSecondaryTextColor + + self.labelNode.attributedText = NSAttributedString(string: item.label, font: Font.regular(17.0), textColor: labelColorValue) + + self.textNode.maximumNumberOfLines = 1 + self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(17.0), textColor: textColorValue) + + let textSize = self.textNode.updateLayout(CGSize(width: width - sideInset * 2.0, height: .greatestFiniteMagnitude)) + let labelSize = self.labelNode.updateLayout(CGSize(width: width - textSize.width - sideInset * 2.0, height: .greatestFiniteMagnitude)) + + let arrowInset: CGFloat = 18.0 + + let textFrame = CGRect(origin: CGPoint(x: sideInset, y: 11.0), size: textSize) + let labelFrame = CGRect(origin: CGPoint(x: width - sideInset - arrowInset - labelSize.width, y: 11.0), size: labelSize) + + let height = textSize.height + 22.0 + + if let arrowImage = PresentationResourcesItemList.disclosureArrowImage(presentationData.theme) { + self.arrowNode.image = arrowImage + let arrowFrame = CGRect(origin: CGPoint(x: width - 7.0 - arrowImage.size.width, y: floorToScreenPixels((height - arrowImage.size.height) / 2.0)), size: arrowImage.size) + transition.updateFrame(node: self.arrowNode, frame: arrowFrame) + } + + transition.updateFrame(node: self.labelNode, frame: labelFrame) + transition.updateFrame(node: self.textNode, frame: textFrame) + + let highlightNodeOffset: CGFloat = topItem == nil ? 0.0 : UIScreenPixel + self.selectionNode.update(size: CGSize(width: width, height: height + highlightNodeOffset), theme: presentationData.theme, transition: transition) + transition.updateFrame(node: self.selectionNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -highlightNodeOffset), size: CGSize(width: width, height: height + highlightNodeOffset))) + + transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: sideInset, y: height - UIScreenPixel), size: CGSize(width: width - sideInset, height: UIScreenPixel))) + transition.updateAlpha(node: self.bottomSeparatorNode, alpha: bottomItem == nil ? 0.0 : 1.0) + + return height + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoScreenSwitchItem.swift b/submodules/TelegramUI/TelegramUI/PeerInfoScreenSwitchItem.swift new file mode 100644 index 0000000000..8a798af589 --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/PeerInfoScreenSwitchItem.swift @@ -0,0 +1,121 @@ +import AsyncDisplayKit +import Display +import TelegramPresentationData + +final class PeerInfoScreenSwitchItem: PeerInfoScreenItem { + let id: AnyHashable + let text: String + let value: Bool + let toggled: ((Bool) -> Void)? + + init(id: AnyHashable, text: String, value: Bool, toggled: ((Bool) -> Void)?) { + self.id = id + self.text = text + self.value = value + self.toggled = toggled + } + + func node() -> PeerInfoScreenItemNode { + return PeerInfoScreenSwitchItemNode() + } +} + +private final class PeerInfoScreenSwitchItemNode: PeerInfoScreenItemNode { + private let selectionNode: PeerInfoScreenSelectableBackgroundNode + private let textNode: ImmediateTextNode + private let switchNode: SwitchNode + private let bottomSeparatorNode: ASDisplayNode + + private var item: PeerInfoScreenSwitchItem? + + private var theme: PresentationTheme? + + override init() { + var bringToFrontForHighlightImpl: (() -> Void)? + self.selectionNode = PeerInfoScreenSelectableBackgroundNode(bringToFrontForHighlight: { bringToFrontForHighlightImpl?() }) + + self.textNode = ImmediateTextNode() + self.textNode.displaysAsynchronously = false + self.textNode.isUserInteractionEnabled = false + + self.switchNode = SwitchNode() + + self.bottomSeparatorNode = ASDisplayNode() + self.bottomSeparatorNode.isLayerBacked = true + + super.init() + + bringToFrontForHighlightImpl = { [weak self] in + self?.bringToFrontForHighlight?() + } + + self.addSubnode(self.bottomSeparatorNode) + self.addSubnode(self.selectionNode) + self.addSubnode(self.textNode) + self.addSubnode(self.switchNode) + + self.switchNode.valueUpdated = { [weak self] value in + self?.item?.toggled?(value) + } + } + + override func update(width: CGFloat, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + guard let item = item as? PeerInfoScreenSwitchItem else { + return 10.0 + } + + let firstTime = self.item == nil + + if self.theme !== presentationData.theme { + self.theme = presentationData.theme + + self.switchNode.frameColor = presentationData.theme.list.itemSwitchColors.frameColor + self.switchNode.contentColor = presentationData.theme.list.itemSwitchColors.contentColor + self.switchNode.handleColor = presentationData.theme.list.itemSwitchColors.handleColor + } + + self.item = item + + self.selectionNode.pressed = nil + + let sideInset: CGFloat = 16.0 + + self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + + let textColorValue: UIColor = presentationData.theme.list.itemPrimaryTextColor + + self.textNode.maximumNumberOfLines = 1 + self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(17.0), textColor: textColorValue) + + let textSize = self.textNode.updateLayout(CGSize(width: width - sideInset * 2.0 - 56.0, height: .greatestFiniteMagnitude)) + + let arrowInset: CGFloat = 18.0 + + let textFrame = CGRect(origin: CGPoint(x: sideInset, y: 11.0), size: textSize) + + let height = textSize.height + 22.0 + + transition.updateFrame(node: self.textNode, frame: textFrame) + + if let switchView = self.switchNode.view as? UISwitch { + if self.switchNode.bounds.size.width.isZero { + switchView.sizeToFit() + } + let switchSize = switchView.bounds.size + + self.switchNode.frame = CGRect(origin: CGPoint(x: width - switchSize.width - 15.0, y: floor((height - switchSize.height) / 2.0)), size: switchSize) + if switchView.isOn != item.value { + switchView.setOn(item.value, animated: !firstTime) + } + } + + let highlightNodeOffset: CGFloat = topItem == nil ? 0.0 : UIScreenPixel + self.selectionNode.update(size: CGSize(width: width, height: height + highlightNodeOffset), theme: presentationData.theme, transition: transition) + transition.updateFrame(node: self.selectionNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -highlightNodeOffset), size: CGSize(width: width, height: height + highlightNodeOffset))) + + transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: sideInset, y: height - UIScreenPixel), size: CGSize(width: width - sideInset, height: UIScreenPixel))) + transition.updateAlpha(node: self.bottomSeparatorNode, alpha: bottomItem == nil ? 0.0 : 1.0) + + return height + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoVisualMediaPane.swift b/submodules/TelegramUI/TelegramUI/PeerInfoVisualMediaPane.swift index f49d9978e6..5cca69a898 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfoVisualMediaPane.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfoVisualMediaPane.swift @@ -8,13 +8,26 @@ import TelegramPresentationData import AccountContext import ContextUI import PhotoResources +import RadialStatusNode +import TelegramStringFormatting +import GridMessageSelectionNode + +private let mediaBadgeBackgroundColor = UIColor(white: 0.0, alpha: 0.6) +private let mediaBadgeTextColor = UIColor.white private final class VisualMediaItemInteraction { let openMessage: (MessageId) -> Void - var hiddenMedia: [MessageId: [Media]] = [:] + let toggleSelection: (MessageId) -> Void - init(openMessage: @escaping (MessageId) -> Void) { + var hiddenMedia: [MessageId: [Media]] = [:] + var selectedMessageIds: Set? + + init( + openMessage: @escaping (MessageId) -> Void, + toggleSelection: @escaping (MessageId) -> Void + ) { self.openMessage = openMessage + self.toggleSelection = toggleSelection } } @@ -24,12 +37,16 @@ private final class VisualMediaItemNode: ASDisplayNode { private let containerNode: ContextControllerSourceNode private let imageNode: TransformImageNode + private var statusNode: RadialStatusNode + private let mediaBadgeNode: ChatMessageInteractiveMediaBadge + private var selectionNode: GridMessageSelectionNode? private let fetchStatusDisposable = MetaDisposable() private let fetchDisposable = MetaDisposable() private var resourceStatus: MediaResourceStatus? private var item: (VisualMediaItem, Media?, CGSize, CGSize?)? + private var theme: PresentationTheme? init(context: AccountContext, interaction: VisualMediaItemInteraction) { self.context = context @@ -37,11 +54,19 @@ private final class VisualMediaItemNode: ASDisplayNode { self.containerNode = ContextControllerSourceNode() self.imageNode = TransformImageNode() + self.statusNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.6)) + let progressDiameter: CGFloat = 40.0 + self.statusNode.frame = CGRect(x: 0.0, y: 0.0, width: progressDiameter, height: progressDiameter) + self.statusNode.isUserInteractionEnabled = false + + self.mediaBadgeNode = ChatMessageInteractiveMediaBadge() + self.mediaBadgeNode.frame = CGRect(origin: CGPoint(x: 6.0, y: 6.0), size: CGSize(width: 50.0, height: 50.0)) super.init() self.addSubnode(self.containerNode) self.containerNode.addSubnode(self.imageNode) + self.containerNode.addSubnode(self.mediaBadgeNode) self.containerNode.isGestureEnabled = false } @@ -69,6 +94,7 @@ private final class VisualMediaItemNode: ASDisplayNode { if item === self.item?.0 && size == self.item?.2 { return } + self.theme = theme var media: Media? for value in item.message.media { if let image = value as? TelegramMediaImage { @@ -88,20 +114,20 @@ private final class VisualMediaItemNode: ASDisplayNode { self.imageNode.setSignal(mediaGridMessagePhoto(account: context.account, photoReference: .message(message: MessageReference(item.message), media: image), fullRepresentationSize: CGSize(width: 300.0, height: 300.0), synchronousLoad: synchronousLoad), attemptSynchronously: synchronousLoad, dispatchOnDisplayLink: true) self.fetchStatusDisposable.set(nil) - /*self.statusNode.transitionToState(.none, completion: { [weak self] in + self.statusNode.transitionToState(.none, completion: { [weak self] in self?.statusNode.isHidden = true - })*/ - //self.mediaBadgeNode.isHidden = true + }) + self.mediaBadgeNode.isHidden = true self.resourceStatus = nil } else if let file = media as? TelegramMediaFile, file.isVideo { mediaDimensions = file.dimensions?.cgSize self.imageNode.setSignal(mediaGridMessageVideo(postbox: context.account.postbox, videoReference: .message(message: MessageReference(item.message), media: file), synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: true), attemptSynchronously: synchronousLoad) - /*self.mediaBadgeNode.isHidden = false + self.mediaBadgeNode.isHidden = false self.resourceStatus = nil - self.fetchStatusDisposable.set((messageMediaFileStatus(context: context, messageId: messageId, file: file) |> deliverOnMainQueue).start(next: { [weak self] status in - if let strongSelf = self, let item = strongSelf.item { + self.fetchStatusDisposable.set((messageMediaFileStatus(context: context, messageId: item.message.id, file: file) |> deliverOnMainQueue).start(next: { [weak self] status in + if let strongSelf = self, let (item, _, _, _) = strongSelf.item { strongSelf.resourceStatus = status let isStreamable = isMediaStreamable(message: item.message, media: file) @@ -158,18 +184,25 @@ private final class VisualMediaItemNode: ASDisplayNode { badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, text: NSAttributedString(string: durationString)) } - strongSelf.mediaBadgeNode.update(theme: item.theme, content: badgeContent, mediaDownloadState: mediaDownloadState, alignment: .right, animated: false, badgeAnimated: false) + strongSelf.mediaBadgeNode.update(theme: nil, content: badgeContent, mediaDownloadState: mediaDownloadState, alignment: .right, animated: false, badgeAnimated: false) } } })) if self.statusNode.supernode == nil { self.imageNode.addSubnode(self.statusNode) - }*/ + } } else { - //self.mediaBadgeNode.isHidden = true + self.mediaBadgeNode.isHidden = true } self.item = (item, media, size, mediaDimensions) + let progressDiameter: CGFloat = 40.0 + self.statusNode.frame = CGRect(origin: CGPoint(x: floor((size.width - progressDiameter) / 2.0), y: floor((size.height - progressDiameter) / 2.0)), size: CGSize(width: progressDiameter, height: progressDiameter)) + + self.mediaBadgeNode.frame = CGRect(origin: CGPoint(x: size.width - 3.0, y: size.height - 18.0 - 3.0), size: CGSize(width: 50.0, height: 50.0)) + + self.selectionNode?.frame = CGRect(origin: CGPoint(), size: size) + self.updateHiddenMedia() } @@ -185,6 +218,46 @@ private final class VisualMediaItemNode: ASDisplayNode { let imageSize = mediaDimensions.aspectFilled(imageFrame.size) self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageFrame.size, intrinsicInsets: UIEdgeInsets(), emptyColor: theme.list.mediaPlaceholderColor))() } + + self.updateSelectionState(animated: false) + } + } + + func updateSelectionState(animated: Bool) { + if let (item, media, _, mediaDimensions) = self.item, let theme = self.theme { + if let selectedIds = self.interaction.selectedMessageIds { + let selected = selectedIds.contains(item.message.id) + + if let selectionNode = self.selectionNode { + selectionNode.updateSelected(selected, animated: animated) + selectionNode.frame = CGRect(origin: CGPoint(), size: self.bounds.size) + } else { + let selectionNode = GridMessageSelectionNode(theme: theme, toggle: { [weak self] value in + if let strongSelf = self, let messageId = strongSelf.item?.0.message.id { + strongSelf.interaction.toggleSelection(messageId) + } + }) + + selectionNode.frame = CGRect(origin: CGPoint(), size: self.bounds.size) + self.containerNode.addSubnode(selectionNode) + self.selectionNode = selectionNode + selectionNode.updateSelected(selected, animated: false) + if animated { + selectionNode.animateIn() + } + } + } else { + if let selectionNode = self.selectionNode { + self.selectionNode = nil + if animated { + selectionNode.animateOut { [weak selectionNode] in + selectionNode?.removeFromSupernode() + } + } else { + selectionNode.removeFromSupernode() + } + } + } } } @@ -194,15 +267,15 @@ private final class VisualMediaItemNode: ASDisplayNode { var statusNodeHidden = false var accessoryHidden = false if let strongSelf = self { - //statusNodeHidden = strongSelf.statusNode.isHidden - //accessoryHidden = strongSelf.mediaBadgeNode.isHidden - //strongSelf.statusNode.isHidden = true - //strongSelf.mediaBadgeNode.isHidden = true + statusNodeHidden = strongSelf.statusNode.isHidden + accessoryHidden = strongSelf.mediaBadgeNode.isHidden + strongSelf.statusNode.isHidden = true + strongSelf.mediaBadgeNode.isHidden = true } let view = imageNode?.view.snapshotContentTree(unhide: true) if let strongSelf = self { - //strongSelf.statusNode.isHidden = statusNodeHidden - //strongSelf.mediaBadgeNode.isHidden = accessoryHidden + strongSelf.statusNode.isHidden = statusNodeHidden + strongSelf.mediaBadgeNode.isHidden = accessoryHidden } return (view, nil) }) @@ -232,6 +305,8 @@ private final class VisualMediaItem { final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScrollViewDelegate { private let context: AccountContext private let peerId: PeerId + private let interaction: PeerInfoPaneInteraction + private let scrollNode: ASScrollNode private var _itemInteraction: VisualMediaItemInteraction? @@ -257,17 +332,24 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro private var isRequestingView: Bool = false private var isFirstHistoryView: Bool = true - init(context: AccountContext, openMessage: @escaping (MessageId) -> Bool, peerId: PeerId) { + init(context: AccountContext, openMessage: @escaping (MessageId) -> Bool, peerId: PeerId, interaction: PeerInfoPaneInteraction) { self.context = context self.peerId = peerId + self.interaction = interaction self.scrollNode = ASScrollNode() super.init() - self._itemInteraction = VisualMediaItemInteraction(openMessage: { id in - openMessage(id) - }) + self._itemInteraction = VisualMediaItemInteraction( + openMessage: { id in + openMessage(id) + }, + toggleSelection: { id in + interaction.toggleMessageSelected(id) + } + ) + self.itemInteraction.selectedMessageIds = self.interaction.selectedMessageIds self.scrollNode.view.showsVerticalScrollIndicator = false if #available(iOS 11.0, *) { @@ -372,6 +454,13 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro return nil } + func updateSelectedMessages(animated: Bool) { + self.itemInteraction.selectedMessageIds = self.interaction.selectedMessageIds + for (_, itemNode) in self.visibleMediaItems { + itemNode.updateSelectionState(animated: animated) + } + } + func update(size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { self.currentParams = (size, isScrollingLockedAtTop, presentationData) @@ -420,10 +509,10 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro maxVisibleRow = min(rowCount - 1, maxVisibleRow) let minVisibleIndex = minVisibleRow * itemsInRow - let maxVisibleIndex = min(self.mediaItems.count - 1, maxVisibleRow * itemsInRow - 1) + let maxVisibleIndex = min(self.mediaItems.count - 1, (maxVisibleRow + 1) * itemsInRow - 1) var validIds = Set() - if minVisibleIndex < maxVisibleIndex { + if minVisibleIndex <= maxVisibleIndex { for i in minVisibleIndex ... maxVisibleIndex { let stableId = self.mediaItems[i].message.stableId validIds.insert(stableId) diff --git a/submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping b/submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping index 7a9fbcb92d1b736e700de3e9ded72262041c5c91..710b3a4ac155ae2009ce9a760e2bab73654950da 100644 GIT binary patch delta 43885 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 delta 44333 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 M)aE$~3WXQ_A0_%ee*gdg diff --git a/submodules/WalletUI/Resources/WalletStrings.mapping b/submodules/WalletUI/Resources/WalletStrings.mapping index 589c6fe85e4fa03a50b6adefffe67915bd39bf1c..9f7c34892095545bdfb3f1e1871a24394137ff12 100644 GIT binary patch delta 17 YcmX@$c))Q(i^Al^3bKrhlN%M}070t;9smFU delta 40 vcmX@$c))Q(i-L?e0|P^NVopwKiC$ String { + public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue) } - public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String { + public func Wallet_Updated_HoursAgo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue) From e2b36c872de8140baee44c9413a4aa86018ab05d Mon Sep 17 00:00:00 2001 From: overtake Date: Fri, 7 Feb 2020 18:53:36 +0400 Subject: [PATCH 07/30] no message --- submodules/Postbox/Sources/Coding.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/Postbox/Sources/Coding.swift b/submodules/Postbox/Sources/Coding.swift index 0e73649666..e25c870781 100644 --- a/submodules/Postbox/Sources/Coding.swift +++ b/submodules/Postbox/Sources/Coding.swift @@ -77,7 +77,7 @@ public class MemoryBuffer: Equatable, CustomStringConvertible { data.copyBytes(to: self.memory.assumingMemoryBound(to: UInt8.self), count: data.count) self.capacity = data.count self.length = data.count - self.freeWhenDone = false + self.freeWhenDone = true } } From 9f73cc401853620b376ba77d849a37430653faf1 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 7 Feb 2020 22:09:58 +0000 Subject: [PATCH 08/30] Mixed WIP --- NotificationService/Serialization.m | 2 +- .../Sources/ChatListController.swift | 49 +-- .../Sources/ChatListControllerNode.swift | 4 +- .../ChatListFilterPresetController.swift | 47 +- .../ChatListFilterPresetListController.swift | 50 +-- .../ChatListFilterPresetListItem.swift | 12 +- .../Sources/Node/ChatListNode.swift | 24 +- .../Sources/Node/ChatListNodeLocation.swift | 26 +- .../Sources/Node/ChatListViewTransition.swift | 2 +- .../TabBarChatListFilterController.swift | 46 +- submodules/Display/Display/ListView.swift | 48 +++ submodules/SyncCore/Sources/Namespaces.swift | 7 + .../TextEntitiesMessageAttribute.swift | 5 + submodules/TelegramApi/Sources/Api0.swift | 32 +- submodules/TelegramApi/Sources/Api1.swift | 404 +++++++++++++++++- submodules/TelegramApi/Sources/Api2.swift | 178 ++++++++ submodules/TelegramApi/Sources/Api3.swift | 92 ++++ submodules/TelegramCore/Sources/Account.swift | 1 + .../TelegramCore/Sources/AccountManager.swift | 1 + .../Sources/ChatListFiltering.swift | 378 ++++++++++++++++ .../ManagedSecretChatOutgoingOperations.swift | 4 + .../TelegramCore/Sources/Serialization.swift | 2 +- .../Sources/StoreMessage_Telegram.swift | 2 + .../TextEntitiesMessageAttribute.swift | 2 + .../Sources/UpdateCachedPeerData.swift | 2 +- .../TelegramUI/DeclareEncodables.swift | 1 - .../TelegramUI/PeerInfoFilesPane.swift | 8 +- .../PeerInfoGroupsInCommonPaneNode.swift | 5 +- .../TelegramUI/PeerInfoScreen.swift | 106 +++-- .../TelegramUI/PeerInfoVisualMediaPane.swift | 83 +++- .../Sources/ChatListFilterSettings.swift | 135 ------ 31 files changed, 1424 insertions(+), 334 deletions(-) create mode 100644 submodules/TelegramCore/Sources/ChatListFiltering.swift delete mode 100644 submodules/TelegramUIPreferences/Sources/ChatListFilterSettings.swift diff --git a/NotificationService/Serialization.m b/NotificationService/Serialization.m index 00a0621e3e..f7eea7807e 100644 --- a/NotificationService/Serialization.m +++ b/NotificationService/Serialization.m @@ -3,7 +3,7 @@ @implementation Serialization - (NSUInteger)currentLayer { - return 109; + return 110; } - (id _Nullable)parseMessage:(NSData * _Nullable)data { diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 57510f6e06..19bdb612a4 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -107,6 +107,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController, private let hideNetworkActivityStatus: Bool public let groupId: PeerGroupId + public let filter: ChatListFilter? public let previewing: Bool let openMessageFromSearchDisposable: MetaDisposable = MetaDisposable() @@ -145,12 +146,13 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController, } } - public init(context: AccountContext, groupId: PeerGroupId, controlsHistoryPreload: Bool, hideNetworkActivityStatus: Bool = false, previewing: Bool = false, enableDebugActions: Bool) { + public init(context: AccountContext, groupId: PeerGroupId, filter: ChatListFilter? = nil, controlsHistoryPreload: Bool, hideNetworkActivityStatus: Bool = false, previewing: Bool = false, enableDebugActions: Bool) { self.context = context self.controlsHistoryPreload = controlsHistoryPreload self.hideNetworkActivityStatus = hideNetworkActivityStatus self.groupId = groupId + self.filter = filter self.previewing = previewing self.presentationData = (context.sharedContext.currentPresentationData.with { $0 }) @@ -163,7 +165,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController, self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style let title: String - if case .root = self.groupId { + if let filter = self.filter { + title = filter.title ?? "" + } else if self.groupId == .root { title = self.presentationData.strings.DialogList_Title self.navigationBar?.item = nil } else { @@ -174,7 +178,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController, self.navigationItem.titleView = self.titleView if !previewing { - if case .root = groupId { + if self.groupId == .root && self.filter == nil { self.tabBarItem.title = self.presentationData.strings.DialogList_Title let icon: UIImage? @@ -270,15 +274,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController, ).start(next: { [weak self] networkState, proxy, passcode, state, chatListFilter in if let strongSelf = self { let defaultTitle: String - if case .root = strongSelf.groupId { + if strongSelf.groupId == .root { if let chatListFilter = chatListFilter { - let title: String - switch chatListFilter.name { - case .unread: - title = "Unread" - case let .custom(value): - title = value - } + let title: String = chatListFilter.title ?? "" defaultTitle = title } else { defaultTitle = strongSelf.presentationData.strings.DialogList_Title @@ -287,7 +285,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController, defaultTitle = strongSelf.presentationData.strings.ChatList_ArchivedChatsTitle } if state.editing { - if case .root = strongSelf.groupId { + if strongSelf.groupId == .root && strongSelf.filter == nil { strongSelf.navigationItem.rightBarButtonItem = nil } @@ -297,9 +295,11 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController, var isRoot = false if case .root = strongSelf.groupId { isRoot = true - let rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationComposeIcon(strongSelf.presentationData.theme), style: .plain, target: strongSelf, action: #selector(strongSelf.composePressed)) - rightBarButtonItem.accessibilityLabel = strongSelf.presentationData.strings.VoiceOver_Navigation_Compose - strongSelf.navigationItem.rightBarButtonItem = rightBarButtonItem + if strongSelf.filter == nil { + let rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationComposeIcon(strongSelf.presentationData.theme), style: .plain, target: strongSelf, action: #selector(strongSelf.composePressed)) + rightBarButtonItem.accessibilityLabel = strongSelf.presentationData.strings.VoiceOver_Navigation_Compose + strongSelf.navigationItem.rightBarButtonItem = rightBarButtonItem + } } let (hasProxy, connectsViaProxy) = proxy @@ -322,7 +322,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController, case .online: strongSelf.titleView.title = NetworkStatusTitle(text: defaultTitle, activity: false, hasProxy: isRoot && hasProxy, connectsViaProxy: connectsViaProxy, isPasscodeSet: isRoot && isPasscodeSet, isManuallyLocked: isRoot && isManuallyLocked) } - if case .root = groupId, checkProxy { + if groupId == .root && filter == nil && checkProxy { if strongSelf.proxyUnavailableTooltipController == nil && !strongSelf.didShowProxyUnavailableTooltipController && strongSelf.isNodeLoaded && strongSelf.displayNode.view.window != nil && strongSelf.navigationController?.topViewController === self { strongSelf.didShowProxyUnavailableTooltipController = true let tooltipController = TooltipController(content: .text(strongSelf.presentationData.strings.Proxy_TooltipUnavailable), baseFontSize: strongSelf.presentationData.listsFontSize.baseDisplaySize, timeout: 60.0, dismissByTapOutside: true) @@ -444,7 +444,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController, editItem = UIBarButtonItem(title: self.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(self.editPressed)) editItem.accessibilityLabel = self.presentationData.strings.Common_Edit } - if case .root = self.groupId { + if self.groupId == .root && self.filter == nil { self.navigationItem.leftBarButtonItem = editItem let rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationComposeIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.composePressed)) rightBarButtonItem.accessibilityLabel = self.presentationData.strings.VoiceOver_Navigation_Compose @@ -464,7 +464,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController, } override public func loadDisplayNode() { - self.displayNode = ChatListControllerNode(context: self.context, groupId: self.groupId, previewing: self.previewing, controlsHistoryPreload: self.controlsHistoryPreload, presentationData: self.presentationData, controller: self) + self.displayNode = ChatListControllerNode(context: self.context, groupId: self.groupId, filter: self.filter, previewing: self.previewing, controlsHistoryPreload: self.controlsHistoryPreload, presentationData: self.presentationData, controller: self) self.chatListDisplayNode.navigationBar = self.navigationBar @@ -1810,9 +1810,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController, public func presentTabBarPreviewingController(sourceNodes: [ASDisplayNode]) { if self.isNodeLoaded { - let _ = (self.context.account.postbox.transaction { transaction -> [ChatListFilterPreset] in - let settings = transaction.getPreferencesEntry(key: ApplicationSpecificPreferencesKeys.chatListFilterSettings) as? ChatListFilterSettings ?? ChatListFilterSettings.default - return settings.presets + let _ = (self.context.account.postbox.transaction { transaction -> [ChatListFilter] in + let settings = transaction.getPreferencesEntry(key: PreferencesKeys.chatListFilters) as? ChatListFiltersState ?? ChatListFiltersState.default + return settings.filters } |> deliverOnMainQueue).start(next: { [weak self] presetList in guard let strongSelf = self else { @@ -1826,7 +1826,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController, guard let strongSelf = self else { return } - if let currentPreset = strongSelf.chatListDisplayNode.chatListNode.chatListFilter { + /*if let currentPreset = strongSelf.chatListDisplayNode.chatListNode.chatListFilter { var found = false if let index = presets.index(where: { $0.id == currentPreset.id }) { found = true @@ -1837,13 +1837,14 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController, if !found { strongSelf.chatListDisplayNode.chatListNode.chatListFilter = nil } - } + }*/ })) }, updatePreset: { value in guard let strongSelf = self else { return } - strongSelf.chatListDisplayNode.chatListNode.chatListFilter = value + strongSelf.push(ChatListControllerImpl(context: strongSelf.context, groupId: .root, filter: value, controlsHistoryPreload: false, hideNetworkActivityStatus: true, previewing: false, enableDebugActions: false)) + //strongSelf.chatListDisplayNode.chatListNode.chatListFilter = value }) strongSelf.context.sharedContext.mainWindow?.present(controller, on: .root) }) diff --git a/submodules/ChatListUI/Sources/ChatListControllerNode.swift b/submodules/ChatListUI/Sources/ChatListControllerNode.swift index 3dd78330a6..9eb336e963 100644 --- a/submodules/ChatListUI/Sources/ChatListControllerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListControllerNode.swift @@ -72,12 +72,12 @@ final class ChatListControllerNode: ASDisplayNode { let debugListView = ListView() - init(context: AccountContext, groupId: PeerGroupId, previewing: Bool, controlsHistoryPreload: Bool, presentationData: PresentationData, controller: ChatListControllerImpl) { + init(context: AccountContext, groupId: PeerGroupId, filter: ChatListFilter?, previewing: Bool, controlsHistoryPreload: Bool, presentationData: PresentationData, controller: ChatListControllerImpl) { self.context = context self.groupId = groupId self.presentationData = presentationData - self.chatListNode = ChatListNode(context: context, groupId: groupId, previewing: previewing, controlsHistoryPreload: controlsHistoryPreload, mode: .chatList, theme: presentationData.theme, fontSize: presentationData.listsFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations) + self.chatListNode = ChatListNode(context: context, groupId: groupId, chatListFilter: filter, previewing: previewing, controlsHistoryPreload: controlsHistoryPreload, mode: .chatList, theme: presentationData.theme, fontSize: presentationData.listsFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations) self.controller = controller diff --git a/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift b/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift index 890a6414cc..27052bb641 100644 --- a/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift +++ b/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift @@ -35,7 +35,7 @@ private enum ChatListFilterPresetControllerSection: Int32 { case additionalPeers } -private func filterEntry(presentationData: ItemListPresentationData, arguments: ChatListFilterPresetControllerArguments, title: String, value: Bool, filter: ChatListIncludeCategoryFilter, section: Int32) -> ItemListCheckboxItem { +private func filterEntry(presentationData: ItemListPresentationData, arguments: ChatListFilterPresetControllerArguments, title: String, value: Bool, filter: ChatListFilterPeerCategories, section: Int32) -> ItemListCheckboxItem { return ItemListCheckboxItem(presentationData: presentationData, title: title, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: section, action: { arguments.updateState { current in var state = current @@ -188,11 +188,7 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry { return ItemListSwitchItem(presentationData: presentationData, title: title, value: value, sectionId: self.section, style: .blocks, updated: { _ in arguments.updateState { current in var state = current - if state.includeCategories.contains(.muted) { - state.includeCategories.remove(.muted) - } else { - state.includeCategories.insert(.muted) - } + state.excludeMuted = !state.excludeMuted return state } }) @@ -200,11 +196,7 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry { return ItemListSwitchItem(presentationData: presentationData, title: title, value: value, sectionId: self.section, style: .blocks, updated: { _ in arguments.updateState { current in var state = current - if state.includeCategories.contains(.read) { - state.includeCategories.remove(.read) - } else { - state.includeCategories.insert(.read) - } + state.excludeRead = !state.excludeRead return state } }) @@ -230,7 +222,9 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry { private struct ChatListFilterPresetControllerState: Equatable { var name: String - var includeCategories: ChatListIncludeCategoryFilter + var includeCategories: ChatListFilterPeerCategories + var excludeMuted: Bool + var excludeRead: Bool var additionallyIncludePeers: [PeerId] var revealedPeerId: PeerId? @@ -239,7 +233,7 @@ private struct ChatListFilterPresetControllerState: Equatable { if self.name.isEmpty { return false } - if self.includeCategories.isEmpty && self.additionallyIncludePeers.isEmpty { + if self.includeCategories.isEmpty && self.additionallyIncludePeers.isEmpty && !self.excludeMuted && !self.excludeRead { return false } return true @@ -259,8 +253,8 @@ private func chatListFilterPresetControllerEntries(presentationData: Presentatio entries.append(.filterPublicGroups(title: "Public Groups", value: state.includeCategories.contains(.publicGroups))) entries.append(.filterChannels(title: "Channels", value: state.includeCategories.contains(.channels))) - entries.append(.filterMuted(title: "Exclude Muted", value: !state.includeCategories.contains(.muted))) - entries.append(.filterRead(title: "Exclude Read", value: !state.includeCategories.contains(.read))) + entries.append(.filterMuted(title: "Exclude Muted", value: state.excludeMuted)) + entries.append(.filterRead(title: "Exclude Read", value: state.excludeRead)) entries.append(.additionalPeersHeader("ALWAYS INCLUDE")) entries.append(.addAdditionalPeer(title: "Add")) @@ -274,19 +268,14 @@ private func chatListFilterPresetControllerEntries(presentationData: Presentatio return entries } -func chatListFilterPresetController(context: AccountContext, currentPreset: ChatListFilterPreset?, updated: @escaping ([ChatListFilterPreset]) -> Void) -> ViewController { +func chatListFilterPresetController(context: AccountContext, currentPreset: ChatListFilter?, updated: @escaping ([ChatListFilter]) -> Void) -> ViewController { let initialName: String if let currentPreset = currentPreset { - switch currentPreset.name { - case .unread: - initialName = "Unread" - case let .custom(value): - initialName = value - } + initialName = currentPreset.title ?? "" } else { initialName = "New Preset" } - let initialState = ChatListFilterPresetControllerState(name: initialName, includeCategories: currentPreset?.includeCategories ?? .all, additionallyIncludePeers: currentPreset?.additionallyIncludePeers ?? []) + let initialState = ChatListFilterPresetControllerState(name: initialName, includeCategories: currentPreset?.categories ?? .all, excludeMuted: currentPreset?.excludeMuted ?? false, excludeRead: currentPreset?.excludeRead ?? false, additionallyIncludePeers: currentPreset?.includePeers ?? []) let stateValue = Atomic(value: initialState) let statePromise = ValuePromise(initialState, ignoreRepeated: true) let updateState: ((ChatListFilterPresetControllerState) -> ChatListFilterPresetControllerState) -> Void = { f in @@ -378,15 +367,19 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat }) let rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: state.isComplete, action: { let state = stateValue.with { $0 } - let preset = ChatListFilterPreset(id: currentPreset?.id ?? arc4random64(), name: .custom(state.name), includeCategories: state.includeCategories, additionallyIncludePeers: state.additionallyIncludePeers) + let preset = ChatListFilter(id: currentPreset?.id ?? -1, title: state.name, categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, includePeers: state.additionallyIncludePeers) let _ = (updateChatListFilterSettingsInteractively(postbox: context.account.postbox, { settings in + var preset = preset + if currentPreset == nil { + preset.id = max(1, settings.filters.map({ $0.id }).max() ?? 1) + } var settings = settings - settings.presets = settings.presets.filter { $0 != preset && $0 != currentPreset } - settings.presets.append(preset) + settings.filters = settings.filters.filter { $0 != preset && $0 != currentPreset } + settings.filters.append(preset) return settings }) |> deliverOnMainQueue).start(next: { settings in - updated(settings.presets) + updated(settings.filters) dismissImpl?() }) }) diff --git a/submodules/ChatListUI/Sources/ChatListFilterPresetListController.swift b/submodules/ChatListUI/Sources/ChatListFilterPresetListController.swift index a3900429f8..c71904a4af 100644 --- a/submodules/ChatListUI/Sources/ChatListFilterPresetListController.swift +++ b/submodules/ChatListUI/Sources/ChatListFilterPresetListController.swift @@ -13,12 +13,12 @@ import AccountContext private final class ChatListFilterPresetListControllerArguments { let context: AccountContext - let openPreset: (ChatListFilterPreset) -> Void + let openPreset: (ChatListFilter) -> Void let addNew: () -> Void - let setItemWithRevealedOptions: (ChatListFilterPreset?, ChatListFilterPreset?) -> Void - let removePreset: (ChatListFilterPreset) -> Void + let setItemWithRevealedOptions: (Int32?, Int32?) -> Void + let removePreset: (Int32) -> Void - init(context: AccountContext, openPreset: @escaping (ChatListFilterPreset) -> Void, addNew: @escaping () -> Void, setItemWithRevealedOptions: @escaping (ChatListFilterPreset?, ChatListFilterPreset?) -> Void, removePreset: @escaping (ChatListFilterPreset) -> Void) { + init(context: AccountContext, openPreset: @escaping (ChatListFilter) -> Void, addNew: @escaping () -> Void, setItemWithRevealedOptions: @escaping (Int32?, Int32?) -> Void, removePreset: @escaping (Int32) -> Void) { self.context = context self.openPreset = openPreset self.addNew = addNew @@ -45,14 +45,14 @@ private func stringForUserCount(_ peers: [PeerId: SelectivePrivacyPeer], strings private enum ChatListFilterPresetListEntryStableId: Hashable { case listHeader - case preset(Int64) + case preset(Int32) case addItem case listFooter } private enum ChatListFilterPresetListEntry: ItemListNodeEntry { case listHeader(String) - case preset(index: Int, title: String, preset: ChatListFilterPreset, canBeReordered: Bool, canBeDeleted: Bool) + case preset(index: Int, title: String?, preset: ChatListFilter, canBeReordered: Bool, canBeDeleted: Bool) case addItem(String) case listFooter(String) @@ -99,12 +99,12 @@ private enum ChatListFilterPresetListEntry: ItemListNodeEntry { case let .listHeader(text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, multiline: true, sectionId: self.section) case let .preset(index, title, preset, canBeReordered, canBeDeleted): - return ChatListFilterPresetListItem(presentationData: presentationData, preset: preset, title: title, editing: ChatListFilterPresetListItemEditing(editable: true, editing: false, revealed: false), canBeReordered: canBeReordered, canBeDeleted: canBeDeleted, sectionId: self.section, action: { + return ChatListFilterPresetListItem(presentationData: presentationData, preset: preset, title: title ?? "", editing: ChatListFilterPresetListItemEditing(editable: true, editing: false, revealed: false), canBeReordered: canBeReordered, canBeDeleted: canBeDeleted, sectionId: self.section, action: { arguments.openPreset(preset) }, setItemWithRevealedOptions: { lhs, rhs in arguments.setItemWithRevealedOptions(lhs, rhs) }, remove: { - arguments.removePreset(preset) + arguments.removePreset(preset.id) }) case let .addItem(text): return ItemListActionItem(presentationData: presentationData, title: text, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: { @@ -117,22 +117,15 @@ private enum ChatListFilterPresetListEntry: ItemListNodeEntry { } private struct ChatListFilterPresetListControllerState: Equatable { - var revealedPreset: ChatListFilterPreset? = nil + var revealedPreset: Int32? = nil } -private func chatListFilterPresetListControllerEntries(presentationData: PresentationData, state: ChatListFilterPresetListControllerState, settings: ChatListFilterSettings) -> [ChatListFilterPresetListEntry] { +private func chatListFilterPresetListControllerEntries(presentationData: PresentationData, state: ChatListFilterPresetListControllerState, settings: ChatListFiltersState) -> [ChatListFilterPresetListEntry] { var entries: [ChatListFilterPresetListEntry] = [] - entries.append(.listHeader("PRESETS")) - for preset in settings.presets { - let title: String - switch preset.name { - case .unread: - title = "Unread" - case let .custom(value): - title = value - } - entries.append(.preset(index: entries.count, title: title, preset: preset, canBeReordered: settings.presets.count > 1, canBeDeleted: true)) + entries.append(.listHeader("FILTERS")) + for preset in settings.filters { + entries.append(.preset(index: entries.count, title: preset.title, preset: preset, canBeReordered: settings.filters.count > 1, canBeDeleted: true)) } entries.append(.addItem("Add New")) entries.append(.listFooter("Add custom presets")) @@ -140,7 +133,7 @@ private func chatListFilterPresetListControllerEntries(presentationData: Present return entries } -func chatListFilterPresetListController(context: AccountContext, updated: @escaping ([ChatListFilterPreset]) -> Void) -> ViewController { +func chatListFilterPresetListController(context: AccountContext, updated: @escaping ([ChatListFilter]) -> Void) -> ViewController { let initialState = ChatListFilterPresetListControllerState() let statePromise = ValuePromise(initialState, ignoreRepeated: true) let stateValue = Atomic(value: initialState) @@ -164,20 +157,20 @@ func chatListFilterPresetListController(context: AccountContext, updated: @escap } return state } - }, removePreset: { preset in + }, removePreset: { id in let _ = (updateChatListFilterSettingsInteractively(postbox: context.account.postbox, { settings in var settings = settings - if let index = settings.presets.index(of: preset) { - settings.presets.remove(at: index) + if let index = settings.filters.index(where: { $0.id == id }) { + settings.filters.remove(at: index) } return settings }) |> deliverOnMainQueue).start(next: { settings in - updated(settings.presets) + updated(settings.filters) }) }) - let preferences = context.account.postbox.preferencesView(keys: [ApplicationSpecificPreferencesKeys.chatListFilterSettings]) + let preferences = context.account.postbox.preferencesView(keys: [PreferencesKeys.chatListFilters]) let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, @@ -185,12 +178,13 @@ func chatListFilterPresetListController(context: AccountContext, updated: @escap preferences ) |> map { presentationData, state, preferences -> (ItemListControllerState, (ItemListNodeState, Any)) in - let settings = preferences.values[ApplicationSpecificPreferencesKeys.chatListFilterSettings] as? ChatListFilterSettings ?? ChatListFilterSettings.default + let settings = preferences.values[PreferencesKeys.chatListFilters] as? ChatListFiltersState ?? ChatListFiltersState.default let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Close), style: .regular, enabled: true, action: { + let _ = replaceRemoteChatListFilters(account: context.account).start() dismissImpl?() }) - let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text("Filter Presets"), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) + let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text("Filter Presets"), leftNavigationButton: leftNavigationButton, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: chatListFilterPresetListControllerEntries(presentationData: presentationData, state: state, settings: settings), style: .blocks, animateChanges: true) return (controllerState, (listState, arguments)) diff --git a/submodules/ChatListUI/Sources/ChatListFilterPresetListItem.swift b/submodules/ChatListUI/Sources/ChatListFilterPresetListItem.swift index 4e8454897f..adad852881 100644 --- a/submodules/ChatListUI/Sources/ChatListFilterPresetListItem.swift +++ b/submodules/ChatListUI/Sources/ChatListFilterPresetListItem.swift @@ -18,26 +18,26 @@ struct ChatListFilterPresetListItemEditing: Equatable { final class ChatListFilterPresetListItem: ListViewItem, ItemListItem { let presentationData: ItemListPresentationData - let preset: ChatListFilterPreset + let preset: ChatListFilter let title: String let editing: ChatListFilterPresetListItemEditing let canBeReordered: Bool let canBeDeleted: Bool let sectionId: ItemListSectionId let action: () -> Void - let setItemWithRevealedOptions: (ChatListFilterPreset?, ChatListFilterPreset?) -> Void + let setItemWithRevealedOptions: (Int32?, Int32?) -> Void let remove: () -> Void init( presentationData: ItemListPresentationData, - preset: ChatListFilterPreset, + preset: ChatListFilter, title: String, editing: ChatListFilterPresetListItemEditing, canBeReordered: Bool, canBeDeleted: Bool, sectionId: ItemListSectionId, action: @escaping () -> Void, - setItemWithRevealedOptions: @escaping (ChatListFilterPreset?, ChatListFilterPreset?) -> Void, + setItemWithRevealedOptions: @escaping (Int32?, Int32?) -> Void, remove: @escaping () -> Void ) { self.presentationData = presentationData @@ -409,13 +409,13 @@ private final class ChatListFilterPresetListItemNode: ItemListRevealOptionsItemN override func revealOptionsInteractivelyOpened() { if let item = self.item { - item.setItemWithRevealedOptions(item.preset, nil) + item.setItemWithRevealedOptions(item.preset.id, nil) } } override func revealOptionsInteractivelyClosed() { if let item = self.item { - item.setItemWithRevealedOptions(nil, item.preset) + item.setItemWithRevealedOptions(nil, item.preset.id) } } diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index 3bd95959cd..fdd814e57a 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -366,21 +366,9 @@ public final class ChatListNode: ListView { } private var currentLocation: ChatListNodeLocation? - var chatListFilter: ChatListFilterPreset? { - didSet { - if self.chatListFilter != oldValue { - self.chatListFilterValue.set(self.chatListFilter) - - if self.chatListFilter?.includeCategories != oldValue?.includeCategories || self.chatListFilter?.additionallyIncludePeers != oldValue?.additionallyIncludePeers { - if let currentLocation = self.currentLocation { - self.setChatListLocation(.initial(count: 50, filter: self.chatListFilter)) - } - } - } - } - } - private let chatListFilterValue = ValuePromise(nil) - var chatListFilterSignal: Signal { + let chatListFilter: ChatListFilter? + private let chatListFilterValue = Promise() + var chatListFilterSignal: Signal { return self.chatListFilterValue.get() } private let chatListLocation = ValuePromise() @@ -425,9 +413,11 @@ public final class ChatListNode: ListView { private var hapticFeedback: HapticFeedback? - public init(context: AccountContext, groupId: PeerGroupId, previewing: Bool, controlsHistoryPreload: Bool, mode: ChatListNodeMode, theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, disableAnimations: Bool) { + public init(context: AccountContext, groupId: PeerGroupId, chatListFilter: ChatListFilter? = nil, previewing: Bool, controlsHistoryPreload: Bool, mode: ChatListNodeMode, theme: PresentationTheme, fontSize: PresentationFontSize, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, disableAnimations: Bool) { self.context = context self.groupId = groupId + self.chatListFilter = chatListFilter + self.chatListFilterValue.set(.single(chatListFilter)) self.controlsHistoryPreload = controlsHistoryPreload self.mode = mode @@ -541,7 +531,7 @@ public final class ChatListNode: ListView { let chatListViewUpdate = self.chatListLocation.get() |> distinctUntilChanged - |> mapToSignal { location -> Signal<(ChatListNodeViewUpdate, ChatListFilterPreset?), NoError> in + |> mapToSignal { location -> Signal<(ChatListNodeViewUpdate, ChatListFilter?), NoError> in return chatListViewForLocation(groupId: groupId, location: location, account: context.account) |> map { update in return (update, location.filter) diff --git a/submodules/ChatListUI/Sources/Node/ChatListNodeLocation.swift b/submodules/ChatListUI/Sources/Node/ChatListNodeLocation.swift index 314f319a9d..5878d7df08 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNodeLocation.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNodeLocation.swift @@ -7,11 +7,11 @@ import Display import TelegramUIPreferences enum ChatListNodeLocation: Equatable { - case initial(count: Int, filter: ChatListFilterPreset?) - case navigation(index: ChatListIndex, filter: ChatListFilterPreset?) - case scroll(index: ChatListIndex, sourceIndex: ChatListIndex, scrollPosition: ListViewScrollPosition, animated: Bool, filter: ChatListFilterPreset?) + case initial(count: Int, filter: ChatListFilter?) + case navigation(index: ChatListIndex, filter: ChatListFilter?) + case scroll(index: ChatListIndex, sourceIndex: ChatListIndex, scrollPosition: ListViewScrollPosition, animated: Bool, filter: ChatListFilter?) - var filter: ChatListFilterPreset? { + var filter: ChatListFilter? { switch self { case let .initial(initial): return initial.filter @@ -32,17 +32,17 @@ struct ChatListNodeViewUpdate { func chatListViewForLocation(groupId: PeerGroupId, location: ChatListNodeLocation, account: Account) -> Signal { let filterPredicate: ((Peer, PeerNotificationSettings?, Bool) -> Bool)? if let filter = location.filter { - let includePeers = Set(filter.additionallyIncludePeers) + let includePeers = Set(filter.includePeers) filterPredicate = { peer, notificationSettings, isUnread in if includePeers.contains(peer.id) { return true } - if !filter.includeCategories.contains(.read) { + if filter.excludeRead { if !isUnread { return false } } - if !filter.includeCategories.contains(.muted) { + if filter.excludeMuted { if let notificationSettings = notificationSettings as? TelegramPeerNotificationSettings { if case .muted = notificationSettings.muteState { return false @@ -51,26 +51,26 @@ func chatListViewForLocation(groupId: PeerGroupId, location: ChatListNodeLocatio return false } } - if !filter.includeCategories.contains(.privateChats) { + if !filter.categories.contains(.privateChats) { if let user = peer as? TelegramUser { if user.botInfo == nil { return false } } } - if !filter.includeCategories.contains(.secretChats) { + if !filter.categories.contains(.secretChats) { if let _ = peer as? TelegramSecretChat { return false } } - if !filter.includeCategories.contains(.bots) { + if !filter.categories.contains(.bots) { if let user = peer as? TelegramUser { if user.botInfo != nil { return false } } } - if !filter.includeCategories.contains(.privateGroups) { + if !filter.categories.contains(.privateGroups) { if let _ = peer as? TelegramGroup { return false } else if let channel = peer as? TelegramChannel { @@ -81,7 +81,7 @@ func chatListViewForLocation(groupId: PeerGroupId, location: ChatListNodeLocatio } } } - if !filter.includeCategories.contains(.publicGroups) { + if !filter.categories.contains(.publicGroups) { if let channel = peer as? TelegramChannel { if case .group = channel.info { if channel.username != nil { @@ -90,7 +90,7 @@ func chatListViewForLocation(groupId: PeerGroupId, location: ChatListNodeLocatio } } } - if !filter.includeCategories.contains(.channels) { + if !filter.categories.contains(.channels) { if let channel = peer as? TelegramChannel { if case .broadcast = channel.info { return false diff --git a/submodules/ChatListUI/Sources/Node/ChatListViewTransition.swift b/submodules/ChatListUI/Sources/Node/ChatListViewTransition.swift index 4b0f09f8c2..d7997ee48c 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListViewTransition.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListViewTransition.swift @@ -12,7 +12,7 @@ struct ChatListNodeView { let originalView: ChatListView let filteredEntries: [ChatListNodeEntry] let isLoading: Bool - let filter: ChatListFilterPreset? + let filter: ChatListFilter? } enum ChatListNodeViewTransitionReason { diff --git a/submodules/ChatListUI/Sources/TabBarChatListFilterController.swift b/submodules/ChatListUI/Sources/TabBarChatListFilterController.swift index 79e09e3b11..6cb265b924 100644 --- a/submodules/ChatListUI/Sources/TabBarChatListFilterController.swift +++ b/submodules/ChatListUI/Sources/TabBarChatListFilterController.swift @@ -8,6 +8,7 @@ import AccountContext import SyncCore import Postbox import TelegramUIPreferences +import TelegramCore final class TabBarChatListFilterController: ViewController { private var controllerNode: TabBarChatListFilterControllerNode { @@ -21,17 +22,17 @@ final class TabBarChatListFilterController: ViewController { private let context: AccountContext private let sourceNodes: [ASDisplayNode] - private let presetList: [ChatListFilterPreset] - private let currentPreset: ChatListFilterPreset? + private let presetList: [ChatListFilter] + private let currentPreset: ChatListFilter? private let setup: () -> Void - private let updatePreset: (ChatListFilterPreset?) -> Void + private let updatePreset: (ChatListFilter?) -> Void private var presentationData: PresentationData private var didPlayPresentationAnimation = false private let hapticFeedback = HapticFeedback() - public init(context: AccountContext, sourceNodes: [ASDisplayNode], presetList: [ChatListFilterPreset], currentPreset: ChatListFilterPreset?, setup: @escaping () -> Void, updatePreset: @escaping (ChatListFilterPreset?) -> Void) { + public init(context: AccountContext, sourceNodes: [ASDisplayNode], presetList: [ChatListFilter], currentPreset: ChatListFilter?, setup: @escaping () -> Void, updatePreset: @escaping (ChatListFilter?) -> Void) { self.context = context self.sourceNodes = sourceNodes self.presetList = presetList @@ -184,7 +185,7 @@ private final class AddFilterItemNode: ASDisplayNode, AbstractTabBarChatListFilt private final class FilterItemNode: ASDisplayNode, AbstractTabBarChatListFilterItemNode { private let context: AccountContext private let title: String - let preset: ChatListFilterPreset? + let preset: ChatListFilter? private let isCurrent: Bool private let presentationData: PresentationData private let action: () -> Bool @@ -199,7 +200,7 @@ private final class FilterItemNode: ASDisplayNode, AbstractTabBarChatListFilterI private let badgeTitleNode: ImmediateTextNode private var badgeText: String = "" - init(context: AccountContext, title: String, preset: ChatListFilterPreset?, isCurrent: Bool, displaySeparator: Bool, presentationData: PresentationData, action: @escaping () -> Bool) { + init(context: AccountContext, title: String, preset: ChatListFilter?, isCurrent: Bool, displaySeparator: Bool, presentationData: PresentationData, action: @escaping () -> Bool) { self.context = context self.title = title self.preset = preset @@ -324,7 +325,7 @@ private final class TabBarChatListFilterControllerNode: ViewControllerTracingNod let isReady = Promise() private var didSetIsReady = false - init(context: AccountContext, presentationData: PresentationData, cancel: @escaping () -> Void, sourceNodes: [ASDisplayNode], presetList: [ChatListFilterPreset], currentPreset: ChatListFilterPreset?, setup: @escaping () -> Void, updatePreset: @escaping (ChatListFilterPreset?) -> Void) { + init(context: AccountContext, presentationData: PresentationData, cancel: @escaping () -> Void, sourceNodes: [ASDisplayNode], presetList: [ChatListFilter], currentPreset: ChatListFilter?, setup: @escaping () -> Void, updatePreset: @escaping (ChatListFilter?) -> Void) { self.presentationData = presentationData self.cancel = cancel self.sourceNodes = sourceNodes @@ -358,21 +359,10 @@ private final class TabBarChatListFilterControllerNode: ViewControllerTracingNod setup() })) - contentNodes.append(FilterItemNode(context: context, title: "All", preset: nil, isCurrent: currentPreset == nil, displaySeparator: !presetList.isEmpty, presentationData: presentationData, action: { - updatePreset(nil) - return false - })) - for i in 0 ..< presetList.count { let preset = presetList[i] - let title: String - switch preset.name { - case .unread: - title = "Unread" - case let .custom(value): - title = value - } + let title: String = preset.title ?? "" contentNodes.append(FilterItemNode(context: context, title: title, preset: preset, isCurrent: currentPreset == preset, displaySeparator: i != presetList.count - 1, presentationData: presentationData, action: { updatePreset(preset) return false @@ -393,7 +383,7 @@ private final class TabBarChatListFilterControllerNode: ViewControllerTracingNod unreadCountItems.append(.total(nil)) var additionalPeerIds = Set() for preset in presetList { - additionalPeerIds.formUnion(preset.additionallyIncludePeers) + additionalPeerIds.formUnion(preset.includePeers) } if !additionalPeerIds.isEmpty { for peerId in additionalPeerIds { @@ -447,36 +437,34 @@ private final class TabBarChatListFilterControllerNode: ViewControllerTracingNod let badgeString: String if let preset = contentNode.preset { var tags: [PeerSummaryCounterTags] = [] - if preset.includeCategories.contains(.privateChats) { + if preset.categories.contains(.privateChats) { tags.append(.privateChat) } - if preset.includeCategories.contains(.secretChats) { + if preset.categories.contains(.secretChats) { tags.append(.secretChat) } - if preset.includeCategories.contains(.privateGroups) { + if preset.categories.contains(.privateGroups) { tags.append(.privateGroup) } - if preset.includeCategories.contains(.bots) { + if preset.categories.contains(.bots) { tags.append(.bot) } - if preset.includeCategories.contains(.publicGroups) { + if preset.categories.contains(.publicGroups) { tags.append(.publicGroup) } - if preset.includeCategories.contains(.channels) { + if preset.categories.contains(.channels) { tags.append(.channel) } var count = 0 if let totalState = totalState { for tag in tags { - if preset.includeCategories.contains(.muted) { - } if let value = totalState.filteredCounters[tag] { count += Int(value.chatCount) } } } - for peerId in preset.additionallyIncludePeers { + for peerId in preset.includePeers { if let (tag, peerCount) = peerTagAndCount[peerId] { if !tags.contains(tag) { count += peerCount diff --git a/submodules/Display/Display/ListView.swift b/submodules/Display/Display/ListView.swift index 7a65d3b39e..9e231040b7 100644 --- a/submodules/Display/Display/ListView.swift +++ b/submodules/Display/Display/ListView.swift @@ -60,6 +60,12 @@ public final class ListViewBackingView: UIView { override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { if !self.isHidden, let target = self.target { + if target.bounds.contains(point) { + if target.decelerationAnimator != nil { + target.decelerationAnimator?.isPaused = true + target.decelerationAnimator = nil + } + } if target.limitHitTestToNodes, !target.internalHitTest(point, with: event) { return nil } @@ -685,6 +691,48 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture } } + fileprivate var decelerationAnimator: ConstantDisplayLinkAnimator? + private var accumulatedTransferVelocityOffset: CGFloat = 0.0 + + public func transferVelocity(_ velocity: CGFloat) { + self.decelerationAnimator?.isPaused = true + let startTime = CACurrentMediaTime() + let decelerationRate: CGFloat = 0.998 + self.decelerationAnimator = ConstantDisplayLinkAnimator(update: { [weak self] in + guard let strongSelf = self else { + return + } + let t = CACurrentMediaTime() - startTime + var currentVelocity = velocity * 15.0 * CGFloat(pow(Double(decelerationRate), 1000.0 * t)) + strongSelf.accumulatedTransferVelocityOffset += currentVelocity + let signFactor: CGFloat = strongSelf.accumulatedTransferVelocityOffset >= 0.0 ? 1.0 : -1.0 + let remainder = abs(strongSelf.accumulatedTransferVelocityOffset).remainder(dividingBy: UIScreenPixel) + //print("accumulated \(strongSelf.accumulatedTransferVelocityOffset), \(remainder), resulting accumulated \(strongSelf.accumulatedTransferVelocityOffset - remainder * signFactor) add delta \(strongSelf.accumulatedTransferVelocityOffset - remainder * signFactor)") + var currentOffset = strongSelf.scroller.contentOffset + let addedDela = strongSelf.accumulatedTransferVelocityOffset - remainder * signFactor + currentOffset.y += addedDela + strongSelf.accumulatedTransferVelocityOffset -= addedDela + let maxOffset = strongSelf.scroller.contentSize.height - strongSelf.scroller.bounds.height + if currentOffset.y >= maxOffset { + currentOffset.y = maxOffset + currentVelocity = 0.0 + } + if currentOffset.y < 0.0 { + currentOffset.y = 0.0 + currentVelocity = 0.0 + } + + if abs(currentVelocity) < 0.1 { + strongSelf.decelerationAnimator?.isPaused = true + strongSelf.decelerationAnimator = nil + } + var contentOffset = strongSelf.scroller.contentOffset + contentOffset.y = floorToScreenPixels(currentOffset.y) + strongSelf.scroller.setContentOffset(contentOffset, animated: false) + }) + self.decelerationAnimator?.isPaused = false + } + public func scrollViewDidScroll(_ scrollView: UIScrollView) { self.updateScrollViewDidScroll(scrollView, synchronous: false) } diff --git a/submodules/SyncCore/Sources/Namespaces.swift b/submodules/SyncCore/Sources/Namespaces.swift index 5317234ea5..76d058ee03 100644 --- a/submodules/SyncCore/Sources/Namespaces.swift +++ b/submodules/SyncCore/Sources/Namespaces.swift @@ -196,6 +196,7 @@ private enum PreferencesKeyValues: Int32 { case secretChatSettings = 17 case walletCollection = 18 case contentSettings = 19 + case chatListFilters = 20 } public func applicationSpecificPreferencesKey(_ value: Int32) -> ValueBoxKey { @@ -306,6 +307,12 @@ public struct PreferencesKeys { key.setInt32(0, value: PreferencesKeyValues.contentSettings.rawValue) return key }() + + public static let chatListFilters: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.chatListFilters.rawValue) + return key + }() } private enum SharedDataKeyValues: Int32 { diff --git a/submodules/SyncCore/Sources/TextEntitiesMessageAttribute.swift b/submodules/SyncCore/Sources/TextEntitiesMessageAttribute.swift index 79fe68a5ed..e0c3f565a9 100644 --- a/submodules/SyncCore/Sources/TextEntitiesMessageAttribute.swift +++ b/submodules/SyncCore/Sources/TextEntitiesMessageAttribute.swift @@ -19,6 +19,7 @@ public enum MessageTextEntityType: Equatable { case Strikethrough case BlockQuote case Underline + case BankCard case Custom(type: CustomEntityType) } @@ -65,6 +66,8 @@ public struct MessageTextEntity: PostboxCoding, Equatable { self.type = .BlockQuote case 15: self.type = .Underline + case 16: + self.type = .BankCard case Int32.max: self.type = .Custom(type: decoder.decodeInt32ForKey("type", orElse: 0)) default: @@ -110,6 +113,8 @@ public struct MessageTextEntity: PostboxCoding, Equatable { encoder.encodeInt32(14, forKey: "_rawValue") case .Underline: encoder.encodeInt32(15, forKey: "_rawValue") + case .BankCard: + encoder.encodeInt32(16, forKey: "_rawValue") case let .Custom(type): encoder.encodeInt32(Int32.max, forKey: "_rawValue") encoder.encodeInt32(type, forKey: "type") diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index ab2f4a7b7b..8816246c2f 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -10,7 +10,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-206066487] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) } dict[-784000893] = { return Api.payments.ValidatedRequestedInfo.parse_validatedRequestedInfo($0) } dict[461151667] = { return Api.ChatFull.parse_chatFull($0) } - dict[763976820] = { return Api.ChatFull.parse_channelFull($0) } + dict[-253335766] = { return Api.ChatFull.parse_channelFull($0) } dict[-932174686] = { return Api.PollResults.parse_pollResults($0) } dict[-925415106] = { return Api.ChatParticipant.parse_chatParticipant($0) } dict[-636267638] = { return Api.ChatParticipant.parse_chatParticipantCreator($0) } @@ -247,6 +247,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-2027964103] = { return Api.Update.parse_updateGeoLiveViewed($0) } dict[1448076945] = { return Api.Update.parse_updateLoginToken($0) } dict[1123585836] = { return Api.Update.parse_updateMessagePollVote($0) } + dict[654302845] = { return Api.Update.parse_updateDialogFilter($0) } + dict[-1512627963] = { return Api.Update.parse_updateDialogFilterOrder($0) } + dict[889491791] = { return Api.Update.parse_updateDialogFilters($0) } dict[136574537] = { return Api.messages.VotesList.parse_votesList($0) } dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) } dict[-373643672] = { return Api.FolderPeer.parse_folderPeer($0) } @@ -412,6 +415,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[2103482845] = { return Api.SecurePlainData.parse_securePlainPhone($0) } dict[569137759] = { return Api.SecurePlainData.parse_securePlainEmail($0) } dict[-1269012015] = { return Api.messages.AffectedHistory.parse_affectedHistory($0) } + dict[1244130093] = { return Api.StatsGraph.parse_statsGraphAsync($0) } + dict[-1092839390] = { return Api.StatsGraph.parse_statsGraphError($0) } + dict[-1057809608] = { return Api.StatsGraph.parse_statsGraph($0) } dict[-1036572727] = { return Api.account.PasswordInputSettings.parse_passwordInputSettings($0) } dict[878078826] = { return Api.PageTableCell.parse_pageTableCell($0) } dict[-1626209256] = { return Api.ChatBannedRights.parse_chatBannedRights($0) } @@ -480,6 +486,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-668391402] = { return Api.InputUser.parse_inputUser($0) } dict[-1366746132] = { return Api.Page.parse_page($0) } dict[871426631] = { return Api.SecureCredentialsEncrypted.parse_secureCredentialsEncrypted($0) } + dict[-875679776] = { return Api.StatsPercentValue.parse_statsPercentValue($0) } dict[157948117] = { return Api.upload.File.parse_file($0) } dict[-242427324] = { return Api.upload.File.parse_fileCdnRedirect($0) } dict[-1078612597] = { return Api.ChannelLocation.parse_channelLocationEmpty($0) } @@ -506,6 +513,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1160215659] = { return Api.InputMessage.parse_inputMessageReplyTo($0) } dict[-2037963464] = { return Api.InputMessage.parse_inputMessagePinned($0) } dict[-1564789301] = { return Api.PhoneCallProtocol.parse_phoneCallProtocol($0) } + dict[-1237848657] = { return Api.StatsDateRangeDays.parse_statsDateRangeDays($0) } dict[-1567175714] = { return Api.MessageFwdAuthor.parse_messageFwdAuthor($0) } dict[-1539849235] = { return Api.WallPaper.parse_wallPaper($0) } dict[-1963717851] = { return Api.WallPaper.parse_wallPaperNoFile($0) } @@ -520,6 +528,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1837345356] = { return Api.InputChatPhoto.parse_inputChatUploadedPhoto($0) } dict[-1991004873] = { return Api.InputChatPhoto.parse_inputChatPhoto($0) } dict[-368917890] = { return Api.PaymentCharge.parse_paymentCharge($0) } + dict[205195937] = { return Api.stats.BroadcastStats.parse_broadcastStats($0) } dict[-484987010] = { return Api.Updates.parse_updatesTooLong($0) } dict[-1857044719] = { return Api.Updates.parse_updateShortMessage($0) } dict[377562760] = { return Api.Updates.parse_updateShortChatMessage($0) } @@ -527,6 +536,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1918567619] = { return Api.Updates.parse_updatesCombined($0) } dict[1957577280] = { return Api.Updates.parse_updates($0) } dict[301019932] = { return Api.Updates.parse_updateShortSentMessage($0) } + dict[-884757282] = { return Api.StatsAbsValueAndPrev.parse_statsAbsValueAndPrev($0) } dict[1038967584] = { return Api.MessageMedia.parse_messageMediaEmpty($0) } dict[1457575028] = { return Api.MessageMedia.parse_messageMediaGeo($0) } dict[-1618676578] = { return Api.MessageMedia.parse_messageMediaUnsupported($0) } @@ -589,6 +599,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1551583367] = { return Api.ReceivedNotifyMessage.parse_receivedNotifyMessage($0) } dict[-57668565] = { return Api.ChatParticipants.parse_chatParticipantsForbidden($0) } dict[1061556205] = { return Api.ChatParticipants.parse_chatParticipants($0) } + dict[351868460] = { return Api.DialogFilter.parse_dialogFilter($0) } dict[-1056001329] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentialsSaved($0) } dict[873977640] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentials($0) } dict[178373535] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentialsApplePay($0) } @@ -761,6 +772,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1041346555] = { return Api.updates.ChannelDifference.parse_channelDifferenceEmpty($0) } dict[543450958] = { return Api.updates.ChannelDifference.parse_channelDifference($0) } dict[-1531132162] = { return Api.updates.ChannelDifference.parse_channelDifferenceTooLong($0) } + dict[-581804346] = { return Api.StatsRowAbsValueAndPrev.parse_statsRowAbsValueAndPrev($0) } dict[-309659827] = { return Api.channels.AdminLogResults.parse_adminLogResults($0) } dict[-264117680] = { return Api.ChatOnlines.parse_chatOnlines($0) } dict[488313413] = { return Api.InputAppEvent.parse_inputAppEvent($0) } @@ -782,6 +794,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1672577397] = { return Api.MessageEntity.parse_messageEntityUnderline($0) } dict[-1090087980] = { return Api.MessageEntity.parse_messageEntityStrike($0) } dict[34469328] = { return Api.MessageEntity.parse_messageEntityBlockquote($0) } + dict[1981704948] = { return Api.MessageEntity.parse_messageEntityBankCard($0) } dict[483901197] = { return Api.InputPhoto.parse_inputPhotoEmpty($0) } dict[1001634122] = { return Api.InputPhoto.parse_inputPhoto($0) } dict[-567906571] = { return Api.contacts.TopPeers.parse_topPeersNotModified($0) } @@ -804,6 +817,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1707344487] = { return Api.messages.HighScores.parse_highScores($0) } dict[-892779534] = { return Api.WebAuthorization.parse_webAuthorization($0) } dict[-805141448] = { return Api.ImportedContact.parse_importedContact($0) } + dict[-1165694006] = { return Api.payments.BankCardData.parse_bankCardData($0) } return dict }() @@ -1081,6 +1095,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.messages.AffectedHistory: _1.serialize(buffer, boxed) + case let _1 as Api.StatsGraph: + _1.serialize(buffer, boxed) case let _1 as Api.account.PasswordInputSettings: _1.serialize(buffer, boxed) case let _1 as Api.PageTableCell: @@ -1151,6 +1167,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.SecureCredentialsEncrypted: _1.serialize(buffer, boxed) + case let _1 as Api.StatsPercentValue: + _1.serialize(buffer, boxed) case let _1 as Api.upload.File: _1.serialize(buffer, boxed) case let _1 as Api.ChannelLocation: @@ -1185,6 +1203,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.PhoneCallProtocol: _1.serialize(buffer, boxed) + case let _1 as Api.StatsDateRangeDays: + _1.serialize(buffer, boxed) case let _1 as Api.MessageFwdAuthor: _1.serialize(buffer, boxed) case let _1 as Api.WallPaper: @@ -1201,8 +1221,12 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.PaymentCharge: _1.serialize(buffer, boxed) + case let _1 as Api.stats.BroadcastStats: + _1.serialize(buffer, boxed) case let _1 as Api.Updates: _1.serialize(buffer, boxed) + case let _1 as Api.StatsAbsValueAndPrev: + _1.serialize(buffer, boxed) case let _1 as Api.MessageMedia: _1.serialize(buffer, boxed) case let _1 as Api.PaymentSavedCredentials: @@ -1251,6 +1275,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.ChatParticipants: _1.serialize(buffer, boxed) + case let _1 as Api.DialogFilter: + _1.serialize(buffer, boxed) case let _1 as Api.InputPaymentCredentials: _1.serialize(buffer, boxed) case let _1 as Api.ShippingOption: @@ -1381,6 +1407,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.updates.ChannelDifference: _1.serialize(buffer, boxed) + case let _1 as Api.StatsRowAbsValueAndPrev: + _1.serialize(buffer, boxed) case let _1 as Api.channels.AdminLogResults: _1.serialize(buffer, boxed) case let _1 as Api.ChatOnlines: @@ -1409,6 +1437,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.ImportedContact: _1.serialize(buffer, boxed) + case let _1 as Api.payments.BankCardData: + _1.serialize(buffer, boxed) default: break } diff --git a/submodules/TelegramApi/Sources/Api1.swift b/submodules/TelegramApi/Sources/Api1.swift index 9e6d38f6d1..fbad69a990 100644 --- a/submodules/TelegramApi/Sources/Api1.swift +++ b/submodules/TelegramApi/Sources/Api1.swift @@ -1805,7 +1805,7 @@ public extension Api { } public enum ChatFull: TypeConstructorDescription { case chatFull(flags: Int32, id: Int32, about: String, participants: Api.ChatParticipants, chatPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite, botInfo: [Api.BotInfo]?, pinnedMsgId: Int32?, folderId: Int32?) - case channelFull(flags: Int32, id: Int32, about: String, participantsCount: Int32?, adminsCount: Int32?, kickedCount: Int32?, bannedCount: Int32?, onlineCount: Int32?, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, chatPhoto: Api.Photo, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite, botInfo: [Api.BotInfo], migratedFromChatId: Int32?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int32?, location: Api.ChannelLocation?, slowmodeSeconds: Int32?, slowmodeNextSendDate: Int32?, pts: Int32) + case channelFull(flags: Int32, id: Int32, about: String, participantsCount: Int32?, adminsCount: Int32?, kickedCount: Int32?, bannedCount: Int32?, onlineCount: Int32?, readInboxMaxId: Int32, readOutboxMaxId: Int32, unreadCount: Int32, chatPhoto: Api.Photo, notifySettings: Api.PeerNotifySettings, exportedInvite: Api.ExportedChatInvite, botInfo: [Api.BotInfo], migratedFromChatId: Int32?, migratedFromMaxId: Int32?, pinnedMsgId: Int32?, stickerset: Api.StickerSet?, availableMinId: Int32?, folderId: Int32?, linkedChatId: Int32?, location: Api.ChannelLocation?, slowmodeSeconds: Int32?, slowmodeNextSendDate: Int32?, statsDc: Int32?, pts: Int32) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -1828,9 +1828,9 @@ public extension Api { if Int(flags) & Int(1 << 6) != 0 {serializeInt32(pinnedMsgId!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 11) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)} break - case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let pts): + case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let statsDc, let pts): if boxed { - buffer.appendInt32(763976820) + buffer.appendInt32(-253335766) } serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(id, buffer: buffer, boxed: false) @@ -1861,6 +1861,7 @@ public extension Api { if Int(flags) & Int(1 << 15) != 0 {location!.serialize(buffer, true)} if Int(flags) & Int(1 << 17) != 0 {serializeInt32(slowmodeSeconds!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 18) != 0 {serializeInt32(slowmodeNextSendDate!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 12) != 0 {serializeInt32(statsDc!, buffer: buffer, boxed: false)} serializeInt32(pts, buffer: buffer, boxed: false) break } @@ -1870,8 +1871,8 @@ public extension Api { switch self { case .chatFull(let flags, let id, let about, let participants, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let pinnedMsgId, let folderId): return ("chatFull", [("flags", flags), ("id", id), ("about", about), ("participants", participants), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("pinnedMsgId", pinnedMsgId), ("folderId", folderId)]) - case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let pts): - return ("channelFull", [("flags", flags), ("id", id), ("about", about), ("participantsCount", participantsCount), ("adminsCount", adminsCount), ("kickedCount", kickedCount), ("bannedCount", bannedCount), ("onlineCount", onlineCount), ("readInboxMaxId", readInboxMaxId), ("readOutboxMaxId", readOutboxMaxId), ("unreadCount", unreadCount), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("migratedFromChatId", migratedFromChatId), ("migratedFromMaxId", migratedFromMaxId), ("pinnedMsgId", pinnedMsgId), ("stickerset", stickerset), ("availableMinId", availableMinId), ("folderId", folderId), ("linkedChatId", linkedChatId), ("location", location), ("slowmodeSeconds", slowmodeSeconds), ("slowmodeNextSendDate", slowmodeNextSendDate), ("pts", pts)]) + case .channelFull(let flags, let id, let about, let participantsCount, let adminsCount, let kickedCount, let bannedCount, let onlineCount, let readInboxMaxId, let readOutboxMaxId, let unreadCount, let chatPhoto, let notifySettings, let exportedInvite, let botInfo, let migratedFromChatId, let migratedFromMaxId, let pinnedMsgId, let stickerset, let availableMinId, let folderId, let linkedChatId, let location, let slowmodeSeconds, let slowmodeNextSendDate, let statsDc, let pts): + return ("channelFull", [("flags", flags), ("id", id), ("about", about), ("participantsCount", participantsCount), ("adminsCount", adminsCount), ("kickedCount", kickedCount), ("bannedCount", bannedCount), ("onlineCount", onlineCount), ("readInboxMaxId", readInboxMaxId), ("readOutboxMaxId", readOutboxMaxId), ("unreadCount", unreadCount), ("chatPhoto", chatPhoto), ("notifySettings", notifySettings), ("exportedInvite", exportedInvite), ("botInfo", botInfo), ("migratedFromChatId", migratedFromChatId), ("migratedFromMaxId", migratedFromMaxId), ("pinnedMsgId", pinnedMsgId), ("stickerset", stickerset), ("availableMinId", availableMinId), ("folderId", folderId), ("linkedChatId", linkedChatId), ("location", location), ("slowmodeSeconds", slowmodeSeconds), ("slowmodeNextSendDate", slowmodeNextSendDate), ("statsDc", statsDc), ("pts", pts)]) } } @@ -1987,7 +1988,9 @@ public extension Api { var _25: Int32? if Int(_1!) & Int(1 << 18) != 0 {_25 = reader.readInt32() } var _26: Int32? - _26 = reader.readInt32() + if Int(_1!) & Int(1 << 12) != 0 {_26 = reader.readInt32() } + var _27: Int32? + _27 = reader.readInt32() let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil @@ -2013,9 +2016,10 @@ public extension Api { let _c23 = (Int(_1!) & Int(1 << 15) == 0) || _23 != nil let _c24 = (Int(_1!) & Int(1 << 17) == 0) || _24 != nil let _c25 = (Int(_1!) & Int(1 << 18) == 0) || _25 != nil - let _c26 = _26 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 { - return Api.ChatFull.channelFull(flags: _1!, id: _2!, about: _3!, participantsCount: _4, adminsCount: _5, kickedCount: _6, bannedCount: _7, onlineCount: _8, readInboxMaxId: _9!, readOutboxMaxId: _10!, unreadCount: _11!, chatPhoto: _12!, notifySettings: _13!, exportedInvite: _14!, botInfo: _15!, migratedFromChatId: _16, migratedFromMaxId: _17, pinnedMsgId: _18, stickerset: _19, availableMinId: _20, folderId: _21, linkedChatId: _22, location: _23, slowmodeSeconds: _24, slowmodeNextSendDate: _25, pts: _26!) + let _c26 = (Int(_1!) & Int(1 << 12) == 0) || _26 != nil + let _c27 = _27 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 && _c27 { + return Api.ChatFull.channelFull(flags: _1!, id: _2!, about: _3!, participantsCount: _4, adminsCount: _5, kickedCount: _6, bannedCount: _7, onlineCount: _8, readInboxMaxId: _9!, readOutboxMaxId: _10!, unreadCount: _11!, chatPhoto: _12!, notifySettings: _13!, exportedInvite: _14!, botInfo: _15!, migratedFromChatId: _16, migratedFromMaxId: _17, pinnedMsgId: _18, stickerset: _19, availableMinId: _20, folderId: _21, linkedChatId: _22, location: _23, slowmodeSeconds: _24, slowmodeNextSendDate: _25, statsDc: _26, pts: _27!) } else { return nil @@ -5861,6 +5865,9 @@ public extension Api { case updateGeoLiveViewed(peer: Api.Peer, msgId: Int32) case updateLoginToken case updateMessagePollVote(pollId: Int64, userId: Int32, options: [Buffer]) + case updateDialogFilter(flags: Int32, id: Int32, filter: Api.DialogFilter?) + case updateDialogFilterOrder(order: [Int32]) + case updateDialogFilters public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -6509,6 +6516,30 @@ public extension Api { for item in options { serializeBytes(item, buffer: buffer, boxed: false) } + break + case .updateDialogFilter(let flags, let id, let filter): + if boxed { + buffer.appendInt32(654302845) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {filter!.serialize(buffer, true)} + break + case .updateDialogFilterOrder(let order): + if boxed { + buffer.appendInt32(-1512627963) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(order.count)) + for item in order { + serializeInt32(item, buffer: buffer, boxed: false) + } + break + case .updateDialogFilters: + if boxed { + buffer.appendInt32(889491791) + } + break } } @@ -6669,6 +6700,12 @@ public extension Api { return ("updateLoginToken", []) case .updateMessagePollVote(let pollId, let userId, let options): return ("updateMessagePollVote", [("pollId", pollId), ("userId", userId), ("options", options)]) + case .updateDialogFilter(let flags, let id, let filter): + return ("updateDialogFilter", [("flags", flags), ("id", id), ("filter", filter)]) + case .updateDialogFilterOrder(let order): + return ("updateDialogFilterOrder", [("order", order)]) + case .updateDialogFilters: + return ("updateDialogFilters", []) } } @@ -7965,6 +8002,41 @@ public extension Api { return nil } } + public static func parse_updateDialogFilter(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Api.DialogFilter? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.DialogFilter + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateDialogFilter(flags: _1!, id: _2!, filter: _3) + } + else { + return nil + } + } + public static func parse_updateDialogFilterOrder(_ reader: BufferReader) -> Update? { + var _1: [Int32]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + let _c1 = _1 != nil + if _c1 { + return Api.Update.updateDialogFilterOrder(order: _1!) + } + else { + return nil + } + } + public static func parse_updateDialogFilters(_ reader: BufferReader) -> Update? { + return Api.Update.updateDialogFilters + } } public enum PopularContact: TypeConstructorDescription { @@ -11956,6 +12028,82 @@ public extension Api { } } + } + public enum StatsGraph: TypeConstructorDescription { + case statsGraphAsync(token: String) + case statsGraphError(error: String) + case statsGraph(json: Api.DataJSON) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .statsGraphAsync(let token): + if boxed { + buffer.appendInt32(1244130093) + } + serializeString(token, buffer: buffer, boxed: false) + break + case .statsGraphError(let error): + if boxed { + buffer.appendInt32(-1092839390) + } + serializeString(error, buffer: buffer, boxed: false) + break + case .statsGraph(let json): + if boxed { + buffer.appendInt32(-1057809608) + } + json.serialize(buffer, true) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .statsGraphAsync(let token): + return ("statsGraphAsync", [("token", token)]) + case .statsGraphError(let error): + return ("statsGraphError", [("error", error)]) + case .statsGraph(let json): + return ("statsGraph", [("json", json)]) + } + } + + public static func parse_statsGraphAsync(_ reader: BufferReader) -> StatsGraph? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.StatsGraph.statsGraphAsync(token: _1!) + } + else { + return nil + } + } + public static func parse_statsGraphError(_ reader: BufferReader) -> StatsGraph? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.StatsGraph.statsGraphError(error: _1!) + } + else { + return nil + } + } + public static func parse_statsGraph(_ reader: BufferReader) -> StatsGraph? { + var _1: Api.DataJSON? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.DataJSON + } + let _c1 = _1 != nil + if _c1 { + return Api.StatsGraph.statsGraph(json: _1!) + } + else { + return nil + } + } + } public enum PageTableCell: TypeConstructorDescription { case pageTableCell(flags: Int32, text: Api.RichText?, colspan: Int32?, rowspan: Int32?) @@ -13662,6 +13810,44 @@ public extension Api { } } + } + public enum StatsPercentValue: TypeConstructorDescription { + case statsPercentValue(part: Double, total: Double) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .statsPercentValue(let part, let total): + if boxed { + buffer.appendInt32(-875679776) + } + serializeDouble(part, buffer: buffer, boxed: false) + serializeDouble(total, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .statsPercentValue(let part, let total): + return ("statsPercentValue", [("part", part), ("total", total)]) + } + } + + public static func parse_statsPercentValue(_ reader: BufferReader) -> StatsPercentValue? { + var _1: Double? + _1 = reader.readDouble() + var _2: Double? + _2 = reader.readDouble() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.StatsPercentValue.statsPercentValue(part: _1!, total: _2!) + } + else { + return nil + } + } + } public enum ChannelLocation: TypeConstructorDescription { case channelLocationEmpty @@ -14434,6 +14620,44 @@ public extension Api { } } + } + public enum StatsDateRangeDays: TypeConstructorDescription { + case statsDateRangeDays(minDate: Int32, maxDate: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .statsDateRangeDays(let minDate, let maxDate): + if boxed { + buffer.appendInt32(-1237848657) + } + serializeInt32(minDate, buffer: buffer, boxed: false) + serializeInt32(maxDate, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .statsDateRangeDays(let minDate, let maxDate): + return ("statsDateRangeDays", [("minDate", minDate), ("maxDate", maxDate)]) + } + } + + public static func parse_statsDateRangeDays(_ reader: BufferReader) -> StatsDateRangeDays? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.StatsDateRangeDays.statsDateRangeDays(minDate: _1!, maxDate: _2!) + } + else { + return nil + } + } + } public enum MessageFwdAuthor: TypeConstructorDescription { case messageFwdAuthor(channelId: Int32) @@ -15098,6 +15322,44 @@ public extension Api { } } + } + public enum StatsAbsValueAndPrev: TypeConstructorDescription { + case statsAbsValueAndPrev(current: Double, previous: Double) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .statsAbsValueAndPrev(let current, let previous): + if boxed { + buffer.appendInt32(-884757282) + } + serializeDouble(current, buffer: buffer, boxed: false) + serializeDouble(previous, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .statsAbsValueAndPrev(let current, let previous): + return ("statsAbsValueAndPrev", [("current", current), ("previous", previous)]) + } + } + + public static func parse_statsAbsValueAndPrev(_ reader: BufferReader) -> StatsAbsValueAndPrev? { + var _1: Double? + _1 = reader.readDouble() + var _2: Double? + _2 = reader.readDouble() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.StatsAbsValueAndPrev.statsAbsValueAndPrev(current: _1!, previous: _2!) + } + else { + return nil + } + } + } public enum MessageMedia: TypeConstructorDescription { case messageMediaEmpty @@ -16814,6 +17076,58 @@ public extension Api { } } + } + public enum DialogFilter: TypeConstructorDescription { + case dialogFilter(flags: Int32, id: Int32, title: String, includePeers: [Api.InputPeer]) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .dialogFilter(let flags, let id, let title, let includePeers): + if boxed { + buffer.appendInt32(351868460) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(includePeers.count)) + for item in includePeers { + item.serialize(buffer, true) + } + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .dialogFilter(let flags, let id, let title, let includePeers): + return ("dialogFilter", [("flags", flags), ("id", id), ("title", title), ("includePeers", includePeers)]) + } + } + + public static func parse_dialogFilter(_ reader: BufferReader) -> DialogFilter? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + var _4: [Api.InputPeer]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputPeer.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.DialogFilter.dialogFilter(flags: _1!, id: _2!, title: _3!, includePeers: _4!) + } + else { + return nil + } + } + } public enum InputPaymentCredentials: TypeConstructorDescription { case inputPaymentCredentialsSaved(id: String, tmpPassword: Buffer) @@ -20880,6 +21194,54 @@ public extension Api { } } + } + public enum StatsRowAbsValueAndPrev: TypeConstructorDescription { + case statsRowAbsValueAndPrev(id: String, title: String, shortTitle: String, values: Api.StatsAbsValueAndPrev) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .statsRowAbsValueAndPrev(let id, let title, let shortTitle, let values): + if boxed { + buffer.appendInt32(-581804346) + } + serializeString(id, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + serializeString(shortTitle, buffer: buffer, boxed: false) + values.serialize(buffer, true) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .statsRowAbsValueAndPrev(let id, let title, let shortTitle, let values): + return ("statsRowAbsValueAndPrev", [("id", id), ("title", title), ("shortTitle", shortTitle), ("values", values)]) + } + } + + public static func parse_statsRowAbsValueAndPrev(_ reader: BufferReader) -> StatsRowAbsValueAndPrev? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.StatsRowAbsValueAndPrev.statsRowAbsValueAndPrev(id: _1!, title: _2!, shortTitle: _3!, values: _4!) + } + else { + return nil + } + } + } public enum ChatOnlines: TypeConstructorDescription { case chatOnlines(onlines: Int32) @@ -20982,6 +21344,7 @@ public extension Api { case messageEntityUnderline(offset: Int32, length: Int32) case messageEntityStrike(offset: Int32, length: Int32) case messageEntityBlockquote(offset: Int32, length: Int32) + case messageEntityBankCard(offset: Int32, length: Int32) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -21115,6 +21478,13 @@ public extension Api { serializeInt32(offset, buffer: buffer, boxed: false) serializeInt32(length, buffer: buffer, boxed: false) break + case .messageEntityBankCard(let offset, let length): + if boxed { + buffer.appendInt32(1981704948) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break } } @@ -21156,6 +21526,8 @@ public extension Api { return ("messageEntityStrike", [("offset", offset), ("length", length)]) case .messageEntityBlockquote(let offset, let length): return ("messageEntityBlockquote", [("offset", offset), ("length", length)]) + case .messageEntityBankCard(let offset, let length): + return ("messageEntityBankCard", [("offset", offset), ("length", length)]) } } @@ -21425,6 +21797,20 @@ public extension Api { return nil } } + public static func parse_messageEntityBankCard(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageEntity.messageEntityBankCard(offset: _1!, length: _2!) + } + else { + return nil + } + } } public enum InputPhoto: TypeConstructorDescription { diff --git a/submodules/TelegramApi/Sources/Api2.swift b/submodules/TelegramApi/Sources/Api2.swift index f0cb6195e9..f279ddec30 100644 --- a/submodules/TelegramApi/Sources/Api2.swift +++ b/submodules/TelegramApi/Sources/Api2.swift @@ -490,6 +490,184 @@ public struct payments { } } + public enum BankCardData: TypeConstructorDescription { + case bankCardData(flags: Int32, brand: String?, country: String?, organization: String?, url: String?, urlName: String?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .bankCardData(let flags, let brand, let country, let organization, let url, let urlName): + if boxed { + buffer.appendInt32(-1165694006) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(brand!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {serializeString(country!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(organization!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeString(url!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {serializeString(urlName!, buffer: buffer, boxed: false)} + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .bankCardData(let flags, let brand, let country, let organization, let url, let urlName): + return ("bankCardData", [("flags", flags), ("brand", brand), ("country", country), ("organization", organization), ("url", url), ("urlName", urlName)]) + } + } + + public static func parse_bankCardData(_ reader: BufferReader) -> BankCardData? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + if Int(_1!) & Int(1 << 0) != 0 {_2 = parseString(reader) } + var _3: String? + if Int(_1!) & Int(1 << 1) != 0 {_3 = parseString(reader) } + var _4: String? + if Int(_1!) & Int(1 << 2) != 0 {_4 = parseString(reader) } + var _5: String? + if Int(_1!) & Int(1 << 3) != 0 {_5 = parseString(reader) } + var _6: String? + if Int(_1!) & Int(1 << 3) != 0 {_6 = parseString(reader) } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 3) == 0) || _5 != nil + let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.payments.BankCardData.bankCardData(flags: _1!, brand: _2, country: _3, organization: _4, url: _5, urlName: _6) + } + else { + return nil + } + } + + } +} +} +public extension Api { +public struct stats { + public enum BroadcastStats: TypeConstructorDescription { + case broadcastStats(period: Api.StatsDateRangeDays, followers: Api.StatsAbsValueAndPrev, viewsPerPost: Api.StatsAbsValueAndPrev, sharesPerPost: Api.StatsAbsValueAndPrev, enabledNotifications: Api.StatsPercentValue, viewsBySource: [Api.StatsRowAbsValueAndPrev], newFollowersBySource: [Api.StatsRowAbsValueAndPrev], languages: [Api.StatsRowAbsValueAndPrev], growthGraph: Api.StatsGraph, followersGraph: Api.StatsGraph, muteGraph: Api.StatsGraph, topHoursGraph: Api.StatsGraph, interactionsGraph: Api.StatsGraph) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let enabledNotifications, let viewsBySource, let newFollowersBySource, let languages, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph): + if boxed { + buffer.appendInt32(205195937) + } + period.serialize(buffer, true) + followers.serialize(buffer, true) + viewsPerPost.serialize(buffer, true) + sharesPerPost.serialize(buffer, true) + enabledNotifications.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(viewsBySource.count)) + for item in viewsBySource { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(newFollowersBySource.count)) + for item in newFollowersBySource { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(languages.count)) + for item in languages { + item.serialize(buffer, true) + } + growthGraph.serialize(buffer, true) + followersGraph.serialize(buffer, true) + muteGraph.serialize(buffer, true) + topHoursGraph.serialize(buffer, true) + interactionsGraph.serialize(buffer, true) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let enabledNotifications, let viewsBySource, let newFollowersBySource, let languages, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph): + return ("broadcastStats", [("period", period), ("followers", followers), ("viewsPerPost", viewsPerPost), ("sharesPerPost", sharesPerPost), ("enabledNotifications", enabledNotifications), ("viewsBySource", viewsBySource), ("newFollowersBySource", newFollowersBySource), ("languages", languages), ("growthGraph", growthGraph), ("followersGraph", followersGraph), ("muteGraph", muteGraph), ("topHoursGraph", topHoursGraph), ("interactionsGraph", interactionsGraph)]) + } + } + + public static func parse_broadcastStats(_ reader: BufferReader) -> BroadcastStats? { + var _1: Api.StatsDateRangeDays? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.StatsDateRangeDays + } + var _2: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _3: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _4: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _5: Api.StatsPercentValue? + if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.StatsPercentValue + } + var _6: [Api.StatsRowAbsValueAndPrev]? + if let _ = reader.readInt32() { + _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsRowAbsValueAndPrev.self) + } + var _7: [Api.StatsRowAbsValueAndPrev]? + if let _ = reader.readInt32() { + _7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsRowAbsValueAndPrev.self) + } + var _8: [Api.StatsRowAbsValueAndPrev]? + if let _ = reader.readInt32() { + _8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsRowAbsValueAndPrev.self) + } + var _9: Api.StatsGraph? + if let signature = reader.readInt32() { + _9 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _10: Api.StatsGraph? + if let signature = reader.readInt32() { + _10 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _11: Api.StatsGraph? + if let signature = reader.readInt32() { + _11 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _12: Api.StatsGraph? + if let signature = reader.readInt32() { + _12 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _13: Api.StatsGraph? + if let signature = reader.readInt32() { + _13 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + let _c10 = _10 != nil + let _c11 = _11 != nil + let _c12 = _12 != nil + let _c13 = _13 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 { + return Api.stats.BroadcastStats.broadcastStats(period: _1!, followers: _2!, viewsPerPost: _3!, sharesPerPost: _4!, enabledNotifications: _5!, viewsBySource: _6!, newFollowersBySource: _7!, languages: _8!, growthGraph: _9!, followersGraph: _10!, muteGraph: _11!, topHoursGraph: _12!, interactionsGraph: _13!) + } + else { + return nil + } + } + + } } } public extension Api { diff --git a/submodules/TelegramApi/Sources/Api3.swift b/submodules/TelegramApi/Sources/Api3.swift index 74e4884bf6..2c7411ffbc 100644 --- a/submodules/TelegramApi/Sources/Api3.swift +++ b/submodules/TelegramApi/Sources/Api3.swift @@ -3214,6 +3214,54 @@ public extension Api { return result }) } + + public static func getDialogFilters() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.DialogFilter]>) { + let buffer = Buffer() + buffer.appendInt32(-241247891) + + return (FunctionDescription(name: "messages.getDialogFilters", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.DialogFilter]? in + let reader = BufferReader(buffer) + var result: [Api.DialogFilter]? + if let _ = reader.readInt32() { + result = Api.parseVector(reader, elementSignature: 0, elementType: Api.DialogFilter.self) + } + return result + }) + } + + public static func updateDialogFilter(flags: Int32, id: Int32, filter: Api.DialogFilter?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(450142282) + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {filter!.serialize(buffer, true)} + return (FunctionDescription(name: "messages.updateDialogFilter", parameters: [("flags", flags), ("id", id), ("filter", filter)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + public static func updateDialogFiltersOrder(order: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-983318044) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(order.count)) + for item in order { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "messages.updateDialogFiltersOrder", parameters: [("order", order)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } } public struct channels { public static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { @@ -3885,6 +3933,50 @@ public extension Api { return result }) } + + public static func getBankCardData(number: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(779736953) + serializeString(number, buffer: buffer, boxed: false) + return (FunctionDescription(name: "payments.getBankCardData", parameters: [("number", number)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.BankCardData? in + let reader = BufferReader(buffer) + var result: Api.payments.BankCardData? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.payments.BankCardData + } + return result + }) + } + } + public struct stats { + public static func getBroadcastStats(flags: Int32, channel: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1421720550) + serializeInt32(flags, buffer: buffer, boxed: false) + channel.serialize(buffer, true) + return (FunctionDescription(name: "stats.getBroadcastStats", parameters: [("flags", flags), ("channel", channel)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.stats.BroadcastStats? in + let reader = BufferReader(buffer) + var result: Api.stats.BroadcastStats? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.stats.BroadcastStats + } + return result + }) + } + + public static func loadAsyncGraph(token: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1749505346) + serializeString(token, buffer: buffer, boxed: false) + return (FunctionDescription(name: "stats.loadAsyncGraph", parameters: [("token", token)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.StatsGraph? in + let reader = BufferReader(buffer) + var result: Api.StatsGraph? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + return result + }) + } } public struct auth { public static func checkPhone(phoneNumber: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { diff --git a/submodules/TelegramCore/Sources/Account.swift b/submodules/TelegramCore/Sources/Account.swift index 65f1145eae..cec053cf33 100644 --- a/submodules/TelegramCore/Sources/Account.swift +++ b/submodules/TelegramCore/Sources/Account.swift @@ -1044,6 +1044,7 @@ public class Account { self.managedOperationsDisposable.add(managedApplyPendingMessageReactionsActions(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) self.managedOperationsDisposable.add(managedSynchronizeEmojiKeywordsOperations(postbox: self.postbox, network: self.network).start()) self.managedOperationsDisposable.add(managedApplyPendingScheduledMessagesActions(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) + self.managedOperationsDisposable.add(managedChatListFilters(postbox: self.postbox, network: self.network).start()) let importantBackgroundOperations: [Signal] = [ managedSynchronizeChatInputStateOperations(postbox: self.postbox, network: self.network) |> map { $0 ? AccountRunningImportantTasks.other : [] }, diff --git a/submodules/TelegramCore/Sources/AccountManager.swift b/submodules/TelegramCore/Sources/AccountManager.swift index f4e0043af9..eb61eb0fec 100644 --- a/submodules/TelegramCore/Sources/AccountManager.swift +++ b/submodules/TelegramCore/Sources/AccountManager.swift @@ -152,6 +152,7 @@ private var declaredEncodables: Void = { declareEncodable(EmbeddedMediaStickersMessageAttribute.self, f: { EmbeddedMediaStickersMessageAttribute(decoder: $0) }) declareEncodable(TelegramMediaWebpageAttribute.self, f: { TelegramMediaWebpageAttribute(decoder: $0) }) declareEncodable(CachedPollOptionResult.self, f: { CachedPollOptionResult(decoder: $0) }) + declareEncodable(ChatListFiltersState.self, f: { ChatListFiltersState(decoder: $0) }) return }() diff --git a/submodules/TelegramCore/Sources/ChatListFiltering.swift b/submodules/TelegramCore/Sources/ChatListFiltering.swift new file mode 100644 index 0000000000..1e01e92c02 --- /dev/null +++ b/submodules/TelegramCore/Sources/ChatListFiltering.swift @@ -0,0 +1,378 @@ +import Foundation +import Postbox +import SwiftSignalKit +import TelegramApi + +import SyncCore + +public struct ChatListFilterPeerCategories: OptionSet { + public var rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } + + public static let privateChats = ChatListFilterPeerCategories(rawValue: 1 << 0) + public static let secretChats = ChatListFilterPeerCategories(rawValue: 1 << 1) + public static let privateGroups = ChatListFilterPeerCategories(rawValue: 1 << 2) + public static let bots = ChatListFilterPeerCategories(rawValue: 1 << 3) + public static let publicGroups = ChatListFilterPeerCategories(rawValue: 1 << 4) + public static let channels = ChatListFilterPeerCategories(rawValue: 1 << 5) + + public static let all: ChatListFilterPeerCategories = [ + .privateChats, + .secretChats, + .privateGroups, + .bots, + .publicGroups, + .channels + ] +} + +private struct ChatListFilterPeerApiCategories: OptionSet { + var rawValue: Int32 + + init(rawValue: Int32) { + self.rawValue = rawValue + } + + static let privateChats = ChatListFilterPeerApiCategories(rawValue: 1 << 0) + static let secretChats = ChatListFilterPeerApiCategories(rawValue: 1 << 1) + static let privateGroups = ChatListFilterPeerApiCategories(rawValue: 1 << 2) + static let publicGroups = ChatListFilterPeerApiCategories(rawValue: 1 << 3) + static let channels = ChatListFilterPeerApiCategories(rawValue: 1 << 4) + static let bots = ChatListFilterPeerApiCategories(rawValue: 1 << 5) +} + +extension ChatListFilterPeerCategories { + init(apiFlags: Int32) { + let flags = ChatListFilterPeerApiCategories(rawValue: apiFlags) + var result: ChatListFilterPeerCategories = [] + if flags.contains(.privateChats) { + result.insert(.privateChats) + } + if flags.contains(.secretChats) { + result.insert(.secretChats) + } + if flags.contains(.privateGroups) { + result.insert(.privateGroups) + } + if flags.contains(.publicGroups) { + result.insert(.publicGroups) + } + if flags.contains(.channels) { + result.insert(.channels) + } + if flags.contains(.bots) { + result.insert(.bots) + } + self = result + } + + var apiFlags: Int32 { + var result: ChatListFilterPeerApiCategories = [] + if self.contains(.privateChats) { + result.insert(.privateChats) + } + if self.contains(.secretChats) { + result.insert(.secretChats) + } + if self.contains(.privateGroups) { + result.insert(.privateGroups) + } + if self.contains(.publicGroups) { + result.insert(.publicGroups) + } + if self.contains(.channels) { + result.insert(.channels) + } + if self.contains(.bots) { + result.insert(.bots) + } + return result.rawValue + } +} + +public struct ChatListFilter: PostboxCoding, Equatable { + public var id: Int32 + public var title: String? + public var categories: ChatListFilterPeerCategories + public var excludeMuted: Bool + public var excludeRead: Bool + public var includePeers: [PeerId] + + public init( + id: Int32, + title: String?, + categories: ChatListFilterPeerCategories, + excludeMuted: Bool, + excludeRead: Bool, + includePeers: [PeerId] + ) { + self.id = id + self.title = title + self.categories = categories + self.excludeMuted = excludeMuted + self.excludeRead = excludeRead + self.includePeers = includePeers + } + + public init(decoder: PostboxDecoder) { + self.id = decoder.decodeInt32ForKey("id", orElse: 0) + self.title = decoder.decodeOptionalStringForKey("title") + self.categories = ChatListFilterPeerCategories(rawValue: decoder.decodeInt32ForKey("categories", orElse: 0)) + self.excludeMuted = decoder.decodeInt32ForKey("excludeMuted", orElse: 0) != 0 + self.excludeRead = decoder.decodeInt32ForKey("excludeRead", orElse: 0) != 0 + self.includePeers = decoder.decodeInt64ArrayForKey("includePeers").map(PeerId.init) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.id, forKey: "id") + if let title = self.title { + encoder.encodeString(title, forKey: "title") + } else { + encoder.encodeNil(forKey: "title") + } + encoder.encodeInt32(self.categories.rawValue, forKey: "categories") + encoder.encodeInt32(self.excludeMuted ? 1 : 0, forKey: "excludeMuted") + encoder.encodeInt32(self.excludeRead ? 1 : 0, forKey: "excludeRead") + encoder.encodeInt64Array(self.includePeers.map { $0.toInt64() }, forKey: "includePeers") + } +} + +extension ChatListFilter { + init(apiFilter: Api.DialogFilter) { + switch apiFilter { + case let .dialogFilter(flags, id, title, includePeers): + self.init( + id: id, + title: title.isEmpty ? nil : title, + categories: ChatListFilterPeerCategories(apiFlags: flags), + excludeMuted: (flags & (1 << 11)) != 0, + excludeRead: (flags & (1 << 12)) != 0, + includePeers: includePeers.compactMap { peer -> PeerId? in + switch peer { + case let .inputPeerUser(userId, _): + return PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + case let .inputPeerChat(chatId): + return PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .inputPeerChannel(channelId, _): + return PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + default: + return nil + } + } + ) + } + } + + func apiFilter(transaction: Transaction) -> Api.DialogFilter { + var flags: Int32 = 0 + if self.excludeMuted { + flags |= 1 << 11 + } + if self.excludeRead { + flags |= 1 << 12 + } + flags |= self.categories.apiFlags + return .dialogFilter(flags: flags, id: self.id, title: self.title ?? "", includePeers: self.includePeers.compactMap { peerId -> Api.InputPeer? in + return transaction.getPeer(peerId).flatMap(apiInputPeer) + }) + } +} + +public enum RequestUpdateChatListFilterError { + case generic +} + +public func requestUpdateChatListFilter(account: Account, id: Int32, filter: ChatListFilter?) -> Signal { + return account.postbox.transaction { transaction -> Api.DialogFilter? in + return filter?.apiFilter(transaction: transaction) + } + |> castError(RequestUpdateChatListFilterError.self) + |> mapToSignal { inputFilter -> Signal in + var flags: Int32 = 0 + if inputFilter != nil { + flags |= 1 << 0 + } + return account.network.request(Api.functions.messages.updateDialogFilter(flags: flags, id: id, filter: inputFilter)) + |> mapError { _ -> RequestUpdateChatListFilterError in + return .generic + } + |> mapToSignal { _ -> Signal in + return .complete() + } + } +} + +public enum RequestUpdateChatListFilterOrderError { + case generic +} + +public func requestUpdateChatListFilterOrder(account: Account, ids: [Int32]) -> Signal { + return account.network.request(Api.functions.messages.updateDialogFiltersOrder(order: ids)) + |> mapError { _ -> RequestUpdateChatListFilterOrderError in + return .generic + } + |> mapToSignal { _ -> Signal in + return .complete() + } +} + +private enum RequestChatListFiltersError { + case generic +} + +private func requestChatListFilters(postbox: Postbox, network: Network) -> Signal<[ChatListFilter], RequestChatListFiltersError> { + return network.request(Api.functions.messages.getDialogFilters()) + |> mapError { _ -> RequestChatListFiltersError in + return .generic + } + |> mapToSignal { result -> Signal<[ChatListFilter], RequestChatListFiltersError> in + return postbox.transaction { transaction -> ([ChatListFilter], [Api.InputPeer]) in + var filters: [ChatListFilter] = [] + var missingPeers: [Api.InputPeer] = [] + var missingPeerIds = Set() + for apiFilter in result { + let filter = ChatListFilter(apiFilter: apiFilter) + filters.append(filter) + switch apiFilter { + case let .dialogFilter(_, _, _, includePeers): + for peer in includePeers { + var peerId: PeerId? + switch peer { + case let .inputPeerUser(userId, _): + peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + case let .inputPeerChat(chatId): + peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId) + case let .inputPeerChannel(channelId, _): + peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId) + default: + break + } + if let peerId = peerId { + if transaction.getPeer(peerId) == nil && !missingPeerIds.contains(peerId) { + missingPeerIds.insert(peerId) + missingPeers.append(peer) + } + } + } + } + } + return (filters, missingPeers) + } + |> castError(RequestChatListFiltersError.self) + |> mapToSignal { filtersAndMissingPeers -> Signal<[ChatListFilter], RequestChatListFiltersError> in + let (filters, missingPeers) = filtersAndMissingPeers + return .single(filters) + } + } +} + +func managedChatListFilters(postbox: Postbox, network: Network) -> Signal { + return requestChatListFilters(postbox: postbox, network: network) + |> `catch` { _ -> Signal<[ChatListFilter], NoError> in + return .complete() + } + |> mapToSignal { filters -> Signal in + return postbox.transaction { transaction in + transaction.updatePreferencesEntry(key: PreferencesKeys.chatListFilters, { entry in + var settings = entry as? ChatListFiltersState ?? ChatListFiltersState.default + settings.filters = filters + return settings + }) + } + |> ignoreValues + } +} + +public func replaceRemoteChatListFilters(account: Account) -> Signal { + return requestChatListFilters(postbox: account.postbox, network: account.network) + |> `catch` { _ -> Signal<[ChatListFilter], NoError> in + return .complete() + } + |> mapToSignal { remoteFilters -> Signal in + var deleteSignals: [Signal] = [] + for filter in remoteFilters { + deleteSignals.append(requestUpdateChatListFilter(account: account, id: filter.id, filter: nil) + |> `catch` { _ -> Signal in + return .complete() + } + |> ignoreValues) + } + + let addFilters = account.postbox.transaction { transaction -> [(Int32, ChatListFilter)] in + let settings = transaction.getPreferencesEntry(key: PreferencesKeys.chatListFilters) as? ChatListFiltersState ?? ChatListFiltersState.default + return settings.filters.map { filter -> (Int32, ChatListFilter) in + return (filter.id, filter) + } + } + |> mapToSignal { filters -> Signal in + var signals: [Signal] = [] + for (id, filter) in filters { + signals.append(requestUpdateChatListFilter(account: account, id: id, filter: filter) + |> `catch` { _ -> Signal in + return .complete() + } + |> ignoreValues) + } + return combineLatest(signals) + |> ignoreValues + } + + return combineLatest( + deleteSignals + ) + |> ignoreValues + |> then( + addFilters + ) + } +} + +public struct ChatListFiltersState: PreferencesEntry, Equatable { + public var filters: [ChatListFilter] + public var remoteFilters: [ChatListFilter]? + + public static var `default` = ChatListFiltersState(filters: [], remoteFilters: nil) + + public init(filters: [ChatListFilter], remoteFilters: [ChatListFilter]?) { + self.filters = filters + self.remoteFilters = remoteFilters + } + + public init(decoder: PostboxDecoder) { + self.filters = decoder.decodeObjectArrayWithDecoderForKey("filters") + self.remoteFilters = decoder.decodeOptionalObjectArrayWithDecoderForKey("remoteFilters") + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObjectArray(self.filters, forKey: "filters") + if let remoteFilters = self.remoteFilters { + encoder.encodeObjectArray(remoteFilters, forKey: "remoteFilters") + } else { + encoder.encodeNil(forKey: "remoteFilters") + } + } + + public func isEqual(to: PreferencesEntry) -> Bool { + if let to = to as? ChatListFiltersState, self == to { + return true + } else { + return false + } + } +} + +public func updateChatListFilterSettingsInteractively(postbox: Postbox, _ f: @escaping (ChatListFiltersState) -> ChatListFiltersState) -> Signal { + return postbox.transaction { transaction -> ChatListFiltersState in + var result: ChatListFiltersState? + transaction.updatePreferencesEntry(key: PreferencesKeys.chatListFilters, { entry in + var settings = entry as? ChatListFiltersState ?? ChatListFiltersState.default + let updated = f(settings) + result = updated + return updated + }) + return result ?? .default + } +} diff --git a/submodules/TelegramCore/Sources/ManagedSecretChatOutgoingOperations.swift b/submodules/TelegramCore/Sources/ManagedSecretChatOutgoingOperations.swift index 7754b00b97..d490602165 100644 --- a/submodules/TelegramCore/Sources/ManagedSecretChatOutgoingOperations.swift +++ b/submodules/TelegramCore/Sources/ManagedSecretChatOutgoingOperations.swift @@ -676,6 +676,8 @@ private func decryptedEntities73(_ entities: [MessageTextEntity]?) -> [SecretApi break case .Underline: break + case .BankCard: + break case .Custom: break } @@ -723,6 +725,8 @@ private func decryptedEntities101(_ entities: [MessageTextEntity]?) -> [SecretAp result.append(.messageEntityBlockquote(offset: Int32(entity.range.lowerBound), length: Int32(entity.range.count))) case .Underline: result.append(.messageEntityUnderline(offset: Int32(entity.range.lowerBound), length: Int32(entity.range.count))) + case .BankCard: + break case .Custom: break } diff --git a/submodules/TelegramCore/Sources/Serialization.swift b/submodules/TelegramCore/Sources/Serialization.swift index 02470ccbac..15b20dd3d8 100644 --- a/submodules/TelegramCore/Sources/Serialization.swift +++ b/submodules/TelegramCore/Sources/Serialization.swift @@ -210,7 +210,7 @@ public class BoxedMessage: NSObject { public class Serialization: NSObject, MTSerialization { public func currentLayer() -> UInt { - return 109 + return 110 } public func parseMessage(_ data: Data!) -> Any! { diff --git a/submodules/TelegramCore/Sources/StoreMessage_Telegram.swift b/submodules/TelegramCore/Sources/StoreMessage_Telegram.swift index d5c0b31029..44751ce910 100644 --- a/submodules/TelegramCore/Sources/StoreMessage_Telegram.swift +++ b/submodules/TelegramCore/Sources/StoreMessage_Telegram.swift @@ -386,6 +386,8 @@ func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [Mes result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Strikethrough)) case let .messageEntityBlockquote(offset, length): result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .BlockQuote)) + case let .messageEntityBankCard(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .BankCard)) } } return result diff --git a/submodules/TelegramCore/Sources/TextEntitiesMessageAttribute.swift b/submodules/TelegramCore/Sources/TextEntitiesMessageAttribute.swift index c898bed30f..1702002184 100644 --- a/submodules/TelegramCore/Sources/TextEntitiesMessageAttribute.swift +++ b/submodules/TelegramCore/Sources/TextEntitiesMessageAttribute.swift @@ -45,6 +45,8 @@ func apiEntitiesFromMessageTextEntities(_ entities: [MessageTextEntity], associa apiEntities.append(.messageEntityBlockquote(offset: offset, length: length)) case .Underline: apiEntities.append(.messageEntityUnderline(offset: offset, length: length)) + case .BankCard: + apiEntities.append(.messageEntityBankCard(offset: offset, length: length)) case .Custom: break } diff --git a/submodules/TelegramCore/Sources/UpdateCachedPeerData.swift b/submodules/TelegramCore/Sources/UpdateCachedPeerData.swift index 1050b92be7..d9d7142db3 100644 --- a/submodules/TelegramCore/Sources/UpdateCachedPeerData.swift +++ b/submodules/TelegramCore/Sources/UpdateCachedPeerData.swift @@ -319,7 +319,7 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI } switch fullChat { - case let .channelFull(flags, _, about, participantsCount, adminsCount, kickedCount, bannedCount, _, _, _, _, _, _, apiExportedInvite, apiBotInfos, migratedFromChatId, migratedFromMaxId, pinnedMsgId, stickerSet, minAvailableMsgId, folderId, linkedChatId, location, slowmodeSeconds, slowmodeNextSendDate, pts): + case let .channelFull(flags, _, about, participantsCount, adminsCount, kickedCount, bannedCount, _, _, _, _, _, _, apiExportedInvite, apiBotInfos, migratedFromChatId, migratedFromMaxId, pinnedMsgId, stickerSet, minAvailableMsgId, folderId, linkedChatId, location, slowmodeSeconds, slowmodeNextSendDate, _, pts): var channelFlags = CachedChannelFlags() if (flags & (1 << 3)) != 0 { channelFlags.insert(.canDisplayParticipants) diff --git a/submodules/TelegramUI/TelegramUI/DeclareEncodables.swift b/submodules/TelegramUI/TelegramUI/DeclareEncodables.swift index 01c3ef9546..8de131f329 100644 --- a/submodules/TelegramUI/TelegramUI/DeclareEncodables.swift +++ b/submodules/TelegramUI/TelegramUI/DeclareEncodables.swift @@ -54,7 +54,6 @@ private var telegramUIDeclaredEncodables: Void = { declareEncodable(WebBrowserSettings.self, f: { WebBrowserSettings(decoder: $0) }) declareEncodable(IntentsSettings.self, f: { IntentsSettings(decoder: $0) }) declareEncodable(CachedGeocode.self, f: { CachedGeocode(decoder: $0) }) - declareEncodable(ChatListFilterSettings.self, f: { ChatListFilterSettings(decoder: $0) }) return }() diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoFilesPane.swift b/submodules/TelegramUI/TelegramUI/PeerInfoFilesPane.swift index e5b8b0bc22..1a2b77ee30 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfoFilesPane.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfoFilesPane.swift @@ -172,7 +172,7 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode { } } - func update(size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { + func update(size: CGSize, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { self.currentParams = (size, isScrollingLockedAtTop, presentationData) transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(), size: size)) @@ -185,6 +185,12 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode { self.listNode.messageInCurrentHistoryView(id) } + func transferVelocity(_ velocity: CGFloat) { + if velocity > 0.0 { + self.listNode.transferVelocity(velocity) + } + } + func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { var transitionNode: (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? self.listNode.forEachItemNode { itemNode in diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoGroupsInCommonPaneNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfoGroupsInCommonPaneNode.swift index 82c1c0b91f..89477a9ce3 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfoGroupsInCommonPaneNode.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfoGroupsInCommonPaneNode.swift @@ -102,7 +102,7 @@ final class PeerInfoGroupsInCommonPaneNode: ASDisplayNode, PeerInfoPaneNode { } } - func update(size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { + func update(size: CGSize, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { let isFirstLayout = self.currentParams == nil self.currentParams = (size, isScrollingLockedAtTop, presentationData) @@ -156,6 +156,9 @@ final class PeerInfoGroupsInCommonPaneNode: ASDisplayNode, PeerInfoPaneNode { return nil } + func transferVelocity(_ velocity: CGFloat) { + } + func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { return nil } diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift b/submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift index fe64232ab7..1c4c6b0612 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift @@ -904,7 +904,7 @@ private final class PeerInfoHeaderNode: ASDisplayNode { private(set) var isAvatarExpanded: Bool - private let avatarListNode: PeerInfoAvatarListNode + let avatarListNode: PeerInfoAvatarListNode let regularContentNode: PeerInfoHeaderRegularContentNode let editingContentNode: PeerInfoHeaderEditingContentNode @@ -1195,7 +1195,7 @@ private final class PeerInfoHeaderNode: ASDisplayNode { } let titleScale = (transitionFraction * transitionSourceTitleFrame.height + (1.0 - transitionFraction) * titleFrame.height * neutralTitleScale) / (titleFrame.height) - let subtitleScale = (transitionFraction * transitionSourceSubtitleFrame.height + (1.0 - transitionFraction) * subtitleFrame.height * neutralSubtitleScale) / (subtitleFrame.height) + let subtitleScale = max(0.01, min(10.0, (transitionFraction * transitionSourceSubtitleFrame.height + (1.0 - transitionFraction) * subtitleFrame.height * neutralSubtitleScale) / (subtitleFrame.height))) let titleOrigin = CGPoint(x: transitionFraction * transitionSourceTitleFrame.minX + (1.0 - transitionFraction) * titleFrame.minX, y: transitionFraction * transitionSourceTitleFrame.minY + (1.0 - transitionFraction) * titleFrame.minY) let subtitleOrigin = CGPoint(x: transitionFraction * transitionSourceSubtitleFrame.minX + (1.0 - transitionFraction) * subtitleFrame.minX, y: transitionFraction * transitionSourceSubtitleFrame.minY + (1.0 - transitionFraction) * subtitleFrame.minY) @@ -1441,8 +1441,9 @@ private final class PeerInfoHeaderNode: ASDisplayNode { protocol PeerInfoPaneNode: ASDisplayNode { var isReady: Signal { get } - func update(size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) + func update(size: CGSize, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) func scrollToTop() -> Bool + func transferVelocity(_ velocity: CGFloat) func findLoadedMessage(id: MessageId) -> Message? func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? func updateSelectedMessages(animated: Bool) @@ -1466,21 +1467,21 @@ final class PeerInfoPaneInteraction { private final class PeerInfoPaneWrapper { let key: PeerInfoPaneKey let node: PeerInfoPaneNode - private var appliedParams: (CGSize, Bool, PresentationData)? + private var appliedParams: (CGSize, CGFloat, Bool, PresentationData)? init(key: PeerInfoPaneKey, node: PeerInfoPaneNode) { self.key = key self.node = node } - func update(size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { - if let (currentSize, currentIsScrollingLockedAtTop, currentPresentationData) = self.appliedParams { + func update(size: CGSize, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { + if let (currentSize, visibleHeight, currentIsScrollingLockedAtTop, currentPresentationData) = self.appliedParams { if currentSize == size && currentIsScrollingLockedAtTop == isScrollingLockedAtTop && currentPresentationData === presentationData { return } } - self.appliedParams = (size, isScrollingLockedAtTop, presentationData) - self.node.update(size: size, isScrollingLockedAtTop: isScrollingLockedAtTop, presentationData: presentationData, synchronous: synchronous, transition: transition) + self.appliedParams = (size, visibleHeight, isScrollingLockedAtTop, presentationData) + self.node.update(size: size, visibleHeight: visibleHeight, isScrollingLockedAtTop: isScrollingLockedAtTop, presentationData: presentationData, synchronous: synchronous, transition: transition) } } @@ -1582,6 +1583,8 @@ private final class PeerInfoPaneTabsContainerNode: ASDisplayNode { func update(size: CGSize, presentationData: PresentationData, paneList: [PeerInfoPaneSpecifier], selectedPane: PeerInfoPaneKey?, transition: ContainedViewLayoutTransition) { transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: size)) + let focusOnSelectedPane = self.currentParams?.1 != selectedPane + if self.currentParams?.2.theme !== presentationData.theme { self.selectedLineNode.image = generateImage(CGSize(width: 7.0, height: 4.0), rotatedContext: { size, context in context.clear(CGRect(origin: CGPoint(), size: size)) @@ -1673,6 +1676,16 @@ private final class PeerInfoPaneTabsContainerNode: ASDisplayNode { if let selectedFrame = selectedFrame { self.selectedLineNode.isHidden = false transition.updateFrame(node: self.selectedLineNode, frame: CGRect(origin: CGPoint(x: selectedFrame.minX, y: size.height - 4.0), size: CGSize(width: selectedFrame.width, height: 4.0))) + if focusOnSelectedPane { + if selectedPane == paneList.first?.key { + transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(), size: self.scrollNode.bounds.size)) + } else if selectedPane == paneList.last?.key { + transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: self.scrollNode.view.contentSize.width - self.scrollNode.bounds.width, y: 0.0), size: self.scrollNode.bounds.size)) + } else { + let contentOffsetX = max(0.0, min(self.scrollNode.view.contentSize.width - self.scrollNode.bounds.width, floor(selectedFrame.midX - self.scrollNode.bounds.width / 2.0))) + transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: contentOffsetX, y: 0.0), size: self.scrollNode.bounds.size)) + } + } } else { self.selectedLineNode.isHidden = true } @@ -1695,9 +1708,9 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { let isReady = Promise() var didSetIsReady = false - private var currentParams: (size: CGSize, expansionFraction: CGFloat, presentationData: PresentationData, data: PeerInfoScreenData?)? + private var currentParams: (size: CGSize, visibleHeight: CGFloat, expansionFraction: CGFloat, presentationData: PresentationData, data: PeerInfoScreenData?)? private(set) var currentPaneKey: PeerInfoPaneKey? - private var currentPane: PeerInfoPaneWrapper? + private(set) var currentPane: PeerInfoPaneWrapper? private var currentCandidatePaneKey: PeerInfoPaneKey? private var candidatePane: (PeerInfoPaneWrapper, Disposable, Bool)? @@ -1763,8 +1776,8 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { } strongSelf.currentCandidatePaneKey = key - if let (size, expansionFraction, presentationData, data) = strongSelf.currentParams { - strongSelf.update(size: size, expansionFraction: expansionFraction, presentationData: presentationData, data: data, transition: .immediate) + if let (size, visibleHeight, expansionFraction, presentationData, data) = strongSelf.currentParams { + strongSelf.update(size: size, visibleHeight: visibleHeight, expansionFraction: expansionFraction, presentationData: presentationData, data: data, transition: .immediate) } } } @@ -1793,7 +1806,7 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { } } - func update(size: CGSize, expansionFraction: CGFloat, presentationData: PresentationData, data: PeerInfoScreenData?, transition: ContainedViewLayoutTransition) { + func update(size: CGSize, visibleHeight: CGFloat, expansionFraction: CGFloat, presentationData: PresentationData, data: PeerInfoScreenData?, transition: ContainedViewLayoutTransition) { let availablePanes = data?.availablePanes ?? [] let previousCurrentPaneKey = self.currentPaneKey @@ -1812,7 +1825,7 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { self.currentCandidatePaneKey = availablePanes.first } - self.currentParams = (size, expansionFraction, presentationData, data) + self.currentParams = (size, visibleHeight, expansionFraction, presentationData, data) transition.updateAlpha(node: self.coveringBackgroundNode, alpha: expansionFraction) @@ -1874,8 +1887,8 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { strongSelf.candidatePane = (candidatePane, disposable, true) if shouldReLayout { - if let (size, expansionFraction, presentationData, data) = strongSelf.currentParams { - strongSelf.update(size: size, expansionFraction: expansionFraction, presentationData: presentationData, data: data, transition: strongSelf.currentPane != nil ? .animated(duration: 0.35, curve: .spring) : .immediate) + if let (size, visibleHeight, expansionFraction, presentationData, data) = strongSelf.currentParams { + strongSelf.update(size: size, visibleHeight: visibleHeight, expansionFraction: expansionFraction, presentationData: presentationData, data: data, transition: strongSelf.currentPane != nil ? .animated(duration: 0.35, curve: .spring) : .immediate) } } } @@ -1897,7 +1910,7 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { self.addSubnode(candidatePane.node) } candidatePane.node.frame = paneFrame - candidatePane.update(size: paneFrame.size, isScrollingLockedAtTop: expansionFraction < 1.0 - CGFloat.ulpOfOne, presentationData: presentationData, synchronous: true, transition: .immediate) + candidatePane.update(size: paneFrame.size, visibleHeight: max(0.0, visibleHeight - paneFrame.minY), isScrollingLockedAtTop: expansionFraction < 1.0 - CGFloat.ulpOfOne, presentationData: presentationData, synchronous: true, transition: .immediate) if let previousPane = previousPane { let directionToRight: Bool @@ -1923,7 +1936,7 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { let paneTransition: ContainedViewLayoutTransition = paneWasAdded ? .immediate : transition paneTransition.updateFrame(node: currentPane.node, frame: paneFrame) - currentPane.update(size: paneFrame.size, isScrollingLockedAtTop: expansionFraction < 1.0 - CGFloat.ulpOfOne, presentationData: presentationData, synchronous: paneWasAdded, transition: paneTransition) + currentPane.update(size: paneFrame.size, visibleHeight: visibleHeight, isScrollingLockedAtTop: expansionFraction < 1.0 - CGFloat.ulpOfOne, presentationData: presentationData, synchronous: paneWasAdded, transition: paneTransition) } transition.updateFrame(node: self.tabsContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: tabsHeight))) @@ -1949,13 +1962,14 @@ private final class PeerInfoPaneContainerNode: ASDisplayNode { if let (candidatePane, _, _) = self.candidatePane { let paneTransition: ContainedViewLayoutTransition = .immediate paneTransition.updateFrame(node: candidatePane.node, frame: paneFrame) - candidatePane.update(size: paneFrame.size, isScrollingLockedAtTop: expansionFraction < 1.0 - CGFloat.ulpOfOne, presentationData: presentationData, synchronous: true, transition: paneTransition) + candidatePane.update(size: paneFrame.size, visibleHeight: visibleHeight, isScrollingLockedAtTop: expansionFraction < 1.0 - CGFloat.ulpOfOne, presentationData: presentationData, synchronous: true, transition: paneTransition) } - if !self.didSetIsReady { - self.didSetIsReady = true + if !self.didSetIsReady && data != nil { if let currentPane = self.currentPane { + self.didSetIsReady = true self.isReady.set(currentPane.node.isReady) - } else { + } else if self.candidatePane == nil { + self.didSetIsReady = true self.isReady.set(.single(true)) } } @@ -3990,7 +4004,17 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD if !self.didSetReady && self.data != nil { self.didSetReady = true - self._ready.set(self.paneContainerNode.isReady.get()) + let avatarReady = self.headerNode.avatarListNode.isReady.get() + let combinedSignal = combineLatest(queue: .mainQueue(), + avatarReady, + self.paneContainerNode.isReady.get() + ) + |> map { lhs, rhs in + return lhs && rhs + } + self._ready.set(combinedSignal + |> filter { $0 } + |> take(1)) } } @@ -4025,7 +4049,9 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD transition.updateAlpha(node: self.headerNode.separatorNode, alpha: 1.0 - effectiveAreaExpansionFraction) - self.paneContainerNode.update(size: self.paneContainerNode.bounds.size, expansionFraction: paneAreaExpansionFraction, presentationData: self.presentationData, data: self.data, transition: transition) + let visibleHeight = self.scrollNode.view.contentOffset.y + self.scrollNode.view.bounds.height - self.paneContainerNode.frame.minY + + self.paneContainerNode.update(size: self.paneContainerNode.bounds.size, visibleHeight: visibleHeight, expansionFraction: paneAreaExpansionFraction, presentationData: self.presentationData, data: self.data, transition: transition) self.headerNode.navigationButtonContainer.frame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: layout.statusBarHeight ?? 0.0), size: CGSize(width: layout.size.width - layout.safeInsets.left * 2.0, height: 44.0)) self.headerNode.navigationButtonContainer.isWhite = self.headerNode.isAvatarExpanded @@ -4058,6 +4084,11 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self.canUpdateAvatarExpansion = true } + private var previousVelocityM1: CGFloat = 0.0 + private var previousVelocity: CGFloat = 0.0 + + private let velocityKey: String = encodeText("`wfsujdbmWfmpdjuz", -1) + func scrollViewDidScroll(_ scrollView: UIScrollView) { if self.ignoreScrolling { return @@ -4065,6 +4096,12 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self.updateNavigation(transition: .immediate, additive: false) if !self.state.isEditing { + self.previousVelocityM1 = self.previousVelocity + if let value = (scrollView.value(forKey: self.velocityKey) as? NSNumber)?.doubleValue { + //print("previousVelocity \(CGFloat(value))") + self.previousVelocity = CGFloat(value) + } + let offsetY = self.scrollNode.view.contentOffset.y var shouldBeExpanded: Bool? if offsetY <= -32.0 && scrollView.isDragging && scrollView.isTracking { @@ -4096,6 +4133,17 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } } + func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { + guard let (_, navigationHeight) = self.validLayout else { + return + } + + let paneAreaExpansionFinalPoint: CGFloat = self.paneContainerNode.frame.minY - navigationHeight + if abs(scrollView.contentOffset.y - paneAreaExpansionFinalPoint) < .ulpOfOne { + self.paneContainerNode.currentPane?.node.transferVelocity(self.previousVelocityM1) + } + } + private func updateNavigationExpansionPresentation(isExpanded: Bool, animated: Bool) { if let controller = self.controller { controller.statusBar.updateStatusBarStyle(isExpanded ? .White : self.presentationData.theme.rootController.statusBarStyle.style, animated: animated) @@ -4413,7 +4461,7 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig } let titleScale = (fraction * previousTitleNode.bounds.height + (1.0 - fraction) * self.headerNode.titleNode.bounds.height) / previousTitleNode.bounds.height - let subtitleScale = (fraction * previousStatusNode.bounds.height + (1.0 - fraction) * self.headerNode.subtitleNode.bounds.height) / previousStatusNode.bounds.height + let subtitleScale = max(0.01, min(10.0, (fraction * previousStatusNode.bounds.height + (1.0 - fraction) * self.headerNode.subtitleNode.bounds.height) / previousStatusNode.bounds.height)) transition.updateFrame(node: previousTitleContainerNode, frame: CGRect(origin: self.headerNode.titleNodeRawContainer.frame.origin.offsetBy(dx: previousTitleFrame.size.width * 0.5 * (titleScale - 1.0), dy: previousTitleFrame.size.height * 0.5 * (titleScale - 1.0)), size: previousTitleFrame.size)) transition.updateFrame(node: previousTitleNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: previousTitleFrame.size)) @@ -4443,3 +4491,11 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig self.screenNode.insertSubnode(self.headerNode, aboveSubnode: self.screenNode.scrollNode) } } + +private func encodeText(_ string: String, _ key: Int) -> String { + var result = "" + for c in string.unicodeScalars { + result.append(Character(UnicodeScalar(UInt32(Int(c.value) + key))!)) + } + return result +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoVisualMediaPane.swift b/submodules/TelegramUI/TelegramUI/PeerInfoVisualMediaPane.swift index 5cca69a898..395b578a67 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfoVisualMediaPane.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfoVisualMediaPane.swift @@ -314,7 +314,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro return self._itemInteraction! } - private var currentParams: (size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData)? + private var currentParams: (size: CGSize, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData)? private let ready = Promise() private var didSetReady: Bool = false @@ -332,6 +332,8 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro private var isRequestingView: Bool = false private var isFirstHistoryView: Bool = true + private var decelerationAnimator: ConstantDisplayLinkAnimator? + init(context: AccountContext, openMessage: @escaping (MessageId) -> Bool, peerId: PeerId, interaction: PeerInfoPaneInteraction) { self.context = context self.peerId = peerId @@ -414,8 +416,8 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro let wasFirstHistoryView = self.isFirstHistoryView self.isFirstHistoryView = false - if let (size, isScrollingLockedAtTop, presentationData) = self.currentParams { - self.update(size: size, isScrollingLockedAtTop: isScrollingLockedAtTop, presentationData: presentationData, synchronous: wasFirstHistoryView, transition: .immediate) + if let (size, visibleHeight, isScrollingLockedAtTop, presentationData) = self.currentParams { + self.update(size: size, visibleHeight: visibleHeight, isScrollingLockedAtTop: isScrollingLockedAtTop, presentationData: presentationData, synchronous: wasFirstHistoryView, transition: .immediate) if !self.didSetReady { self.didSetReady = true self.ready.set(.single(true)) @@ -442,6 +444,43 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro return nil } + func transferVelocity(_ velocity: CGFloat) { + if velocity > 0.0 { + //print("transferVelocity \(velocity)") + self.decelerationAnimator?.isPaused = true + let startTime = CACurrentMediaTime() + var currentOffset = self.scrollNode.view.contentOffset + let decelerationRate: CGFloat = 0.998 + self.decelerationAnimator = ConstantDisplayLinkAnimator(update: { [weak self] in + guard let strongSelf = self else { + return + } + let t = CACurrentMediaTime() - startTime + var currentVelocity = velocity * 15.0 * CGFloat(pow(Double(decelerationRate), 1000.0 * t)) + //print("value at \(t) = \(currentVelocity)") + currentOffset.y += currentVelocity + let maxOffset = strongSelf.scrollNode.view.contentSize.height - strongSelf.scrollNode.bounds.height + if currentOffset.y >= maxOffset { + currentOffset.y = maxOffset + currentVelocity = 0.0 + } + if currentOffset.y < 0.0 { + currentOffset.y = 0.0 + currentVelocity = 0.0 + } + + if abs(currentVelocity) < 0.1 { + strongSelf.decelerationAnimator?.isPaused = true + strongSelf.decelerationAnimator = nil + } + var contentOffset = strongSelf.scrollNode.view.contentOffset + contentOffset.y = floorToScreenPixels(currentOffset.y) + strongSelf.scrollNode.view.setContentOffset(contentOffset, animated: false) + }) + self.decelerationAnimator?.isPaused = false + } + } + func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { for item in self.mediaItems { if item.message.id == messageId { @@ -461,8 +500,8 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro } } - func update(size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { - self.currentParams = (size, isScrollingLockedAtTop, presentationData) + func update(size: CGSize, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { + self.currentParams = (size, visibleHeight, isScrollingLockedAtTop, presentationData) transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: size)) @@ -474,7 +513,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro let contentHeight = CGFloat(rowCount + 1) * itemSpacing + CGFloat(rowCount) * itemSize self.scrollNode.view.contentSize = CGSize(width: size.width, height: contentHeight) - self.updateVisibleItems(size: size, theme: presentationData.theme, synchronousLoad: synchronous) + self.updateVisibleItems(size: size, visibleHeight: visibleHeight, theme: presentationData.theme, synchronousLoad: synchronous) if isScrollingLockedAtTop { transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(), size: self.scrollNode.bounds.size)) @@ -482,9 +521,14 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro self.scrollNode.view.isScrollEnabled = !isScrollingLockedAtTop } + func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { + self.decelerationAnimator?.isPaused = true + self.decelerationAnimator = nil + } + func scrollViewDidScroll(_ scrollView: UIScrollView) { - if let (size, _, presentationData) = self.currentParams { - self.updateVisibleItems(size: size, theme: presentationData.theme, synchronousLoad: false) + if let (size, visibleHeight, _, presentationData) = self.currentParams { + self.updateVisibleItems(size: size, visibleHeight: visibleHeight, theme: presentationData.theme, synchronousLoad: false) if scrollView.contentOffset.y >= scrollView.contentSize.height - scrollView.bounds.height * 2.0, let currentView = self.currentView, currentView.earlierId != nil { if !self.isRequestingView { @@ -495,9 +539,9 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro } } - private func updateVisibleItems(size: CGSize, theme: PresentationTheme, synchronousLoad: Bool) { + private func updateVisibleItems(size: CGSize, visibleHeight: CGFloat, theme: PresentationTheme, synchronousLoad: Bool) { let itemSpacing: CGFloat = 1.0 - let itemsInRow: Int = max(3, min(6, Int(size.width / 100.0))) + let itemsInRow: Int = max(3, min(6, Int(size.width / 140.0))) let itemSize: CGFloat = floor(size.width / CGFloat(itemsInRow)) let rowCount: Int = self.mediaItems.count / itemsInRow + (self.mediaItems.count % itemsInRow == 0 ? 0 : 1) @@ -529,7 +573,11 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro self.scrollNode.addSubnode(itemNode) } itemNode.frame = itemFrame - itemNode.update(size: itemFrame.size, item: self.mediaItems[i], theme: theme, synchronousLoad: synchronousLoad) + var itemSynchronousLoad = false + if itemFrame.maxY <= visibleHeight { + itemSynchronousLoad = synchronousLoad + } + itemNode.update(size: itemFrame.size, item: self.mediaItems[i], theme: theme, synchronousLoad: itemSynchronousLoad) } } var removeKeys: [UInt32] = [] @@ -544,4 +592,17 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro } } } + + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + guard let result = super.hitTest(point, with: event) else { + return nil + } + if self.decelerationAnimator != nil { + self.decelerationAnimator?.isPaused = true + self.decelerationAnimator = nil + + return self.scrollNode.view + } + return result + } } diff --git a/submodules/TelegramUIPreferences/Sources/ChatListFilterSettings.swift b/submodules/TelegramUIPreferences/Sources/ChatListFilterSettings.swift deleted file mode 100644 index 684bdbaa1a..0000000000 --- a/submodules/TelegramUIPreferences/Sources/ChatListFilterSettings.swift +++ /dev/null @@ -1,135 +0,0 @@ -import Foundation -import Postbox -import SwiftSignalKit -import SyncCore - -public struct ChatListIncludeCategoryFilter: OptionSet { - public var rawValue: Int32 - - public init(rawValue: Int32) { - self.rawValue = rawValue - } - - public static let muted = ChatListIncludeCategoryFilter(rawValue: 1 << 1) - public static let privateChats = ChatListIncludeCategoryFilter(rawValue: 1 << 2) - public static let secretChats = ChatListIncludeCategoryFilter(rawValue: 1 << 3) - public static let privateGroups = ChatListIncludeCategoryFilter(rawValue: 1 << 4) - public static let bots = ChatListIncludeCategoryFilter(rawValue: 1 << 5) - public static let publicGroups = ChatListIncludeCategoryFilter(rawValue: 1 << 6) - public static let channels = ChatListIncludeCategoryFilter(rawValue: 1 << 7) - public static let read = ChatListIncludeCategoryFilter(rawValue: 1 << 8) - - public static let all: ChatListIncludeCategoryFilter = [ - .muted, - .privateChats, - .secretChats, - .privateGroups, - .bots, - .publicGroups, - .channels, - .read - ] -} - -public enum ChatListFilterPresetName: Equatable, Hashable, PostboxCoding { - case unread - case custom(String) - - public init(decoder: PostboxDecoder) { - switch decoder.decodeInt32ForKey("_t", orElse: 0) { - case 0: - self = .unread - case 1: - self = .custom(decoder.decodeStringForKey("title", orElse: "Preset")) - default: - assertionFailure() - self = .custom("Preset") - } - } - - public func encode(_ encoder: PostboxEncoder) { - switch self { - case .unread: - encoder.encodeInt32(0, forKey: "_t") - case let .custom(title): - encoder.encodeInt32(1, forKey: "_t") - encoder.encodeString(title, forKey: "title") - } - } -} - -public struct ChatListFilterPreset: Equatable, PostboxCoding { - public var id: Int64 - public var name: ChatListFilterPresetName - public var includeCategories: ChatListIncludeCategoryFilter - public var additionallyIncludePeers: [PeerId] - - public init(id: Int64, name: ChatListFilterPresetName, includeCategories: ChatListIncludeCategoryFilter, additionallyIncludePeers: [PeerId]) { - self.id = id - self.name = name - self.includeCategories = includeCategories - self.additionallyIncludePeers = additionallyIncludePeers - } - - public init(decoder: PostboxDecoder) { - self.id = decoder.decodeInt64ForKey("id", orElse: 0) - self.name = decoder.decodeObjectForKey("name", decoder: { ChatListFilterPresetName(decoder: $0) }) as? ChatListFilterPresetName ?? ChatListFilterPresetName.custom("Preset") - self.includeCategories = ChatListIncludeCategoryFilter(rawValue: decoder.decodeInt32ForKey("includeCategories", orElse: 0)) - self.additionallyIncludePeers = decoder.decodeInt64ArrayForKey("additionallyIncludePeers").map(PeerId.init) - } - - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt64(self.id, forKey: "id") - encoder.encodeObject(self.name, forKey: "name") - encoder.encodeInt32(self.includeCategories.rawValue, forKey: "includeCategories") - encoder.encodeInt64Array(self.additionallyIncludePeers.map { $0.toInt64() }, forKey: "additionallyIncludePeers") - } -} - -public struct ChatListFilterSettings: PreferencesEntry, Equatable { - public var presets: [ChatListFilterPreset] - - public static var `default`: ChatListFilterSettings { - return ChatListFilterSettings(presets: [ - ChatListFilterPreset( - id: Int64(arc4random()), - name: .unread, - includeCategories: ChatListIncludeCategoryFilter.all.subtracting(.read), - additionallyIncludePeers: [] - ) - ]) - } - - public init(presets: [ChatListFilterPreset]) { - self.presets = presets - } - - public init(decoder: PostboxDecoder) { - self.presets = decoder.decodeObjectArrayWithDecoderForKey("presets") - } - - public func encode(_ encoder: PostboxEncoder) { - encoder.encodeObjectArray(self.presets, forKey: "presets") - } - - public func isEqual(to: PreferencesEntry) -> Bool { - if let to = to as? ChatListFilterSettings { - return self == to - } else { - return false - } - } -} - -public func updateChatListFilterSettingsInteractively(postbox: Postbox, _ f: @escaping (ChatListFilterSettings) -> ChatListFilterSettings) -> Signal { - return postbox.transaction { transaction -> ChatListFilterSettings in - var result: ChatListFilterSettings? - transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.chatListFilterSettings, { entry in - var settings = entry as? ChatListFilterSettings ?? ChatListFilterSettings.default - let updated = f(settings) - result = updated - return updated - }) - return result ?? .default - } -} From 65b22f6ca50696b912c1c31440a21c48704af00c Mon Sep 17 00:00:00 2001 From: Ali <> Date: Sat, 8 Feb 2020 23:07:06 +0000 Subject: [PATCH 09/30] User Info UI improvements --- .../ChatListFilterPresetController.swift | 2 +- .../Sources/ChatListSearchContainerNode.swift | 6 +- .../ContainedViewLayoutTransition.swift | 24 + .../Display/Display/ImmediateTextNode.swift | 14 + .../Navigation/NavigationContainer.swift | 24 +- .../Navigation/NavigationController.swift | 35 +- .../Navigation/NavigationSplitContainer.swift | 10 + .../Display/Display/ViewController.swift | 2 + submodules/LocalMediaResources/BUCK | 4 +- submodules/PeerAvatarGalleryUI/BUCK | 4 +- submodules/SaveToCameraRoll/BUCK | 4 +- .../Sources/SearchDisplayController.swift | 6 +- submodules/SettingsUI/BUCK | 4 +- .../TelegramUI/ChatAvatarNavigationNode.swift | 14 +- .../TelegramUI/ChatController.swift | 20 +- .../ChatInterfaceStateNavigationButtons.swift | 5 + .../TelegramUI/TelegramUI/ChatTitleView.swift | 100 +- .../TelegramUI/ListMessageFileItemNode.swift | 4 +- .../ListItems}/PeerInfoScreenActionItem.swift | 0 .../PeerInfoScreenDisclosureItem.swift | 0 .../PeerInfoScreenLabeledValueItem.swift | 0 ...erInfoScreenSelectableBackgroundNode.swift | 0 .../ListItems}/PeerInfoScreenSwitchItem.swift | 0 .../PeerInfoGroupsInCommonPaneNode.swift | 35 +- .../PeerInfo/Panes/PeerInfoListPaneNode.swift | 125 + .../Panes/PeerInfoVisualMediaPaneNode.swift} | 103 +- .../TelegramUI/PeerInfo/PeerInfoData.swift | 306 ++ .../PeerInfo/PeerInfoHeaderNode.swift | 1497 +++++++++ .../PeerInfo/PeerInfoPaneContainerNode.swift | 553 ++++ .../{ => PeerInfo}/PeerInfoScreen.swift | 2880 +++-------------- .../TelegramUI/PeerInfoFilesPane.swift | 217 -- 31 files changed, 3264 insertions(+), 2734 deletions(-) rename submodules/TelegramUI/TelegramUI/{ => PeerInfo/ListItems}/PeerInfoScreenActionItem.swift (100%) rename submodules/TelegramUI/TelegramUI/{ => PeerInfo/ListItems}/PeerInfoScreenDisclosureItem.swift (100%) rename submodules/TelegramUI/TelegramUI/{ => PeerInfo/ListItems}/PeerInfoScreenLabeledValueItem.swift (100%) rename submodules/TelegramUI/TelegramUI/{ => PeerInfo/ListItems}/PeerInfoScreenSelectableBackgroundNode.swift (100%) rename submodules/TelegramUI/TelegramUI/{ => PeerInfo/ListItems}/PeerInfoScreenSwitchItem.swift (100%) rename submodules/TelegramUI/TelegramUI/{ => PeerInfo/Panes}/PeerInfoGroupsInCommonPaneNode.swift (77%) create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoListPaneNode.swift rename submodules/TelegramUI/TelegramUI/{PeerInfoVisualMediaPane.swift => PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift} (82%) create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift rename submodules/TelegramUI/TelegramUI/{ => PeerInfo}/PeerInfoScreen.swift (51%) delete mode 100644 submodules/TelegramUI/TelegramUI/PeerInfoFilesPane.swift diff --git a/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift b/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift index 27052bb641..49065df51e 100644 --- a/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift +++ b/submodules/ChatListUI/Sources/ChatListFilterPresetController.swift @@ -371,7 +371,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat let _ = (updateChatListFilterSettingsInteractively(postbox: context.account.postbox, { settings in var preset = preset if currentPreset == nil { - preset.id = max(1, settings.filters.map({ $0.id }).max() ?? 1) + preset.id = max(2, settings.filters.map({ $0.id }).max() ?? 2) } var settings = settings settings.filters = settings.filters.filter { $0 != preset && $0 != currentPreset } diff --git a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift index 79fa26f3f7..19cb9e585f 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift @@ -193,8 +193,10 @@ private enum ChatListRecentEntry: Comparable, Identifiable { } }, setPeerIdWithRevealedOptions: setPeerIdWithRevealedOptions, deletePeer: deletePeer, contextAction: peerContextAction.flatMap { peerContextAction in return { node, gesture in - if let chatPeer = peer.peer.peers[peer.peer.peerId] { + if let chatPeer = peer.peer.peers[peer.peer.peerId], chatPeer.id.namespace != Namespaces.Peer.SecretChat { peerContextAction(chatPeer, .recentSearch, node, gesture) + } else { + gesture?.cancel() } } }) @@ -415,7 +417,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable { interaction.peerSelected(peer) }, contextAction: peerContextAction.flatMap { peerContextAction in return { node, gesture in - if let chatPeer = chatPeer { + if let chatPeer = chatPeer, chatPeer.id.namespace != Namespaces.Peer.SecretChat { peerContextAction(chatPeer, .search, node, gesture) } else { gesture?.cancel() diff --git a/submodules/Display/Display/ContainedViewLayoutTransition.swift b/submodules/Display/Display/ContainedViewLayoutTransition.swift index 0200f6f212..7635ad88ba 100644 --- a/submodules/Display/Display/ContainedViewLayoutTransition.swift +++ b/submodules/Display/Display/ContainedViewLayoutTransition.swift @@ -567,6 +567,30 @@ public extension ContainedViewLayoutTransition { } } + func animateTransformScale(view: UIView, from fromScale: CGFloat, completion: ((Bool) -> Void)? = nil) { + let t = view.layer.transform + let currentScale = sqrt((t.m11 * t.m11) + (t.m12 * t.m12) + (t.m13 * t.m13)) + if currentScale.isEqual(to: fromScale) { + if let completion = completion { + completion(true) + } + return + } + + switch self { + case .immediate: + if let completion = completion { + completion(true) + } + case let .animated(duration, curve): + view.layer.animateScale(from: fromScale, to: currentScale, duration: duration, timingFunction: curve.timingFunction, mediaTimingFunction: curve.mediaTimingFunction, completion: { result in + if let completion = completion { + completion(result) + } + }) + } + } + func updateTransformScale(node: ASDisplayNode, scale: CGFloat, beginWithCurrentState: Bool = false, completion: ((Bool) -> Void)? = nil) { let t = node.layer.transform let currentScale = sqrt((t.m11 * t.m11) + (t.m12 * t.m12) + (t.m13 * t.m13)) diff --git a/submodules/Display/Display/ImmediateTextNode.swift b/submodules/Display/Display/ImmediateTextNode.swift index 38488ecda3..25d8fb69e7 100644 --- a/submodules/Display/Display/ImmediateTextNode.swift +++ b/submodules/Display/Display/ImmediateTextNode.swift @@ -38,6 +38,20 @@ public class ImmediateTextNode: TextNode { let node = TextNode() node.cachedLayout = self.cachedLayout node.frame = self.frame + if let subnodes = self.subnodes { + for subnode in subnodes { + if let subnode = subnode as? ASImageNode { + let copySubnode = ASImageNode() + copySubnode.isLayerBacked = subnode.isLayerBacked + copySubnode.image = subnode.image + copySubnode.displaysAsynchronously = false + copySubnode.displayWithoutProcessing = true + copySubnode.frame = subnode.frame + copySubnode.alpha = subnode.alpha + node.addSubnode(copySubnode) + } + } + } return node } diff --git a/submodules/Display/Display/Navigation/NavigationContainer.swift b/submodules/Display/Display/Navigation/NavigationContainer.swift index ec6f8803d5..fe79956916 100644 --- a/submodules/Display/Display/Navigation/NavigationContainer.swift +++ b/submodules/Display/Display/Navigation/NavigationContainer.swift @@ -133,6 +133,13 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { }*/ } + func hasNonReadyControllers() -> Bool { + if let pending = self.state.pending, !pending.isReady { + return true + } + return false + } + public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return false } @@ -185,6 +192,17 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { if let strongSelf = self { if let top = strongSelf.state.top { strongSelf.syncKeyboard(leftEdge: top.value.displayNode.frame.minX, transition: transition) + + var updatedStatusBarStyle = strongSelf.statusBarStyle + if let childTransition = strongSelf.state.transition, childTransition.coordinator.progress >= 0.3 { + updatedStatusBarStyle = childTransition.previous.value.statusBar.statusBarStyle + } else { + updatedStatusBarStyle = top.value.statusBar.statusBarStyle + } + if strongSelf.statusBarStyle != updatedStatusBarStyle { + strongSelf.statusBarStyle = updatedStatusBarStyle + strongSelf.statusBarStyleUpdated?(.animated(duration: 0.3, curve: .easeInOut)) + } } } }) @@ -337,7 +355,11 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { } } self.applyLayout(layout: updatedLayout, to: top, isMaster: true, transition: transition) - updatedStatusBarStyle = top.value.statusBar.statusBarStyle + if let childTransition = self.state.transition, childTransition.coordinator.progress >= 0.3 { + updatedStatusBarStyle = childTransition.previous.value.statusBar.statusBarStyle + } else { + updatedStatusBarStyle = top.value.statusBar.statusBarStyle + } } else { updatedStatusBarStyle = .Ignore } diff --git a/submodules/Display/Display/Navigation/NavigationController.swift b/submodules/Display/Display/Navigation/NavigationController.swift index 037b2fc65d..b709a8a5fd 100644 --- a/submodules/Display/Display/Navigation/NavigationController.swift +++ b/submodules/Display/Display/Navigation/NavigationController.swift @@ -274,6 +274,18 @@ open class NavigationController: UINavigationController, ContainableController, return true } } + if let rootContainer = self.rootContainer { + switch rootContainer { + case let .flat(container): + if container.hasNonReadyControllers() { + return true + } + case let .split(splitContainer): + if splitContainer.hasNonReadyControllers() { + return true + } + } + } return false } @@ -1001,27 +1013,8 @@ open class NavigationController: UINavigationController, ContainableController, } public func pushViewController(_ controller: ViewController, animated: Bool = true, completion: @escaping () -> Void) { - let navigateAction: () -> Void = { [weak self] in - guard let strongSelf = self else { - return - } - - if !controller.hasActiveInput { - //strongSelf.view.endEditing(true) - } - /*strongSelf.scheduleAfterLayout({ - guard let strongSelf = self else { - return - }*/ - strongSelf.pushViewController(controller, animated: animated) - completion() - //}) - } - - /*if let lastController = self.viewControllers.last as? ViewController, !lastController.attemptNavigation(navigateAction) { - } else {*/ - navigateAction() - //} + self.pushViewController(controller, animated: animated) + completion() } open override func pushViewController(_ viewController: UIViewController, animated: Bool) { diff --git a/submodules/Display/Display/Navigation/NavigationSplitContainer.swift b/submodules/Display/Display/Navigation/NavigationSplitContainer.swift index 155fd2a186..ac6c7772db 100644 --- a/submodules/Display/Display/Navigation/NavigationSplitContainer.swift +++ b/submodules/Display/Display/Navigation/NavigationSplitContainer.swift @@ -57,6 +57,16 @@ final class NavigationSplitContainer: ASDisplayNode { self.view.addSubview(self.detailScrollToTopView) } + func hasNonReadyControllers() -> Bool { + if self.masterContainer.hasNonReadyControllers() { + return true + } + if self.detailContainer.hasNonReadyControllers() { + return true + } + return false + } + func updateTheme(theme: NavigationControllerTheme) { self.separator.backgroundColor = theme.navigationBar.separatorColor } diff --git a/submodules/Display/Display/ViewController.swift b/submodules/Display/Display/ViewController.swift index 392644c300..a8d2ca9516 100644 --- a/submodules/Display/Display/ViewController.swift +++ b/submodules/Display/Display/ViewController.swift @@ -93,6 +93,8 @@ public enum ViewControllerNavigationPresentation { } } + var blocksInteractionUntilReady: Bool = false + public final var isOpaqueWhenInOverlay: Bool = false public final var blocksBackgroundWhenInOverlay: Bool = false public final var automaticallyControlPresentationContextLayout: Bool = true diff --git a/submodules/LocalMediaResources/BUCK b/submodules/LocalMediaResources/BUCK index 6739a9b6cf..12b32376f0 100644 --- a/submodules/LocalMediaResources/BUCK +++ b/submodules/LocalMediaResources/BUCK @@ -15,6 +15,8 @@ static_library( frameworks = [ "$SDKROOT/System/Library/Frameworks/Foundation.framework", "$SDKROOT/System/Library/Frameworks/UIKit.framework", - "$SDKROOT/System/Library/Frameworks/Photos.framework", + ], + weak_frameworks = [ + "Photos", ], ) diff --git a/submodules/PeerAvatarGalleryUI/BUCK b/submodules/PeerAvatarGalleryUI/BUCK index bde6746427..f61fd2951b 100644 --- a/submodules/PeerAvatarGalleryUI/BUCK +++ b/submodules/PeerAvatarGalleryUI/BUCK @@ -26,6 +26,8 @@ static_library( "$SDKROOT/System/Library/Frameworks/Foundation.framework", "$SDKROOT/System/Library/Frameworks/UIKit.framework", "$SDKROOT/System/Library/Frameworks/QuickLook.framework", - "$SDKROOT/System/Library/Frameworks/Photos.framework", + ], + weak_frameworks = [ + "Photos", ], ) diff --git a/submodules/SaveToCameraRoll/BUCK b/submodules/SaveToCameraRoll/BUCK index d594ecc651..b75130a540 100644 --- a/submodules/SaveToCameraRoll/BUCK +++ b/submodules/SaveToCameraRoll/BUCK @@ -18,6 +18,8 @@ static_library( "$SDKROOT/System/Library/Frameworks/Foundation.framework", "$SDKROOT/System/Library/Frameworks/UIKit.framework", "$SDKROOT/System/Library/Frameworks/MobileCoreServices.framework", - "$SDKROOT/System/Library/Frameworks/Photos.framework", + ], + weak_frameworks = [ + "Photos", ], ) diff --git a/submodules/SearchUI/Sources/SearchDisplayController.swift b/submodules/SearchUI/Sources/SearchDisplayController.swift index 66d5fd6e9b..d3c6254589 100644 --- a/submodules/SearchUI/Sources/SearchDisplayController.swift +++ b/submodules/SearchUI/Sources/SearchDisplayController.swift @@ -22,7 +22,7 @@ public final class SearchDisplayController { private var isSearchingDisposable: Disposable? - public init(presentationData: PresentationData, mode: SearchDisplayControllerMode = .navigation, contentNode: SearchDisplayControllerContentNode, cancel: @escaping () -> Void) { + public init(presentationData: PresentationData, mode: SearchDisplayControllerMode = .navigation, placeholder: String? = nil, contentNode: SearchDisplayControllerContentNode, cancel: @escaping () -> Void) { self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: presentationData.theme, hasSeparator: false), strings: presentationData.strings, fieldStyle: .modern) self.mode = mode self.contentNode = contentNode @@ -48,6 +48,9 @@ public final class SearchDisplayController { self?.searchBar.prefixString = prefix self?.searchBar.text = query } + if let placeholder = placeholder { + self.searchBar.placeholderString = NSAttributedString(string: placeholder, font: Font.regular(17.0), textColor: presentationData.theme.rootController.navigationSearchBar.inputPlaceholderTextColor) + } self.contentNode.setPlaceholder = { [weak self] string in guard string != self?.searchBar.placeholderString?.string else { return @@ -153,6 +156,7 @@ public final class SearchDisplayController { if let placeholder = placeholder { self.searchBar.animateIn(from: placeholder, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring) } else { + self.searchBar.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) self.contentNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) } } diff --git a/submodules/SettingsUI/BUCK b/submodules/SettingsUI/BUCK index df9f9d6aa7..49fcfda198 100644 --- a/submodules/SettingsUI/BUCK +++ b/submodules/SettingsUI/BUCK @@ -92,8 +92,10 @@ static_library( "$SDKROOT/System/Library/Frameworks/UIKit.framework", "$SDKROOT/System/Library/Frameworks/MessageUI.framework", "$SDKROOT/System/Library/Frameworks/LocalAuthentication.framework", - "$SDKROOT/System/Library/Frameworks/Photos.framework", "$SDKROOT/System/Library/Frameworks/QuickLook.framework", "$SDKROOT/System/Library/Frameworks/CoreTelephony.framework", ], + weak_frameworks = [ + "Photos", + ], ) diff --git a/submodules/TelegramUI/TelegramUI/ChatAvatarNavigationNode.swift b/submodules/TelegramUI/TelegramUI/ChatAvatarNavigationNode.swift index 30d69469e3..4e63ec7863 100644 --- a/submodules/TelegramUI/TelegramUI/ChatAvatarNavigationNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatAvatarNavigationNode.swift @@ -80,12 +80,20 @@ final class ChatAvatarNavigationNode: ASDisplayNode { (self.view as? ChatAvatarNavigationNodeView)?.targetNode = self (self.view as? ChatAvatarNavigationNodeView)?.chatController = self.chatController - self.avatarNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.avatarTapGesture(_:)))) + let tapRecognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.avatarTapGesture(_:))) + self.avatarNode.view.addGestureRecognizer(tapRecognizer) } - @objc private func avatarTapGesture(_ recognizer: UITapGestureRecognizer) { + @objc private func avatarTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { if case .ended = recognizer.state { - self.tapped?() + if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation { + switch gesture { + case .tap: + self.tapped?() + default: + break + } + } } } diff --git a/submodules/TelegramUI/TelegramUI/ChatController.swift b/submodules/TelegramUI/TelegramUI/ChatController.swift index 09d4a6ebdb..b2fa3154bc 100644 --- a/submodules/TelegramUI/TelegramUI/ChatController.swift +++ b/submodules/TelegramUI/TelegramUI/ChatController.swift @@ -1866,12 +1866,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.controllerInteraction = controllerInteraction - var displayNavigationAvatar = false - if case let .peer(peerId) = chatLocation, peerId != context.account.peerId { - displayNavigationAvatar = true + if case let .peer(peerId) = chatLocation, peerId != context.account.peerId, subject != .scheduledMessages { self.navigationBar?.userInfo = PeerInfoNavigationSourceTag(peerId: peerId) } - self.chatTitleView = ChatTitleView(account: self.context.account, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, displayAvatar: displayNavigationAvatar) + self.chatTitleView = ChatTitleView(account: self.context.account, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, displayAvatar: true) if let avatarNode = self.chatTitleView?.avatarNode { avatarNode.chatController = self avatarNode.contextAction = { [weak self] node, gesture in @@ -1988,8 +1986,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if let strongSelf = self { if let peer = peerViewMainPeer(peerView) { strongSelf.chatTitleView?.titleContent = .peer(peerView: peerView, onlineMemberCount: onlineMemberCount, isScheduledMessages: isScheduledMessages) - strongSelf.chatTitleView?.avatarNode?.avatarNode.setPeer(context: strongSelf.context, theme: strongSelf.presentationData.theme, peer: peer, overrideImage: peer.isDeleted ? .deletedIcon : .none) - (strongSelf.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.contextActionIsEnabled = peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil + let imageOverride: AvatarNodeImageOverride? + if strongSelf.context.account.peerId == peer.id { + imageOverride = .savedMessagesIcon + } else if peer.isDeleted { + imageOverride = .deletedIcon + } else { + imageOverride = nil + } + strongSelf.chatTitleView?.avatarNode?.avatarNode.setPeer(context: strongSelf.context, theme: strongSelf.presentationData.theme, peer: peer, overrideImage: imageOverride) + strongSelf.chatTitleView?.avatarNode?.contextActionIsEnabled = peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil && imageOverride == nil && peer.smallProfileImage != nil } if strongSelf.peerView === peerView && strongSelf.reportIrrelvantGeoNotice == peerReportNotice && strongSelf.hasScheduledMessages == hasScheduledMessages { @@ -5075,6 +5081,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.leftNavigationButton = nil } + self.chatTitleView?.displayAvatar = updatedChatPresentationInterfaceState.interfaceState.selectionState == nil + if let button = rightNavigationButtonForChatInterfaceState(updatedChatPresentationInterfaceState, strings: updatedChatPresentationInterfaceState.strings, currentButton: self.rightNavigationButton, target: self, selector: #selector(self.rightNavigationButtonAction), chatInfoNavigationButton: self.chatInfoNavigationButton) { if self.rightNavigationButton != button { var animated = transition.isAnimated diff --git a/submodules/TelegramUI/TelegramUI/ChatInterfaceStateNavigationButtons.swift b/submodules/TelegramUI/TelegramUI/ChatInterfaceStateNavigationButtons.swift index 3e0f9c33a0..12964d2a8b 100644 --- a/submodules/TelegramUI/TelegramUI/ChatInterfaceStateNavigationButtons.swift +++ b/submodules/TelegramUI/TelegramUI/ChatInterfaceStateNavigationButtons.swift @@ -72,7 +72,12 @@ func rightNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Ch } } + if presentationInterfaceState.isScheduledMessages { + return nil + } + if case .standard(true) = presentationInterfaceState.mode { + return nil } else if let peer = presentationInterfaceState.renderedPeer?.peer { if presentationInterfaceState.accountPeerId == peer.id { if presentationInterfaceState.isScheduledMessages { diff --git a/submodules/TelegramUI/TelegramUI/ChatTitleView.swift b/submodules/TelegramUI/TelegramUI/ChatTitleView.swift index 27802c7185..d399138c28 100644 --- a/submodules/TelegramUI/TelegramUI/ChatTitleView.swift +++ b/submodules/TelegramUI/TelegramUI/ChatTitleView.swift @@ -179,6 +179,15 @@ final class ChatTitleView: UIView, NavigationBarTitleView { var pressed: (() -> Void)? + var displayAvatar: Bool = true { + didSet { + if self.displayAvatar != oldValue { + self.avatarNode?.isHidden = !self.displayAvatar + self.setNeedsLayout() + } + } + } + var titleContent: ChatTitleContent? { didSet { if let titleContent = self.titleContent { @@ -529,19 +538,13 @@ final class ChatTitleView: UIView, NavigationBarTitleView { if highlighted { strongSelf.titleNode.layer.removeAnimation(forKey: "opacity") strongSelf.activityNode.layer.removeAnimation(forKey: "opacity") - strongSelf.titleLeftIconNode.layer.removeAnimation(forKey: "opacity") - strongSelf.titleRightIconNode.layer.removeAnimation(forKey: "opacity") strongSelf.titleCredibilityIconNode.layer.removeAnimation(forKey: "opacity") strongSelf.titleNode.alpha = 0.4 strongSelf.activityNode.alpha = 0.4 - strongSelf.titleLeftIconNode.alpha = 0.4 - strongSelf.titleRightIconNode.alpha = 0.4 strongSelf.titleCredibilityIconNode.alpha = 0.4 } else { strongSelf.titleNode.alpha = 1.0 strongSelf.activityNode.alpha = 1.0 - strongSelf.titleLeftIconNode.alpha = 1.0 - strongSelf.titleRightIconNode.alpha = 1.0 strongSelf.titleCredibilityIconNode.alpha = 1.0 strongSelf.titleNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) strongSelf.activityNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) @@ -592,7 +595,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { if let image = self.titleLeftIconNode.image { if self.titleLeftIconNode.supernode == nil { - self.contentContainer.addSubnode(self.titleLeftIconNode) + self.titleNode.addSubnode(self.titleLeftIconNode) } leftIconWidth = image.size.width + 6.0 } else if self.titleLeftIconNode.supernode != nil { @@ -610,7 +613,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { if let image = self.titleRightIconNode.image { if self.titleRightIconNode.supernode == nil { - self.contentContainer.addSubnode(self.titleRightIconNode) + self.titleNode.addSubnode(self.titleRightIconNode) } rightIconWidth = image.size.width + 3.0 } else if self.titleRightIconNode.supernode != nil { @@ -622,68 +625,43 @@ final class ChatTitleView: UIView, NavigationBarTitleView { let avatarSize = CGSize(width: 37.0, height: 37.0) let avatarFrame = CGRect(origin: CGPoint(x: leftInset + 10.0, y: floor((size.height - avatarSize.height) / 2.0)), size: avatarSize) avatarNode.frame = avatarFrame - leftInset += avatarSize.width + 10.0 + 8.0 + if self.displayAvatar { + leftInset += avatarSize.width + 10.0 + 8.0 + } } self.button.frame = CGRect(origin: CGPoint(x: leftInset - 20.0, y: 0.0), size: CGSize(width: clearBounds.width - leftInset, height: size.height)) let titleSideInset: CGFloat = 3.0 - if size.height > 40.0 { - var titleSize = self.titleNode.updateLayout(CGSize(width: clearBounds.width - leftIconWidth - credibilityIconWidth - rightIconWidth - titleSideInset * 2.0 - leftInset, height: size.height)) - titleSize.width += credibilityIconWidth - let activitySize = self.activityNode.updateLayout(clearBounds.size, alignment: .left) - let titleInfoSpacing: CGFloat = 0.0 - - var titleFrame: CGRect - - if activitySize.height.isZero { - titleFrame = CGRect(origin: CGPoint(x: leftInset + leftIconWidth, y: floor((size.height - titleSize.height) / 2.0)), size: titleSize) - self.titleNode.frame = titleFrame - } else { - let combinedHeight = titleSize.height + activitySize.height + titleInfoSpacing - - titleFrame = CGRect(origin: CGPoint(x: leftInset + leftIconWidth, y: floor((size.height - combinedHeight) / 2.0)), size: titleSize) - self.titleNode.frame = titleFrame - - var activityFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((size.height - combinedHeight) / 2.0) + titleSize.height + titleInfoSpacing), size: activitySize) - self.activityNode.frame = activityFrame - } - - if let image = self.titleLeftIconNode.image { - self.titleLeftIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.minX - image.size.width - 3.0 - UIScreenPixel, y: titleFrame.minY + 4.0), size: image.size) - } - if let image = self.titleCredibilityIconNode.image { - self.titleCredibilityIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.maxX - image.size.width - 1.0, y: titleFrame.minY + 2.0), size: image.size) - } - if let image = self.titleRightIconNode.image { - self.titleRightIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.maxX + 3.0, y: titleFrame.minY + 6.0), size: image.size) - } - } else { - let titleSize = self.titleNode.updateLayout(CGSize(width: floor(clearBounds.width / 2.0 - leftIconWidth - credibilityIconWidth - rightIconWidth - titleSideInset * 2.0), height: size.height)) - let activitySize = self.activityNode.updateLayout(CGSize(width: floor(clearBounds.width / 2.0), height: size.height), alignment: .center) - - let titleInfoSpacing: CGFloat = 8.0 - let combinedWidth = titleSize.width + leftIconWidth + credibilityIconWidth + rightIconWidth + activitySize.width + titleInfoSpacing - - let titleFrame = CGRect(origin: CGPoint(x: leftIconWidth + floor((clearBounds.width - combinedWidth) / 2.0), y: floor((size.height - titleSize.height) / 2.0)), size: titleSize) + var titleSize = self.titleNode.updateLayout(CGSize(width: clearBounds.width - leftIconWidth - credibilityIconWidth - rightIconWidth - titleSideInset * 2.0 - leftInset, height: size.height)) + titleSize.width += credibilityIconWidth + let activitySize = self.activityNode.updateLayout(clearBounds.size, alignment: .left) + let titleInfoSpacing: CGFloat = 0.0 + + var titleFrame: CGRect + + if activitySize.height.isZero { + titleFrame = CGRect(origin: CGPoint(x: leftInset + leftIconWidth, y: floor((size.height - titleSize.height) / 2.0)), size: titleSize) self.titleNode.frame = titleFrame - self.activityNode.frame = CGRect(origin: CGPoint(x: floor((clearBounds.width - combinedWidth) / 2.0 + titleSize.width + leftIconWidth + credibilityIconWidth + rightIconWidth + titleInfoSpacing), y: floor((size.height - activitySize.height) / 2.0)), size: activitySize) + } else { + let combinedHeight = titleSize.height + activitySize.height + titleInfoSpacing - if let image = self.titleLeftIconNode.image { - self.titleLeftIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.minX, y: titleFrame.minY + 4.0), size: image.size) - } - if let image = self.titleCredibilityIconNode.image { - self.titleCredibilityIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.maxX - image.size.width - 1.0, y: titleFrame.minY + 6.0), size: image.size) - } - if let image = self.titleRightIconNode.image { - self.titleRightIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.maxX - image.size.width - 1.0, y: titleFrame.minY + 6.0), size: image.size) - } + titleFrame = CGRect(origin: CGPoint(x: leftInset + leftIconWidth, y: floor((size.height - combinedHeight) / 2.0)), size: titleSize) + self.titleNode.frame = titleFrame + + var activityFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((size.height - combinedHeight) / 2.0) + titleSize.height + titleInfoSpacing), size: activitySize) + self.activityNode.frame = activityFrame } - /*if let networkStatusNode = self.networkStatusNode { - transition.updateFrame(node: networkStatusNode, frame: CGRect(origin: CGPoint(), size: size)) - networkStatusNode.updateLayout(size: size, transition: transition) - }*/ + if let image = self.titleLeftIconNode.image { + self.titleLeftIconNode.frame = CGRect(origin: CGPoint(x: -image.size.width - 3.0 - UIScreenPixel, y: 4.0), size: image.size) + } + if let image = self.titleCredibilityIconNode.image { + self.titleCredibilityIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.maxX - image.size.width - 1.0, y: titleFrame.minY + 2.0), size: image.size) + } + if let image = self.titleRightIconNode.image { + self.titleRightIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.width + 3.0, y: 6.0), size: image.size) + } } @objc func buttonPressed() { diff --git a/submodules/TelegramUI/TelegramUI/ListMessageFileItemNode.swift b/submodules/TelegramUI/TelegramUI/ListMessageFileItemNode.swift index 57daa968c1..43ce473a32 100644 --- a/submodules/TelegramUI/TelegramUI/ListMessageFileItemNode.swift +++ b/submodules/TelegramUI/TelegramUI/ListMessageFileItemNode.swift @@ -658,7 +658,7 @@ final class ListMessageFileItemNode: ListMessageNode { strongSelf.addSubnode(waveformScrubbingNode) } - strongSelf.waveformScrubbingNode?.frame = CGRect(origin: CGPoint(x: leftOffset + leftInset, y: 10.0), size: CGSize(width: params.width - (leftOffset + leftInset) - 16.0, height: 12.0)) + transition.updateFrame(node: waveformScrubbingNode, frame: CGRect(origin: CGPoint(x: leftOffset + leftInset, y: 10.0), size: CGSize(width: params.width - leftInset - 16.0, height: 12.0))) waveformNode.setup(color: item.theme.list.controlSecondaryColor, waveform: waveform) waveformForegroundNode.setup(color: item.theme.list.itemAccentColor, waveform: waveform) @@ -809,7 +809,7 @@ final class ListMessageFileItemNode: ListMessageNode { } } self.waveformScrubbingNode?.enableScrubbing = enableScrubbing - if let musicIsPlaying = musicIsPlaying, !isVoice { + if let musicIsPlaying = musicIsPlaying, !isVoice, !isInstantVideo { if self.playbackOverlayNode == nil { let playbackOverlayNode = ListMessagePlaybackOverlayNode() playbackOverlayNode.frame = self.iconImageNode.frame diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoScreenActionItem.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenActionItem.swift similarity index 100% rename from submodules/TelegramUI/TelegramUI/PeerInfoScreenActionItem.swift rename to submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenActionItem.swift diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoScreenDisclosureItem.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenDisclosureItem.swift similarity index 100% rename from submodules/TelegramUI/TelegramUI/PeerInfoScreenDisclosureItem.swift rename to submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenDisclosureItem.swift diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoScreenLabeledValueItem.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenLabeledValueItem.swift similarity index 100% rename from submodules/TelegramUI/TelegramUI/PeerInfoScreenLabeledValueItem.swift rename to submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenLabeledValueItem.swift diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoScreenSelectableBackgroundNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenSelectableBackgroundNode.swift similarity index 100% rename from submodules/TelegramUI/TelegramUI/PeerInfoScreenSelectableBackgroundNode.swift rename to submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenSelectableBackgroundNode.swift diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoScreenSwitchItem.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenSwitchItem.swift similarity index 100% rename from submodules/TelegramUI/TelegramUI/PeerInfoScreenSwitchItem.swift rename to submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenSwitchItem.swift diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoGroupsInCommonPaneNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoGroupsInCommonPaneNode.swift similarity index 77% rename from submodules/TelegramUI/TelegramUI/PeerInfoGroupsInCommonPaneNode.swift rename to submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoGroupsInCommonPaneNode.swift index 89477a9ce3..04db539477 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfoGroupsInCommonPaneNode.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoGroupsInCommonPaneNode.swift @@ -35,24 +35,24 @@ private struct GroupsInCommonListEntry: Comparable, Identifiable { return lhs.index < rhs.index } - func item(context: AccountContext, presentationData: PresentationData, openPeer: @escaping (Peer) -> Void) -> ListViewItem { + func item(context: AccountContext, presentationData: PresentationData, openPeer: @escaping (Peer) -> Void, openPeerContextAction: @escaping (Peer, ASDisplayNode, ContextGesture?) -> Void) -> ListViewItem { let peer = self.peer return ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: context, peer: self.peer, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: nil, enabled: true, selectable: true, sectionId: 0, action: { openPeer(peer) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, contextAction: { node, gesture in - //arguments.contextAction(peer, node, gesture) + openPeerContextAction(peer, node, gesture) }, hasTopStripe: false, noInsets: true) } } -private func preparedTransition(from fromEntries: [GroupsInCommonListEntry], to toEntries: [GroupsInCommonListEntry], context: AccountContext, presentationData: PresentationData, openPeer: @escaping (Peer) -> Void) -> GroupsInCommonListTransaction { +private func preparedTransition(from fromEntries: [GroupsInCommonListEntry], to toEntries: [GroupsInCommonListEntry], context: AccountContext, presentationData: PresentationData, openPeer: @escaping (Peer) -> Void, openPeerContextAction: @escaping (Peer, ASDisplayNode, ContextGesture?) -> Void) -> GroupsInCommonListTransaction { 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(context: context, presentationData: presentationData, openPeer: openPeer), directionHint: nil) } - let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, openPeer: openPeer), directionHint: nil) } + let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, openPeer: openPeer, openPeerContextAction: openPeerContextAction), directionHint: nil) } + let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, openPeer: openPeer, openPeerContextAction: openPeerContextAction), directionHint: nil) } return GroupsInCommonListTransaction(deletions: deletions, insertions: insertions, updates: updates) } @@ -60,7 +60,8 @@ private func preparedTransition(from fromEntries: [GroupsInCommonListEntry], to final class PeerInfoGroupsInCommonPaneNode: ASDisplayNode, PeerInfoPaneNode { private let context: AccountContext private let peerId: PeerId - private let paneInteraction: PeerInfoPaneInteraction + private let chatControllerInteraction: ChatControllerInteraction + private let openPeerContextAction: (Peer, ASDisplayNode, ContextGesture?) -> Void private let listNode: ListView private var peers: [Peer] = [] @@ -75,10 +76,11 @@ final class PeerInfoGroupsInCommonPaneNode: ASDisplayNode, PeerInfoPaneNode { return self.ready.get() } - init(context: AccountContext, peerId: PeerId, interaction: PeerInfoPaneInteraction, peers: [Peer]) { + init(context: AccountContext, peerId: PeerId, chatControllerInteraction: ChatControllerInteraction, openPeerContextAction: @escaping (Peer, ASDisplayNode, ContextGesture?) -> Void, peers: [Peer]) { self.context = context self.peerId = peerId - self.paneInteraction = interaction + self.chatControllerInteraction = chatControllerInteraction + self.openPeerContextAction = openPeerContextAction self.listNode = ListView() @@ -102,14 +104,14 @@ final class PeerInfoGroupsInCommonPaneNode: ASDisplayNode, PeerInfoPaneNode { } } - func update(size: CGSize, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { + func update(size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { let isFirstLayout = self.currentParams == nil self.currentParams = (size, isScrollingLockedAtTop, presentationData) transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(), size: size)) let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition) - self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: size, insets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0), headerInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0), scrollIndicatorInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0), duration: duration, curve: curve), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) + self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: size, insets: UIEdgeInsets(top: 0.0, left: sideInset, bottom: bottomInset, right: sideInset), duration: duration, curve: curve), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) self.listNode.scrollEnabled = !isScrollingLockedAtTop @@ -124,7 +126,9 @@ final class PeerInfoGroupsInCommonPaneNode: ASDisplayNode, PeerInfoPaneNode { entries.append(GroupsInCommonListEntry(index: entries.count, peer: peer)) } let transaction = preparedTransition(from: self.currentEntries, to: entries, context: self.context, presentationData: presentationData, openPeer: { [weak self] peer in - self?.paneInteraction.openPeer(peer) + self?.chatControllerInteraction.openPeer(peer.id, .default, nil) + }, openPeerContextAction: { [weak self] peer, node, gesture in + self?.openPeerContextAction(peer, node, gesture) }) self.currentEntries = entries self.enqueuedTransactions.append(transaction) @@ -156,13 +160,22 @@ final class PeerInfoGroupsInCommonPaneNode: ASDisplayNode, PeerInfoPaneNode { return nil } + func updateHiddenMedia() { + } + func transferVelocity(_ velocity: CGFloat) { + if velocity > 0.0 { + self.listNode.transferVelocity(velocity) + } } func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { return nil } + func addToTransitionSurface(view: UIView) { + } + func updateSelectedMessages(animated: Bool) { } } diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoListPaneNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoListPaneNode.swift new file mode 100644 index 0000000000..b021f9542c --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoListPaneNode.swift @@ -0,0 +1,125 @@ +import AsyncDisplayKit +import Display +import TelegramCore +import SyncCore +import SwiftSignalKit +import Postbox +import TelegramPresentationData +import AccountContext +import ContextUI +import PhotoResources +import TelegramUIPreferences + +final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode { + private let context: AccountContext + private let peerId: PeerId + private let chatControllerInteraction: ChatControllerInteraction + + private let listNode: ChatHistoryListNode + + private var currentParams: (size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData)? + + private let ready = Promise() + private var didSetReady: Bool = false + var isReady: Signal { + return self.ready.get() + } + + private let selectedMessagesPromise = Promise?>(nil) + private var selectedMessages: Set? { + didSet { + if self.selectedMessages != oldValue { + self.selectedMessagesPromise.set(.single(self.selectedMessages)) + } + } + } + + private var hiddenMediaDisposable: Disposable? + + init(context: AccountContext, chatControllerInteraction: ChatControllerInteraction, peerId: PeerId, tagMask: MessageTags) { + self.context = context + self.peerId = peerId + self.chatControllerInteraction = chatControllerInteraction + + self.selectedMessages = chatControllerInteraction.selectionState.flatMap { $0.selectedIds } + self.selectedMessagesPromise.set(.single(self.selectedMessages)) + + self.listNode = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), tagMask: tagMask, subject: nil, controllerInteraction: chatControllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), mode: .list(search: false, reversed: false)) + + super.init() + + self.listNode.preloadPages = true + self.addSubnode(self.listNode) + + self.ready.set(self.listNode.historyState.get() + |> take(1) + |> map { _ -> Bool in true }) + } + + deinit { + self.hiddenMediaDisposable?.dispose() + } + + func scrollToTop() -> Bool { + let offset = self.listNode.visibleContentOffset() + switch offset { + case let .known(value) where value <= CGFloat.ulpOfOne: + return false + default: + self.listNode.scrollToEndOfHistory() + return true + } + } + + func update(size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { + self.currentParams = (size, isScrollingLockedAtTop, presentationData) + + transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(), size: size)) + let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition) + self.listNode.updateLayout(transition: transition, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: size, insets: UIEdgeInsets(top: 0.0, left: sideInset, bottom: bottomInset, right: sideInset), duration: duration, curve: curve)) + self.listNode.scrollEnabled = !isScrollingLockedAtTop + } + + func findLoadedMessage(id: MessageId) -> Message? { + self.listNode.messageInCurrentHistoryView(id) + } + + func updateHiddenMedia() { + self.listNode.forEachItemNode { itemNode in + if let itemNode = itemNode as? ListMessageNode { + itemNode.updateHiddenMedia() + } + } + } + + func transferVelocity(_ velocity: CGFloat) { + if velocity > 0.0 { + self.listNode.transferVelocity(velocity) + } + } + + func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { + var transitionNode: (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? + self.listNode.forEachItemNode { itemNode in + if let itemNode = itemNode as? ListMessageNode { + if let result = itemNode.transitionNode(id: messageId, media: media) { + transitionNode = result + } + } + } + return transitionNode + } + + func addToTransitionSurface(view: UIView) { + self.view.addSubview(view) + } + + func updateSelectedMessages(animated: Bool) { + self.listNode.forEachItemNode { itemNode in + if let itemNode = itemNode as? ChatMessageItemView { + itemNode.updateSelectionState(animated: animated) + } + } + self.selectedMessages = self.chatControllerInteraction.selectionState.flatMap { $0.selectedIds } + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoVisualMediaPane.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift similarity index 82% rename from submodules/TelegramUI/TelegramUI/PeerInfoVisualMediaPane.swift rename to submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift index 395b578a67..f374730a20 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfoVisualMediaPane.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift @@ -16,17 +16,20 @@ private let mediaBadgeBackgroundColor = UIColor(white: 0.0, alpha: 0.6) private let mediaBadgeTextColor = UIColor.white private final class VisualMediaItemInteraction { - let openMessage: (MessageId) -> Void - let toggleSelection: (MessageId) -> Void + let openMessage: (Message) -> Void + let openMessageContextActions: (Message, ASDisplayNode, CGRect, ContextGesture?) -> Void + let toggleSelection: (MessageId, Bool) -> Void var hiddenMedia: [MessageId: [Media]] = [:] var selectedMessageIds: Set? init( - openMessage: @escaping (MessageId) -> Void, - toggleSelection: @escaping (MessageId) -> Void + openMessage: @escaping (Message) -> Void, + openMessageContextActions: @escaping (Message, ASDisplayNode, CGRect, ContextGesture?) -> Void, + toggleSelection: @escaping (MessageId, Bool) -> Void ) { self.openMessage = openMessage + self.openMessageContextActions = openMessageContextActions self.toggleSelection = toggleSelection } } @@ -68,7 +71,12 @@ private final class VisualMediaItemNode: ASDisplayNode { self.containerNode.addSubnode(self.imageNode) self.containerNode.addSubnode(self.mediaBadgeNode) - self.containerNode.isGestureEnabled = false + self.containerNode.activated = { [weak self] gesture in + guard let strongSelf = self, let item = strongSelf.item else { + return + } + strongSelf.interaction.openMessageContextActions(item.0.message, strongSelf.containerNode, strongSelf.containerNode.bounds, gesture) + } } deinit { @@ -79,13 +87,17 @@ private final class VisualMediaItemNode: ASDisplayNode { override func didLoad() { super.didLoad() - self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))) + self.view.addGestureRecognizer(TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))) } - @objc func tapGesture(_ recognizer: UITapGestureRecognizer) { + @objc func tapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { if case .ended = recognizer.state { - if let (item, _, _, _) = self.item { - self.interaction.openMessage(item.message.id) + if let (gesture, _) = recognizer.lastRecognizedGestureAndLocation { + if case .tap = gesture { + if let (item, _, _, _) = self.item { + self.interaction.openMessage(item.message) + } + } } } } @@ -132,8 +144,8 @@ private final class VisualMediaItemNode: ASDisplayNode { let isStreamable = isMediaStreamable(message: item.message, media: file) - let statusState: RadialStatusNodeState - if isStreamable { + let statusState: RadialStatusNodeState = .none + /*if isStreamable { statusState = .none } else { switch status { @@ -145,7 +157,7 @@ private final class VisualMediaItemNode: ASDisplayNode { case .Remote: statusState = .download(.white) } - } + }*/ switch statusState { case .none: @@ -234,7 +246,11 @@ private final class VisualMediaItemNode: ASDisplayNode { } else { let selectionNode = GridMessageSelectionNode(theme: theme, toggle: { [weak self] value in if let strongSelf = self, let messageId = strongSelf.item?.0.message.id { - strongSelf.interaction.toggleSelection(messageId) + var toggledValue = true + if let selectedMessageIds = strongSelf.interaction.selectedMessageIds, selectedMessageIds.contains(messageId) { + toggledValue = false + } + strongSelf.interaction.toggleSelection(messageId, toggledValue) } }) @@ -305,7 +321,7 @@ private final class VisualMediaItem { final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScrollViewDelegate { private let context: AccountContext private let peerId: PeerId - private let interaction: PeerInfoPaneInteraction + private let chatControllerInteraction: ChatControllerInteraction private let scrollNode: ASScrollNode @@ -314,7 +330,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro return self._itemInteraction! } - private var currentParams: (size: CGSize, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData)? + private var currentParams: (size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData)? private let ready = Promise() private var didSetReady: Bool = false @@ -334,24 +350,27 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro private var decelerationAnimator: ConstantDisplayLinkAnimator? - init(context: AccountContext, openMessage: @escaping (MessageId) -> Bool, peerId: PeerId, interaction: PeerInfoPaneInteraction) { + init(context: AccountContext, chatControllerInteraction: ChatControllerInteraction, peerId: PeerId) { self.context = context self.peerId = peerId - self.interaction = interaction + self.chatControllerInteraction = chatControllerInteraction self.scrollNode = ASScrollNode() super.init() self._itemInteraction = VisualMediaItemInteraction( - openMessage: { id in - openMessage(id) + openMessage: { [weak self] message in + self?.chatControllerInteraction.openMessage(message, .default) }, - toggleSelection: { id in - interaction.toggleMessageSelected(id) + openMessageContextActions: { [weak self] message, sourceNode, sourceRect, gesture in + self?.chatControllerInteraction.openMessageContextActions(message, sourceNode, sourceRect, gesture) + }, + toggleSelection: { [weak self] id, value in + self?.chatControllerInteraction.toggleMessagesSelection([id], value) } ) - self.itemInteraction.selectedMessageIds = self.interaction.selectedMessageIds + self.itemInteraction.selectedMessageIds = chatControllerInteraction.selectionState.flatMap { $0.selectedIds } self.scrollNode.view.showsVerticalScrollIndicator = false if #available(iOS 11.0, *) { @@ -416,8 +435,8 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro let wasFirstHistoryView = self.isFirstHistoryView self.isFirstHistoryView = false - if let (size, visibleHeight, isScrollingLockedAtTop, presentationData) = self.currentParams { - self.update(size: size, visibleHeight: visibleHeight, isScrollingLockedAtTop: isScrollingLockedAtTop, presentationData: presentationData, synchronous: wasFirstHistoryView, transition: .immediate) + if let (size, sideInset, bottomInset, visibleHeight, isScrollingLockedAtTop, presentationData) = self.currentParams { + self.update(size: size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, isScrollingLockedAtTop: isScrollingLockedAtTop, presentationData: presentationData, synchronous: wasFirstHistoryView, transition: .immediate) if !self.didSetReady { self.didSetReady = true self.ready.set(.single(true)) @@ -444,6 +463,12 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro return nil } + func updateHiddenMedia() { + for (_, itemNode) in self.visibleMediaItems { + itemNode.updateHiddenMedia() + } + } + func transferVelocity(_ velocity: CGFloat) { if velocity > 0.0 { //print("transferVelocity \(velocity)") @@ -493,15 +518,19 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro return nil } + func addToTransitionSurface(view: UIView) { + self.scrollNode.view.addSubview(view) + } + func updateSelectedMessages(animated: Bool) { - self.itemInteraction.selectedMessageIds = self.interaction.selectedMessageIds + self.itemInteraction.selectedMessageIds = self.chatControllerInteraction.selectionState.flatMap { $0.selectedIds } for (_, itemNode) in self.visibleMediaItems { itemNode.updateSelectionState(animated: animated) } } - func update(size: CGSize, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { - self.currentParams = (size, visibleHeight, isScrollingLockedAtTop, presentationData) + func update(size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { + self.currentParams = (size, sideInset, bottomInset, visibleHeight, isScrollingLockedAtTop, presentationData) transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: size)) @@ -510,10 +539,10 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro let itemSize: CGFloat = floor(size.width / CGFloat(itemsInRow)) let rowCount: Int = self.mediaItems.count / itemsInRow + (self.mediaItems.count % itemsInRow == 0 ? 0 : 1) - let contentHeight = CGFloat(rowCount + 1) * itemSpacing + CGFloat(rowCount) * itemSize + let contentHeight = CGFloat(rowCount + 1) * itemSpacing + CGFloat(rowCount) * itemSize + bottomInset self.scrollNode.view.contentSize = CGSize(width: size.width, height: contentHeight) - self.updateVisibleItems(size: size, visibleHeight: visibleHeight, theme: presentationData.theme, synchronousLoad: synchronous) + self.updateVisibleItems(size: size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, theme: presentationData.theme, synchronousLoad: synchronous) if isScrollingLockedAtTop { transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(), size: self.scrollNode.bounds.size)) @@ -527,8 +556,8 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro } func scrollViewDidScroll(_ scrollView: UIScrollView) { - if let (size, visibleHeight, _, presentationData) = self.currentParams { - self.updateVisibleItems(size: size, visibleHeight: visibleHeight, theme: presentationData.theme, synchronousLoad: false) + if let (size, sideInset, bottomInset, visibleHeight, _, presentationData) = self.currentParams { + self.updateVisibleItems(size: size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, theme: presentationData.theme, synchronousLoad: false) if scrollView.contentOffset.y >= scrollView.contentSize.height - scrollView.bounds.height * 2.0, let currentView = self.currentView, currentView.earlierId != nil { if !self.isRequestingView { @@ -539,10 +568,12 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro } } - private func updateVisibleItems(size: CGSize, visibleHeight: CGFloat, theme: PresentationTheme, synchronousLoad: Bool) { + private func updateVisibleItems(size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, theme: PresentationTheme, synchronousLoad: Bool) { + let availableWidth = size.width - sideInset * 2.0 + let itemSpacing: CGFloat = 1.0 - let itemsInRow: Int = max(3, min(6, Int(size.width / 140.0))) - let itemSize: CGFloat = floor(size.width / CGFloat(itemsInRow)) + let itemsInRow: Int = max(3, min(6, Int(availableWidth / 140.0))) + let itemSize: CGFloat = floor(availableWidth / CGFloat(itemsInRow)) let rowCount: Int = self.mediaItems.count / itemsInRow + (self.mediaItems.count % itemsInRow == 0 ? 0 : 1) @@ -562,8 +593,8 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro validIds.insert(stableId) let rowIndex = i / Int(itemsInRow) let columnIndex = i % Int(itemsInRow) - let itemOrigin = CGPoint(x: CGFloat(columnIndex) * (itemSize + itemSpacing), y: itemSpacing + CGFloat(rowIndex) * (itemSize + itemSpacing)) - let itemFrame = CGRect(origin: itemOrigin, size: CGSize(width: columnIndex == itemsInRow ? (size.width - itemOrigin.x) : itemSize, height: itemSize)) + let itemOrigin = CGPoint(x: sideInset + CGFloat(columnIndex) * (itemSize + itemSpacing), y: itemSpacing + CGFloat(rowIndex) * (itemSize + itemSpacing)) + let itemFrame = CGRect(origin: itemOrigin, size: CGSize(width: columnIndex == itemsInRow ? (availableWidth - itemOrigin.x) : itemSize, height: itemSize)) let itemNode: VisualMediaItemNode if let current = self.visibleMediaItems[stableId] { itemNode = current diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift new file mode 100644 index 0000000000..feb2c71926 --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift @@ -0,0 +1,306 @@ +import Foundation +import UIKit +import Postbox +import SyncCore +import TelegramCore +import SwiftSignalKit +import AccountContext +import PeerPresenceStatusManager +import TelegramStringFormatting +import TelegramPresentationData + +final class PeerInfoState { + let isEditing: Bool + let isSearching: Bool + let selectedMessageIds: Set? + + init( + isEditing: Bool, + isSearching: Bool, + selectedMessageIds: Set? + ) { + self.isEditing = isEditing + self.isSearching = isSearching + self.selectedMessageIds = selectedMessageIds + } + + func withIsEditing(_ isEditing: Bool) -> PeerInfoState { + return PeerInfoState( + isEditing: isEditing, + isSearching: self.isSearching, + selectedMessageIds: self.selectedMessageIds + ) + } + + func withSelectedMessageIds(_ selectedMessageIds: Set?) -> PeerInfoState { + return PeerInfoState( + isEditing: self.isEditing, + isSearching: self.isSearching, + selectedMessageIds: selectedMessageIds + ) + } +} + +final class PeerInfoScreenData { + let peer: Peer? + let cachedData: CachedPeerData? + let status: PeerInfoStatusData? + let notificationSettings: TelegramPeerNotificationSettings? + let globalNotificationSettings: GlobalNotificationSettings? + let isContact: Bool + let availablePanes: [PeerInfoPaneKey] + let groupsInCommon: [Peer]? + + init( + peer: Peer?, + cachedData: CachedPeerData?, + status: PeerInfoStatusData?, + notificationSettings: TelegramPeerNotificationSettings?, + globalNotificationSettings: GlobalNotificationSettings?, + isContact: Bool, + availablePanes: [PeerInfoPaneKey], + groupsInCommon: [Peer]? + ) { + self.peer = peer + self.cachedData = cachedData + self.status = status + self.notificationSettings = notificationSettings + self.globalNotificationSettings = globalNotificationSettings + self.isContact = isContact + self.availablePanes = availablePanes + self.groupsInCommon = groupsInCommon + } +} + +enum PeerInfoScreenInputData: Equatable { + case none + case user(userId: PeerId, secretChatId: PeerId?, isBot: Bool) +} + +func peerInfoAvailableMediaPanes(context: AccountContext, peerId: PeerId) -> Signal<[PeerInfoPaneKey], NoError> { + let tags: [(MessageTags, PeerInfoPaneKey)] = [ + (.photoOrVideo, .media), + (.file, .files), + (.music, .music), + (.voiceOrInstantVideo, .voice), + (.webPage, .links) + ] + return combineLatest(tags.map { tagAndKey -> Signal in + let (tag, key) = tagAndKey + return context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId), index: .upperBound, anchorIndex: .upperBound, count: 20, clipHoles: false, fixedCombinedReadStates: nil, tagMask: tag) + |> map { (view, _, _) -> PeerInfoPaneKey? in + if view.entries.isEmpty { + return nil + } else { + return key + } + } + }) + |> map { keys -> [PeerInfoPaneKey] in + return keys.compactMap { $0 } + } + |> distinctUntilChanged + /*return context.account.postbox.combinedView(keys: tags.map { (tag, _) -> PostboxViewKey in + return .historyTagInfo(peerId: peerId, tag: tag) + }) + |> map { view -> [PeerInfoPaneKey] in + return tags.compactMap { (tag, key) -> PeerInfoPaneKey? in + if let info = view.views[.historyTagInfo(peerId: peerId, tag: tag)] as? HistoryTagInfoView, !info.isEmpty { + return key + } else { + return nil + } + } + } + |> distinctUntilChanged*/ +} + +struct PeerInfoStatusData: Equatable { + var text: String + var isActivity: Bool +} + +func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) -> Signal { + return context.account.postbox.combinedView(keys: [.basicPeer(peerId)]) + |> map { view -> PeerInfoScreenInputData in + guard let peer = (view.views[.basicPeer(peerId)] as? BasicPeerView)?.peer else { + return .none + } + if let user = peer as? TelegramUser { + return .user(userId: user.id, secretChatId: nil, isBot: user.botInfo != nil) + } else { + preconditionFailure() + } + } + |> distinctUntilChanged + |> mapToSignal { inputData -> Signal in + switch inputData { + case .none: + return .single(PeerInfoScreenData( + peer: nil, + cachedData: nil, + status: nil, + notificationSettings: nil, + globalNotificationSettings: nil, + isContact: false, + availablePanes: [], + groupsInCommon: nil + )) + case let .user(peerId, secretChatId, isBot): + let groupsInCommonSignal: Signal<[Peer]?, NoError> + if isBot { + groupsInCommonSignal = .single([]) + } else { + groupsInCommonSignal = .single(nil) + |> then( + groupsInCommon(account: context.account, peerId: peerId) + |> map(Optional.init) + ) + } + enum StatusInputData: Equatable { + case none + case presence(TelegramUserPresence) + case bot + } + let status = Signal { subscriber in + class Manager { + var currentValue: TelegramUserPresence? = nil + var updateManager: QueueLocalObject? = nil + } + let manager = Atomic(value: Manager()) + let notify: () -> Void = { + let data = manager.with { manager -> PeerInfoStatusData? in + if let presence = manager.currentValue { + let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 + let (text, isActivity) = stringAndActivityForUserPresence(strings: strings, dateTimeFormat: dateTimeFormat, presence: presence, relativeTo: Int32(timestamp), expanded: true) + return PeerInfoStatusData(text: text, isActivity: isActivity) + } else { + return nil + } + } + subscriber.putNext(data) + } + let disposable = (context.account.viewTracker.peerView(peerId, updateData: false) + |> map { view -> StatusInputData in + guard let user = view.peers[peerId] as? TelegramUser else { + return .none + } + if user.isDeleted { + return .none + } + if user.botInfo != nil { + return .bot + } + if user.flags.contains(.isSupport) { + return .none + } + guard let presence = view.peerPresences[peerId] as? TelegramUserPresence else { + return .none + } + return .presence(presence) + } + |> distinctUntilChanged).start(next: { inputData in + switch inputData { + case .bot: + subscriber.putNext(PeerInfoStatusData(text: strings.Bot_GenericBotStatus, isActivity: false)) + default: + var presence: TelegramUserPresence? + if case let .presence(value) = inputData { + presence = value + } + let _ = manager.with { manager -> Void in + manager.currentValue = presence + if let presence = presence { + let updateManager: QueueLocalObject + if let current = manager.updateManager { + updateManager = current + } else { + updateManager = QueueLocalObject(queue: .mainQueue(), generate: { + return PeerPresenceStatusManager(update: { + notify() + }) + }) + } + updateManager.with { updateManager in + updateManager.reset(presence: presence) + } + } else if let _ = manager.updateManager { + manager.updateManager = nil + } + } + notify() + } + }) + return disposable + } + |> distinctUntilChanged + let globalNotificationsKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.globalNotifications])) + var combinedKeys: [PostboxViewKey] = [] + combinedKeys.append(globalNotificationsKey) + if let secretChatId = secretChatId { + combinedKeys.append(.peerChatState(peerId: peerId)) + } + return combineLatest( + context.account.viewTracker.peerView(peerId, updateData: true), + peerInfoAvailableMediaPanes(context: context, peerId: peerId), + context.account.postbox.combinedView(keys: combinedKeys), + status, + groupsInCommonSignal + ) + |> map { peerView, availablePanes, combinedView, status, groupsInCommon -> PeerInfoScreenData in + var globalNotificationSettings: GlobalNotificationSettings = .defaultSettings + if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView { + if let settings = preferencesView.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings { + globalNotificationSettings = settings + } + } + + var availablePanes = availablePanes + if let groupsInCommon = groupsInCommon, !groupsInCommon.isEmpty { + availablePanes.append(.groupsInCommon) + } + + return PeerInfoScreenData( + peer: peerView.peers[peerId], + cachedData: peerView.cachedData, + status: status, + notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings, + globalNotificationSettings: globalNotificationSettings, + isContact: peerView.peerIsContact, + availablePanes: availablePanes, + groupsInCommon: groupsInCommon + ) + } + } + } +} + +func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?) -> [PeerInfoHeaderButtonKey] { + var result: [PeerInfoHeaderButtonKey] = [] + if let user = peer as? TelegramUser { + result.append(.message) + var callsAvailable = false + if !user.isDeleted, user.botInfo == nil, !user.flags.contains(.isSupport), let cachedUserData = cachedData as? CachedUserData { + callsAvailable = cachedUserData.callsAvailable + } + if callsAvailable { + result.append(.call) + } + result.append(.mute) + + if !user.isDeleted, user.botInfo == nil && !user.flags.contains(.isSupport) { + result.append(.more) + } + } + return result +} + +func peerInfoCanEdit(peer: Peer?, cachedData: CachedPeerData?) -> Bool { + if let user = peer as? TelegramUser { + if user.isDeleted { + return false + } + return true + } + return false +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift new file mode 100644 index 0000000000..b601a275e4 --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift @@ -0,0 +1,1497 @@ +import Foundation +import UIKit +import AsyncDisplayKit +import Display +import Postbox +import SyncCore +import TelegramCore +import AvatarNode +import AccountContext +import SwiftSignalKit +import TelegramPresentationData +import PhotoResources +import PeerAvatarGalleryUI +import TelegramStringFormatting + +enum PeerInfoHeaderButtonKey: Hashable { + case message + case call + case mute + case more + case addMember +} + +enum PeerInfoHeaderButtonIcon { + case message + case call + case mute + case unmute + case more + case addMember +} + +final class PeerInfoHeaderButtonNode: HighlightableButtonNode { + let key: PeerInfoHeaderButtonKey + private let action: (PeerInfoHeaderButtonNode) -> Void + let containerNode: ASDisplayNode + private let backgroundNode: ASImageNode + private let textNode: ImmediateTextNode + + private var theme: PresentationTheme? + private var icon: PeerInfoHeaderButtonIcon? + + init(key: PeerInfoHeaderButtonKey, action: @escaping (PeerInfoHeaderButtonNode) -> Void) { + self.key = key + self.action = action + + self.containerNode = ASDisplayNode() + + self.backgroundNode = ASImageNode() + self.backgroundNode.displaysAsynchronously = false + self.backgroundNode.displayWithoutProcessing = true + + self.textNode = ImmediateTextNode() + self.textNode.displaysAsynchronously = false + + super.init() + + self.addSubnode(self.containerNode) + self.containerNode.addSubnode(self.backgroundNode) + self.containerNode.addSubnode(self.textNode) + + self.highligthedChanged = { [weak self] highlighted in + if let strongSelf = self { + if highlighted { + strongSelf.layer.removeAnimation(forKey: "opacity") + strongSelf.alpha = 0.4 + } else { + strongSelf.alpha = 1.0 + strongSelf.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) + } + } + } + + self.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside) + } + + @objc private func buttonPressed() { + self.action(self) + } + + func update(size: CGSize, text: String, icon: PeerInfoHeaderButtonIcon, isExpanded: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) { + if self.theme != presentationData.theme || self.icon != icon { + self.theme = presentationData.theme + self.icon = icon + self.backgroundNode.image = generateImage(CGSize(width: 40.0, height: 40.0), contextGenerator: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + context.setFillColor(presentationData.theme.list.itemAccentColor.cgColor) + context.fillEllipse(in: CGRect(origin: CGPoint(), size: size)) + context.setBlendMode(.normal) + context.setFillColor(presentationData.theme.list.itemCheckColors.foregroundColor.cgColor) + let imageName: String + switch icon { + case .message: + imageName = "Peer Info/ButtonMessage" + case .call: + imageName = "Peer Info/ButtonCall" + case .mute: + imageName = "Peer Info/ButtonMute" + case .unmute: + imageName = "Peer Info/ButtonUnmute" + case .more: + imageName = "Peer Info/ButtonMore" + case .addMember: + imageName = "Peer Info/ButtonAddMember" + } + if let image = UIImage(bundleImageName: imageName) { + let imageRect = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size) + context.clip(to: imageRect, mask: image.cgImage!) + context.fill(imageRect) + } + }) + } + + self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(12.0), textColor: presentationData.theme.list.itemAccentColor) + let titleSize = self.textNode.updateLayout(CGSize(width: 120.0, height: .greatestFiniteMagnitude)) + + transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(), size: size)) + transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size)) + transition.updateFrameAdditiveToCenter(node: self.textNode, frame: CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: size.height + 6.0), size: titleSize)) + transition.updateAlpha(node: self.textNode, alpha: isExpanded ? 0.0 : 1.0) + } +} + +final class PeerInfoHeaderNavigationTransition { + let sourceNavigationBar: NavigationBar + let sourceTitleView: ChatTitleView + let sourceTitleFrame: CGRect + let sourceSubtitleFrame: CGRect + let fraction: CGFloat + + init(sourceNavigationBar: NavigationBar, sourceTitleView: ChatTitleView, sourceTitleFrame: CGRect, sourceSubtitleFrame: CGRect, fraction: CGFloat) { + self.sourceNavigationBar = sourceNavigationBar + self.sourceTitleView = sourceTitleView + self.sourceTitleFrame = sourceTitleFrame + self.sourceSubtitleFrame = sourceSubtitleFrame + self.fraction = fraction + } +} + +enum PeerInfoAvatarListItem: Equatable { + case topImage([ImageRepresentationWithReference]) + case image(TelegramMediaImageReference?, [ImageRepresentationWithReference]) + + var id: WrappedMediaResourceId { + switch self { + case let .topImage(representations): + let representation = largestImageRepresentation(representations.map { $0.representation }) ?? representations[representations.count - 1].representation + return WrappedMediaResourceId(representation.resource.id) + case let .image(_, representations): + let representation = largestImageRepresentation(representations.map { $0.representation }) ?? representations[representations.count - 1].representation + return WrappedMediaResourceId(representation.resource.id) + } + } +} + +final class PeerInfoAvatarListItemNode: ASDisplayNode { + let imageNode: TransformImageNode + + let isReady = Promise() + private var didSetReady: Bool = false + + init(context: AccountContext, item: PeerInfoAvatarListItem) { + self.imageNode = TransformImageNode() + + super.init() + + self.addSubnode(self.imageNode) + let representations: [ImageRepresentationWithReference] + switch item { + case let .topImage(topRepresentations): + representations = topRepresentations + case let .image(_, imageRepresentations): + representations = imageRepresentations + } + self.imageNode.setSignal(chatAvatarGalleryPhoto(account: context.account, representations: representations, autoFetchFullSize: true), dispatchOnDisplayLink: false) + + self.imageNode.imageUpdated = { [weak self] _ in + guard let strongSelf = self else { + return + } + if !strongSelf.didSetReady { + strongSelf.didSetReady = true + strongSelf.isReady.set(.single(true)) + } + } + } + + func update(size: CGSize, transition: ContainedViewLayoutTransition) { + let imageSize = CGSize(width: min(size.width, size.height), height: min(size.width, size.height)) + let makeLayout = self.imageNode.asyncLayout() + let applyLayout = makeLayout(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets())) + let _ = applyLayout() + transition.updateFrame(node: self.imageNode, frame: CGRect(origin: CGPoint(x: floor((size.width - imageSize.width) / 2.0), y: floor((size.height - imageSize.height) / 2.0)), size: imageSize)) + } +} + +final class PeerInfoAvatarListContainerNode: ASDisplayNode { + private let context: AccountContext + + let controlsContainerNode: ASDisplayNode + let controlsContainerTransformNode: ASDisplayNode + let shadowNode: ASDisplayNode + + let contentNode: ASDisplayNode + private(set) var galleryEntries: [AvatarGalleryEntry] = [] + private var items: [PeerInfoAvatarListItem] = [] + private var itemNodes: [WrappedMediaResourceId: PeerInfoAvatarListItemNode] = [:] + private var currentIndex: Int = 0 + private var transitionFraction: CGFloat = 0.0 + + private var validLayout: CGSize? + + private let disposable = MetaDisposable() + private var initializedList = false + + let isReady = Promise() + private var didSetReady = false + + var currentItemNode: PeerInfoAvatarListItemNode? { + if self.currentIndex >= 0 && self.currentIndex < self.items.count { + return self.itemNodes[self.items[self.currentIndex].id] + } else { + return nil + } + } + + init(context: AccountContext) { + self.context = context + + self.contentNode = ASDisplayNode() + + self.controlsContainerNode = ASDisplayNode() + self.controlsContainerNode.isUserInteractionEnabled = false + + self.controlsContainerTransformNode = ASDisplayNode() + self.controlsContainerTransformNode.isUserInteractionEnabled = false + + self.shadowNode = ASDisplayNode() + //self.shadowNode.backgroundColor = .green + + super.init() + + self.backgroundColor = .black + + self.addSubnode(self.contentNode) + + self.controlsContainerNode.addSubnode(self.shadowNode) + self.controlsContainerTransformNode.addSubnode(self.controlsContainerNode) + self.addSubnode(self.controlsContainerTransformNode) + + self.view.disablesInteractiveTransitionGestureRecognizer = true + self.view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))) + } + + deinit { + self.disposable.dispose() + } + + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + return super.hitTest(point, with: event) + } + + func selectFirstItem() { + self.currentIndex = 0 + if let size = self.validLayout { + self.updateItems(size: size, transition: .immediate) + } + } + + @objc private func panGesture(_ recognizer: UIPanGestureRecognizer) { + switch recognizer.state { + case .changed: + let translation = recognizer.translation(in: self.view) + var transitionFraction = translation.x / self.bounds.width + if self.currentIndex <= 0 { + transitionFraction = min(0.0, transitionFraction) + } + if self.currentIndex >= self.items.count - 1 { + transitionFraction = max(0.0, transitionFraction) + } + self.transitionFraction = transitionFraction + if let size = self.validLayout { + self.updateItems(size: size, transition: .animated(duration: 0.3, curve: .spring)) + } + case .cancelled, .ended: + let translation = recognizer.translation(in: self.view) + let velocity = recognizer.velocity(in: self.view) + var directionIsToRight = false + if abs(velocity.x) > 10.0 { + directionIsToRight = velocity.x < 0.0 + } else { + directionIsToRight = translation.x > self.bounds.width / 2.0 + } + var updatedIndex = self.currentIndex + if directionIsToRight { + updatedIndex = min(updatedIndex + 1, self.items.count - 1) + } else { + updatedIndex = max(updatedIndex - 1, 0) + } + self.currentIndex = updatedIndex + self.transitionFraction = 0.0 + if let size = self.validLayout { + self.updateItems(size: size, transition: .animated(duration: 0.3, curve: .spring)) + } + default: + break + } + } + + func update(size: CGSize, peer: Peer?, transition: ContainedViewLayoutTransition) { + self.validLayout = size + if let peer = peer, !self.initializedList { + self.initializedList = true + self.disposable.set((fetchedAvatarGalleryEntries(account: self.context.account, peer: peer) + |> deliverOnMainQueue).start(next: { [weak self] entries in + guard let strongSelf = self else { + return + } + var items: [PeerInfoAvatarListItem] = [] + for entry in entries { + switch entry { + case let .topImage(representations, _): + items.append(.topImage(representations)) + case let .image(reference, representations, _, _, _, _): + items.append(.image(reference, representations)) + } + } + strongSelf.galleryEntries = entries + strongSelf.items = items + if let size = strongSelf.validLayout { + strongSelf.updateItems(size: size, transition: .immediate) + } + if items.isEmpty { + if !strongSelf.didSetReady { + strongSelf.didSetReady = true + strongSelf.isReady.set(.single(true)) + } + } + })) + } + self.updateItems(size: size, transition: transition) + } + + private func updateItems(size: CGSize, transition: ContainedViewLayoutTransition) { + var validIds: [WrappedMediaResourceId] = [] + var addedItemNodesForAdditiveTransition: [PeerInfoAvatarListItemNode] = [] + var additiveTransitionOffset: CGFloat = 0.0 + if self.currentIndex >= 0 && self.currentIndex < self.items.count { + for i in max(0, self.currentIndex - 1) ... min(self.currentIndex + 1, self.items.count - 1) { + validIds.append(self.items[i].id) + let itemNode: PeerInfoAvatarListItemNode + var wasAdded = false + if let current = self.itemNodes[self.items[i].id] { + itemNode = current + } else { + wasAdded = true + itemNode = PeerInfoAvatarListItemNode(context: self.context, item: self.items[i]) + self.itemNodes[self.items[i].id] = itemNode + self.contentNode.addSubnode(itemNode) + } + let indexOffset = CGFloat(i - self.currentIndex) + let itemFrame = CGRect(origin: CGPoint(x: indexOffset * size.width + self.transitionFraction * size.width - size.width / 2.0, y: -size.height / 2.0), size: size) + + if wasAdded { + addedItemNodesForAdditiveTransition.append(itemNode) + itemNode.frame = itemFrame + itemNode.update(size: size, transition: .immediate) + } else { + additiveTransitionOffset = itemNode.frame.minX - itemFrame.minX + transition.updateFrame(node: itemNode, frame: itemFrame) + itemNode.update(size: size, transition: transition) + } + } + } + for itemNode in addedItemNodesForAdditiveTransition { + transition.animatePositionAdditive(node: itemNode, offset: CGPoint(x: additiveTransitionOffset, y: 0.0)) + } + var removeIds: [WrappedMediaResourceId] = [] + for (id, _) in self.itemNodes { + if !validIds.contains(id) { + removeIds.append(id) + } + } + for id in removeIds { + if let itemNode = self.itemNodes.removeValue(forKey: id) { + itemNode.removeFromSupernode() + } + } + + if let item = self.items.first, let itemNode = self.itemNodes[item.id] { + if !self.didSetReady { + self.didSetReady = true + self.isReady.set(itemNode.isReady.get()) + } + } + } +} + +final class PeerInfoAvatarTransformContainerNode: ASDisplayNode { + let context: AccountContext + let avatarNode: AvatarNode + + var tapped: (() -> Void)? + + private var isFirstAvatarLoading = true + + init(context: AccountContext) { + self.context = context + let avatarFont = avatarPlaceholderFont(size: floor(100.0 * 16.0 / 37.0)) + self.avatarNode = AvatarNode(font: avatarFont) + + super.init() + + self.addSubnode(self.avatarNode) + self.avatarNode.frame = CGRect(origin: CGPoint(x: -50.0, y: -50.0), size: CGSize(width: 100.0, height: 100.0)) + + self.avatarNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))) + } + + @objc private func tapGesture(_ recognizer: UITapGestureRecognizer) { + if case .ended = recognizer.state { + self.tapped?() + } + } + + func update(peer: Peer?, theme: PresentationTheme) { + if let peer = peer { + var overrideImage: AvatarNodeImageOverride? + if peer.isDeleted { + overrideImage = .deletedIcon + } + self.avatarNode.setPeer(context: self.context, theme: theme, peer: peer, overrideImage: overrideImage, synchronousLoad: self.isFirstAvatarLoading, displayDimensions: CGSize(width: 100.0, height: 100.0)) + self.isFirstAvatarLoading = false + } + } +} + +final class PeerInfoEditingAvatarNode: ASDisplayNode { + let context: AccountContext + let avatarNode: AvatarNode + + var tapped: (() -> Void)? + + init(context: AccountContext) { + self.context = context + let avatarFont = avatarPlaceholderFont(size: floor(100.0 * 16.0 / 37.0)) + self.avatarNode = AvatarNode(font: avatarFont) + + super.init() + + self.addSubnode(self.avatarNode) + self.avatarNode.frame = CGRect(origin: CGPoint(x: -50.0, y: -50.0), size: CGSize(width: 100.0, height: 100.0)) + + self.avatarNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))) + } + + @objc private func tapGesture(_ recognizer: UITapGestureRecognizer) { + if case .ended = recognizer.state { + self.tapped?() + } + } + + func update(peer: Peer?, theme: PresentationTheme) { + if let peer = peer { + self.avatarNode.setPeer(context: self.context, theme: theme, peer: peer, synchronousLoad: false, displayDimensions: CGSize(width: 100.0, height: 100.0)) + } + } +} + +final class PeerInfoAvatarListNode: ASDisplayNode { + let avatarContainerNode: PeerInfoAvatarTransformContainerNode + let listContainerTransformNode: ASDisplayNode + let listContainerNode: PeerInfoAvatarListContainerNode + + let isReady = Promise() + + init(context: AccountContext, readyWhenGalleryLoads: Bool) { + self.avatarContainerNode = PeerInfoAvatarTransformContainerNode(context: context) + self.listContainerTransformNode = ASDisplayNode() + self.listContainerNode = PeerInfoAvatarListContainerNode(context: context) + self.listContainerNode.clipsToBounds = true + self.listContainerNode.isHidden = true + + super.init() + + self.addSubnode(self.avatarContainerNode) + self.listContainerTransformNode.addSubnode(self.listContainerNode) + self.addSubnode(self.listContainerTransformNode) + + let avatarReady = self.avatarContainerNode.avatarNode.ready + |> mapToSignal { _ -> Signal in + return .complete() + } + |> then(.single(true)) + + let galleryReady = self.listContainerNode.isReady.get() + |> filter { $0 } + |> take(1) + + let combinedSignal: Signal + if readyWhenGalleryLoads { + combinedSignal = combineLatest(queue: .mainQueue(), + avatarReady, + galleryReady + ) + |> map { lhs, rhs in + return lhs && rhs + } + } else { + combinedSignal = avatarReady + } + + self.isReady.set(combinedSignal + |> filter { $0 } + |> take(1)) + } + + func update(size: CGSize, isExpanded: Bool, peer: Peer?, theme: PresentationTheme, transition: ContainedViewLayoutTransition) { + self.avatarContainerNode.update(peer: peer, theme: theme) + } + + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + if !self.listContainerNode.isHidden { + if let result = self.listContainerNode.view.hitTest(self.view.convert(point, to: self.listContainerNode.view), with: event) { + return result + } + } else { + if let result = self.avatarContainerNode.avatarNode.view.hitTest(self.view.convert(point, to: self.avatarContainerNode.avatarNode.view), with: event) { + return result + } + } + + return super.hitTest(point, with: event) + } + + func animateAvatarCollapse(transition: ContainedViewLayoutTransition) { + if let currentItemNode = self.listContainerNode.currentItemNode, let avatarCopyView = self.avatarContainerNode.avatarNode.view.snapshotContentTree(), case let .animated(duration, curve) = transition { + avatarCopyView.center = currentItemNode.imageNode.position + currentItemNode.view.addSubview(avatarCopyView) + let scale = currentItemNode.imageNode.bounds.height / avatarCopyView.bounds.height + avatarCopyView.layer.transform = CATransform3DMakeScale(scale, scale, scale) + avatarCopyView.alpha = 0.0 + transition.updateAlpha(layer: avatarCopyView.layer, alpha: 1.0, completion: { [weak avatarCopyView] _ in + Queue.mainQueue().after(0.1, { + avatarCopyView?.removeFromSuperview() + }) + }) + } + } +} + +final class PeerInfoHeaderNavigationButton: HighlightableButtonNode { + private let regularTextNode: ImmediateTextNode + private let whiteTextNode: ImmediateTextNode + private let iconNode: ASImageNode + + private var key: PeerInfoHeaderNavigationButtonKey? + private var theme: PresentationTheme? + + var isWhite: Bool = false { + didSet { + if self.isWhite != oldValue { + self.regularTextNode.isHidden = self.isWhite + self.whiteTextNode.isHidden = !self.isWhite + } + } + } + + var action: (() -> Void)? + + override init() { + self.regularTextNode = ImmediateTextNode() + self.whiteTextNode = ImmediateTextNode() + self.whiteTextNode.isHidden = true + + self.iconNode = ASImageNode() + self.iconNode.displaysAsynchronously = false + self.iconNode.displayWithoutProcessing = true + + super.init() + + self.addSubnode(self.regularTextNode) + self.addSubnode(self.whiteTextNode) + self.addSubnode(self.iconNode) + + self.addTarget(self, action: #selector(self.pressed), forControlEvents: .touchUpInside) + } + + @objc private func pressed() { + self.action?() + } + + func update(key: PeerInfoHeaderNavigationButtonKey, presentationData: PresentationData) -> CGSize { + let textSize: CGSize + if self.key != key || self.theme !== presentationData.theme { + self.key = key + self.theme = presentationData.theme + + let text: String + var icon: UIImage? + var isBold = false + switch key { + case .edit: + text = presentationData.strings.Common_Edit + case .done, .cancel, .selectionDone: + text = presentationData.strings.Common_Done + isBold = true + case .select: + text = presentationData.strings.Common_Select + case .search: + text = "" + icon = PresentationResourcesRootController.navigationCompactSearchIcon(presentationData.theme) + } + + let font: UIFont = isBold ? Font.semibold(17.0) : Font.regular(17.0) + + self.regularTextNode.attributedText = NSAttributedString(string: text, font: font, textColor: presentationData.theme.rootController.navigationBar.accentTextColor) + self.whiteTextNode.attributedText = NSAttributedString(string: text, font: font, textColor: .white) + self.iconNode.image = icon + + textSize = self.regularTextNode.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude)) + let _ = self.whiteTextNode.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude)) + } else { + textSize = self.regularTextNode.bounds.size + } + + let inset: CGFloat = 0.0 + let height: CGFloat = 44.0 + + let textFrame = CGRect(origin: CGPoint(x: inset, y: floor((height - textSize.height) / 2.0)), size: textSize) + self.regularTextNode.frame = textFrame + self.whiteTextNode.frame = textFrame + + if let image = self.iconNode.image { + self.iconNode.frame = CGRect(origin: CGPoint(x: inset, y: floor((height - image.size.height) / 2.0)), size: image.size) + + return CGSize(width: image.size.width + inset * 2.0, height: height) + } else { + return CGSize(width: textSize.width + inset * 2.0, height: height) + } + } +} + +enum PeerInfoHeaderNavigationButtonKey { + case edit + case done + case cancel + case select + case selectionDone + case search +} + +struct PeerInfoHeaderNavigationButtonSpec: Equatable { + let key: PeerInfoHeaderNavigationButtonKey + let isForExpandedView: Bool +} + +final class PeerInfoHeaderNavigationButtonContainerNode: ASDisplayNode { + private var buttonNodes: [PeerInfoHeaderNavigationButtonKey: PeerInfoHeaderNavigationButton] = [:] + + private var currentButtons: [PeerInfoHeaderNavigationButtonSpec] = [] + + var isWhite: Bool = false { + didSet { + if self.isWhite != oldValue { + for (_, buttonNode) in self.buttonNodes { + buttonNode.isWhite = self.isWhite + } + } + } + } + + var performAction: ((PeerInfoHeaderNavigationButtonKey) -> Void)? + + override init() { + super.init() + } + + func update(size: CGSize, presentationData: PresentationData, buttons: [PeerInfoHeaderNavigationButtonSpec], expandFraction: CGFloat, transition: ContainedViewLayoutTransition) { + let maximumExpandOffset: CGFloat = 14.0 + let expandOffset: CGFloat = -expandFraction * maximumExpandOffset + if self.currentButtons != buttons { + self.currentButtons = buttons + + var nextRegularButtonOrigin = size.width - 16.0 + var nextExpandedButtonOrigin = size.width - 16.0 + for spec in buttons.reversed() { + let buttonNode: PeerInfoHeaderNavigationButton + var wasAdded = false + if let current = self.buttonNodes[spec.key] { + buttonNode = current + } else { + wasAdded = true + buttonNode = PeerInfoHeaderNavigationButton() + self.buttonNodes[spec.key] = buttonNode + self.addSubnode(buttonNode) + buttonNode.isWhite = self.isWhite + buttonNode.action = { [weak self] in + self?.performAction?(spec.key) + } + } + let buttonSize = buttonNode.update(key: spec.key, presentationData: presentationData) + var nextButtonOrigin = spec.isForExpandedView ? nextExpandedButtonOrigin : nextRegularButtonOrigin + let buttonFrame = CGRect(origin: CGPoint(x: nextButtonOrigin - buttonSize.width, y: expandOffset + (spec.isForExpandedView ? maximumExpandOffset : 0.0)), size: buttonSize) + nextButtonOrigin -= buttonSize.width + 4.0 + if spec.isForExpandedView { + nextExpandedButtonOrigin = nextButtonOrigin + } else { + nextRegularButtonOrigin = nextButtonOrigin + } + if wasAdded { + buttonNode.frame = buttonFrame + } else { + transition.updateFrameAdditiveToCenter(node: buttonNode, frame: buttonFrame) + } + let alphaFactor: CGFloat = spec.isForExpandedView ? expandFraction : (1.0 - expandFraction) + transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor) + } + var removeKeys: [PeerInfoHeaderNavigationButtonKey] = [] + for (key, _) in self.buttonNodes { + if !buttons.contains(where: { $0.key == key }) { + removeKeys.append(key) + } + } + for key in removeKeys { + if let buttonNode = self.buttonNodes.removeValue(forKey: key) { + buttonNode.removeFromSupernode() + } + } + } else { + var nextRegularButtonOrigin = size.width - 16.0 + var nextExpandedButtonOrigin = size.width - 16.0 + for spec in buttons.reversed() { + if let buttonNode = self.buttonNodes[spec.key] { + let buttonSize = buttonNode.bounds.size + var nextButtonOrigin = spec.isForExpandedView ? nextExpandedButtonOrigin : nextRegularButtonOrigin + let buttonFrame = CGRect(origin: CGPoint(x: nextButtonOrigin - buttonSize.width, y: expandOffset + (spec.isForExpandedView ? maximumExpandOffset : 0.0)), size: buttonSize) + nextButtonOrigin -= buttonSize.width + 4.0 + if spec.isForExpandedView { + nextExpandedButtonOrigin = nextButtonOrigin + } else { + nextRegularButtonOrigin = nextButtonOrigin + } + transition.updateFrameAdditiveToCenter(node: buttonNode, frame: buttonFrame) + let alphaFactor: CGFloat = spec.isForExpandedView ? expandFraction : (1.0 - expandFraction) + transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor) + } + } + } + } +} + +final class PeerInfoHeaderRegularContentNode: ASDisplayNode { + +} + +enum PeerInfoHeaderTextFieldNodeKey { + case firstName + case lastName + case title + case description +} + +protocol PeerInfoHeaderTextFieldNode: ASDisplayNode { + var text: String { get } + + func update(width: CGFloat, safeInset: CGFloat, hasPrevious: Bool, placeholder: String, isEnabled: Bool, presentationData: PresentationData, updateText: String?) -> CGFloat +} + +final class PeerInfoHeaderSingleLineTextFieldNode: ASDisplayNode, PeerInfoHeaderTextFieldNode { + private let textNode: TextFieldNode + private let topSeparator: ASDisplayNode + + private var theme: PresentationTheme? + + var text: String { + return self.textNode.textField.text ?? "" + } + + override init() { + self.textNode = TextFieldNode() + self.topSeparator = ASDisplayNode() + + super.init() + + self.addSubnode(self.textNode) + self.addSubnode(self.topSeparator) + } + + func update(width: CGFloat, safeInset: CGFloat, hasPrevious: Bool, placeholder: String, isEnabled: Bool, presentationData: PresentationData, updateText: String?) -> CGFloat { + if self.theme !== presentationData.theme { + self.theme = presentationData.theme + self.textNode.textField.textColor = presentationData.theme.list.itemPrimaryTextColor + //self.textNode.textField.keyboardAppearance = presentationData.theme.keyboardAppearance + self.textNode.textField.tintColor = presentationData.theme.list.itemAccentColor + } + + let attributedPlaceholderText = NSAttributedString(string: placeholder, font: Font.regular(17.0), textColor: presentationData.theme.list.itemPlaceholderTextColor) + if self.textNode.textField.attributedPlaceholder == nil || !self.textNode.textField.attributedPlaceholder!.isEqual(to: attributedPlaceholderText) { + self.textNode.textField.attributedPlaceholder = attributedPlaceholderText + self.textNode.textField.accessibilityHint = attributedPlaceholderText.string + } + + if let updateText = updateText { + self.textNode.textField.text = updateText + } + + self.topSeparator.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + self.topSeparator.frame = CGRect(origin: CGPoint(x: safeInset + (hasPrevious ? 16.0 : 0.0), y: 0.0), size: CGSize(width: width, height: UIScreenPixel)) + + let height: CGFloat = 44.0 + + self.textNode.frame = CGRect(origin: CGPoint(x: safeInset + 16.0, y: floor((height - 40.0) / 2.0)), size: CGSize(width: max(1.0, width - 16.0 * 2.0), height: 40.0)) + + self.textNode.isUserInteractionEnabled = isEnabled + self.textNode.alpha = isEnabled ? 1.0 : 0.6 + + return height + } +} + +/*final class PeerInfoHeaderMultiLineTextFieldNode: ASDisplayNode, PeerInfoHeaderTextFieldNode { + private let textNode: TextFieldNode + private let topSeparator: ASDisplayNode + + override init() { + self.textNode = TextFieldNode() + self.topSeparator = ASDisplayNode() + + super.init() + } + + func update(width: CGFloat, safeInset: CGFloat) -> CGFloat { + return 44.0 + } +}*/ + +final class PeerInfoHeaderEditingContentNode: ASDisplayNode { + private let context: AccountContext + let avatarNode: PeerInfoEditingAvatarNode + + var itemNodes: [PeerInfoHeaderTextFieldNodeKey: PeerInfoHeaderTextFieldNode] = [:] + + init(context: AccountContext) { + self.context = context + self.avatarNode = PeerInfoEditingAvatarNode(context: context) + + super.init() + + self.addSubnode(self.avatarNode) + } + + func editingTextForKey(_ key: PeerInfoHeaderTextFieldNodeKey) -> String? { + return self.itemNodes[key]?.text + } + + func update(width: CGFloat, safeInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, peer: Peer?, isContact: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) -> CGFloat { + let avatarSize: CGFloat = 100.0 + let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 10.0), size: CGSize(width: avatarSize, height: avatarSize)) + transition.updateFrameAdditiveToCenter(node: self.avatarNode, frame: CGRect(origin: avatarFrame.center, size: CGSize())) + + var contentHeight: CGFloat = statusBarHeight + 10.0 + 100.0 + 20.0 + + var fieldKeys: [PeerInfoHeaderTextFieldNodeKey] = [] + if let user = peer as? TelegramUser { + if !user.isDeleted { + fieldKeys.append(.firstName) + if user.botInfo == nil { + fieldKeys.append(.lastName) + } + } + } + var hasPrevious = false + for key in fieldKeys { + let itemNode: PeerInfoHeaderTextFieldNode + var updateText: String? + if let current = self.itemNodes[key] { + itemNode = current + } else { + switch key { + case .firstName: + updateText = (peer as? TelegramUser)?.firstName ?? "" + case .lastName: + updateText = (peer as? TelegramUser)?.lastName ?? "" + case .title: + updateText = (peer as? TelegramUser)?.debugDisplayTitle ?? "" + case .description: + break + } + itemNode = PeerInfoHeaderSingleLineTextFieldNode() + self.itemNodes[key] = itemNode + self.addSubnode(itemNode) + } + let placeholder: String + var isEnabled = true + switch key { + case .firstName: + placeholder = "First Name" + isEnabled = isContact + case .lastName: + placeholder = "Last Name" + isEnabled = isContact + case .title: + placeholder = "Title" + case .description: + placeholder = "Description" + } + let itemHeight = itemNode.update(width: width, safeInset: safeInset, hasPrevious: hasPrevious, placeholder: placeholder, isEnabled: isEnabled, presentationData: presentationData, updateText: updateText) + transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: itemHeight))) + contentHeight += itemHeight + hasPrevious = true + } + var removeKeys: [PeerInfoHeaderTextFieldNodeKey] = [] + for (key, _) in self.itemNodes { + if !fieldKeys.contains(key) { + removeKeys.append(key) + } + } + for key in removeKeys { + if let itemNode = self.itemNodes.removeValue(forKey: key) { + itemNode.removeFromSupernode() + } + } + + return contentHeight + } +} + +final class PeerInfoHeaderNode: ASDisplayNode { + private var context: AccountContext + private var presentationData: PresentationData? + + private(set) var isAvatarExpanded: Bool + + let avatarListNode: PeerInfoAvatarListNode + + let regularContentNode: PeerInfoHeaderRegularContentNode + let editingContentNode: PeerInfoHeaderEditingContentNode + let titleNodeContainer: ASDisplayNode + let titleNodeRawContainer: ASDisplayNode + let titleNode: ImmediateTextNode + let titleCredibilityIconNode: ASImageNode + let subtitleNodeContainer: ASDisplayNode + let subtitleNodeRawContainer: ASDisplayNode + let subtitleNode: ImmediateTextNode + private var buttonNodes: [PeerInfoHeaderButtonKey: PeerInfoHeaderButtonNode] = [:] + private let backgroundNode: ASDisplayNode + private let expandedBackgroundNode: ASDisplayNode + let separatorNode: ASDisplayNode + let navigationButtonContainer: PeerInfoHeaderNavigationButtonContainerNode + + var performButtonAction: ((PeerInfoHeaderButtonKey) -> Void)? + var requestAvatarExpansion: (([AvatarGalleryEntry], (ASDisplayNode, CGRect, () -> (UIView?, UIView?))) -> Void)? + + var navigationTransition: PeerInfoHeaderNavigationTransition? + + init(context: AccountContext, avatarInitiallyExpanded: Bool) { + self.context = context + self.isAvatarExpanded = avatarInitiallyExpanded + + self.avatarListNode = PeerInfoAvatarListNode(context: context, readyWhenGalleryLoads: avatarInitiallyExpanded) + + self.titleNodeContainer = ASDisplayNode() + self.titleNodeRawContainer = ASDisplayNode() + self.titleNode = ImmediateTextNode() + self.titleNode.displaysAsynchronously = false + + self.titleCredibilityIconNode = ASImageNode() + self.titleCredibilityIconNode.displaysAsynchronously = false + self.titleCredibilityIconNode.displayWithoutProcessing = true + self.titleNode.addSubnode(self.titleCredibilityIconNode) + + self.subtitleNodeContainer = ASDisplayNode() + self.subtitleNodeRawContainer = ASDisplayNode() + self.subtitleNode = ImmediateTextNode() + self.subtitleNode.displaysAsynchronously = false + + self.regularContentNode = PeerInfoHeaderRegularContentNode() + self.editingContentNode = PeerInfoHeaderEditingContentNode(context: context) + self.editingContentNode.alpha = 0.0 + + self.navigationButtonContainer = PeerInfoHeaderNavigationButtonContainerNode() + + self.backgroundNode = ASDisplayNode() + self.backgroundNode.isLayerBacked = true + self.expandedBackgroundNode = ASDisplayNode() + self.expandedBackgroundNode.isLayerBacked = true + + self.separatorNode = ASDisplayNode() + self.separatorNode.isLayerBacked = true + + super.init() + + self.addSubnode(self.backgroundNode) + self.addSubnode(self.expandedBackgroundNode) + self.addSubnode(self.separatorNode) + self.titleNodeContainer.addSubnode(self.titleNode) + self.regularContentNode.addSubnode(self.titleNodeContainer) + self.subtitleNodeContainer.addSubnode(self.subtitleNode) + self.regularContentNode.addSubnode(self.subtitleNodeContainer) + self.regularContentNode.addSubnode(self.avatarListNode) + self.addSubnode(self.regularContentNode) + self.addSubnode(self.editingContentNode) + self.addSubnode(self.navigationButtonContainer) + + self.avatarListNode.avatarContainerNode.tapped = { [weak self] in + guard let strongSelf = self else { + return + } + let avatarNode = strongSelf.avatarListNode.avatarContainerNode.avatarNode + strongSelf.requestAvatarExpansion?(strongSelf.avatarListNode.listContainerNode.galleryEntries, (avatarNode, avatarNode.bounds, { [weak avatarNode] in + return (avatarNode?.view.snapshotContentTree(unhide: true), nil) + })) + } + } + + func updateAvatarIsHidden(_ isHidden: Bool) { + self.avatarListNode.avatarContainerNode.avatarNode.isHidden = isHidden + } + + func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, contentOffset: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, notificationSettings: TelegramPeerNotificationSettings?, statusData: PeerInfoStatusData?, isContact: Bool, state: PeerInfoState, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat { + let themeUpdated = self.presentationData?.theme !== presentationData.theme + self.presentationData = presentationData + + if themeUpdated { + self.titleCredibilityIconNode.image = PresentationResourcesItemList.verifiedPeerIcon(presentationData.theme) + } + + self.regularContentNode.alpha = state.isEditing ? 0.0 : 1.0 + self.editingContentNode.alpha = state.isEditing ? 1.0 : 0.0 + + let editingContentHeight = self.editingContentNode.update(width: width, safeInset: containerInset, statusBarHeight: statusBarHeight, navigationHeight: navigationHeight, peer: state.isEditing ? peer : nil, isContact: isContact, presentationData: presentationData, transition: transition) + transition.updateFrame(node: self.editingContentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -contentOffset), size: CGSize(width: width, height: editingContentHeight))) + + var transitionSourceHeight: CGFloat = 0.0 + var transitionFraction: CGFloat = 0.0 + var transitionSourceAvatarFrame = CGRect() + var transitionSourceTitleFrame = CGRect() + var transitionSourceSubtitleFrame = CGRect() + + self.backgroundNode.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor + self.expandedBackgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.backgroundColor + + if let navigationTransition = self.navigationTransition, let sourceAvatarNode = navigationTransition.sourceTitleView.avatarNode?.avatarNode { + transitionSourceHeight = navigationTransition.sourceNavigationBar.bounds.height + transitionFraction = navigationTransition.fraction + transitionSourceAvatarFrame = sourceAvatarNode.view.convert(sourceAvatarNode.view.bounds, to: navigationTransition.sourceNavigationBar.view) + transitionSourceTitleFrame = navigationTransition.sourceTitleFrame + transitionSourceSubtitleFrame = navigationTransition.sourceSubtitleFrame + + transition.updateAlpha(node: self.expandedBackgroundNode, alpha: transitionFraction) + } else { + let backgroundTransitionFraction: CGFloat = max(0.0, min(1.0, contentOffset / (212.0))) + transition.updateAlpha(node: self.expandedBackgroundNode, alpha: backgroundTransitionFraction) + } + + self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + + let defaultButtonSize: CGFloat = 40.0 + let defaultMaxButtonSpacing: CGFloat = 40.0 + let expandedAvatarListHeight = min(width, containerHeight - 64.0) + let expandedAvatarListSize = CGSize(width: width, height: expandedAvatarListHeight) + + let buttonKeys: [PeerInfoHeaderButtonKey] = peerInfoHeaderButtons(peer: peer, cachedData: cachedData) + + if let peer = peer { + self.titleNode.attributedText = NSAttributedString(string: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.medium(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor) + + let subtitleString: NSAttributedString? + if let statusData = statusData { + let subtitleColor: UIColor + if statusData.isActivity { + subtitleColor = presentationData.theme.list.itemAccentColor + } else { + subtitleColor = presentationData.theme.list.itemSecondaryTextColor + } + subtitleString = NSAttributedString(string: statusData.text, font: Font.regular(15.0), textColor: subtitleColor) + } else { + subtitleString = nil + } + self.subtitleNode.attributedText = subtitleString + } + + let textSideInset: CGFloat = 16.0 + let expandedAvatarControlsHeight: CGFloat = 64.0 + let expandedAvatarHeight: CGFloat = expandedAvatarListSize.height + expandedAvatarControlsHeight + + let avatarSize: CGFloat = 100.0 + let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 10.0), size: CGSize(width: avatarSize, height: avatarSize)) + let avatarCenter = CGPoint(x: (1.0 - transitionFraction) * avatarFrame.midX + transitionFraction * transitionSourceAvatarFrame.midX, y: (1.0 - transitionFraction) * avatarFrame.midY + transitionFraction * transitionSourceAvatarFrame.midY) + + var isVerified = false + if let peer = peer, peer.isVerified { + isVerified = true + } + + let titleSize = self.titleNode.updateLayout(CGSize(width: width - textSideInset * 2.0 - (isVerified ? 16.0 : 0.0), height: .greatestFiniteMagnitude)) + let subtitleSize = self.subtitleNode.updateLayout(CGSize(width: width - textSideInset * 2.0, height: .greatestFiniteMagnitude)) + + if let image = self.titleCredibilityIconNode.image { + transition.updateFrame(node: self.titleCredibilityIconNode, frame: CGRect(origin: CGPoint(x: titleSize.width + 4.0, y: floor((titleSize.height - image.size.height) / 2.0) + 1.0), size: image.size)) + self.titleCredibilityIconNode.isHidden = !isVerified + } + + let titleFrame: CGRect + let subtitleFrame: CGRect + if self.isAvatarExpanded { + titleFrame = CGRect(origin: CGPoint(x: 16.0, y: expandedAvatarHeight - expandedAvatarControlsHeight + 12.0 + (subtitleSize.height.isZero ? 10.0 : 0.0)), size: titleSize) + subtitleFrame = CGRect(origin: CGPoint(x: 16.0, y: titleFrame.maxY - 5.0), size: subtitleSize) + } else { + titleFrame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: avatarFrame.maxY + 10.0 + (subtitleSize.height.isZero ? 11.0 : 0.0)), size: titleSize) + subtitleFrame = CGRect(origin: CGPoint(x: floor((width - subtitleSize.width) / 2.0), y: titleFrame.maxY + 1.0), size: subtitleSize) + } + + let titleLockOffset: CGFloat = 7.0 + (subtitleSize.height.isZero ? 8.0 : 0.0) + let titleMaxLockOffset: CGFloat = 7.0 + let titleCollapseOffset = titleFrame.midY - statusBarHeight - titleLockOffset + let titleOffset = -min(titleCollapseOffset, contentOffset) + let titleCollapseFraction = max(0.0, min(1.0, contentOffset / titleCollapseOffset)) + + let titleMinScale: CGFloat = 0.7 + let subtitleMinScale: CGFloat = 0.8 + let avatarMinScale: CGFloat = 0.7 + + let apparentTitleLockOffset = (1.0 - titleCollapseFraction) * 0.0 + titleCollapseFraction * titleMaxLockOffset + + let avatarScale: CGFloat + let avatarOffset: CGFloat + if self.navigationTransition != nil { + avatarScale = ((1.0 - transitionFraction) * avatarFrame.width + transitionFraction * transitionSourceAvatarFrame.width) / avatarFrame.width + avatarOffset = 0.0 + } else { + avatarScale = 1.0 * (1.0 - titleCollapseFraction) + avatarMinScale * titleCollapseFraction + avatarOffset = apparentTitleLockOffset + 0.0 * (1.0 - titleCollapseFraction) + 10.0 * titleCollapseFraction + } + let avatarListFrame = CGRect(origin: CGPoint(), size: expandedAvatarListSize) + + if self.isAvatarExpanded { + self.avatarListNode.listContainerNode.isHidden = false + if !transitionSourceAvatarFrame.width.isZero { + transition.updateCornerRadius(node: self.avatarListNode.listContainerNode, cornerRadius: transitionFraction * transitionSourceAvatarFrame.width / 2.0) + } else { + transition.updateCornerRadius(node: self.avatarListNode.listContainerNode, cornerRadius: 0.0) + } + } else if self.avatarListNode.listContainerNode.cornerRadius != 50.0 { + transition.updateCornerRadius(node: self.avatarListNode.listContainerNode, cornerRadius: 50.0, completion: { [weak self] _ in + guard let strongSelf = self else { + return + } + strongSelf.avatarListNode.listContainerNode.isHidden = true + }) + } + + self.avatarListNode.update(size: CGSize(), isExpanded: self.isAvatarExpanded, peer: peer, theme: presentationData.theme, transition: transition) + self.editingContentNode.avatarNode.update(peer: peer, theme: presentationData.theme) + if additive { + transition.updateSublayerTransformScaleAdditive(node: self.avatarListNode.avatarContainerNode, scale: avatarScale) + } else { + transition.updateSublayerTransformScale(node: self.avatarListNode.avatarContainerNode, scale: avatarScale) + } + let apparentAvatarFrame: CGRect + if self.isAvatarExpanded { + let expandedAvatarCenter = CGPoint(x: expandedAvatarListSize.width / 2.0, y: expandedAvatarListSize.height / 2.0 - contentOffset / 2.0) + apparentAvatarFrame = CGRect(origin: CGPoint(x: expandedAvatarCenter.x * (1.0 - transitionFraction) + transitionFraction * avatarCenter.x, y: expandedAvatarCenter.y * (1.0 - transitionFraction) + transitionFraction * avatarCenter.y), size: CGSize()) + } else { + apparentAvatarFrame = CGRect(origin: CGPoint(x: avatarCenter.x - avatarFrame.width / 2.0, y: -contentOffset + avatarOffset + avatarCenter.y - avatarFrame.height / 2.0), size: avatarFrame.size) + } + if case let .animated(duration, curve) = transition, !transitionSourceAvatarFrame.width.isZero, false { + let previousFrame = self.avatarListNode.frame + self.avatarListNode.frame = CGRect(origin: apparentAvatarFrame.center, size: CGSize()) + let horizontalTransition: ContainedViewLayoutTransition + let verticalTransition: ContainedViewLayoutTransition + if transitionFraction < .ulpOfOne { + horizontalTransition = .animated(duration: duration * 0.85, curve: curve) + verticalTransition = .animated(duration: duration * 1.15, curve: curve) + } else { + horizontalTransition = transition + verticalTransition = .animated(duration: duration * 0.6, curve: curve) + } + horizontalTransition.animatePositionAdditive(node: self.avatarListNode, offset: CGPoint(x: previousFrame.midX - apparentAvatarFrame.midX, y: 0.0)) + verticalTransition.animatePositionAdditive(node: self.avatarListNode, offset: CGPoint(x: 0.0, y: previousFrame.midY - apparentAvatarFrame.midY)) + } else { + transition.updateFrameAdditive(node: self.avatarListNode, frame: CGRect(origin: apparentAvatarFrame.center, size: CGSize())) + } + + let avatarListContainerFrame: CGRect + let avatarListContainerScale: CGFloat + if self.isAvatarExpanded { + if !transitionSourceAvatarFrame.width.isZero { + let neutralAvatarListContainerSize = expandedAvatarListSize + let avatarListContainerSize = CGSize(width: neutralAvatarListContainerSize.width * (1.0 - transitionFraction) + transitionSourceAvatarFrame.width * transitionFraction, height: neutralAvatarListContainerSize.height * (1.0 - transitionFraction) + transitionSourceAvatarFrame.height * transitionFraction) + avatarListContainerFrame = CGRect(origin: CGPoint(x: -avatarListContainerSize.width / 2.0, y: -avatarListContainerSize.height / 2.0), size: avatarListContainerSize) + } else { + avatarListContainerFrame = CGRect(origin: CGPoint(x: -expandedAvatarListSize.width / 2.0, y: -expandedAvatarListSize.height / 2.0), size: expandedAvatarListSize) + } + avatarListContainerScale = 1.0 + max(0.0, -contentOffset / avatarListContainerFrame.height) + } else { + avatarListContainerFrame = CGRect(origin: CGPoint(x: -apparentAvatarFrame.width / 2.0, y: -apparentAvatarFrame.height / 2.0), size: apparentAvatarFrame.size) + avatarListContainerScale = avatarScale + } + transition.updateFrame(node: self.avatarListNode.listContainerNode, frame: avatarListContainerFrame) + let innerScale = avatarListContainerFrame.height / expandedAvatarListSize.height + let innerDeltaX = (avatarListContainerFrame.width - expandedAvatarListSize.width) / 2.0 + let innerDeltaY = (avatarListContainerFrame.height - expandedAvatarListSize.height) / 2.0 + transition.updateSublayerTransformScale(node: self.avatarListNode.listContainerNode, scale: innerScale) + transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.contentNode, frame: CGRect(origin: CGPoint(x: innerDeltaX + expandedAvatarListSize.width / 2.0, y: innerDeltaY + expandedAvatarListSize.height / 2.0), size: CGSize())) + + transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.controlsContainerTransformNode, frame: CGRect(origin: CGPoint(x: expandedAvatarListSize.width / 2.0, y: expandedAvatarListSize.height / 2.0 - innerDeltaY), size: CGSize())) + transition.updateSublayerTransformScale(node: self.avatarListNode.listContainerNode.controlsContainerNode, scale: 1.0 / innerScale) + transition.updateSublayerTransformScaleAdditive(node: self.avatarListNode.listContainerNode.controlsContainerTransformNode, scale: 1.0 / avatarListContainerScale) + transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.shadowNode, frame: CGRect(origin: CGPoint(x: -apparentAvatarFrame.minX, y: -apparentAvatarFrame.minY), size: CGSize(width: expandedAvatarListSize.width, height: navigationHeight))) + + if additive { + transition.updateSublayerTransformScaleAdditive(node: self.avatarListNode.listContainerTransformNode, scale: avatarListContainerScale) + } else { + transition.updateSublayerTransformScale(node: self.avatarListNode.listContainerTransformNode, scale: avatarListContainerScale) + } + + self.avatarListNode.listContainerNode.update(size: expandedAvatarListSize, peer: peer, transition: transition) + + let buttonsCollapseStart = titleCollapseOffset + let buttonsCollapseEnd = 212.0 - (navigationHeight - statusBarHeight) + 10.0 + + let buttonsCollapseFraction = max(0.0, contentOffset - buttonsCollapseStart) / (buttonsCollapseEnd - buttonsCollapseStart) + + let rawHeight: CGFloat + let height: CGFloat + if self.isAvatarExpanded { + rawHeight = expandedAvatarHeight + height = max(navigationHeight, rawHeight - contentOffset) + } else { + rawHeight = navigationHeight + 212.0 + height = navigationHeight + max(0.0, 212.0 - contentOffset) + } + + let apparentHeight = (1.0 - transitionFraction) * height + transitionFraction * transitionSourceHeight + + if !titleSize.width.isZero && !titleSize.height.isZero { + if self.navigationTransition != nil { + var neutralTitleScale: CGFloat = 1.0 + var neutralSubtitleScale: CGFloat = 1.0 + if self.isAvatarExpanded { + neutralTitleScale = 0.7 + neutralSubtitleScale = 1.0 + } + + let titleScale = (transitionFraction * transitionSourceTitleFrame.height + (1.0 - transitionFraction) * titleFrame.height * neutralTitleScale) / (titleFrame.height) + let subtitleScale = max(0.01, min(10.0, (transitionFraction * transitionSourceSubtitleFrame.height + (1.0 - transitionFraction) * subtitleFrame.height * neutralSubtitleScale) / (subtitleFrame.height))) + + let titleOrigin = CGPoint(x: transitionFraction * transitionSourceTitleFrame.minX + (1.0 - transitionFraction) * titleFrame.minX, y: transitionFraction * transitionSourceTitleFrame.minY + (1.0 - transitionFraction) * titleFrame.minY) + let subtitleOrigin = CGPoint(x: transitionFraction * transitionSourceSubtitleFrame.minX + (1.0 - transitionFraction) * subtitleFrame.minX, y: transitionFraction * transitionSourceSubtitleFrame.minY + (1.0 - transitionFraction) * subtitleFrame.minY) + + let rawTitleFrame = CGRect(origin: titleOrigin, size: titleFrame.size) + self.titleNodeRawContainer.frame = rawTitleFrame + transition.updateFrameAdditiveToCenter(node: self.titleNodeContainer, frame: rawTitleFrame.offsetBy(dx: rawTitleFrame.width * 0.5 * (titleScale - 1.0), dy: titleOffset + rawTitleFrame.height * 0.5 * (titleScale - 1.0))) + transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(), size: titleFrame.size)) + let rawSubtitleFrame = CGRect(origin: subtitleOrigin, size: subtitleFrame.size) + self.subtitleNodeRawContainer.frame = rawSubtitleFrame + transition.updateFrameAdditiveToCenter(node: self.subtitleNodeContainer, frame: rawSubtitleFrame.offsetBy(dx: rawSubtitleFrame.width * 0.5 * (subtitleScale - 1.0), dy: titleOffset + rawSubtitleFrame.height * 0.5 * (subtitleScale - 1.0))) + transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(), size: subtitleFrame.size)) + transition.updateSublayerTransformScale(node: self.titleNodeContainer, scale: titleScale) + transition.updateSublayerTransformScale(node: self.subtitleNodeContainer, scale: subtitleScale) + } else { + let titleScale: CGFloat + let subtitleScale: CGFloat + if self.isAvatarExpanded { + titleScale = 0.7 + subtitleScale = 1.0 + } else { + titleScale = (1.0 - titleCollapseFraction) * 1.0 + titleCollapseFraction * titleMinScale + subtitleScale = (1.0 - titleCollapseFraction) * 1.0 + titleCollapseFraction * subtitleMinScale + } + + let rawTitleFrame = titleFrame + self.titleNodeRawContainer.frame = rawTitleFrame + transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(), size: titleFrame.size)) + let rawSubtitleFrame = subtitleFrame + self.subtitleNodeRawContainer.frame = rawSubtitleFrame + if self.isAvatarExpanded { + transition.updateFrameAdditive(node: self.titleNodeContainer, frame: rawTitleFrame.offsetBy(dx: 0.0, dy: titleOffset + apparentTitleLockOffset).offsetBy(dx: rawTitleFrame.width * 0.5 * (titleScale - 1.0), dy: rawTitleFrame.height * 0.5 * (titleScale - 1.0))) + transition.updateFrameAdditive(node: self.subtitleNodeContainer, frame: rawSubtitleFrame.offsetBy(dx: 0.0, dy: titleOffset).offsetBy(dx: rawSubtitleFrame.width * 0.5 * (subtitleScale - 1.0), dy: rawSubtitleFrame.height * 0.5 * (subtitleScale - 1.0))) + } else { + transition.updateFrameAdditiveToCenter(node: self.titleNodeContainer, frame: rawTitleFrame.offsetBy(dx: 0.0, dy: titleOffset + apparentTitleLockOffset)) + transition.updateFrameAdditiveToCenter(node: self.subtitleNodeContainer, frame: rawSubtitleFrame.offsetBy(dx: 0.0, dy: titleOffset)) + } + transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(), size: subtitleFrame.size)) + transition.updateSublayerTransformScaleAdditive(node: self.titleNodeContainer, scale: titleScale) + transition.updateSublayerTransformScaleAdditive(node: self.subtitleNodeContainer, scale: subtitleScale) + } + } + + let buttonSpacing: CGFloat + if self.isAvatarExpanded { + buttonSpacing = 16.0 + } else { + buttonSpacing = min(defaultMaxButtonSpacing, width - floor(CGFloat(buttonKeys.count) * defaultButtonSize / CGFloat(buttonKeys.count + 1))) + } + + let expandedButtonSize: CGFloat = 32.0 + let buttonsWidth = buttonSpacing * CGFloat(buttonKeys.count - 1) + CGFloat(buttonKeys.count) * defaultButtonSize + var buttonRightOrigin: CGPoint + if self.isAvatarExpanded { + buttonRightOrigin = CGPoint(x: width - 16.0, y: apparentHeight - 74.0) + } else { + buttonRightOrigin = CGPoint(x: floor((width - buttonsWidth) / 2.0) + buttonsWidth, y: apparentHeight - 74.0) + } + let buttonsScale: CGFloat + let buttonsAlpha: CGFloat + let apparentButtonSize: CGFloat + let buttonsVerticalOffset: CGFloat + if self.navigationTransition != nil { + if self.isAvatarExpanded { + apparentButtonSize = expandedButtonSize + } else { + apparentButtonSize = defaultButtonSize + } + let neutralButtonsScale = apparentButtonSize / defaultButtonSize + buttonsScale = (1.0 - transitionFraction) * neutralButtonsScale + 0.2 * transitionFraction + buttonsAlpha = 1.0 - transitionFraction + + let neutralButtonsOffset: CGFloat + if self.isAvatarExpanded { + neutralButtonsOffset = 74.0 - 15.0 - defaultButtonSize + (defaultButtonSize - apparentButtonSize) / 2.0 + } else { + neutralButtonsOffset = (1.0 - buttonsScale) * apparentButtonSize + } + + buttonsVerticalOffset = (1.0 - transitionFraction) * neutralButtonsOffset + ((1.0 - buttonsScale) * apparentButtonSize) * transitionFraction + } else { + apparentButtonSize = self.isAvatarExpanded ? expandedButtonSize : defaultButtonSize + if self.isAvatarExpanded { + buttonsScale = apparentButtonSize / defaultButtonSize + buttonsVerticalOffset = 74.0 - 15.0 - defaultButtonSize + (defaultButtonSize - apparentButtonSize) / 2.0 + } else { + buttonsScale = (1.0 - buttonsCollapseFraction) * 1.0 + 0.2 * buttonsCollapseFraction + buttonsVerticalOffset = (1.0 - buttonsScale) * apparentButtonSize + } + buttonsAlpha = 1.0 - buttonsCollapseFraction + } + let buttonsScaledOffset = (defaultButtonSize - apparentButtonSize) / 2.0 + for buttonKey in buttonKeys.reversed() { + let buttonNode: PeerInfoHeaderButtonNode + var wasAdded = false + if let current = self.buttonNodes[buttonKey] { + buttonNode = current + } else { + wasAdded = true + buttonNode = PeerInfoHeaderButtonNode(key: buttonKey, action: { [weak self] buttonNode in + self?.buttonPressed(buttonNode) + }) + self.buttonNodes[buttonKey] = buttonNode + self.regularContentNode.addSubnode(buttonNode) + } + + let buttonFrame = CGRect(origin: CGPoint(x: buttonRightOrigin.x - defaultButtonSize + buttonsScaledOffset, y: buttonRightOrigin.y), size: CGSize(width: defaultButtonSize, height: defaultButtonSize)) + let buttonTransition: ContainedViewLayoutTransition = wasAdded ? .immediate : transition + + let apparentButtonFrame = buttonFrame.offsetBy(dx: 0.0, dy: buttonsVerticalOffset) + if additive { + buttonTransition.updateFrameAdditiveToCenter(node: buttonNode, frame: apparentButtonFrame) + } else { + buttonTransition.updateFrame(node: buttonNode, frame: apparentButtonFrame) + } + let buttonText: String + let buttonIcon: PeerInfoHeaderButtonIcon + switch buttonKey { + case .message: + buttonText = "Message" + buttonIcon = .message + case .call: + buttonText = "Call" + buttonIcon = .call + case .mute: + if let notificationSettings = notificationSettings, case .muted = notificationSettings.muteState { + buttonText = "Unmute" + buttonIcon = .unmute + } else { + buttonText = "Mute" + buttonIcon = .mute + } + case .more: + buttonText = "More" + buttonIcon = .more + case .addMember: + buttonText = "Add Member" + buttonIcon = .addMember + } + buttonNode.update(size: buttonFrame.size, text: buttonText, icon: buttonIcon, isExpanded: self.isAvatarExpanded, presentationData: presentationData, transition: buttonTransition) + transition.updateSublayerTransformScaleAdditive(node: buttonNode, scale: buttonsScale) + + transition.updateAlpha(node: buttonNode, alpha: buttonsAlpha) + + let hiddenWhileExpanded: Bool + switch buttonKey { + case .mute: + hiddenWhileExpanded = true + default: + hiddenWhileExpanded = false + } + + if self.isAvatarExpanded, hiddenWhileExpanded { + if case let .animated(duration, curve) = transition { + ContainedViewLayoutTransition.animated(duration: duration * 0.3, curve: curve).updateAlpha(node: buttonNode.containerNode, alpha: 0.0) + } else { + transition.updateAlpha(node: buttonNode.containerNode, alpha: 0.0) + } + } else { + if case .mute = buttonKey, buttonNode.containerNode.alpha.isZero, additive { + if case let .animated(duration, curve) = transition { + ContainedViewLayoutTransition.animated(duration: duration * 0.3, curve: curve).updateAlpha(node: buttonNode.containerNode, alpha: 1.0) + } else { + transition.updateAlpha(node: buttonNode.containerNode, alpha: 1.0) + } + } else { + transition.updateAlpha(node: buttonNode.containerNode, alpha: 1.0) + } + buttonRightOrigin.x -= apparentButtonSize + buttonSpacing + } + } + + for key in self.buttonNodes.keys { + if !buttonKeys.contains(key) { + if let buttonNode = self.buttonNodes[key] { + self.buttonNodes.removeValue(forKey: key) + buttonNode.removeFromSupernode() + } + } + } + + let resolvedRegularHeight: CGFloat + if self.isAvatarExpanded { + resolvedRegularHeight = expandedAvatarListSize.height + expandedAvatarControlsHeight + } else { + resolvedRegularHeight = 212.0 + navigationHeight + } + + let backgroundFrame: CGRect + let separatorFrame: CGRect + + let resolvedHeight: CGFloat + if state.isEditing { + resolvedHeight = editingContentHeight + backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -2000.0 + resolvedHeight - contentOffset), size: CGSize(width: width, height: 2000.0)) + separatorFrame = CGRect(origin: CGPoint(x: 0.0, y: resolvedHeight - contentOffset), size: CGSize(width: width, height: UIScreenPixel)) + } else { + resolvedHeight = resolvedRegularHeight + backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -2000.0 + apparentHeight), size: CGSize(width: width, height: 2000.0)) + separatorFrame = CGRect(origin: CGPoint(x: 0.0, y: apparentHeight), size: CGSize(width: width, height: UIScreenPixel)) + } + + transition.updateFrame(node: self.regularContentNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: resolvedHeight))) + + if additive { + transition.updateFrameAdditive(node: self.backgroundNode, frame: backgroundFrame) + transition.updateFrameAdditive(node: self.expandedBackgroundNode, frame: backgroundFrame) + transition.updateFrameAdditive(node: self.separatorNode, frame: separatorFrame) + } else { + transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame) + transition.updateFrame(node: self.expandedBackgroundNode, frame: backgroundFrame) + transition.updateFrame(node: self.separatorNode, frame: separatorFrame) + } + + return resolvedHeight + } + + private func buttonPressed(_ buttonNode: PeerInfoHeaderButtonNode) { + self.performButtonAction?(buttonNode.key) + } + + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + guard let result = super.hitTest(point, with: event) else { + return nil + } + if result.isDescendant(of: self.navigationButtonContainer.view) { + return result + } + if !self.backgroundNode.frame.contains(point) { + return nil + } + if result == self.view || result == self.regularContentNode.view || result == self.editingContentNode.view { + return nil + } + return result + } + + func updateIsAvatarExpanded(_ isAvatarExpanded: Bool, transition: ContainedViewLayoutTransition) { + if self.isAvatarExpanded != isAvatarExpanded { + self.isAvatarExpanded = isAvatarExpanded + if isAvatarExpanded { + self.avatarListNode.listContainerNode.selectFirstItem() + } + if case .animated = transition, !isAvatarExpanded { + self.avatarListNode.animateAvatarCollapse(transition: transition) + } + } + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift new file mode 100644 index 0000000000..976036603b --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift @@ -0,0 +1,553 @@ +import Foundation +import UIKit +import AsyncDisplayKit +import Display +import SwiftSignalKit +import TelegramPresentationData +import Postbox +import SyncCore +import TelegramCore +import AccountContext +import ContextUI + +protocol PeerInfoPaneNode: ASDisplayNode { + var isReady: Signal { get } + + func update(size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) + func scrollToTop() -> Bool + func transferVelocity(_ velocity: CGFloat) + func findLoadedMessage(id: MessageId) -> Message? + func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? + func addToTransitionSurface(view: UIView) + func updateHiddenMedia() + func updateSelectedMessages(animated: Bool) +} + +final class PeerInfoPaneWrapper { + let key: PeerInfoPaneKey + let node: PeerInfoPaneNode + private var appliedParams: (CGSize, CGFloat, CGFloat, CGFloat, Bool, PresentationData)? + + init(key: PeerInfoPaneKey, node: PeerInfoPaneNode) { + self.key = key + self.node = node + } + + func update(size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { + if let (currentSize, currentSideInset, currentBottomInset, visibleHeight, currentIsScrollingLockedAtTop, currentPresentationData) = self.appliedParams { + if currentSize == size && currentSideInset == sideInset && currentBottomInset == bottomInset, currentIsScrollingLockedAtTop == isScrollingLockedAtTop && currentPresentationData === presentationData { + return + } + } + self.appliedParams = (size, sideInset, bottomInset, visibleHeight, isScrollingLockedAtTop, presentationData) + self.node.update(size: size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, isScrollingLockedAtTop: isScrollingLockedAtTop, presentationData: presentationData, synchronous: synchronous, transition: transition) + } +} + +enum PeerInfoPaneKey { + case media + case files + case links + case voice + case music + case groupsInCommon +} + +final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode { + private let pressed: () -> Void + + private let titleNode: ImmediateTextNode + private let buttonNode: HighlightTrackingButtonNode + + init(pressed: @escaping () -> Void) { + self.pressed = pressed + + self.titleNode = ImmediateTextNode() + self.titleNode.displaysAsynchronously = false + + self.buttonNode = HighlightTrackingButtonNode() + + super.init() + + self.addSubnode(self.titleNode) + self.addSubnode(self.buttonNode) + + self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside) + self.buttonNode.highligthedChanged = { [weak self] highlighted in + if let strongSelf = self { + if highlighted { + strongSelf.titleNode.layer.removeAnimation(forKey: "opacity") + strongSelf.titleNode.alpha = 0.4 + } else { + strongSelf.titleNode.alpha = 1.0 + strongSelf.titleNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) + } + } + } + } + + @objc private func buttonPressed() { + self.pressed() + } + + func updateText(_ title: String, isSelected: Bool, presentationData: PresentationData) { + self.titleNode.attributedText = NSAttributedString(string: title, font: Font.medium(14.0), textColor: isSelected ? presentationData.theme.list.itemAccentColor : presentationData.theme.list.itemSecondaryTextColor) + } + + func updateLayout(height: CGFloat) -> CGFloat { + let titleSize = self.titleNode.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude)) + self.titleNode.frame = CGRect(origin: CGPoint(x: 0.0, y: floor((height - titleSize.height) / 2.0)), size: titleSize) + return titleSize.width + } + + func updateArea(size: CGSize, sideInset: CGFloat) { + self.buttonNode.frame = CGRect(origin: CGPoint(x: -sideInset, y: 0.0), size: CGSize(width: size.width + sideInset * 2.0, height: size.height)) + } +} + +struct PeerInfoPaneSpecifier: Equatable { + var key: PeerInfoPaneKey + var title: String +} + +final class PeerInfoPaneTabsContainerNode: ASDisplayNode { + private let scrollNode: ASScrollNode + private var paneNodes: [PeerInfoPaneKey: PeerInfoPaneTabsContainerPaneNode] = [:] + private let selectedLineNode: ASImageNode + + private var currentParams: ([PeerInfoPaneSpecifier], PeerInfoPaneKey?, PresentationData)? + + var requestSelectPane: ((PeerInfoPaneKey) -> Void)? + + override init() { + self.scrollNode = ASScrollNode() + + self.selectedLineNode = ASImageNode() + self.selectedLineNode.displaysAsynchronously = false + self.selectedLineNode.displayWithoutProcessing = true + + super.init() + + self.scrollNode.view.disablesInteractiveTransitionGestureRecognizer = true + self.scrollNode.view.showsHorizontalScrollIndicator = false + self.scrollNode.view.scrollsToTop = false + if #available(iOS 11.0, *) { + self.scrollNode.view.contentInsetAdjustmentBehavior = .never + } + + self.addSubnode(self.scrollNode) + self.scrollNode.addSubnode(self.selectedLineNode) + } + + func update(size: CGSize, presentationData: PresentationData, paneList: [PeerInfoPaneSpecifier], selectedPane: PeerInfoPaneKey?, transition: ContainedViewLayoutTransition) { + transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: size)) + + let focusOnSelectedPane = self.currentParams?.1 != selectedPane + + if self.currentParams?.2.theme !== presentationData.theme { + self.selectedLineNode.image = generateImage(CGSize(width: 7.0, height: 4.0), rotatedContext: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + context.setFillColor(presentationData.theme.list.itemAccentColor.cgColor) + context.fillEllipse(in: CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.width))) + })?.stretchableImage(withLeftCapWidth: 4, topCapHeight: 1) + } + + if self.currentParams?.0 != paneList || self.currentParams?.1 != selectedPane || self.currentParams?.2 !== presentationData { + self.currentParams = (paneList, selectedPane, presentationData) + for specifier in paneList { + let paneNode: PeerInfoPaneTabsContainerPaneNode + var wasAdded = false + if let current = self.paneNodes[specifier.key] { + paneNode = current + } else { + wasAdded = true + paneNode = PeerInfoPaneTabsContainerPaneNode(pressed: { [weak self] in + self?.paneSelected(specifier.key) + }) + self.paneNodes[specifier.key] = paneNode + self.scrollNode.addSubnode(paneNode) + } + paneNode.updateText(specifier.title, isSelected: selectedPane == specifier.key, presentationData: presentationData) + } + var removeKeys: [PeerInfoPaneKey] = [] + for (key, _) in self.paneNodes { + if !paneList.contains(where: { $0.key == key }) { + removeKeys.append(key) + } + } + for key in removeKeys { + if let paneNode = self.paneNodes.removeValue(forKey: key) { + paneNode.removeFromSupernode() + } + } + } + + var tabSizes: [(CGSize, PeerInfoPaneTabsContainerPaneNode)] = [] + var totalRawTabSize: CGFloat = 0.0 + + var selectedFrame: CGRect? + for specifier in paneList { + guard let paneNode = self.paneNodes[specifier.key] else { + continue + } + let paneNodeWidth = paneNode.updateLayout(height: size.height) + let paneNodeSize = CGSize(width: paneNodeWidth, height: size.height) + tabSizes.append((paneNodeSize, paneNode)) + totalRawTabSize += paneNodeSize.width + } + + let spacing: CGFloat = 32.0 + if tabSizes.count == 1 { + for i in 0 ..< tabSizes.count { + let (paneNodeSize, paneNode) = tabSizes[i] + let leftOffset: CGFloat = 16.0 + + let paneFrame = CGRect(origin: CGPoint(x: leftOffset, y: floor((size.height - paneNodeSize.height) / 2.0)), size: paneNodeSize) + paneNode.frame = paneFrame + let areaSideInset: CGFloat = 16.0 + paneNode.updateArea(size: paneFrame.size, sideInset: areaSideInset) + paneNode.hitTestSlop = UIEdgeInsets(top: 0.0, left: -areaSideInset, bottom: 0.0, right: -areaSideInset) + + if paneList[i].key == selectedPane { + selectedFrame = paneFrame + } + } + self.scrollNode.view.contentSize = CGSize(width: size.width, height: size.height) + } else if totalRawTabSize + CGFloat(tabSizes.count + 1) * spacing <= size.width { + let availableSpace = size.width + let availableSpacing = availableSpace - totalRawTabSize + let perTabSpacing = floor(availableSpacing / CGFloat(tabSizes.count + 1)) + + var leftOffset = perTabSpacing + for i in 0 ..< tabSizes.count { + let (paneNodeSize, paneNode) = tabSizes[i] + + let paneFrame = CGRect(origin: CGPoint(x: leftOffset, y: floor((size.height - paneNodeSize.height) / 2.0)), size: paneNodeSize) + paneNode.frame = paneFrame + let areaSideInset = floor(perTabSpacing / 2.0) + paneNode.updateArea(size: paneFrame.size, sideInset: areaSideInset) + paneNode.hitTestSlop = UIEdgeInsets(top: 0.0, left: -areaSideInset, bottom: 0.0, right: -areaSideInset) + + leftOffset += paneNodeSize.width + perTabSpacing + + if paneList[i].key == selectedPane { + selectedFrame = paneFrame + } + } + self.scrollNode.view.contentSize = CGSize(width: size.width, height: size.height) + } else { + let sideInset: CGFloat = 16.0 + var leftOffset: CGFloat = sideInset + for i in 0 ..< tabSizes.count { + let (paneNodeSize, paneNode) = tabSizes[i] + let paneFrame = CGRect(origin: CGPoint(x: leftOffset, y: floor((size.height - paneNodeSize.height) / 2.0)), size: paneNodeSize) + paneNode.frame = paneFrame + paneNode.updateArea(size: paneFrame.size, sideInset: spacing) + paneNode.hitTestSlop = UIEdgeInsets(top: 0.0, left: -spacing, bottom: 0.0, right: -spacing) + if paneList[i].key == selectedPane { + selectedFrame = paneFrame + } + leftOffset += paneNodeSize.width + spacing + } + self.scrollNode.view.contentSize = CGSize(width: leftOffset + sideInset, height: size.height) + } + + if let selectedFrame = selectedFrame { + self.selectedLineNode.isHidden = false + transition.updateFrame(node: self.selectedLineNode, frame: CGRect(origin: CGPoint(x: selectedFrame.minX, y: size.height - 4.0), size: CGSize(width: selectedFrame.width, height: 4.0))) + if focusOnSelectedPane { + if selectedPane == paneList.first?.key { + transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(), size: self.scrollNode.bounds.size)) + } else if selectedPane == paneList.last?.key { + transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: self.scrollNode.view.contentSize.width - self.scrollNode.bounds.width, y: 0.0), size: self.scrollNode.bounds.size)) + } else { + let contentOffsetX = max(0.0, min(self.scrollNode.view.contentSize.width - self.scrollNode.bounds.width, floor(selectedFrame.midX - self.scrollNode.bounds.width / 2.0))) + transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: contentOffsetX, y: 0.0), size: self.scrollNode.bounds.size)) + } + } + } else { + self.selectedLineNode.isHidden = true + } + } + + private func paneSelected(_ key: PeerInfoPaneKey) { + self.requestSelectPane?(key) + } +} + +final class PeerInfoPaneContainerNode: ASDisplayNode { + private let context: AccountContext + private let peerId: PeerId + + private let coveringBackgroundNode: ASDisplayNode + private let separatorNode: ASDisplayNode + private let tabsContainerNode: PeerInfoPaneTabsContainerNode + private let tapsSeparatorNode: ASDisplayNode + + let isReady = Promise() + var didSetIsReady = false + + private var currentParams: (size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, expansionFraction: CGFloat, presentationData: PresentationData, data: PeerInfoScreenData?)? + private(set) var currentPaneKey: PeerInfoPaneKey? + private(set) var currentPane: PeerInfoPaneWrapper? + + private var currentCandidatePaneKey: PeerInfoPaneKey? + private var candidatePane: (PeerInfoPaneWrapper, Disposable, Bool)? + + var selectionPanelNode: PeerInfoSelectionPanelNode? + + var chatControllerInteraction: ChatControllerInteraction? + var openPeerContextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)? + + var currentPaneUpdated: (() -> Void)? + + private var currentAvailablePanes: [PeerInfoPaneKey]? + + init(context: AccountContext, peerId: PeerId) { + self.context = context + self.peerId = peerId + + self.separatorNode = ASDisplayNode() + self.separatorNode.isLayerBacked = true + + self.coveringBackgroundNode = ASDisplayNode() + self.coveringBackgroundNode.isLayerBacked = true + + self.tabsContainerNode = PeerInfoPaneTabsContainerNode() + + self.tapsSeparatorNode = ASDisplayNode() + self.tapsSeparatorNode.isLayerBacked = true + + super.init() + + self.addSubnode(self.separatorNode) + self.addSubnode(self.coveringBackgroundNode) + self.addSubnode(self.tabsContainerNode) + self.addSubnode(self.tapsSeparatorNode) + + self.tabsContainerNode.requestSelectPane = { [weak self] key in + guard let strongSelf = self else { + return + } + if strongSelf.currentPaneKey == key { + strongSelf.currentPane?.node.scrollToTop() + return + } + if strongSelf.currentCandidatePaneKey == key { + return + } + strongSelf.currentCandidatePaneKey = key + + if let (size, sideInset, bottomInset, visibleHeight, expansionFraction, presentationData, data) = strongSelf.currentParams { + strongSelf.update(size: size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, expansionFraction: expansionFraction, presentationData: presentationData, data: data, transition: .immediate) + } + } + } + + func scrollToTop() -> Bool { + if let currentPane = self.currentPane { + return currentPane.node.scrollToTop() + } else { + return false + } + } + + func findLoadedMessage(id: MessageId) -> Message? { + return self.currentPane?.node.findLoadedMessage(id: id) + } + + func updateHiddenMedia() { + self.currentPane?.node.updateHiddenMedia() + } + + func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { + return self.currentPane?.node.transitionNodeForGallery(messageId: messageId, media: media) + } + + func updateSelectedMessageIds(_ selectedMessageIds: Set?, animated: Bool) { + self.currentPane?.node.updateSelectedMessages(animated: animated) + self.candidatePane?.0.node.updateSelectedMessages(animated: animated) + } + + func update(size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, expansionFraction: CGFloat, presentationData: PresentationData, data: PeerInfoScreenData?, transition: ContainedViewLayoutTransition) { + let previousAvailablePanes = self.currentAvailablePanes ?? [] + let availablePanes = data?.availablePanes ?? [] + self.currentAvailablePanes = availablePanes + + if let currentPaneKey = self.currentPaneKey, !availablePanes.contains(currentPaneKey) { + var nextCandidatePaneKey: PeerInfoPaneKey? + if let index = previousAvailablePanes.index(of: currentPaneKey), index != 0 { + for i in (0 ... index - 1).reversed() { + if availablePanes.contains(previousAvailablePanes[i]) { + nextCandidatePaneKey = previousAvailablePanes[i] + } + } + } + if nextCandidatePaneKey == nil { + nextCandidatePaneKey = availablePanes.first + } + + if let nextCandidatePaneKey = nextCandidatePaneKey { + if self.currentCandidatePaneKey != nextCandidatePaneKey { + self.currentCandidatePaneKey = nextCandidatePaneKey + } + } else { + self.currentCandidatePaneKey = nil + if let (_, disposable, _) = self.candidatePane { + disposable.dispose() + self.candidatePane = nil + } + if let currentPane = self.currentPane { + self.currentPane = nil + currentPane.node.removeFromSupernode() + } + } + } else if self.currentPaneKey == nil { + self.currentCandidatePaneKey = availablePanes.first + } + + let previousCurrentPaneKey = self.currentPaneKey + + self.currentParams = (size, sideInset, bottomInset, visibleHeight, expansionFraction, presentationData, data) + + transition.updateAlpha(node: self.coveringBackgroundNode, alpha: expansionFraction) + + self.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor + self.coveringBackgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.backgroundColor + self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + self.tapsSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + + let tabsHeight: CGFloat = 48.0 + + transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: size.width, height: UIScreenPixel))) + transition.updateFrame(node: self.coveringBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: size.width, height: tabsHeight + UIScreenPixel))) + + transition.updateFrame(node: self.tapsSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: tabsHeight - UIScreenPixel), size: CGSize(width: size.width, height: UIScreenPixel))) + + let paneFrame = CGRect(origin: CGPoint(x: 0.0, y: tabsHeight), size: CGSize(width: size.width, height: size.height - tabsHeight)) + + if let currentCandidatePaneKey = self.currentCandidatePaneKey { + if self.candidatePane?.0.key != currentCandidatePaneKey { + self.candidatePane?.1.dispose() + + let paneNode: PeerInfoPaneNode + switch currentCandidatePaneKey { + case .media: + paneNode = PeerInfoVisualMediaPaneNode(context: self.context, chatControllerInteraction: self.chatControllerInteraction!, peerId: self.peerId) + case .files: + paneNode = PeerInfoListPaneNode(context: self.context, chatControllerInteraction: self.chatControllerInteraction!, peerId: self.peerId, tagMask: .file) + case .links: + paneNode = PeerInfoListPaneNode(context: self.context, chatControllerInteraction: self.chatControllerInteraction!, peerId: self.peerId, tagMask: .webPage) + case .voice: + paneNode = PeerInfoListPaneNode(context: self.context, chatControllerInteraction: self.chatControllerInteraction!, peerId: self.peerId, tagMask: .voiceOrInstantVideo) + case .music: + paneNode = PeerInfoListPaneNode(context: self.context, chatControllerInteraction: self.chatControllerInteraction!, peerId: self.peerId, tagMask: .music) + case .groupsInCommon: + paneNode = PeerInfoGroupsInCommonPaneNode(context: self.context, peerId: peerId, chatControllerInteraction: self.chatControllerInteraction!, openPeerContextAction: self.openPeerContextAction!, peers: data?.groupsInCommon ?? []) + } + + let disposable = MetaDisposable() + self.candidatePane = (PeerInfoPaneWrapper(key: currentCandidatePaneKey, node: paneNode), disposable, false) + + var shouldReLayout = false + disposable.set((paneNode.isReady + |> take(1) + |> deliverOnMainQueue).start(next: { [weak self] _ in + guard let strongSelf = self else { + return + } + if let (candidatePane, disposable, _) = strongSelf.candidatePane { + strongSelf.candidatePane = (candidatePane, disposable, true) + + if shouldReLayout { + if let (size, sideInset, bottomInset, visibleHeight, expansionFraction, presentationData, data) = strongSelf.currentParams { + strongSelf.update(size: size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, expansionFraction: expansionFraction, presentationData: presentationData, data: data, transition: strongSelf.currentPane != nil ? .animated(duration: 0.35, curve: .spring) : .immediate) + } + } + } + })) + shouldReLayout = true + } + } + + if let (candidatePane, _, isReady) = self.candidatePane, isReady { + let previousPane = self.currentPane + self.candidatePane = nil + self.currentPaneKey = candidatePane.key + self.currentCandidatePaneKey = nil + self.currentPane = candidatePane + + if let selectionPanelNode = self.selectionPanelNode { + self.insertSubnode(candidatePane.node, belowSubnode: selectionPanelNode) + } else { + self.addSubnode(candidatePane.node) + } + candidatePane.node.frame = paneFrame + candidatePane.update(size: paneFrame.size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: max(0.0, visibleHeight - paneFrame.minY), isScrollingLockedAtTop: expansionFraction < 1.0 - CGFloat.ulpOfOne, presentationData: presentationData, synchronous: true, transition: .immediate) + + if let previousPane = previousPane { + let directionToRight: Bool + if let previousIndex = availablePanes.index(of: previousPane.key), let updatedIndex = availablePanes.index(of: candidatePane.key) { + directionToRight = previousIndex < updatedIndex + } else { + directionToRight = false + } + + let offset: CGFloat = directionToRight ? previousPane.node.bounds.width : -previousPane.node.bounds.width + + transition.animatePositionAdditive(node: candidatePane.node, offset: CGPoint(x: offset, y: 0.0)) + let previousNode = previousPane.node + transition.updateFrame(node: previousNode, frame: paneFrame.offsetBy(dx: -offset, dy: 0.0), completion: { [weak previousNode] _ in + previousNode?.removeFromSupernode() + }) + } + } else if let currentPane = self.currentPane { + let paneWasAdded = currentPane.node.supernode == nil + if paneWasAdded { + self.addSubnode(currentPane.node) + } + + let paneTransition: ContainedViewLayoutTransition = paneWasAdded ? .immediate : transition + paneTransition.updateFrame(node: currentPane.node, frame: paneFrame) + currentPane.update(size: paneFrame.size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, isScrollingLockedAtTop: expansionFraction < 1.0 - CGFloat.ulpOfOne, presentationData: presentationData, synchronous: paneWasAdded, transition: paneTransition) + } + + transition.updateFrame(node: self.tabsContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: tabsHeight))) + self.tabsContainerNode.update(size: CGSize(width: size.width, height: tabsHeight), presentationData: presentationData, paneList: availablePanes.map { key in + let title: String + switch key { + case .media: + title = "Media" + case .files: + title = "Files" + case .links: + title = "Links" + case .voice: + title = "Voice Messages" + case .music: + title = "Audio" + case .groupsInCommon: + title = "Groups" + } + return PeerInfoPaneSpecifier(key: key, title: title) + }, selectedPane: self.currentPaneKey, transition: transition) + + if let (candidatePane, _, _) = self.candidatePane { + let paneTransition: ContainedViewLayoutTransition = .immediate + paneTransition.updateFrame(node: candidatePane.node, frame: paneFrame) + candidatePane.update(size: paneFrame.size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, isScrollingLockedAtTop: expansionFraction < 1.0 - CGFloat.ulpOfOne, presentationData: presentationData, synchronous: true, transition: paneTransition) + } + if !self.didSetIsReady && data != nil { + if let currentPane = self.currentPane { + self.didSetIsReady = true + self.isReady.set(currentPane.node.isReady) + } else if self.candidatePane == nil { + self.didSetIsReady = true + self.isReady.set(.single(true)) + } + } + if let previousCurrentPaneKey = previousCurrentPaneKey, self.currentPaneKey != previousCurrentPaneKey { + self.currentPaneUpdated?() + } + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift similarity index 51% rename from submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift rename to submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift index 1c4c6b0612..26aa03313d 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfoScreen.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift @@ -24,1960 +24,10 @@ import TelegramIntents import PeerInfoUI import SearchBarNode import SearchUI - -private enum PeerInfoHeaderButtonKey: Hashable { - case message - case call - case mute - case more - case addMember -} - -private enum PeerInfoHeaderButtonIcon { - case message - case call - case mute - case unmute - case more - case addMember -} - -private final class PeerInfoHeaderButtonNode: HighlightableButtonNode { - let key: PeerInfoHeaderButtonKey - private let action: (PeerInfoHeaderButtonNode) -> Void - let containerNode: ASDisplayNode - private let backgroundNode: ASImageNode - private let textNode: ImmediateTextNode - - private var theme: PresentationTheme? - private var icon: PeerInfoHeaderButtonIcon? - - init(key: PeerInfoHeaderButtonKey, action: @escaping (PeerInfoHeaderButtonNode) -> Void) { - self.key = key - self.action = action - - self.containerNode = ASDisplayNode() - - self.backgroundNode = ASImageNode() - self.backgroundNode.displaysAsynchronously = false - self.backgroundNode.displayWithoutProcessing = true - - self.textNode = ImmediateTextNode() - self.textNode.displaysAsynchronously = false - - super.init() - - self.addSubnode(self.containerNode) - self.containerNode.addSubnode(self.backgroundNode) - self.containerNode.addSubnode(self.textNode) - - self.highligthedChanged = { [weak self] highlighted in - if let strongSelf = self { - if highlighted { - strongSelf.layer.removeAnimation(forKey: "opacity") - strongSelf.alpha = 0.4 - } else { - strongSelf.alpha = 1.0 - strongSelf.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) - } - } - } - - self.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside) - } - - @objc private func buttonPressed() { - self.action(self) - } - - func update(size: CGSize, text: String, icon: PeerInfoHeaderButtonIcon, isExpanded: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) { - if self.theme != presentationData.theme || self.icon != icon { - self.theme = presentationData.theme - self.icon = icon - self.backgroundNode.image = generateImage(CGSize(width: 40.0, height: 40.0), contextGenerator: { size, context in - context.clear(CGRect(origin: CGPoint(), size: size)) - context.setFillColor(presentationData.theme.list.itemAccentColor.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(), size: size)) - context.setBlendMode(.normal) - context.setFillColor(presentationData.theme.list.itemCheckColors.foregroundColor.cgColor) - let imageName: String - switch icon { - case .message: - imageName = "Peer Info/ButtonMessage" - case .call: - imageName = "Peer Info/ButtonCall" - case .mute: - imageName = "Peer Info/ButtonMute" - case .unmute: - imageName = "Peer Info/ButtonUnmute" - case .more: - imageName = "Peer Info/ButtonMore" - case .addMember: - imageName = "Peer Info/ButtonAddMember" - } - if let image = UIImage(bundleImageName: imageName) { - let imageRect = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size) - context.clip(to: imageRect, mask: image.cgImage!) - context.fill(imageRect) - } - }) - } - - self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(12.0), textColor: presentationData.theme.list.itemAccentColor) - let titleSize = self.textNode.updateLayout(CGSize(width: 120.0, height: .greatestFiniteMagnitude)) - - transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(), size: size)) - transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size)) - transition.updateFrameAdditiveToCenter(node: self.textNode, frame: CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: size.height + 6.0), size: titleSize)) - transition.updateAlpha(node: self.textNode, alpha: isExpanded ? 0.0 : 1.0) - } -} - -private final class PeerInfoHeaderNavigationTransition { - let sourceNavigationBar: NavigationBar - let sourceTitleView: ChatTitleView - let sourceTitleFrame: CGRect - let sourceSubtitleFrame: CGRect - let fraction: CGFloat - - init(sourceNavigationBar: NavigationBar, sourceTitleView: ChatTitleView, sourceTitleFrame: CGRect, sourceSubtitleFrame: CGRect, fraction: CGFloat) { - self.sourceNavigationBar = sourceNavigationBar - self.sourceTitleView = sourceTitleView - self.sourceTitleFrame = sourceTitleFrame - self.sourceSubtitleFrame = sourceSubtitleFrame - self.fraction = fraction - } -} - -private enum PeerInfoAvatarListItem: Equatable { - case topImage([ImageRepresentationWithReference]) - case image(TelegramMediaImageReference?, [ImageRepresentationWithReference]) - - var id: WrappedMediaResourceId { - switch self { - case let .topImage(representations): - let representation = largestImageRepresentation(representations.map { $0.representation }) ?? representations[representations.count - 1].representation - return WrappedMediaResourceId(representation.resource.id) - case let .image(_, representations): - let representation = largestImageRepresentation(representations.map { $0.representation }) ?? representations[representations.count - 1].representation - return WrappedMediaResourceId(representation.resource.id) - } - } -} - -private final class PeerInfoAvatarListItemNode: ASDisplayNode { - private let imageNode: TransformImageNode - - let isReady = Promise() - private var didSetReady: Bool = false - - init(context: AccountContext, item: PeerInfoAvatarListItem) { - self.imageNode = TransformImageNode() - - super.init() - - self.addSubnode(self.imageNode) - let representations: [ImageRepresentationWithReference] - switch item { - case let .topImage(topRepresentations): - representations = topRepresentations - case let .image(_, imageRepresentations): - representations = imageRepresentations - } - self.imageNode.setSignal(chatAvatarGalleryPhoto(account: context.account, representations: representations, autoFetchFullSize: true), dispatchOnDisplayLink: false) - - self.imageNode.imageUpdated = { [weak self] _ in - guard let strongSelf = self else { - return - } - if !strongSelf.didSetReady { - strongSelf.didSetReady = true - strongSelf.isReady.set(.single(true)) - } - } - } - - func update(size: CGSize, transition: ContainedViewLayoutTransition) { - let imageSize = CGSize(width: min(size.width, size.height), height: min(size.width, size.height)) - let makeLayout = self.imageNode.asyncLayout() - let applyLayout = makeLayout(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets())) - let _ = applyLayout() - transition.updateFrame(node: self.imageNode, frame: CGRect(origin: CGPoint(x: floor((size.width - imageSize.width) / 2.0), y: floor((size.height - imageSize.height) / 2.0)), size: imageSize)) - } -} - -private final class PeerInfoAvatarListContainerNode: ASDisplayNode { - private let context: AccountContext - - let controlsContainerNode: ASDisplayNode - let controlsContainerTransformNode: ASDisplayNode - let shadowNode: ASDisplayNode - - let contentNode: ASDisplayNode - private var items: [PeerInfoAvatarListItem] = [] - private var itemNodes: [WrappedMediaResourceId: PeerInfoAvatarListItemNode] = [:] - private var currentIndex: Int = 0 - private var transitionFraction: CGFloat = 0.0 - - private var validLayout: CGSize? - - private let disposable = MetaDisposable() - private var initializedList = false - - let isReady = Promise() - private var didSetReady = false - - init(context: AccountContext) { - self.context = context - - self.contentNode = ASDisplayNode() - - self.controlsContainerNode = ASDisplayNode() - self.controlsContainerNode.isUserInteractionEnabled = false - - self.controlsContainerTransformNode = ASDisplayNode() - self.controlsContainerTransformNode.isUserInteractionEnabled = false - - self.shadowNode = ASDisplayNode() - //self.shadowNode.backgroundColor = .green - - super.init() - - self.backgroundColor = .black - - self.addSubnode(self.contentNode) - - self.controlsContainerNode.addSubnode(self.shadowNode) - self.controlsContainerTransformNode.addSubnode(self.controlsContainerNode) - self.addSubnode(self.controlsContainerTransformNode) - - self.view.disablesInteractiveTransitionGestureRecognizer = true - self.view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))) - } - - deinit { - self.disposable.dispose() - } - - override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { - return super.hitTest(point, with: event) - } - - @objc private func panGesture(_ recognizer: UIPanGestureRecognizer) { - switch recognizer.state { - case .changed: - let translation = recognizer.translation(in: self.view) - var transitionFraction = translation.x / self.bounds.width - if self.currentIndex <= 0 { - transitionFraction = min(0.0, transitionFraction) - } - if self.currentIndex >= self.items.count - 1 { - transitionFraction = max(0.0, transitionFraction) - } - self.transitionFraction = transitionFraction - if let size = self.validLayout { - self.updateItems(size: size, transition: .animated(duration: 0.3, curve: .spring)) - } - case .cancelled, .ended: - let translation = recognizer.translation(in: self.view) - let velocity = recognizer.velocity(in: self.view) - var directionIsToRight = false - if abs(velocity.x) > 10.0 { - directionIsToRight = velocity.x < 0.0 - } else { - directionIsToRight = translation.x > self.bounds.width / 2.0 - } - var updatedIndex = self.currentIndex - if directionIsToRight { - updatedIndex = min(updatedIndex + 1, self.items.count - 1) - } else { - updatedIndex = max(updatedIndex - 1, 0) - } - self.currentIndex = updatedIndex - self.transitionFraction = 0.0 - if let size = self.validLayout { - self.updateItems(size: size, transition: .animated(duration: 0.3, curve: .spring)) - } - default: - break - } - } - - func update(size: CGSize, peer: Peer?, transition: ContainedViewLayoutTransition) { - self.validLayout = size - if let peer = peer, !self.initializedList { - self.initializedList = true - self.disposable.set((fetchedAvatarGalleryEntries(account: self.context.account, peer: peer) - |> deliverOnMainQueue).start(next: { [weak self] entries in - guard let strongSelf = self else { - return - } - var items: [PeerInfoAvatarListItem] = [] - for entry in entries { - switch entry { - case let .topImage(representations, _): - items.append(.topImage(representations)) - case let .image(reference, representations, _, _, _, _): - items.append(.image(reference, representations)) - } - } - strongSelf.items = items - if let size = strongSelf.validLayout { - strongSelf.updateItems(size: size, transition: .immediate) - } - if items.isEmpty { - if !strongSelf.didSetReady { - strongSelf.didSetReady = true - strongSelf.isReady.set(.single(true)) - } - } - })) - } - self.updateItems(size: size, transition: transition) - } - - private func updateItems(size: CGSize, transition: ContainedViewLayoutTransition) { - var validIds: [WrappedMediaResourceId] = [] - var addedItemNodesForAdditiveTransition: [PeerInfoAvatarListItemNode] = [] - var additiveTransitionOffset: CGFloat = 0.0 - if self.currentIndex >= 0 && self.currentIndex < self.items.count { - for i in max(0, self.currentIndex - 1) ... min(self.currentIndex + 1, self.items.count - 1) { - validIds.append(self.items[i].id) - let itemNode: PeerInfoAvatarListItemNode - var wasAdded = false - if let current = self.itemNodes[self.items[i].id] { - itemNode = current - } else { - wasAdded = true - itemNode = PeerInfoAvatarListItemNode(context: self.context, item: self.items[i]) - self.itemNodes[self.items[i].id] = itemNode - self.contentNode.addSubnode(itemNode) - } - let indexOffset = CGFloat(i - self.currentIndex) - let itemFrame = CGRect(origin: CGPoint(x: indexOffset * size.width + self.transitionFraction * size.width - size.width / 2.0, y: -size.height / 2.0), size: size) - - if wasAdded { - addedItemNodesForAdditiveTransition.append(itemNode) - itemNode.frame = itemFrame - itemNode.update(size: size, transition: .immediate) - } else { - additiveTransitionOffset = itemNode.frame.minX - itemFrame.minX - transition.updateFrame(node: itemNode, frame: itemFrame) - itemNode.update(size: size, transition: transition) - } - } - } - for itemNode in addedItemNodesForAdditiveTransition { - transition.animatePositionAdditive(node: itemNode, offset: CGPoint(x: additiveTransitionOffset, y: 0.0)) - } - var removeIds: [WrappedMediaResourceId] = [] - for (id, _) in self.itemNodes { - if !validIds.contains(id) { - removeIds.append(id) - } - } - for id in removeIds { - if let itemNode = self.itemNodes.removeValue(forKey: id) { - itemNode.removeFromSupernode() - } - } - - if let item = self.items.first, let itemNode = self.itemNodes[item.id] { - if !self.didSetReady { - self.didSetReady = true - self.isReady.set(itemNode.isReady.get()) - } - } - } -} - -private final class PeerInfoAvatarTransformContainerNode: ASDisplayNode { - let context: AccountContext - let avatarNode: AvatarNode - - var tapped: (() -> Void)? - - private var isFirstAvatarLoading = true - - init(context: AccountContext) { - self.context = context - let avatarFont = avatarPlaceholderFont(size: floor(100.0 * 16.0 / 37.0)) - self.avatarNode = AvatarNode(font: avatarFont) - - super.init() - - self.addSubnode(self.avatarNode) - self.avatarNode.frame = CGRect(origin: CGPoint(x: -50.0, y: -50.0), size: CGSize(width: 100.0, height: 100.0)) - - self.avatarNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))) - } - - @objc private func tapGesture(_ recognizer: UITapGestureRecognizer) { - if case .ended = recognizer.state { - self.tapped?() - } - } - - func update(peer: Peer?, theme: PresentationTheme) { - if let peer = peer { - self.avatarNode.setPeer(context: self.context, theme: theme, peer: peer, synchronousLoad: self.isFirstAvatarLoading, displayDimensions: CGSize(width: 100.0, height: 100.0)) - self.isFirstAvatarLoading = false - } - } -} - -private final class PeerInfoEditingAvatarNode: ASDisplayNode { - let context: AccountContext - let avatarNode: AvatarNode - - var tapped: (() -> Void)? - - init(context: AccountContext) { - self.context = context - let avatarFont = avatarPlaceholderFont(size: floor(100.0 * 16.0 / 37.0)) - self.avatarNode = AvatarNode(font: avatarFont) - - super.init() - - self.addSubnode(self.avatarNode) - self.avatarNode.frame = CGRect(origin: CGPoint(x: -50.0, y: -50.0), size: CGSize(width: 100.0, height: 100.0)) - - self.avatarNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))) - } - - @objc private func tapGesture(_ recognizer: UITapGestureRecognizer) { - if case .ended = recognizer.state { - self.tapped?() - } - } - - func update(peer: Peer?, theme: PresentationTheme) { - if let peer = peer { - self.avatarNode.setPeer(context: self.context, theme: theme, peer: peer, synchronousLoad: false, displayDimensions: CGSize(width: 100.0, height: 100.0)) - } - } -} - -private final class PeerInfoAvatarListNode: ASDisplayNode { - let avatarContainerNode: PeerInfoAvatarTransformContainerNode - let listContainerTransformNode: ASDisplayNode - let listContainerNode: PeerInfoAvatarListContainerNode - - let isReady = Promise() - - init(context: AccountContext, readyWhenGalleryLoads: Bool) { - self.avatarContainerNode = PeerInfoAvatarTransformContainerNode(context: context) - self.listContainerTransformNode = ASDisplayNode() - self.listContainerNode = PeerInfoAvatarListContainerNode(context: context) - self.listContainerNode.clipsToBounds = true - self.listContainerNode.isHidden = true - - super.init() - - self.addSubnode(self.avatarContainerNode) - self.listContainerTransformNode.addSubnode(self.listContainerNode) - self.addSubnode(self.listContainerTransformNode) - - let avatarReady = self.avatarContainerNode.avatarNode.ready - |> mapToSignal { _ -> Signal in - return .complete() - } - |> then(.single(true)) - - let galleryReady = self.listContainerNode.isReady.get() - |> filter { $0 } - |> take(1) - - let combinedSignal: Signal - if readyWhenGalleryLoads { - combinedSignal = combineLatest(queue: .mainQueue(), - avatarReady, - galleryReady - ) - |> map { lhs, rhs in - return lhs && rhs - } - } else { - combinedSignal = avatarReady - } - - self.isReady.set(combinedSignal - |> filter { $0 } - |> take(1)) - } - - func update(size: CGSize, isExpanded: Bool, peer: Peer?, theme: PresentationTheme, transition: ContainedViewLayoutTransition) { - self.avatarContainerNode.update(peer: peer, theme: theme) - } - - override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { - if !self.listContainerNode.isHidden { - if let result = self.listContainerNode.view.hitTest(self.view.convert(point, to: self.listContainerNode.view), with: event) { - return result - } - } else { - if let result = self.avatarContainerNode.avatarNode.view.hitTest(self.view.convert(point, to: self.avatarContainerNode.avatarNode.view), with: event) { - return result - } - } - - return super.hitTest(point, with: event) - } -} - -private final class PeerInfoHeaderNavigationButton: HighlightableButtonNode { - private let regularTextNode: ImmediateTextNode - private let whiteTextNode: ImmediateTextNode - private let iconNode: ASImageNode - - private var key: PeerInfoHeaderNavigationButtonKey? - private var theme: PresentationTheme? - - var isWhite: Bool = false { - didSet { - if self.isWhite != oldValue { - self.regularTextNode.isHidden = self.isWhite - self.whiteTextNode.isHidden = !self.isWhite - } - } - } - - var action: (() -> Void)? - - override init() { - self.regularTextNode = ImmediateTextNode() - self.whiteTextNode = ImmediateTextNode() - self.whiteTextNode.isHidden = true - - self.iconNode = ASImageNode() - self.iconNode.displaysAsynchronously = false - self.iconNode.displayWithoutProcessing = true - - super.init() - - self.addSubnode(self.regularTextNode) - self.addSubnode(self.whiteTextNode) - self.addSubnode(self.iconNode) - - self.addTarget(self, action: #selector(self.pressed), forControlEvents: .touchUpInside) - } - - @objc private func pressed() { - self.action?() - } - - func update(key: PeerInfoHeaderNavigationButtonKey, presentationData: PresentationData) -> CGSize { - let textSize: CGSize - if self.key != key || self.theme !== presentationData.theme { - self.key = key - self.theme = presentationData.theme - - let text: String - var icon: UIImage? - var isBold = false - switch key { - case .edit: - text = presentationData.strings.Common_Edit - case .done, .cancel, .selectionDone: - text = presentationData.strings.Common_Done - isBold = true - case .select: - text = presentationData.strings.Common_Select - case .search: - text = "" - icon = PresentationResourcesRootController.navigationCompactSearchIcon(presentationData.theme) - } - - let font: UIFont = isBold ? Font.semibold(17.0) : Font.regular(17.0) - - self.regularTextNode.attributedText = NSAttributedString(string: text, font: font, textColor: presentationData.theme.rootController.navigationBar.accentTextColor) - self.whiteTextNode.attributedText = NSAttributedString(string: text, font: font, textColor: .white) - self.iconNode.image = icon - - textSize = self.regularTextNode.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude)) - let _ = self.whiteTextNode.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude)) - } else { - textSize = self.regularTextNode.bounds.size - } - - let inset: CGFloat = 0.0 - let height: CGFloat = 44.0 - - let textFrame = CGRect(origin: CGPoint(x: inset, y: floor((height - textSize.height) / 2.0)), size: textSize) - self.regularTextNode.frame = textFrame - self.whiteTextNode.frame = textFrame - - if let image = self.iconNode.image { - self.iconNode.frame = CGRect(origin: CGPoint(x: inset, y: floor((height - image.size.height) / 2.0)), size: image.size) - - return CGSize(width: image.size.width + inset * 2.0, height: height) - } else { - return CGSize(width: textSize.width + inset * 2.0, height: height) - } - } -} - -private enum PeerInfoHeaderNavigationButtonKey { - case edit - case done - case cancel - case select - case selectionDone - case search -} - -private struct PeerInfoHeaderNavigationButtonSpec: Equatable { - let key: PeerInfoHeaderNavigationButtonKey - let isForExpandedView: Bool -} - -private final class PeerInfoHeaderNavigationButtonContainerNode: ASDisplayNode { - private var buttonNodes: [PeerInfoHeaderNavigationButtonKey: PeerInfoHeaderNavigationButton] = [:] - - private var currentButtons: [PeerInfoHeaderNavigationButtonSpec] = [] - - var isWhite: Bool = false { - didSet { - if self.isWhite != oldValue { - for (_, buttonNode) in self.buttonNodes { - buttonNode.isWhite = self.isWhite - } - } - } - } - - var performAction: ((PeerInfoHeaderNavigationButtonKey) -> Void)? - - override init() { - super.init() - } - - func update(size: CGSize, presentationData: PresentationData, buttons: [PeerInfoHeaderNavigationButtonSpec], expandFraction: CGFloat, transition: ContainedViewLayoutTransition) { - let maximumExpandOffset: CGFloat = 14.0 - let expandOffset: CGFloat = -expandFraction * maximumExpandOffset - if self.currentButtons != buttons { - self.currentButtons = buttons - - var nextRegularButtonOrigin = size.width - 16.0 - var nextExpandedButtonOrigin = size.width - 16.0 - for spec in buttons.reversed() { - let buttonNode: PeerInfoHeaderNavigationButton - var wasAdded = false - if let current = self.buttonNodes[spec.key] { - buttonNode = current - } else { - wasAdded = true - buttonNode = PeerInfoHeaderNavigationButton() - self.buttonNodes[spec.key] = buttonNode - self.addSubnode(buttonNode) - buttonNode.isWhite = self.isWhite - buttonNode.action = { [weak self] in - self?.performAction?(spec.key) - } - } - let buttonSize = buttonNode.update(key: spec.key, presentationData: presentationData) - var nextButtonOrigin = spec.isForExpandedView ? nextExpandedButtonOrigin : nextRegularButtonOrigin - let buttonFrame = CGRect(origin: CGPoint(x: nextButtonOrigin - buttonSize.width, y: expandOffset + (spec.isForExpandedView ? maximumExpandOffset : 0.0)), size: buttonSize) - nextButtonOrigin -= buttonSize.width + 4.0 - if spec.isForExpandedView { - nextExpandedButtonOrigin = nextButtonOrigin - } else { - nextRegularButtonOrigin = nextButtonOrigin - } - if wasAdded { - buttonNode.frame = buttonFrame - } else { - transition.updateFrameAdditiveToCenter(node: buttonNode, frame: buttonFrame) - } - let alphaFactor: CGFloat = spec.isForExpandedView ? expandFraction : (1.0 - expandFraction) - transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor) - } - var removeKeys: [PeerInfoHeaderNavigationButtonKey] = [] - for (key, _) in self.buttonNodes { - if !buttons.contains(where: { $0.key == key }) { - removeKeys.append(key) - } - } - for key in removeKeys { - if let buttonNode = self.buttonNodes.removeValue(forKey: key) { - buttonNode.removeFromSupernode() - } - } - } else { - var nextRegularButtonOrigin = size.width - 16.0 - var nextExpandedButtonOrigin = size.width - 16.0 - for spec in buttons.reversed() { - if let buttonNode = self.buttonNodes[spec.key] { - let buttonSize = buttonNode.bounds.size - var nextButtonOrigin = spec.isForExpandedView ? nextExpandedButtonOrigin : nextRegularButtonOrigin - let buttonFrame = CGRect(origin: CGPoint(x: nextButtonOrigin - buttonSize.width, y: expandOffset + (spec.isForExpandedView ? maximumExpandOffset : 0.0)), size: buttonSize) - nextButtonOrigin -= buttonSize.width + 4.0 - if spec.isForExpandedView { - nextExpandedButtonOrigin = nextButtonOrigin - } else { - nextRegularButtonOrigin = nextButtonOrigin - } - transition.updateFrameAdditiveToCenter(node: buttonNode, frame: buttonFrame) - let alphaFactor: CGFloat = spec.isForExpandedView ? expandFraction : (1.0 - expandFraction) - transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor) - } - } - } - } -} - -private final class PeerInfoHeaderRegularContentNode: ASDisplayNode { - -} - -private enum PeerInfoHeaderTextFieldNodeKey { - case firstName - case lastName - case title - case description -} - -private protocol PeerInfoHeaderTextFieldNode: ASDisplayNode { - var text: String { get } - - func update(width: CGFloat, safeInset: CGFloat, hasPrevious: Bool, placeholder: String, isEnabled: Bool, presentationData: PresentationData, updateText: String?) -> CGFloat -} - -private final class PeerInfoHeaderSingleLineTextFieldNode: ASDisplayNode, PeerInfoHeaderTextFieldNode { - private let textNode: TextFieldNode - private let topSeparator: ASDisplayNode - - private var theme: PresentationTheme? - - var text: String { - return self.textNode.textField.text ?? "" - } - - override init() { - self.textNode = TextFieldNode() - self.topSeparator = ASDisplayNode() - - super.init() - - self.addSubnode(self.textNode) - self.addSubnode(self.topSeparator) - } - - func update(width: CGFloat, safeInset: CGFloat, hasPrevious: Bool, placeholder: String, isEnabled: Bool, presentationData: PresentationData, updateText: String?) -> CGFloat { - if self.theme !== presentationData.theme { - self.theme = presentationData.theme - self.textNode.textField.textColor = presentationData.theme.list.itemPrimaryTextColor - //self.textNode.textField.keyboardAppearance = presentationData.theme.keyboardAppearance - self.textNode.textField.tintColor = presentationData.theme.list.itemAccentColor - } - - let attributedPlaceholderText = NSAttributedString(string: placeholder, font: Font.regular(17.0), textColor: presentationData.theme.list.itemPlaceholderTextColor) - if self.textNode.textField.attributedPlaceholder == nil || !self.textNode.textField.attributedPlaceholder!.isEqual(to: attributedPlaceholderText) { - self.textNode.textField.attributedPlaceholder = attributedPlaceholderText - self.textNode.textField.accessibilityHint = attributedPlaceholderText.string - } - - if let updateText = updateText { - self.textNode.textField.text = updateText - } - - self.topSeparator.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor - self.topSeparator.frame = CGRect(origin: CGPoint(x: safeInset + (hasPrevious ? 16.0 : 0.0), y: 0.0), size: CGSize(width: width, height: UIScreenPixel)) - - let height: CGFloat = 44.0 - - self.textNode.frame = CGRect(origin: CGPoint(x: safeInset + 16.0, y: floor((height - 40.0) / 2.0)), size: CGSize(width: max(1.0, width - 16.0 * 2.0), height: 40.0)) - - self.textNode.isUserInteractionEnabled = isEnabled - self.textNode.alpha = isEnabled ? 1.0 : 0.6 - - return height - } -} - -/*private final class PeerInfoHeaderMultiLineTextFieldNode: ASDisplayNode, PeerInfoHeaderTextFieldNode { - private let textNode: TextFieldNode - private let topSeparator: ASDisplayNode - - override init() { - self.textNode = TextFieldNode() - self.topSeparator = ASDisplayNode() - - super.init() - } - - func update(width: CGFloat, safeInset: CGFloat) -> CGFloat { - return 44.0 - } -}*/ - -private final class PeerInfoHeaderEditingContentNode: ASDisplayNode { - private let context: AccountContext - let avatarNode: PeerInfoEditingAvatarNode - - var itemNodes: [PeerInfoHeaderTextFieldNodeKey: PeerInfoHeaderTextFieldNode] = [:] - - init(context: AccountContext) { - self.context = context - self.avatarNode = PeerInfoEditingAvatarNode(context: context) - - super.init() - - self.addSubnode(self.avatarNode) - } - - func editingTextForKey(_ key: PeerInfoHeaderTextFieldNodeKey) -> String? { - return self.itemNodes[key]?.text - } - - func update(width: CGFloat, safeInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, peer: Peer?, isContact: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) -> CGFloat { - let avatarSize: CGFloat = 100.0 - let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 10.0), size: CGSize(width: avatarSize, height: avatarSize)) - transition.updateFrameAdditiveToCenter(node: self.avatarNode, frame: CGRect(origin: avatarFrame.center, size: CGSize())) - - var contentHeight: CGFloat = statusBarHeight + 10.0 + 100.0 + 20.0 - - var fieldKeys: [PeerInfoHeaderTextFieldNodeKey] = [] - if let _ = peer as? TelegramUser { - fieldKeys.append(.firstName) - fieldKeys.append(.lastName) - } - var hasPrevious = false - for key in fieldKeys { - let itemNode: PeerInfoHeaderTextFieldNode - var updateText: String? - if let current = self.itemNodes[key] { - itemNode = current - } else { - switch key { - case .firstName: - updateText = (peer as? TelegramUser)?.firstName ?? "" - case .lastName: - updateText = (peer as? TelegramUser)?.lastName ?? "" - case .title: - updateText = (peer as? TelegramUser)?.debugDisplayTitle ?? "" - case .description: - break - } - itemNode = PeerInfoHeaderSingleLineTextFieldNode() - self.itemNodes[key] = itemNode - self.addSubnode(itemNode) - } - let placeholder: String - var isEnabled = true - switch key { - case .firstName: - placeholder = "First Name" - isEnabled = isContact - case .lastName: - placeholder = "Last Name" - isEnabled = isContact - case .title: - placeholder = "Title" - case .description: - placeholder = "Description" - } - let itemHeight = itemNode.update(width: width, safeInset: safeInset, hasPrevious: hasPrevious, placeholder: placeholder, isEnabled: isEnabled, presentationData: presentationData, updateText: updateText) - transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: itemHeight))) - contentHeight += itemHeight - hasPrevious = true - } - var removeKeys: [PeerInfoHeaderTextFieldNodeKey] = [] - for (key, _) in self.itemNodes { - if !fieldKeys.contains(key) { - removeKeys.append(key) - } - } - for key in removeKeys { - if let itemNode = self.itemNodes.removeValue(forKey: key) { - itemNode.removeFromSupernode() - } - } - - return contentHeight - } -} - -private final class PeerInfoHeaderNode: ASDisplayNode { - private var context: AccountContext - private var presentationData: PresentationData? - - private(set) var isAvatarExpanded: Bool - - let avatarListNode: PeerInfoAvatarListNode - - let regularContentNode: PeerInfoHeaderRegularContentNode - let editingContentNode: PeerInfoHeaderEditingContentNode - let titleNodeContainer: ASDisplayNode - let titleNodeRawContainer: ASDisplayNode - let titleNode: ImmediateTextNode - let subtitleNodeContainer: ASDisplayNode - let subtitleNodeRawContainer: ASDisplayNode - let subtitleNode: ImmediateTextNode - private var buttonNodes: [PeerInfoHeaderButtonKey: PeerInfoHeaderButtonNode] = [:] - private let backgroundNode: ASDisplayNode - private let expandedBackgroundNode: ASDisplayNode - let separatorNode: ASDisplayNode - let navigationButtonContainer: PeerInfoHeaderNavigationButtonContainerNode - - var performButtonAction: ((PeerInfoHeaderButtonKey) -> Void)? - var requestAvatarExpansion: (() -> Void)? - - var navigationTransition: PeerInfoHeaderNavigationTransition? - - init(context: AccountContext, avatarInitiallyExpanded: Bool) { - self.context = context - self.isAvatarExpanded = avatarInitiallyExpanded - - self.avatarListNode = PeerInfoAvatarListNode(context: context, readyWhenGalleryLoads: avatarInitiallyExpanded) - - self.titleNodeContainer = ASDisplayNode() - self.titleNodeRawContainer = ASDisplayNode() - self.titleNode = ImmediateTextNode() - self.titleNode.displaysAsynchronously = false - - self.subtitleNodeContainer = ASDisplayNode() - self.subtitleNodeRawContainer = ASDisplayNode() - self.subtitleNode = ImmediateTextNode() - self.subtitleNode.displaysAsynchronously = false - - self.regularContentNode = PeerInfoHeaderRegularContentNode() - self.editingContentNode = PeerInfoHeaderEditingContentNode(context: context) - self.editingContentNode.alpha = 0.0 - - self.navigationButtonContainer = PeerInfoHeaderNavigationButtonContainerNode() - - self.backgroundNode = ASDisplayNode() - self.backgroundNode.isLayerBacked = true - self.expandedBackgroundNode = ASDisplayNode() - self.expandedBackgroundNode.isLayerBacked = true - - self.separatorNode = ASDisplayNode() - self.separatorNode.isLayerBacked = true - - super.init() - - self.addSubnode(self.backgroundNode) - self.addSubnode(self.expandedBackgroundNode) - self.addSubnode(self.separatorNode) - self.titleNodeContainer.addSubnode(self.titleNode) - self.regularContentNode.addSubnode(self.titleNodeContainer) - self.subtitleNodeContainer.addSubnode(self.subtitleNode) - self.regularContentNode.addSubnode(self.subtitleNodeContainer) - self.regularContentNode.addSubnode(self.avatarListNode) - self.addSubnode(self.regularContentNode) - self.addSubnode(self.editingContentNode) - self.addSubnode(self.navigationButtonContainer) - - self.avatarListNode.avatarContainerNode.tapped = { [weak self] in - guard let strongSelf = self else { - return - } - if !strongSelf.isAvatarExpanded { - strongSelf.requestAvatarExpansion?() - } - } - } - - func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, contentOffset: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, notificationSettings: TelegramPeerNotificationSettings?, presence: TelegramUserPresence?, isContact: Bool, state: PeerInfoState, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat { - self.presentationData = presentationData - - self.regularContentNode.alpha = state.isEditing ? 0.0 : 1.0 - self.editingContentNode.alpha = state.isEditing ? 1.0 : 0.0 - - let editingContentHeight = self.editingContentNode.update(width: width, safeInset: containerInset, statusBarHeight: statusBarHeight, navigationHeight: navigationHeight, peer: state.isEditing ? peer : nil, isContact: isContact, presentationData: presentationData, transition: transition) - transition.updateFrame(node: self.editingContentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -contentOffset), size: CGSize(width: width, height: editingContentHeight))) - - var transitionSourceHeight: CGFloat = 0.0 - var transitionFraction: CGFloat = 0.0 - var transitionSourceAvatarFrame = CGRect() - var transitionSourceTitleFrame = CGRect() - var transitionSourceSubtitleFrame = CGRect() - - self.backgroundNode.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor - self.expandedBackgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.backgroundColor - - if let navigationTransition = self.navigationTransition, let sourceAvatarNode = navigationTransition.sourceTitleView.avatarNode?.avatarNode { - transitionSourceHeight = navigationTransition.sourceNavigationBar.bounds.height - transitionFraction = navigationTransition.fraction - transitionSourceAvatarFrame = sourceAvatarNode.view.convert(sourceAvatarNode.view.bounds, to: navigationTransition.sourceNavigationBar.view) - transitionSourceTitleFrame = navigationTransition.sourceTitleFrame - transitionSourceSubtitleFrame = navigationTransition.sourceSubtitleFrame - - //transition.updateBackgroundColor(node: self.backgroundNode, color: presentationData.theme.list.itemBlocksBackgroundColor.interpolateTo(presentationData.theme.rootController.navigationBar.backgroundColor, fraction: transitionFraction)!) - transition.updateAlpha(node: self.expandedBackgroundNode, alpha: transitionFraction) - } else { - let backgroundTransitionFraction: CGFloat = max(0.0, min(1.0, contentOffset / (212.0))) - transition.updateAlpha(node: self.expandedBackgroundNode, alpha: backgroundTransitionFraction) - //transition.updateBackgroundColor(node: self.backgroundNode, color: presentationData.theme.list.itemBlocksBackgroundColor.interpolateTo(presentationData.theme.rootController.navigationBar.backgroundColor, fraction: backgroundTransitionFraction)!) - } - - self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor - - let defaultButtonSize: CGFloat = 40.0 - let defaultMaxButtonSpacing: CGFloat = 40.0 - let expandedAvatarListHeight = min(width, containerHeight - 64.0) - let expandedAvatarListSize = CGSize(width: width, height: expandedAvatarListHeight) - - var buttonKeys: [PeerInfoHeaderButtonKey] = [] - - if let peer = peer { - buttonKeys.append(.message) - buttonKeys.append(.call) - buttonKeys.append(.mute) - buttonKeys.append(.more) - - self.titleNode.attributedText = NSAttributedString(string: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.medium(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor) - - let presence = presence ?? TelegramUserPresence(status: .none, lastActivity: 0) - let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 - let (subtitleString, activity) = stringAndActivityForUserPresence(strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, presence: presence, relativeTo: Int32(timestamp), expanded: true) - let subtitleColor: UIColor - if activity { - subtitleColor = presentationData.theme.list.itemAccentColor - } else { - subtitleColor = presentationData.theme.list.itemSecondaryTextColor - } - self.subtitleNode.attributedText = NSAttributedString(string: subtitleString, font: Font.regular(15.0), textColor: subtitleColor) - } - - let textSideInset: CGFloat = 16.0 - let expandedAvatarControlsHeight: CGFloat = 64.0 - let expandedAvatarHeight: CGFloat = expandedAvatarListSize.height + expandedAvatarControlsHeight - - let avatarSize: CGFloat = 100.0 - let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 10.0), size: CGSize(width: avatarSize, height: avatarSize)) - let avatarCenter = CGPoint(x: (1.0 - transitionFraction) * avatarFrame.midX + transitionFraction * transitionSourceAvatarFrame.midX, y: (1.0 - transitionFraction) * avatarFrame.midY + transitionFraction * transitionSourceAvatarFrame.midY) - - let titleSize = self.titleNode.updateLayout(CGSize(width: width - textSideInset * 2.0, height: .greatestFiniteMagnitude)) - let subtitleSize = self.subtitleNode.updateLayout(CGSize(width: width - textSideInset * 2.0, height: .greatestFiniteMagnitude)) - - let titleFrame: CGRect - let subtitleFrame: CGRect - if self.isAvatarExpanded { - titleFrame = CGRect(origin: CGPoint(x: 16.0, y: expandedAvatarHeight - expandedAvatarControlsHeight + 12.0), size: titleSize) - subtitleFrame = CGRect(origin: CGPoint(x: 16.0, y: titleFrame.maxY - 5.0), size: subtitleSize) - } else { - titleFrame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: avatarFrame.maxY + 10.0), size: titleSize) - subtitleFrame = CGRect(origin: CGPoint(x: floor((width - subtitleSize.width) / 2.0), y: titleFrame.maxY + 1.0), size: subtitleSize) - } - - let titleLockOffset: CGFloat = 7.0 - let titleMaxLockOffset: CGFloat = 7.0 - let titleCollapseOffset = titleFrame.midY - statusBarHeight - titleLockOffset - let titleOffset = -min(titleCollapseOffset, contentOffset) - let titleCollapseFraction = max(0.0, min(1.0, contentOffset / titleCollapseOffset)) - - let titleMinScale: CGFloat = 0.7 - let subtitleMinScale: CGFloat = 0.8 - let avatarMinScale: CGFloat = 0.7 - - let apparentTitleLockOffset = (1.0 - titleCollapseFraction) * 0.0 + titleCollapseFraction * titleMaxLockOffset - - let avatarScale: CGFloat - let avatarOffset: CGFloat - if self.navigationTransition != nil { - avatarScale = ((1.0 - transitionFraction) * avatarFrame.width + transitionFraction * transitionSourceAvatarFrame.width) / avatarFrame.width - avatarOffset = 0.0 - } else { - avatarScale = 1.0 * (1.0 - titleCollapseFraction) + avatarMinScale * titleCollapseFraction - avatarOffset = apparentTitleLockOffset + 0.0 * (1.0 - titleCollapseFraction) + 10.0 * titleCollapseFraction - } - let avatarListFrame = CGRect(origin: CGPoint(), size: expandedAvatarListSize) - - if self.isAvatarExpanded { - self.avatarListNode.listContainerNode.isHidden = false - if !transitionSourceAvatarFrame.width.isZero { - transition.updateCornerRadius(node: self.avatarListNode.listContainerNode, cornerRadius: transitionFraction * transitionSourceAvatarFrame.width / 2.0) - } else { - transition.updateCornerRadius(node: self.avatarListNode.listContainerNode, cornerRadius: 0.0) - } - } else if self.avatarListNode.listContainerNode.cornerRadius != 50.0 { - transition.updateCornerRadius(node: self.avatarListNode.listContainerNode, cornerRadius: 50.0, completion: { [weak self] _ in - guard let strongSelf = self else { - return - } - strongSelf.avatarListNode.listContainerNode.isHidden = true - }) - } - - self.avatarListNode.update(size: CGSize(), isExpanded: self.isAvatarExpanded, peer: peer, theme: presentationData.theme, transition: transition) - self.editingContentNode.avatarNode.update(peer: peer, theme: presentationData.theme) - if additive { - transition.updateSublayerTransformScaleAdditive(node: self.avatarListNode.avatarContainerNode, scale: avatarScale) - } else { - transition.updateSublayerTransformScale(node: self.avatarListNode.avatarContainerNode, scale: avatarScale) - } - let apparentAvatarFrame: CGRect - if self.isAvatarExpanded { - let expandedAvatarCenter = CGPoint(x: expandedAvatarListSize.width / 2.0, y: expandedAvatarListSize.height / 2.0 - contentOffset / 2.0) - apparentAvatarFrame = CGRect(origin: CGPoint(x: expandedAvatarCenter.x * (1.0 - transitionFraction) + transitionFraction * avatarCenter.x, y: expandedAvatarCenter.y * (1.0 - transitionFraction) + transitionFraction * avatarCenter.y), size: CGSize()) - } else { - apparentAvatarFrame = CGRect(origin: CGPoint(x: avatarCenter.x - avatarFrame.width / 2.0, y: -contentOffset + avatarOffset + avatarCenter.y - avatarFrame.height / 2.0), size: avatarFrame.size) - } - if case let .animated(duration, curve) = transition, !transitionSourceAvatarFrame.width.isZero, false { - let previousFrame = self.avatarListNode.frame - self.avatarListNode.frame = CGRect(origin: apparentAvatarFrame.center, size: CGSize()) - let horizontalTransition: ContainedViewLayoutTransition - let verticalTransition: ContainedViewLayoutTransition - if transitionFraction < .ulpOfOne { - horizontalTransition = .animated(duration: duration * 0.85, curve: curve) - verticalTransition = .animated(duration: duration * 1.15, curve: curve) - } else { - horizontalTransition = transition - verticalTransition = .animated(duration: duration * 0.6, curve: curve) - } - horizontalTransition.animatePositionAdditive(node: self.avatarListNode, offset: CGPoint(x: previousFrame.midX - apparentAvatarFrame.midX, y: 0.0)) - verticalTransition.animatePositionAdditive(node: self.avatarListNode, offset: CGPoint(x: 0.0, y: previousFrame.midY - apparentAvatarFrame.midY)) - } else { - transition.updateFrameAdditive(node: self.avatarListNode, frame: CGRect(origin: apparentAvatarFrame.center, size: CGSize())) - } - - let avatarListContainerFrame: CGRect - let avatarListContainerScale: CGFloat - if self.isAvatarExpanded { - if !transitionSourceAvatarFrame.width.isZero { - let neutralAvatarListContainerSize = expandedAvatarListSize - let avatarListContainerSize = CGSize(width: neutralAvatarListContainerSize.width * (1.0 - transitionFraction) + transitionSourceAvatarFrame.width * transitionFraction, height: neutralAvatarListContainerSize.height * (1.0 - transitionFraction) + transitionSourceAvatarFrame.height * transitionFraction) - avatarListContainerFrame = CGRect(origin: CGPoint(x: -avatarListContainerSize.width / 2.0, y: -avatarListContainerSize.height / 2.0), size: avatarListContainerSize) - } else { - avatarListContainerFrame = CGRect(origin: CGPoint(x: -expandedAvatarListSize.width / 2.0, y: -expandedAvatarListSize.height / 2.0), size: expandedAvatarListSize) - } - avatarListContainerScale = 1.0 + max(0.0, -contentOffset / avatarListContainerFrame.height) - } else { - avatarListContainerFrame = CGRect(origin: CGPoint(x: -apparentAvatarFrame.width / 2.0, y: -apparentAvatarFrame.height / 2.0), size: apparentAvatarFrame.size) - avatarListContainerScale = avatarScale - } - transition.updateFrame(node: self.avatarListNode.listContainerNode, frame: avatarListContainerFrame) - let innerScale = avatarListContainerFrame.height / expandedAvatarListSize.height - let innerDeltaX = (avatarListContainerFrame.width - expandedAvatarListSize.width) / 2.0 - let innerDeltaY = (avatarListContainerFrame.height - expandedAvatarListSize.height) / 2.0 - transition.updateSublayerTransformScale(node: self.avatarListNode.listContainerNode, scale: innerScale) - transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.contentNode, frame: CGRect(origin: CGPoint(x: innerDeltaX + expandedAvatarListSize.width / 2.0, y: innerDeltaY + expandedAvatarListSize.height / 2.0), size: CGSize())) - - transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.controlsContainerTransformNode, frame: CGRect(origin: CGPoint(x: expandedAvatarListSize.width / 2.0, y: expandedAvatarListSize.height / 2.0 - innerDeltaY), size: CGSize())) - transition.updateSublayerTransformScale(node: self.avatarListNode.listContainerNode.controlsContainerNode, scale: 1.0 / innerScale) - transition.updateSublayerTransformScaleAdditive(node: self.avatarListNode.listContainerNode.controlsContainerTransformNode, scale: 1.0 / avatarListContainerScale) - transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.shadowNode, frame: CGRect(origin: CGPoint(x: -apparentAvatarFrame.minX, y: -apparentAvatarFrame.minY), size: CGSize(width: expandedAvatarListSize.width, height: navigationHeight))) - - if additive { - transition.updateSublayerTransformScaleAdditive(node: self.avatarListNode.listContainerTransformNode, scale: avatarListContainerScale) - } else { - transition.updateSublayerTransformScale(node: self.avatarListNode.listContainerTransformNode, scale: avatarListContainerScale) - } - - self.avatarListNode.listContainerNode.update(size: expandedAvatarListSize, peer: peer, transition: transition) - - let buttonsCollapseStart = titleCollapseOffset - let buttonsCollapseEnd = 212.0 - (navigationHeight - statusBarHeight) + 10.0 - - let buttonsCollapseFraction = max(0.0, contentOffset - buttonsCollapseStart) / (buttonsCollapseEnd - buttonsCollapseStart) - - let rawHeight: CGFloat - let height: CGFloat - if self.isAvatarExpanded { - rawHeight = expandedAvatarHeight - height = max(navigationHeight, rawHeight - contentOffset) - } else { - rawHeight = navigationHeight + 212.0 - height = navigationHeight + max(0.0, 212.0 - contentOffset) - } - - let apparentHeight = (1.0 - transitionFraction) * height + transitionFraction * transitionSourceHeight - - if !titleSize.width.isZero && !titleSize.height.isZero { - if self.navigationTransition != nil { - var neutralTitleScale: CGFloat = 1.0 - var neutralSubtitleScale: CGFloat = 1.0 - if self.isAvatarExpanded { - neutralTitleScale = 0.7 - neutralSubtitleScale = 1.0 - } - - let titleScale = (transitionFraction * transitionSourceTitleFrame.height + (1.0 - transitionFraction) * titleFrame.height * neutralTitleScale) / (titleFrame.height) - let subtitleScale = max(0.01, min(10.0, (transitionFraction * transitionSourceSubtitleFrame.height + (1.0 - transitionFraction) * subtitleFrame.height * neutralSubtitleScale) / (subtitleFrame.height))) - - let titleOrigin = CGPoint(x: transitionFraction * transitionSourceTitleFrame.minX + (1.0 - transitionFraction) * titleFrame.minX, y: transitionFraction * transitionSourceTitleFrame.minY + (1.0 - transitionFraction) * titleFrame.minY) - let subtitleOrigin = CGPoint(x: transitionFraction * transitionSourceSubtitleFrame.minX + (1.0 - transitionFraction) * subtitleFrame.minX, y: transitionFraction * transitionSourceSubtitleFrame.minY + (1.0 - transitionFraction) * subtitleFrame.minY) - - let rawTitleFrame = CGRect(origin: titleOrigin, size: titleFrame.size) - self.titleNodeRawContainer.frame = rawTitleFrame - transition.updateFrameAdditiveToCenter(node: self.titleNodeContainer, frame: rawTitleFrame.offsetBy(dx: rawTitleFrame.width * 0.5 * (titleScale - 1.0), dy: titleOffset + rawTitleFrame.height * 0.5 * (titleScale - 1.0))) - transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(), size: titleFrame.size)) - let rawSubtitleFrame = CGRect(origin: subtitleOrigin, size: subtitleFrame.size) - self.subtitleNodeRawContainer.frame = rawSubtitleFrame - transition.updateFrameAdditiveToCenter(node: self.subtitleNodeContainer, frame: rawSubtitleFrame.offsetBy(dx: rawSubtitleFrame.width * 0.5 * (subtitleScale - 1.0), dy: titleOffset + rawSubtitleFrame.height * 0.5 * (subtitleScale - 1.0))) - transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(), size: subtitleFrame.size)) - transition.updateSublayerTransformScale(node: self.titleNodeContainer, scale: titleScale) - transition.updateSublayerTransformScale(node: self.subtitleNodeContainer, scale: subtitleScale) - } else { - let titleScale: CGFloat - let subtitleScale: CGFloat - if self.isAvatarExpanded { - titleScale = 0.7 - subtitleScale = 1.0 - } else { - titleScale = (1.0 - titleCollapseFraction) * 1.0 + titleCollapseFraction * titleMinScale - subtitleScale = (1.0 - titleCollapseFraction) * 1.0 + titleCollapseFraction * subtitleMinScale - } - - let rawTitleFrame = titleFrame - self.titleNodeRawContainer.frame = rawTitleFrame - transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(), size: titleFrame.size)) - let rawSubtitleFrame = subtitleFrame - self.subtitleNodeRawContainer.frame = rawSubtitleFrame - if self.isAvatarExpanded { - transition.updateFrameAdditive(node: self.titleNodeContainer, frame: rawTitleFrame.offsetBy(dx: 0.0, dy: titleOffset + apparentTitleLockOffset).offsetBy(dx: rawTitleFrame.width * 0.5 * (titleScale - 1.0), dy: rawTitleFrame.height * 0.5 * (titleScale - 1.0))) - transition.updateFrameAdditive(node: self.subtitleNodeContainer, frame: rawSubtitleFrame.offsetBy(dx: 0.0, dy: titleOffset).offsetBy(dx: rawSubtitleFrame.width * 0.5 * (subtitleScale - 1.0), dy: rawSubtitleFrame.height * 0.5 * (subtitleScale - 1.0))) - } else { - transition.updateFrameAdditiveToCenter(node: self.titleNodeContainer, frame: rawTitleFrame.offsetBy(dx: 0.0, dy: titleOffset + apparentTitleLockOffset)) - transition.updateFrameAdditiveToCenter(node: self.subtitleNodeContainer, frame: rawSubtitleFrame.offsetBy(dx: 0.0, dy: titleOffset)) - } - transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(), size: subtitleFrame.size)) - transition.updateSublayerTransformScaleAdditive(node: self.titleNodeContainer, scale: titleScale) - transition.updateSublayerTransformScaleAdditive(node: self.subtitleNodeContainer, scale: subtitleScale) - } - } - - let buttonSpacing: CGFloat - if self.isAvatarExpanded { - buttonSpacing = 16.0 - } else { - buttonSpacing = min(defaultMaxButtonSpacing, width - floor(CGFloat(buttonKeys.count) * defaultButtonSize / CGFloat(buttonKeys.count + 1))) - } - - let expandedButtonSize: CGFloat = 32.0 - let buttonsWidth = buttonSpacing * CGFloat(buttonKeys.count - 1) + CGFloat(buttonKeys.count) * defaultButtonSize - var buttonRightOrigin: CGPoint - if self.isAvatarExpanded { - buttonRightOrigin = CGPoint(x: width - 16.0, y: apparentHeight - 74.0) - } else { - buttonRightOrigin = CGPoint(x: floor((width - buttonsWidth) / 2.0) + buttonsWidth, y: apparentHeight - 74.0) - } - let buttonsScale: CGFloat - let buttonsAlpha: CGFloat - let apparentButtonSize: CGFloat - let buttonsVerticalOffset: CGFloat - if self.navigationTransition != nil { - if self.isAvatarExpanded { - apparentButtonSize = expandedButtonSize - } else { - apparentButtonSize = defaultButtonSize - } - let neutralButtonsScale = apparentButtonSize / defaultButtonSize - buttonsScale = (1.0 - transitionFraction) * neutralButtonsScale + 0.2 * transitionFraction - buttonsAlpha = 1.0 - transitionFraction - - let neutralButtonsOffset: CGFloat - if self.isAvatarExpanded { - neutralButtonsOffset = 74.0 - 15.0 - defaultButtonSize + (defaultButtonSize - apparentButtonSize) / 2.0 - } else { - neutralButtonsOffset = (1.0 - buttonsScale) * apparentButtonSize - } - - buttonsVerticalOffset = (1.0 - transitionFraction) * neutralButtonsOffset + ((1.0 - buttonsScale) * apparentButtonSize) * transitionFraction - } else { - apparentButtonSize = self.isAvatarExpanded ? expandedButtonSize : defaultButtonSize - if self.isAvatarExpanded { - buttonsScale = apparentButtonSize / defaultButtonSize - buttonsVerticalOffset = 74.0 - 15.0 - defaultButtonSize + (defaultButtonSize - apparentButtonSize) / 2.0 - } else { - buttonsScale = (1.0 - buttonsCollapseFraction) * 1.0 + 0.2 * buttonsCollapseFraction - buttonsVerticalOffset = (1.0 - buttonsScale) * apparentButtonSize - } - buttonsAlpha = 1.0 - buttonsCollapseFraction - } - let buttonsScaledOffset = (defaultButtonSize - apparentButtonSize) / 2.0 - for buttonKey in buttonKeys.reversed() { - let buttonNode: PeerInfoHeaderButtonNode - var wasAdded = false - if let current = self.buttonNodes[buttonKey] { - buttonNode = current - } else { - wasAdded = true - buttonNode = PeerInfoHeaderButtonNode(key: buttonKey, action: { [weak self] buttonNode in - self?.buttonPressed(buttonNode) - }) - self.buttonNodes[buttonKey] = buttonNode - self.regularContentNode.addSubnode(buttonNode) - } - - let buttonFrame = CGRect(origin: CGPoint(x: buttonRightOrigin.x - defaultButtonSize + buttonsScaledOffset, y: buttonRightOrigin.y), size: CGSize(width: defaultButtonSize, height: defaultButtonSize)) - let buttonTransition: ContainedViewLayoutTransition = wasAdded ? .immediate : transition - - let apparentButtonFrame = buttonFrame.offsetBy(dx: 0.0, dy: buttonsVerticalOffset) - if additive { - buttonTransition.updateFrameAdditiveToCenter(node: buttonNode, frame: apparentButtonFrame) - } else { - buttonTransition.updateFrame(node: buttonNode, frame: apparentButtonFrame) - } - let buttonText: String - let buttonIcon: PeerInfoHeaderButtonIcon - switch buttonKey { - case .message: - buttonText = "Message" - buttonIcon = .message - case .call: - buttonText = "Call" - buttonIcon = .call - case .mute: - if let notificationSettings = notificationSettings, case .muted = notificationSettings.muteState { - buttonText = "Unmute" - buttonIcon = .unmute - } else { - buttonText = "Mute" - buttonIcon = .mute - } - case .more: - buttonText = "More" - buttonIcon = .more - case .addMember: - buttonText = "Add Member" - buttonIcon = .addMember - } - buttonNode.update(size: buttonFrame.size, text: buttonText, icon: buttonIcon, isExpanded: self.isAvatarExpanded, presentationData: presentationData, transition: buttonTransition) - transition.updateSublayerTransformScaleAdditive(node: buttonNode, scale: buttonsScale) - - transition.updateAlpha(node: buttonNode, alpha: buttonsAlpha) - - let hiddenWhileExpanded: Bool - switch buttonKey { - case .more: - hiddenWhileExpanded = false - default: - hiddenWhileExpanded = true - } - - if self.isAvatarExpanded, hiddenWhileExpanded { - if case let .animated(duration, curve) = transition { - ContainedViewLayoutTransition.animated(duration: duration * 0.3, curve: curve).updateAlpha(node: buttonNode.containerNode, alpha: 0.0) - } else { - transition.updateAlpha(node: buttonNode.containerNode, alpha: 0.0) - } - } else { - if case .mute = buttonKey, buttonNode.containerNode.alpha.isZero, additive { - if case let .animated(duration, curve) = transition { - ContainedViewLayoutTransition.animated(duration: duration * 0.3, curve: curve).updateAlpha(node: buttonNode.containerNode, alpha: 1.0) - } else { - transition.updateAlpha(node: buttonNode.containerNode, alpha: 1.0) - } - } else { - transition.updateAlpha(node: buttonNode.containerNode, alpha: 1.0) - } - buttonRightOrigin.x -= apparentButtonSize + buttonSpacing - } - } - - for key in self.buttonNodes.keys { - if !buttonKeys.contains(key) { - if let buttonNode = self.buttonNodes[key] { - self.buttonNodes.removeValue(forKey: key) - buttonNode.removeFromSupernode() - } - } - } - - let resolvedRegularHeight: CGFloat - if self.isAvatarExpanded { - resolvedRegularHeight = expandedAvatarListSize.height + expandedAvatarControlsHeight - } else { - resolvedRegularHeight = 212.0 + navigationHeight - } - - let backgroundFrame: CGRect - let separatorFrame: CGRect - - let resolvedHeight: CGFloat - if state.isEditing { - resolvedHeight = editingContentHeight - backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -2000.0 + resolvedHeight - contentOffset), size: CGSize(width: width, height: 2000.0)) - separatorFrame = CGRect(origin: CGPoint(x: 0.0, y: resolvedHeight - contentOffset), size: CGSize(width: width, height: UIScreenPixel)) - } else { - resolvedHeight = resolvedRegularHeight - backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -2000.0 + apparentHeight), size: CGSize(width: width, height: 2000.0)) - separatorFrame = CGRect(origin: CGPoint(x: 0.0, y: apparentHeight), size: CGSize(width: width, height: UIScreenPixel)) - } - - transition.updateFrame(node: self.regularContentNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: resolvedHeight))) - - if additive { - transition.updateFrameAdditive(node: self.backgroundNode, frame: backgroundFrame) - transition.updateFrameAdditive(node: self.expandedBackgroundNode, frame: backgroundFrame) - transition.updateFrameAdditive(node: self.separatorNode, frame: separatorFrame) - } else { - transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame) - transition.updateFrame(node: self.expandedBackgroundNode, frame: backgroundFrame) - transition.updateFrame(node: self.separatorNode, frame: separatorFrame) - } - - return resolvedHeight - } - - private func buttonPressed(_ buttonNode: PeerInfoHeaderButtonNode) { - self.performButtonAction?(buttonNode.key) - } - - override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { - guard let result = super.hitTest(point, with: event) else { - return nil - } - if result.isDescendant(of: self.navigationButtonContainer.view) { - return result - } - if !self.backgroundNode.frame.contains(point) { - return nil - } - if result == self.view || result == self.regularContentNode.view || result == self.editingContentNode.view { - return nil - } - return result - } - - func updateIsAvatarExpanded(_ isAvatarExpanded: Bool) { - self.isAvatarExpanded = isAvatarExpanded - } -} - -protocol PeerInfoPaneNode: ASDisplayNode { - var isReady: Signal { get } - - func update(size: CGSize, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) - func scrollToTop() -> Bool - func transferVelocity(_ velocity: CGFloat) - func findLoadedMessage(id: MessageId) -> Message? - func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? - func updateSelectedMessages(animated: Bool) -} - -final class PeerInfoPaneInteraction { - var selectedMessageIds: Set? - - let toggleMessageSelected: (MessageId) -> Void - let openPeer: (Peer) -> Void - - init( - toggleMessageSelected: @escaping (MessageId) -> Void, - openPeer: @escaping (Peer) -> Void - ) { - self.toggleMessageSelected = toggleMessageSelected - self.openPeer = openPeer - } -} - -private final class PeerInfoPaneWrapper { - let key: PeerInfoPaneKey - let node: PeerInfoPaneNode - private var appliedParams: (CGSize, CGFloat, Bool, PresentationData)? - - init(key: PeerInfoPaneKey, node: PeerInfoPaneNode) { - self.key = key - self.node = node - } - - func update(size: CGSize, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { - if let (currentSize, visibleHeight, currentIsScrollingLockedAtTop, currentPresentationData) = self.appliedParams { - if currentSize == size && currentIsScrollingLockedAtTop == isScrollingLockedAtTop && currentPresentationData === presentationData { - return - } - } - self.appliedParams = (size, visibleHeight, isScrollingLockedAtTop, presentationData) - self.node.update(size: size, visibleHeight: visibleHeight, isScrollingLockedAtTop: isScrollingLockedAtTop, presentationData: presentationData, synchronous: synchronous, transition: transition) - } -} - -private enum PeerInfoPaneKey { - case media - case files - case links - case voice - case music - case groupsInCommon -} - -private final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode { - private let pressed: () -> Void - - private let titleNode: ImmediateTextNode - private let buttonNode: HighlightTrackingButtonNode - - init(pressed: @escaping () -> Void) { - self.pressed = pressed - - self.titleNode = ImmediateTextNode() - self.titleNode.displaysAsynchronously = false - - self.buttonNode = HighlightTrackingButtonNode() - - super.init() - - self.addSubnode(self.titleNode) - self.addSubnode(self.buttonNode) - - self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside) - self.buttonNode.highligthedChanged = { [weak self] highlighted in - if let strongSelf = self { - if highlighted { - strongSelf.titleNode.layer.removeAnimation(forKey: "opacity") - strongSelf.titleNode.alpha = 0.4 - } else { - strongSelf.titleNode.alpha = 1.0 - strongSelf.titleNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) - } - } - } - } - - @objc private func buttonPressed() { - self.pressed() - } - - func updateText(_ title: String, isSelected: Bool, presentationData: PresentationData) { - self.titleNode.attributedText = NSAttributedString(string: title, font: Font.medium(14.0), textColor: isSelected ? presentationData.theme.list.itemAccentColor : presentationData.theme.list.itemSecondaryTextColor) - } - - func updateLayout(height: CGFloat) -> CGFloat { - let titleSize = self.titleNode.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude)) - self.titleNode.frame = CGRect(origin: CGPoint(x: 0.0, y: floor((height - titleSize.height) / 2.0)), size: titleSize) - return titleSize.width - } - - func updateArea(size: CGSize, sideInset: CGFloat) { - self.buttonNode.frame = CGRect(origin: CGPoint(x: -sideInset, y: 0.0), size: CGSize(width: size.width + sideInset * 2.0, height: size.height)) - } -} - -private struct PeerInfoPaneSpecifier: Equatable { - var key: PeerInfoPaneKey - var title: String -} - -private final class PeerInfoPaneTabsContainerNode: ASDisplayNode { - private let scrollNode: ASScrollNode - private var paneNodes: [PeerInfoPaneKey: PeerInfoPaneTabsContainerPaneNode] = [:] - private let selectedLineNode: ASImageNode - - private var currentParams: ([PeerInfoPaneSpecifier], PeerInfoPaneKey?, PresentationData)? - - var requestSelectPane: ((PeerInfoPaneKey) -> Void)? - - override init() { - self.scrollNode = ASScrollNode() - - self.selectedLineNode = ASImageNode() - self.selectedLineNode.displaysAsynchronously = false - self.selectedLineNode.displayWithoutProcessing = true - - super.init() - - self.scrollNode.view.disablesInteractiveTransitionGestureRecognizer = true - self.scrollNode.view.showsHorizontalScrollIndicator = false - self.scrollNode.view.scrollsToTop = false - if #available(iOS 11.0, *) { - self.scrollNode.view.contentInsetAdjustmentBehavior = .never - } - - self.addSubnode(self.scrollNode) - self.scrollNode.addSubnode(self.selectedLineNode) - } - - func update(size: CGSize, presentationData: PresentationData, paneList: [PeerInfoPaneSpecifier], selectedPane: PeerInfoPaneKey?, transition: ContainedViewLayoutTransition) { - transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: size)) - - let focusOnSelectedPane = self.currentParams?.1 != selectedPane - - if self.currentParams?.2.theme !== presentationData.theme { - self.selectedLineNode.image = generateImage(CGSize(width: 7.0, height: 4.0), rotatedContext: { size, context in - context.clear(CGRect(origin: CGPoint(), size: size)) - context.setFillColor(presentationData.theme.list.itemAccentColor.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.width))) - })?.stretchableImage(withLeftCapWidth: 4, topCapHeight: 1) - } - - if self.currentParams?.0 != paneList || self.currentParams?.1 != selectedPane || self.currentParams?.2 !== presentationData { - self.currentParams = (paneList, selectedPane, presentationData) - for specifier in paneList { - let paneNode: PeerInfoPaneTabsContainerPaneNode - var wasAdded = false - if let current = self.paneNodes[specifier.key] { - paneNode = current - } else { - wasAdded = true - paneNode = PeerInfoPaneTabsContainerPaneNode(pressed: { [weak self] in - self?.paneSelected(specifier.key) - }) - self.paneNodes[specifier.key] = paneNode - self.scrollNode.addSubnode(paneNode) - } - paneNode.updateText(specifier.title, isSelected: selectedPane == specifier.key, presentationData: presentationData) - } - var removeKeys: [PeerInfoPaneKey] = [] - for (key, _) in self.paneNodes { - if !paneList.contains(where: { $0.key == key }) { - removeKeys.append(key) - } - } - for key in removeKeys { - if let paneNode = self.paneNodes.removeValue(forKey: key) { - paneNode.removeFromSupernode() - } - } - } - - var tabSizes: [(CGSize, PeerInfoPaneTabsContainerPaneNode)] = [] - var totalRawTabSize: CGFloat = 0.0 - - var selectedFrame: CGRect? - for specifier in paneList { - guard let paneNode = self.paneNodes[specifier.key] else { - continue - } - let paneNodeWidth = paneNode.updateLayout(height: size.height) - let paneNodeSize = CGSize(width: paneNodeWidth, height: size.height) - tabSizes.append((paneNodeSize, paneNode)) - totalRawTabSize += paneNodeSize.width - } - - let spacing: CGFloat = 32.0 - if totalRawTabSize + CGFloat(tabSizes.count + 1) * spacing <= size.width { - let singleTabSpace = floor((size.width - spacing * 2.0) / CGFloat(tabSizes.count)) - - for i in 0 ..< tabSizes.count { - let (paneNodeSize, paneNode) = tabSizes[i] - let leftOffset = spacing + CGFloat(i) * singleTabSpace + floor((singleTabSpace - paneNodeSize.width) / 2.0) - - let paneFrame = CGRect(origin: CGPoint(x: leftOffset, y: floor((size.height - paneNodeSize.height) / 2.0)), size: paneNodeSize) - paneNode.frame = paneFrame - let areaSideInset = floor((singleTabSpace - paneFrame.size.width) / 2.0) - paneNode.updateArea(size: paneFrame.size, sideInset: areaSideInset) - paneNode.hitTestSlop = UIEdgeInsets(top: 0.0, left: -areaSideInset, bottom: 0.0, right: -areaSideInset) - - if paneList[i].key == selectedPane { - selectedFrame = paneFrame - } - } - self.scrollNode.view.contentSize = CGSize(width: size.width, height: size.height) - } else { - let sideInset: CGFloat = 16.0 - var leftOffset: CGFloat = sideInset - for i in 0 ..< tabSizes.count { - let (paneNodeSize, paneNode) = tabSizes[i] - let paneFrame = CGRect(origin: CGPoint(x: leftOffset, y: floor((size.height - paneNodeSize.height) / 2.0)), size: paneNodeSize) - paneNode.frame = paneFrame - paneNode.updateArea(size: paneFrame.size, sideInset: spacing) - paneNode.hitTestSlop = UIEdgeInsets(top: 0.0, left: -spacing, bottom: 0.0, right: -spacing) - if paneList[i].key == selectedPane { - selectedFrame = paneFrame - } - leftOffset += paneNodeSize.width + spacing - } - self.scrollNode.view.contentSize = CGSize(width: leftOffset + sideInset, height: size.height) - } - - if let selectedFrame = selectedFrame { - self.selectedLineNode.isHidden = false - transition.updateFrame(node: self.selectedLineNode, frame: CGRect(origin: CGPoint(x: selectedFrame.minX, y: size.height - 4.0), size: CGSize(width: selectedFrame.width, height: 4.0))) - if focusOnSelectedPane { - if selectedPane == paneList.first?.key { - transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(), size: self.scrollNode.bounds.size)) - } else if selectedPane == paneList.last?.key { - transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: self.scrollNode.view.contentSize.width - self.scrollNode.bounds.width, y: 0.0), size: self.scrollNode.bounds.size)) - } else { - let contentOffsetX = max(0.0, min(self.scrollNode.view.contentSize.width - self.scrollNode.bounds.width, floor(selectedFrame.midX - self.scrollNode.bounds.width / 2.0))) - transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: contentOffsetX, y: 0.0), size: self.scrollNode.bounds.size)) - } - } - } else { - self.selectedLineNode.isHidden = true - } - } - - private func paneSelected(_ key: PeerInfoPaneKey) { - self.requestSelectPane?(key) - } -} - -private final class PeerInfoPaneContainerNode: ASDisplayNode { - private let context: AccountContext - private let peerId: PeerId - - private let coveringBackgroundNode: ASDisplayNode - private let separatorNode: ASDisplayNode - private let tabsContainerNode: PeerInfoPaneTabsContainerNode - private let tapsSeparatorNode: ASDisplayNode - - let isReady = Promise() - var didSetIsReady = false - - private var currentParams: (size: CGSize, visibleHeight: CGFloat, expansionFraction: CGFloat, presentationData: PresentationData, data: PeerInfoScreenData?)? - private(set) var currentPaneKey: PeerInfoPaneKey? - private(set) var currentPane: PeerInfoPaneWrapper? - - private var currentCandidatePaneKey: PeerInfoPaneKey? - private var candidatePane: (PeerInfoPaneWrapper, Disposable, Bool)? - - var selectionPanelNode: PeerInfoSelectionPanelNode? - - var _paneInteraction: PeerInfoPaneInteraction? - var paneInteraction: PeerInfoPaneInteraction { - return self._paneInteraction! - } - - var openMessage: ((MessageId) -> Bool)? - var toggleMessageSelected: ((MessageId) -> Void)? - var openPeer: ((Peer) -> Void)? - var currentPaneUpdated: (() -> Void)? - - init(context: AccountContext, peerId: PeerId) { - self.context = context - self.peerId = peerId - - self.separatorNode = ASDisplayNode() - self.separatorNode.isLayerBacked = true - - self.coveringBackgroundNode = ASDisplayNode() - self.coveringBackgroundNode.isLayerBacked = true - - self.tabsContainerNode = PeerInfoPaneTabsContainerNode() - - self.tapsSeparatorNode = ASDisplayNode() - self.tapsSeparatorNode.isLayerBacked = true - - super.init() - - self._paneInteraction = PeerInfoPaneInteraction( - toggleMessageSelected: { [weak self] id in - guard let strongSelf = self else { - return - } - strongSelf.toggleMessageSelected?(id) - }, - openPeer: { [weak self] peer in - guard let strongSelf = self else { - return - } - strongSelf.openPeer?(peer) - } - ) - - self.addSubnode(self.separatorNode) - self.addSubnode(self.coveringBackgroundNode) - self.addSubnode(self.tabsContainerNode) - self.addSubnode(self.tapsSeparatorNode) - - self.tabsContainerNode.requestSelectPane = { [weak self] key in - guard let strongSelf = self else { - return - } - if strongSelf.currentPaneKey == key { - return - } - if strongSelf.currentCandidatePaneKey == key { - return - } - strongSelf.currentCandidatePaneKey = key - - if let (size, visibleHeight, expansionFraction, presentationData, data) = strongSelf.currentParams { - strongSelf.update(size: size, visibleHeight: visibleHeight, expansionFraction: expansionFraction, presentationData: presentationData, data: data, transition: .immediate) - } - } - } - - func scrollToTop() -> Bool { - if let currentPane = self.currentPane { - return currentPane.node.scrollToTop() - } else { - return false - } - } - - func findLoadedMessage(id: MessageId) -> Message? { - return self.currentPane?.node.findLoadedMessage(id: id) - } - - func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { - return self.currentPane?.node.transitionNodeForGallery(messageId: messageId, media: media) - } - - func updateSelectedMessageIds(_ selectedMessageIds: Set?, animated: Bool) { - if self.paneInteraction.selectedMessageIds != selectedMessageIds { - self.paneInteraction.selectedMessageIds = selectedMessageIds - self.currentPane?.node.updateSelectedMessages(animated: animated) - self.candidatePane?.0.node.updateSelectedMessages(animated: animated) - } - } - - func update(size: CGSize, visibleHeight: CGFloat, expansionFraction: CGFloat, presentationData: PresentationData, data: PeerInfoScreenData?, transition: ContainedViewLayoutTransition) { - let availablePanes = data?.availablePanes ?? [] - - let previousCurrentPaneKey = self.currentPaneKey - if availablePanes.isEmpty { - self.currentPaneKey = nil - self.currentCandidatePaneKey = nil - if let (_, disposable, _) = self.candidatePane { - disposable.dispose() - self.candidatePane = nil - } - if let currentPane = self.currentPane { - self.currentPane = nil - currentPane.node.removeFromSupernode() - } - } else if (self.currentParams?.data?.availablePanes ?? []).isEmpty { - self.currentCandidatePaneKey = availablePanes.first - } - - self.currentParams = (size, visibleHeight, expansionFraction, presentationData, data) - - transition.updateAlpha(node: self.coveringBackgroundNode, alpha: expansionFraction) - - self.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor - self.coveringBackgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.backgroundColor - self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor - self.tapsSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor - - let tabsHeight: CGFloat = 48.0 - - transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: size.width, height: UIScreenPixel))) - transition.updateFrame(node: self.coveringBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: size.width, height: tabsHeight + UIScreenPixel))) - - transition.updateFrame(node: self.tapsSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: tabsHeight - UIScreenPixel), size: CGSize(width: size.width, height: UIScreenPixel))) - - let paneFrame = CGRect(origin: CGPoint(x: 0.0, y: tabsHeight), size: CGSize(width: size.width, height: size.height - tabsHeight)) - - if let currentCandidatePaneKey = self.currentCandidatePaneKey { - if self.candidatePane?.0.key != currentCandidatePaneKey { - self.candidatePane?.1.dispose() - - let paneNode: PeerInfoPaneNode - switch currentCandidatePaneKey { - case .media: - paneNode = PeerInfoVisualMediaPaneNode(context: self.context, openMessage: { [weak self] id in - return self?.openMessage?(id) ?? false - }, peerId: self.peerId, interaction: self.paneInteraction) - case .files: - paneNode = PeerInfoListPaneNode(context: self.context, openMessage: { [weak self] id in - return self?.openMessage?(id) ?? false - }, peerId: self.peerId, tagMask: .file, interaction: self.paneInteraction) - case .links: - paneNode = PeerInfoListPaneNode(context: self.context, openMessage: { [weak self] id in - return self?.openMessage?(id) ?? false - }, peerId: self.peerId, tagMask: .webPage, interaction: self.paneInteraction) - case .voice: - paneNode = PeerInfoListPaneNode(context: self.context, openMessage: { [weak self] id in - return self?.openMessage?(id) ?? false - }, peerId: self.peerId, tagMask: .voiceOrInstantVideo, interaction: self.paneInteraction) - case .music: - paneNode = PeerInfoListPaneNode(context: self.context, openMessage: { [weak self] id in - return self?.openMessage?(id) ?? false - }, peerId: self.peerId, tagMask: .music, interaction: self.paneInteraction) - case .groupsInCommon: - paneNode = PeerInfoGroupsInCommonPaneNode(context: self.context, peerId: peerId, interaction: self.paneInteraction, peers: data?.groupsInCommon ?? []) - } - - let disposable = MetaDisposable() - self.candidatePane = (PeerInfoPaneWrapper(key: currentCandidatePaneKey, node: paneNode), disposable, false) - - var shouldReLayout = false - disposable.set((paneNode.isReady - |> take(1) - |> deliverOnMainQueue).start(next: { [weak self] _ in - guard let strongSelf = self else { - return - } - if let (candidatePane, disposable, _) = strongSelf.candidatePane { - strongSelf.candidatePane = (candidatePane, disposable, true) - - if shouldReLayout { - if let (size, visibleHeight, expansionFraction, presentationData, data) = strongSelf.currentParams { - strongSelf.update(size: size, visibleHeight: visibleHeight, expansionFraction: expansionFraction, presentationData: presentationData, data: data, transition: strongSelf.currentPane != nil ? .animated(duration: 0.35, curve: .spring) : .immediate) - } - } - } - })) - shouldReLayout = true - } - } - - if let (candidatePane, _, isReady) = self.candidatePane, isReady { - let previousPane = self.currentPane - self.candidatePane = nil - self.currentPaneKey = candidatePane.key - self.currentCandidatePaneKey = nil - self.currentPane = candidatePane - - if let selectionPanelNode = self.selectionPanelNode { - self.insertSubnode(candidatePane.node, belowSubnode: selectionPanelNode) - } else { - self.addSubnode(candidatePane.node) - } - candidatePane.node.frame = paneFrame - candidatePane.update(size: paneFrame.size, visibleHeight: max(0.0, visibleHeight - paneFrame.minY), isScrollingLockedAtTop: expansionFraction < 1.0 - CGFloat.ulpOfOne, presentationData: presentationData, synchronous: true, transition: .immediate) - - if let previousPane = previousPane { - let directionToRight: Bool - if let previousIndex = availablePanes.index(of: previousPane.key), let updatedIndex = availablePanes.index(of: candidatePane.key) { - directionToRight = previousIndex < updatedIndex - } else { - directionToRight = false - } - - let offset: CGFloat = directionToRight ? previousPane.node.bounds.width : -previousPane.node.bounds.width - - transition.animatePositionAdditive(node: candidatePane.node, offset: CGPoint(x: offset, y: 0.0)) - let previousNode = previousPane.node - transition.updateFrame(node: previousNode, frame: paneFrame.offsetBy(dx: -offset, dy: 0.0), completion: { [weak previousNode] _ in - previousNode?.removeFromSupernode() - }) - } - } else if let currentPane = self.currentPane { - let paneWasAdded = currentPane.node.supernode == nil - if paneWasAdded { - self.addSubnode(currentPane.node) - } - - let paneTransition: ContainedViewLayoutTransition = paneWasAdded ? .immediate : transition - paneTransition.updateFrame(node: currentPane.node, frame: paneFrame) - currentPane.update(size: paneFrame.size, visibleHeight: visibleHeight, isScrollingLockedAtTop: expansionFraction < 1.0 - CGFloat.ulpOfOne, presentationData: presentationData, synchronous: paneWasAdded, transition: paneTransition) - } - - transition.updateFrame(node: self.tabsContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: tabsHeight))) - self.tabsContainerNode.update(size: CGSize(width: size.width, height: tabsHeight), presentationData: presentationData, paneList: availablePanes.map { key in - let title: String - switch key { - case .media: - title = "Media" - case .files: - title = "Files" - case .links: - title = "Links" - case .voice: - title = "Voice Messages" - case .music: - title = "Audio" - case .groupsInCommon: - title = "Groups" - } - return PeerInfoPaneSpecifier(key: key, title: title) - }, selectedPane: self.currentPaneKey, transition: transition) - - if let (candidatePane, _, _) = self.candidatePane { - let paneTransition: ContainedViewLayoutTransition = .immediate - paneTransition.updateFrame(node: candidatePane.node, frame: paneFrame) - candidatePane.update(size: paneFrame.size, visibleHeight: visibleHeight, isScrollingLockedAtTop: expansionFraction < 1.0 - CGFloat.ulpOfOne, presentationData: presentationData, synchronous: true, transition: paneTransition) - } - if !self.didSetIsReady && data != nil { - if let currentPane = self.currentPane { - self.didSetIsReady = true - self.isReady.set(currentPane.node.isReady) - } else if self.candidatePane == nil { - self.didSetIsReady = true - self.isReady.set(.single(true)) - } - } - if let previousCurrentPaneKey = previousCurrentPaneKey, self.currentPaneKey != previousCurrentPaneKey { - self.currentPaneUpdated?() - } - } -} +import ContextUI +import OpenInExternalAppUI +import SafariServices +import GalleryUI protocol PeerInfoScreenItem: class { var id: AnyHashable { get } @@ -2090,7 +140,7 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { } } -private final class PeerInfoSelectionPanelNode: ASDisplayNode { +final class PeerInfoSelectionPanelNode: ASDisplayNode { private let context: AccountContext private let peerId: PeerId @@ -2197,7 +247,7 @@ private final class PeerInfoSelectionPanelNode: ASDisplayNode { }, displaySearchResultsTooltip: { _, _ in }, statuses: nil) - selectionPanel.interfaceInteraction = interfaceInteraction + self.selectionPanel.interfaceInteraction = interfaceInteraction super.init() @@ -2206,192 +256,28 @@ private final class PeerInfoSelectionPanelNode: ASDisplayNode { self.addSubnode(self.selectionPanel) } - func update(width: CGFloat, safeInset: CGFloat, metrics: LayoutMetrics, presentationData: PresentationData, transition: ContainedViewLayoutTransition) -> CGFloat { + func update(layout: ContainerViewLayout, presentationData: PresentationData, transition: ContainedViewLayoutTransition) -> CGFloat { self.backgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.backgroundColor self.separatorNode.backgroundColor = presentationData.theme.rootController.navigationBar.separatorColor let interfaceState = ChatPresentationInterfaceState(chatWallpaper: .color(0), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, limitsConfiguration: .defaultValue, fontSize: .regular, bubbleCorners: PresentationChatBubbleCorners(mainRadius: 16.0, auxiliaryRadius: 8.0, mergeBubbleCorners: true), accountPeerId: self.context.account.peerId, mode: .standard(previewing: false), chatLocation: .peer(self.peerId), isScheduledMessages: false) - let panelHeight = self.selectionPanel.updateLayout(width: width, leftInset: safeInset, rightInset: safeInset, maxHeight: 0.0, isSecondary: false, transition: transition, interfaceState: interfaceState, metrics: metrics) + let panelHeight = self.selectionPanel.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, maxHeight: 0.0, isSecondary: false, transition: transition, interfaceState: interfaceState, metrics: layout.metrics) - transition.updateFrame(node: self.selectionPanel, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))) - transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))) - transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel))) + transition.updateFrame(node: self.selectionPanel, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: panelHeight))) - return panelHeight + let panelHeightWithInset = panelHeight + layout.intrinsicInsets.bottom + + transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: panelHeightWithInset))) + transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: layout.size.width, height: UIScreenPixel))) + + return panelHeightWithInset } } -private final class PeerInfoState { - let isEditing: Bool - let isSearching: Bool - let selectedMessageIds: Set? - - init( - isEditing: Bool, - isSearching: Bool, - selectedMessageIds: Set? - ) { - self.isEditing = isEditing - self.isSearching = isSearching - self.selectedMessageIds = selectedMessageIds - } - - func withIsEditing(_ isEditing: Bool) -> PeerInfoState { - return PeerInfoState( - isEditing: isEditing, - isSearching: self.isSearching, - selectedMessageIds: self.selectedMessageIds - ) - } - - func withSelectedMessageIds(_ selectedMessageIds: Set?) -> PeerInfoState { - return PeerInfoState( - isEditing: self.isEditing, - isSearching: self.isSearching, - selectedMessageIds: selectedMessageIds - ) - } -} - -private final class PeerInfoScreenData { - let peer: Peer? - let cachedData: CachedPeerData? - let presence: TelegramUserPresence? - let notificationSettings: TelegramPeerNotificationSettings? - let globalNotificationSettings: GlobalNotificationSettings? - let isContact: Bool - let availablePanes: [PeerInfoPaneKey] - let groupsInCommon: [Peer]? - - init( - peer: Peer?, - cachedData: CachedPeerData?, - presence: TelegramUserPresence?, - notificationSettings: TelegramPeerNotificationSettings?, - globalNotificationSettings: GlobalNotificationSettings?, - isContact: Bool, - availablePanes: [PeerInfoPaneKey], - groupsInCommon: [Peer]? - ) { - self.peer = peer - self.cachedData = cachedData - self.presence = presence - self.notificationSettings = notificationSettings - self.globalNotificationSettings = globalNotificationSettings - self.isContact = isContact - self.availablePanes = availablePanes - self.groupsInCommon = groupsInCommon - } -} - -private enum PeerInfoScreenInputData: Equatable { - case none - case user -} - -private func peerInfoAvailableMediaPanes(context: AccountContext, peerId: PeerId) -> Signal<[PeerInfoPaneKey], NoError> { - let tags: [(MessageTags, PeerInfoPaneKey)] = [ - (.photoOrVideo, .media), - (.file, .files), - (.music, .music), - (.voiceOrInstantVideo, .voice), - (.webPage, .links) - ] - return combineLatest(tags.map { tagAndKey -> Signal in - let (tag, key) = tagAndKey - return context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId), index: .upperBound, anchorIndex: .upperBound, count: 2, clipHoles: false, fixedCombinedReadStates: nil, tagMask: tag) - |> map { (view, _, _) -> PeerInfoPaneKey? in - if view.entries.isEmpty { - return nil - } else { - return key - } - } - }) - |> map { keys -> [PeerInfoPaneKey] in - return keys.compactMap { $0 } - } - |> distinctUntilChanged - /*return context.account.postbox.combinedView(keys: tags.map { (tag, _) -> PostboxViewKey in - return .historyTagInfo(peerId: peerId, tag: tag) - }) - |> map { view -> [PeerInfoPaneKey] in - return tags.compactMap { (tag, key) -> PeerInfoPaneKey? in - if let info = view.views[.historyTagInfo(peerId: peerId, tag: tag)] as? HistoryTagInfoView, !info.isEmpty { - return key - } else { - return nil - } - } - } - |> distinctUntilChanged*/ -} - -private func peerInfoScreenData(context: AccountContext, peerId: PeerId) -> Signal { - return context.account.postbox.combinedView(keys: [.basicPeer(peerId)]) - |> map { view -> PeerInfoScreenInputData in - guard let peer = (view.views[.basicPeer(peerId)] as? BasicPeerView)?.peer else { - return .none - } - if let _ = peer as? TelegramUser { - return .user - } else { - preconditionFailure() - } - } - |> distinctUntilChanged - |> mapToSignal { inputData -> Signal in - switch inputData { - case .none: - return .single(PeerInfoScreenData( - peer: nil, - cachedData: nil, - presence: nil, - notificationSettings: nil, - globalNotificationSettings: nil, - isContact: false, - availablePanes: [], - groupsInCommon: nil - )) - case .user: - let groupsInCommonSignal: Signal<[Peer]?, NoError> = .single(nil) - |> then( - groupsInCommon(account: context.account, peerId: peerId) - |> map(Optional.init) - ) - let globalNotificationsKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.globalNotifications])) - return combineLatest( - context.account.viewTracker.peerView(peerId, updateData: true), - peerInfoAvailableMediaPanes(context: context, peerId: peerId), - context.account.postbox.combinedView(keys: [.peerChatState(peerId: peerId), globalNotificationsKey]), - groupsInCommonSignal - ) - |> map { peerView, availablePanes, combinedView, groupsInCommon -> PeerInfoScreenData in - var globalNotificationSettings: GlobalNotificationSettings = .defaultSettings - if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView { - if let settings = preferencesView.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings { - globalNotificationSettings = settings - } - } - - var availablePanes = availablePanes - if let groupsInCommon = groupsInCommon, !groupsInCommon.isEmpty { - availablePanes.append(.groupsInCommon) - } - - return PeerInfoScreenData( - peer: peerView.peers[peerId], - cachedData: peerView.cachedData, - presence: peerView.peerPresences[peerId] as? TelegramUserPresence, - notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings, - globalNotificationSettings: globalNotificationSettings, - isContact: peerView.peerIsContact, - availablePanes: availablePanes, - groupsInCommon: groupsInCommon - ) - } - } - } +private enum PeerInfoBotCommand { + case settings + case help + case privacy } private final class PeerInfoInteraction { @@ -2403,6 +289,10 @@ private final class PeerInfoInteraction { let requestDeleteContact: () -> Void let openAddContact: () -> Void let updateBlocked: (Bool) -> Void + let openReport: () -> Void + let openShareBot: () -> Void + let openAddBotToGroup: () -> Void + let performBotCommand: (PeerInfoBotCommand) -> Void init( openUsername: @escaping (String) -> Void, @@ -2412,7 +302,11 @@ private final class PeerInfoInteraction { editingToggleShowMessageText: @escaping (Bool) -> Void, requestDeleteContact: @escaping () -> Void, openAddContact: @escaping () -> Void, - updateBlocked: @escaping (Bool) -> Void + updateBlocked: @escaping (Bool) -> Void, + openReport: @escaping () -> Void, + openShareBot: @escaping () -> Void, + openAddBotToGroup: @escaping () -> Void, + performBotCommand: @escaping (PeerInfoBotCommand) -> Void ) { self.openUsername = openUsername self.openPhone = openPhone @@ -2422,6 +316,10 @@ private final class PeerInfoInteraction { self.requestDeleteContact = requestDeleteContact self.openAddContact = openAddContact self.updateBlocked = updateBlocked + self.openReport = openReport + self.openShareBot = openShareBot + self.openAddBotToGroup = openAddBotToGroup + self.performBotCommand = performBotCommand } } @@ -2447,23 +345,57 @@ private func peerInfoSectionItems(data: PeerInfoScreenData?, presentationData: P } } if !data.isContact { - items.append(PeerInfoScreenActionItem(id: 3, text: "Add Contact", action: { - interaction.openAddContact() - })) + if let botInfo = user.botInfo { + if botInfo.flags.contains(.worksWithGroups) { + items.append(PeerInfoScreenActionItem(id: 6, text: presentationData.strings.UserInfo_InviteBotToGroup, action: { + interaction.openAddBotToGroup() + })) + } + items.append(PeerInfoScreenActionItem(id: 7, text: presentationData.strings.UserInfo_ShareBot, action: { + interaction.openShareBot() + })) + + if let cachedData = data.cachedData as? CachedUserData, let botInfo = cachedData.botInfo { + for command in botInfo.commands { + if command.text == "settings" { + items.append(PeerInfoScreenActionItem(id: 8, text: presentationData.strings.UserInfo_BotSettings, action: { + interaction.performBotCommand(.settings) + })) + } else if command.text == "help" { + items.append(PeerInfoScreenActionItem(id: 9, text: presentationData.strings.UserInfo_BotHelp, action: { + interaction.performBotCommand(.help) + })) + } else if command.text == "privacy" { + items.append(PeerInfoScreenActionItem(id: 10, text: presentationData.strings.UserInfo_BotPrivacy, action: { + interaction.performBotCommand(.privacy) + })) + } + } + } + } else { + items.append(PeerInfoScreenActionItem(id: 3, text: "Add Contact", action: { + interaction.openAddContact() + })) + } if let cachedData = data.cachedData as? CachedUserData { if cachedData.isBlocked { - items.append(PeerInfoScreenActionItem(id: 4, text: "Unblock", action: { + items.append(PeerInfoScreenActionItem(id: 4, text: user.botInfo != nil ? "Restart Bot" : "Unblock", action: { interaction.updateBlocked(false) })) } else { if user.flags.contains(.isSupport) { } else { - items.append(PeerInfoScreenActionItem(id: 4, text: "Block User", color: .destructive, action: { + items.append(PeerInfoScreenActionItem(id: 4, text: user.botInfo != nil ? "Stop Bot" : "Block User", color: .destructive, action: { interaction.updateBlocked(true) })) } } } + if user.botInfo != nil, !user.isVerified { + items.append(PeerInfoScreenActionItem(id: 5, text: presentationData.strings.ReportPeer_Report, action: { + interaction.openReport() + })) + } } } return items @@ -2547,6 +479,8 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD private var chatInterfaceInteraction: ChatControllerInteraction { return self._chatInterfaceInteraction! } + private var hiddenMediaDisposable: Disposable? + private let hiddenAvatarRepresentationDisposable = MetaDisposable() private(set) var validLayout: (ContainerViewLayout, CGFloat)? private(set) var data: PeerInfoScreenData? @@ -2558,6 +492,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD private var dataDisposable: Disposable? private let activeActionDisposable = MetaDisposable() + private let resolveUrlDisposable = MetaDisposable() private let _ready = Promise() var ready: Promise { @@ -2605,56 +540,33 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }, updateBlocked: { [weak self] block in self?.updateBlocked(block: block) + }, + openReport: { [weak self] in + self?.openReport() + }, + openShareBot: { [weak self] in + self?.openShareBot() + }, + openAddBotToGroup: { [weak self] in + self?.openAddBotToGroup() + }, + performBotCommand: { [weak self] command in + self?.performBotCommand(command: command) } ) - self._chatInterfaceInteraction = ChatControllerInteraction(openMessage: { message, mode in - /*if let strongSelf = self, strongSelf.isNodeLoaded, let galleryMessage = strongSelf.mediaCollectionDisplayNode.messageForGallery(message.id) { - guard let navigationController = strongSelf.navigationController as? NavigationController else { - return false - } - strongSelf.mediaCollectionDisplayNode.view.endEditing(true) - return context.sharedContext.openChatMessage(OpenChatMessageParams(context: context, message: galleryMessage.message, standalone: false, reverseMessageGalleryOrder: true, navigationController: navigationController, dismissInput: { - self?.mediaCollectionDisplayNode.view.endEditing(true) - }, present: { c, a in - self?.present(c, in: .window(.root), with: a, blockInteraction: true) - }, transitionNode: { messageId, media in - if let strongSelf = self { - return strongSelf.mediaCollectionDisplayNode.transitionNodeForGallery(messageId: messageId, media: media) - } - return nil - }, addToTransitionSurface: { view in - if let strongSelf = self { - var belowSubview: UIView? - if let historyNode = strongSelf.mediaCollectionDisplayNode.historyNode as? ChatHistoryGridNode { - if let lowestSectionNode = historyNode.lowestSectionNode() { - belowSubview = lowestSectionNode.view - } - } - strongSelf.mediaCollectionDisplayNode.historyNode - if let belowSubview = belowSubview { - strongSelf.mediaCollectionDisplayNode.historyNode.view.insertSubview(view, belowSubview: belowSubview) - } else { - strongSelf.mediaCollectionDisplayNode.historyNode.view.addSubview(view) - } - } - }, openUrl: { url in - self?.openUrl(url) - }, openPeer: { peer, navigation in - self?.controllerInteraction?.openPeer(peer.id, navigation, nil) - }, callPeer: { peerId in - self?.controllerInteraction?.callPeer(peerId) - }, enqueueMessage: { _ in - }, sendSticker: nil, setupTemporaryHiddenMedia: { _, _, _ in }, chatAvatarHiddenMedia: { _, _ in })) - }*/ - return false - }, openPeer: { id, navigation, _ in - /*if let strongSelf = self, let id = id, let navigationController = strongSelf.navigationController as? NavigationController { - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(id))) - }*/ + self._chatInterfaceInteraction = ChatControllerInteraction(openMessage: { [weak self] message, mode in + guard let strongSelf = self else { + return false + } + return strongSelf.openMessage(id: message.id) + }, openPeer: { [weak self] id, navigation, _ in + if let id = id { + self?.openPeer(peerId: id, navigation: navigation) + } }, openPeerMention: { _ in - }, openMessageContextMenu: { message, _, _, _, _ in - /*guard let strongSelf = self else { + }, openMessageContextMenu: { [weak self] message, _, _, _, _ in + guard let strongSelf = self else { return } let items = (chatAvailableMessageActionsImpl(postbox: strongSelf.context.account.postbox, accountPeerId: strongSelf.context.account.peerId, messageIds: [message.id]) @@ -2662,28 +574,28 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD var messageIds = Set() messageIds.insert(message.id) - if let strongSelf = self, strongSelf.isNodeLoaded { - if let message = strongSelf.mediaCollectionDisplayNode.messageForGallery(message.id)?.message { + if let strongSelf = self { + if let message = strongSelf.paneContainerNode.findLoadedMessage(id: message.id) { let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData) var items: [ActionSheetButtonItem] = [] items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.SharedMedia_ViewInChat, color: .accent, action: { [weak actionSheet] in actionSheet?.dismissAnimated() - if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController { + if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController { strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(strongSelf.peerId), subject: .message(message.id))) } })) items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_ContextMenuForward, color: .accent, action: { [weak actionSheet] in actionSheet?.dismissAnimated() if let strongSelf = self { - strongSelf.forwardMessages(messageIds) + strongSelf.forwardMessages(messageIds: messageIds) } })) if actions.options.contains(.deleteLocally) || actions.options.contains(.deleteGlobally) { items.append( ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_ContextMenuDelete, color: .destructive, action: { [weak actionSheet] in actionSheet?.dismissAnimated() if let strongSelf = self { - strongSelf.deleteMessages(messageIds) + strongSelf.deleteMessages(messageIds: Set(messageIds)) } })) } @@ -2692,18 +604,18 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD actionSheet?.dismissAnimated() }) ])]) - strongSelf.mediaCollectionDisplayNode.view.endEditing(true) - strongSelf.present(actionSheet, in: .window(.root)) + strongSelf.view.endEditing(true) + strongSelf.controller?.present(actionSheet, in: .window(.root)) } } - })*/ - }, openMessageContextActions: { message, node, rect, gesture in - /*guard let strongSelf = self else { + }) + }, openMessageContextActions: { [weak self] message, node, rect, gesture in + guard let strongSelf = self else { gesture?.cancel() return } - let _ = (chatMediaListPreviewControllerData(context: strongSelf.context, message: message, standalone: false, reverseMessageGalleryOrder: false, navigationController: strongSelf.navigationController as? NavigationController) + let _ = (chatMediaListPreviewControllerData(context: strongSelf.context, message: message, standalone: false, reverseMessageGalleryOrder: false, navigationController: strongSelf.controller?.navigationController as? NavigationController) |> deliverOnMainQueue).start(next: { previewData in guard let strongSelf = self else { gesture?.cancel() @@ -2718,7 +630,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD items.append(.action(ContextMenuActionItem(text: strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { c, f in c.dismiss(completion: { - if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController { + if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController { strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(strongSelf.peerId), subject: .message(message.id))) } }) @@ -2727,7 +639,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD items.append(.action(ContextMenuActionItem(text: strings.Conversation_ContextMenuForward, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { c, f in c.dismiss(completion: { if let strongSelf = self { - strongSelf.forwardMessages([message.id]) + strongSelf.forwardMessages(messageIds: [message.id]) } }) }))) @@ -2759,7 +671,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD items.append(.action(ContextMenuActionItem(text: globalTitle, textColor: .destructive, icon: { _ in nil }, action: { c, f in c.dismiss(completion: { if let strongSelf = self { - strongSelf.updateInterfaceState(animated: true, { $0.withoutSelectionState() }) + strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone) let _ = deleteMessagesInteractively(account: strongSelf.context.account, messageIds: Array(messageIds), type: .forEveryone).start() } }) @@ -2778,7 +690,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD items.append(.action(ContextMenuActionItem(text: localOptionText, textColor: .destructive, icon: { _ in nil }, action: { c, f in c.dismiss(completion: { if let strongSelf = self { - strongSelf.updateInterfaceState(animated: true, { $0.withoutSelectionState() }) + strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone) let _ = deleteMessagesInteractively(account: strongSelf.context.account, messageIds: Array(messageIds), type: .forLocalPeer).start() } }) @@ -2798,30 +710,35 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD case let .gallery(gallery): gallery.setHintWillBePresentedInPreviewingContext(true) let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: gallery, sourceNode: node)), items: items, reactionItems: [], gesture: gesture) - strongSelf.presentInGlobalOverlay(contextController) + strongSelf.controller?.presentInGlobalOverlay(contextController) case .instantPage: break } } - })*/ + }) }, navigateToMessage: { fromId, id in - /*if let strongSelf = self, strongSelf.isNodeLoaded { - if id.peerId == strongSelf.peerId { - var fromIndex: MessageIndex? - - if let message = strongSelf.mediaCollectionDisplayNode.historyNode.messageInCurrentHistoryView(fromId) { - fromIndex = message.index - } - } else { - (strongSelf.navigationController as? NavigationController)?.pushViewController(ChatControllerImpl(context: strongSelf.context, chatLocation: .peer(id.peerId), subject: .message(id))) - } - }*/ }, tapMessage: nil, clickThroughMessage: { - //self?.view.endEditing(true) - }, toggleMessagesSelection: { ids, value in - /*if let strongSelf = self, strongSelf.isNodeLoaded { - strongSelf.updateInterfaceState(animated: true, { $0.withToggledSelectedMessages(ids, value: value) }) - }*/ + }, toggleMessagesSelection: { [weak self] ids, value in + guard let strongSelf = self else { + return + } + if var selectedMessageIds = strongSelf.state.selectedMessageIds { + for id in ids { + if value { + selectedMessageIds.insert(id) + } else { + selectedMessageIds.remove(id) + } + } + strongSelf.state = strongSelf.state.withSelectedMessageIds(selectedMessageIds) + } else { + strongSelf.state = strongSelf.state.withSelectedMessageIds(value ? Set(ids) : Set()) + } + strongSelf.chatInterfaceInteraction.selectionState = strongSelf.state.selectedMessageIds.flatMap { ChatInterfaceSelectionState(selectedIds: $0) } + if let (layout, navigationHeight) = strongSelf.validLayout { + strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.4, curve: .spring), additive: false) + } + strongSelf.paneContainerNode.updateSelectedMessageIds(strongSelf.state.selectedMessageIds, animated: true) }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _ in @@ -2831,21 +748,37 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }, requestMessageActionCallback: { _, _, _ in }, requestMessageActionUrlAuth: { _, _, _ in }, activateSwitchInline: { _, _ in - }, openUrl: { url, _, external, _ in - //self?.openUrl(url, external: external ?? false) + }, openUrl: { [weak self] url, _, external, _ in + guard let strongSelf = self else { + return + } + strongSelf.openUrl(url: url, external: external ?? false) }, shareCurrentLocation: { }, shareAccountContact: { }, sendBotCommand: { _, _ in - }, openInstantPage: { message, associatedData in - /*if let strongSelf = self, strongSelf.isNodeLoaded, let navigationController = strongSelf.navigationController as? NavigationController, let message = strongSelf.mediaCollectionDisplayNode.messageForGallery(message.id)?.message { - openChatInstantPage(context: strongSelf.context, message: message, sourcePeerType: associatedData?.automaticDownloadPeerType, navigationController: navigationController) - }*/ - }, openWallpaper: { message in - /*if let strongSelf = self, strongSelf.isNodeLoaded, let message = strongSelf.mediaCollectionDisplayNode.messageForGallery(message.id)?.message { - openChatWallpaper(context: strongSelf.context, message: message, present: { [weak self] c, a in - self?.present(c, in: .window(.root), with: a, blockInteraction: true) - }) - }*/ + }, openInstantPage: { [weak self] message, associatedData in + guard let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController else { + return + } + var foundGalleryMessage: Message? + if let searchContentNode = strongSelf.searchDisplayController?.contentNode as? ChatHistorySearchContainerNode { + if let galleryMessage = searchContentNode.messageForGallery(message.id) { + let _ = (strongSelf.context.account.postbox.transaction { transaction -> Void in + if transaction.getMessage(galleryMessage.id) == nil { + storeMessageFromSearch(transaction: transaction, message: galleryMessage) + } + }).start() + foundGalleryMessage = galleryMessage + } + } + if foundGalleryMessage == nil, let galleryMessage = strongSelf.paneContainerNode.findLoadedMessage(id: message.id) { + foundGalleryMessage = galleryMessage + } + + if let foundGalleryMessage = foundGalleryMessage { + openChatInstantPage(context: strongSelf.context, message: foundGalleryMessage, sourcePeerType: associatedData?.automaticDownloadPeerType, navigationController: navigationController) + } + }, openWallpaper: { _ in }, openTheme: { _ in }, openHashtag: { _, _ in }, updateInputState: { _ in @@ -2859,55 +792,55 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }, reactionContainerNode: { return nil }, presentGlobalOverlayController: { _, _ in }, callPeer: { _ in - }, longTap: { content, _ in - /*if let strongSelf = self { - strongSelf.view.endEditing(true) - switch content { - case let .url(url): - let canOpenIn = availableOpenInOptions(context: strongSelf.context, item: .url(url: url)).count > 1 - let openText = canOpenIn ? strongSelf.presentationData.strings.Conversation_FileOpenIn : strongSelf.presentationData.strings.Conversation_LinkDialogOpen - let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData) - actionSheet.setItemGroups([ActionSheetItemGroup(items: [ - ActionSheetTextItem(title: url), - ActionSheetButtonItem(title: openText, color: .accent, action: { [weak actionSheet] in - actionSheet?.dismissAnimated() - if let strongSelf = self { - if canOpenIn { - let actionSheet = OpenInActionSheetController(context: strongSelf.context, item: .url(url: url), openUrl: { [weak self] url in - if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController { - strongSelf.context.sharedContext.openExternalUrl(context: strongSelf.context, urlContext: .generic, url: url, forceExternal: true, presentationData: strongSelf.presentationData, navigationController: navigationController, dismissInput: { - }) - } + }, longTap: { [weak self] content, _ in + guard let strongSelf = self else { + return + } + strongSelf.view.endEditing(true) + switch content { + case let .url(url): + let canOpenIn = availableOpenInOptions(context: strongSelf.context, item: .url(url: url)).count > 1 + let openText = canOpenIn ? strongSelf.presentationData.strings.Conversation_FileOpenIn : strongSelf.presentationData.strings.Conversation_LinkDialogOpen + let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData) + actionSheet.setItemGroups([ActionSheetItemGroup(items: [ + ActionSheetTextItem(title: url), + ActionSheetButtonItem(title: openText, color: .accent, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + if let strongSelf = self { + if canOpenIn { + let actionSheet = OpenInActionSheetController(context: strongSelf.context, item: .url(url: url), openUrl: { [weak self] url in + if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController { + strongSelf.context.sharedContext.openExternalUrl(context: strongSelf.context, urlContext: .generic, url: url, forceExternal: true, presentationData: strongSelf.presentationData, navigationController: navigationController, dismissInput: { }) - strongSelf.present(actionSheet, in: .window(.root)) - } else { - strongSelf.context.sharedContext.applicationBindings.openUrl(url) } - } - }), - ActionSheetButtonItem(title: strongSelf.presentationData.strings.ShareMenu_CopyShareLink, color: .accent, action: { [weak actionSheet] in - actionSheet?.dismissAnimated() - UIPasteboard.general.string = url - }), - ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_AddToReadingList, color: .accent, action: { [weak actionSheet] in - actionSheet?.dismissAnimated() - if let link = URL(string: url) { - let _ = try? SSReadingList.default()?.addItem(with: link, title: nil, previewText: nil) - } - }) - ]), ActionSheetItemGroup(items: [ - ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in - actionSheet?.dismissAnimated() - }) - ])]) - strongSelf.present(actionSheet, in: .window(.root)) - default: - break - } - }*/ + }) + strongSelf.controller?.present(actionSheet, in: .window(.root)) + } else { + strongSelf.context.sharedContext.applicationBindings.openUrl(url) + } + } + }), + ActionSheetButtonItem(title: strongSelf.presentationData.strings.ShareMenu_CopyShareLink, color: .accent, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + UIPasteboard.general.string = url + }), + ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_AddToReadingList, color: .accent, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + if let link = URL(string: url) { + let _ = try? SSReadingList.default()?.addItem(with: link, title: nil, previewText: nil) + } + }) + ]), ActionSheetItemGroup(items: [ + ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + }) + ])]) + strongSelf.controller?.present(actionSheet, in: .window(.root)) + default: + break + } }, openCheckoutOrReceipt: { _ in }, openSearch: { - //self?.activateSearch() }, setupReply: { _ in }, canSetupReply: { _ in return false @@ -2934,6 +867,19 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }, cancelInteractiveKeyboardGestures: { }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false)) + self.hiddenMediaDisposable = context.sharedContext.mediaManager.galleryHiddenMediaManager.hiddenIds().start(next: { [weak self] ids in + guard let strongSelf = self else { + return + } + var hiddenMedia: [MessageId: [Media]] = [:] + for id in ids { + if case let .chat(accountId, messageId, media) = id, accountId == strongSelf.context.account.id { + hiddenMedia[messageId] = [media] + } + } + strongSelf.chatInterfaceInteraction.hiddenMedia = hiddenMedia + strongSelf.paneContainerNode.updateHiddenMedia() + }) self.backgroundColor = self.presentationData.theme.list.blocksBackgroundColor @@ -2951,35 +897,22 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self.scrollNode.addSubnode(self.paneContainerNode) self.addSubnode(self.headerNode) - self.paneContainerNode.openMessage = { [weak self] id in - return self?.openMessage(id: id) ?? false - } - - self.paneContainerNode.toggleMessageSelected = { [weak self] id in - guard let strongSelf = self else { + self.paneContainerNode.chatControllerInteraction = self.chatInterfaceInteraction + self.paneContainerNode.openPeerContextAction = { [weak self] peer, node, gesture in + guard let strongSelf = self, let controller = strongSelf.controller else { return } - if var selectedMessageIds = strongSelf.state.selectedMessageIds { - if selectedMessageIds.contains(id) { - selectedMessageIds.remove(id) - } else { - selectedMessageIds.insert(id) - } - strongSelf.state = strongSelf.state.withSelectedMessageIds(selectedMessageIds) - strongSelf.paneContainerNode.updateSelectedMessageIds(strongSelf.state.selectedMessageIds, animated: true) - if let (layout, navigationHeight) = strongSelf.validLayout { - strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.4, curve: .spring), additive: false) - } - } - } - - self.paneContainerNode.openPeer = { [weak self] peer in - guard let strongSelf = self else { - return - } - if let navigationController = strongSelf.controller?.navigationController as? NavigationController { - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id), keepStack: .always)) - } + let presentationData = strongSelf.presentationData + let chatController = strongSelf.context.sharedContext.makeChatController(context: context, chatLocation: .peer(peer.id), subject: nil, botStart: nil, mode: .standard(previewing: true)) + chatController.canReadHistory.set(false) + let items: [ContextMenuItem] = [ + .action(ContextMenuActionItem(text: presentationData.strings.Conversation_LinkDialogOpen, icon: { _ in nil }, action: { _, f in + f(.dismissWithoutContent) + self?.chatInterfaceInteraction.openPeer(peer.id, .default, nil) + })) + ] + let contextController = ContextController(account: strongSelf.context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture) + controller.presentInGlobalOverlay(contextController) } self.paneContainerNode.currentPaneUpdated = { [weak self] in @@ -2996,19 +929,25 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self?.performButtonAction(key: key) } - self.headerNode.requestAvatarExpansion = { [weak self] in + self.headerNode.requestAvatarExpansion = { [weak self] entries, transitionNode in guard let strongSelf = self, let peer = strongSelf.data?.peer, peer.smallProfileImage != nil else { return } - let transition: ContainedViewLayoutTransition = .animated(duration: 0.35, curve: .spring) - - strongSelf.headerNode.updateIsAvatarExpanded(true) - strongSelf.updateNavigationExpansionPresentation(isExpanded: true, animated: true) - - if let (layout, navigationHeight) = strongSelf.validLayout { - strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: transition, additive: true) - } + let entriesPromise = Promise<[AvatarGalleryEntry]>(entries) + let galleryController = AvatarGalleryController(context: strongSelf.context, peer: peer, remoteEntries: entriesPromise, replaceRootController: { controller, ready in + }) + strongSelf.hiddenAvatarRepresentationDisposable.set((galleryController.hiddenMedia |> deliverOnMainQueue).start(next: { entry in + if entry == entries.first { + self?.headerNode.updateAvatarIsHidden(true) + } else { + self?.headerNode.updateAvatarIsHidden(false) + } + })) + strongSelf.controller?.present(galleryController, in: .window(.root), with: AvatarGalleryControllerPresentationArguments(transitionArguments: { _ in + return GalleryTransitionArguments(transitionNode: transitionNode, addToTransitionSurface: { _ in + }) + })) } self.headerNode.navigationButtonContainer.performAction = { [weak self] key in @@ -3019,7 +958,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD case .edit: strongSelf.state = strongSelf.state.withIsEditing(true) if strongSelf.headerNode.isAvatarExpanded { - strongSelf.headerNode.updateIsAvatarExpanded(false) + strongSelf.headerNode.updateIsAvatarExpanded(false, transition: .immediate) strongSelf.updateNavigationExpansionPresentation(isExpanded: false, animated: true) } if let (layout, navigationHeight) = strongSelf.validLayout { @@ -3092,19 +1031,21 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD if let (layout, navigationHeight) = strongSelf.validLayout { strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.4, curve: .spring), additive: false) } + strongSelf.chatInterfaceInteraction.selectionState = strongSelf.state.selectedMessageIds.flatMap { ChatInterfaceSelectionState(selectedIds: $0) } strongSelf.paneContainerNode.updateSelectedMessageIds(strongSelf.state.selectedMessageIds, animated: true) case .selectionDone: strongSelf.state = strongSelf.state.withSelectedMessageIds(nil) if let (layout, navigationHeight) = strongSelf.validLayout { strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.4, curve: .spring), additive: false) } + strongSelf.chatInterfaceInteraction.selectionState = strongSelf.state.selectedMessageIds.flatMap { ChatInterfaceSelectionState(selectedIds: $0) } strongSelf.paneContainerNode.updateSelectedMessageIds(strongSelf.state.selectedMessageIds, animated: true) case .search: strongSelf.activateSearch() } } - self.dataDisposable = (peerInfoScreenData(context: context, peerId: peerId) + self.dataDisposable = (peerInfoScreenData(context: context, peerId: peerId, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat) |> deliverOnMainQueue).start(next: { [weak self] data in guard let strongSelf = self else { return @@ -3115,7 +1056,10 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD deinit { self.dataDisposable?.dispose() + self.hiddenMediaDisposable?.dispose() self.activeActionDisposable.dispose() + self.resolveUrlDisposable.dispose() + self.hiddenAvatarRepresentationDisposable.dispose() } override func didLoad() { @@ -3130,7 +1074,9 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } func scrollToTop() { - self.scrollNode.view.setContentOffset(CGPoint(), animated: true) + if !self.paneContainerNode.scrollToTop() { + self.scrollNode.view.setContentOffset(CGPoint(), animated: true) + } } @objc private func editingCancelPressed() { @@ -3138,7 +1084,25 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } private func openMessage(id: MessageId) -> Bool { - guard let galleryMessage = self.paneContainerNode.findLoadedMessage(id: id), let controller = self.controller, let navigationController = controller.navigationController as? NavigationController else { + guard let controller = self.controller, let navigationController = controller.navigationController as? NavigationController else { + return false + } + var foundGalleryMessage: Message? + if let searchContentNode = self.searchDisplayController?.contentNode as? ChatHistorySearchContainerNode { + if let galleryMessage = searchContentNode.messageForGallery(id) { + let _ = (self.context.account.postbox.transaction { transaction -> Void in + if transaction.getMessage(galleryMessage.id) == nil { + storeMessageFromSearch(transaction: transaction, message: galleryMessage) + } + }).start() + foundGalleryMessage = galleryMessage + } + } + if foundGalleryMessage == nil, let galleryMessage = self.paneContainerNode.findLoadedMessage(id: id) { + foundGalleryMessage = galleryMessage + } + + guard let galleryMessage = foundGalleryMessage else { return false } self.view.endEditing(true) @@ -3156,17 +1120,73 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD guard let strongSelf = self else { return } - strongSelf.view.addSubview(view) - }, openUrl: { url in - //self?.openUrl(url) - }, openPeer: { peer, navigation in - //self?.controllerInteraction?.openPeer(peer.id, navigation, nil) + strongSelf.paneContainerNode.currentPane?.node.addToTransitionSurface(view: view) + }, openUrl: { [weak self] url in + self?.openUrl(url: url, external: false) + }, openPeer: { [weak self] peer, navigation in + self?.openPeer(peerId: peer.id, navigation: navigation) }, callPeer: { peerId in //self?.controllerInteraction?.callPeer(peerId) }, enqueueMessage: { _ in }, sendSticker: nil, setupTemporaryHiddenMedia: { _, _, _ in }, chatAvatarHiddenMedia: { _, _ in })) } + private func openUrl(url: String, external: Bool) { + let disposable = self.resolveUrlDisposable + + let resolvedUrl: Signal + if external { + resolvedUrl = .single(.externalUrl(url)) + } else { + resolvedUrl = self.context.sharedContext.resolveUrl(account: self.context.account, url: url) + } + + disposable.set((resolvedUrl + |> deliverOnMainQueue).start(next: { [weak self] result in + guard let strongSelf = self else { + return + } + strongSelf.context.sharedContext.openResolvedUrl(result, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.controller?.navigationController as? NavigationController, openPeer: { peerId, navigation in + self?.openPeer(peerId: peerId, navigation: navigation) + }, sendFile: nil, + sendSticker: nil, + present: { c, a in + self?.controller?.present(c, in: .window(.root), with: a) + }, dismissInput: { + self?.view.endEditing(true) + }, contentContext: nil) + })) + } + + private func openPeer(peerId: PeerId, navigation: ChatControllerInteractionNavigateToPeer) { + switch navigation { + case .default: + if let navigationController = self.controller?.navigationController as? NavigationController { + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peerId), keepStack: .always)) + } + case let .chat(_, subject): + if let navigationController = self.controller?.navigationController as? NavigationController { + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peerId), subject: subject, keepStack: .always)) + } + case .info: + self.resolveUrlDisposable.set((self.context.account.postbox.loadedPeerWithId(peerId) + |> take(1) + |> deliverOnMainQueue).start(next: { [weak self] peer in + if let strongSelf = self, peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil { + if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + (strongSelf.controller?.navigationController as? NavigationController)?.pushViewController(infoController) + } + } + })) + case let .withBotStartPayload(startPayload): + if let navigationController = self.controller?.navigationController as? NavigationController { + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peerId), botStart: startPayload)) + } + default: + break + } + } + private func performButtonAction(key: PeerInfoHeaderButtonKey) { guard let controller = self.controller else { return @@ -3215,6 +1235,9 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD strongSelf.controller?.present(muteSettingsController, in: .window(.root)) }) case .more: + guard let data = self.data, let peer = data.peer else { + return + } let actionSheet = ActionSheetController(presentationData: self.presentationData) let dismissAction: () -> Void = { [weak actionSheet] in actionSheet?.dismissAnimated() @@ -3222,24 +1245,14 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD var reportSpam = false var deleteChat = false var items: [ActionSheetItem] = [] - if self.headerNode.isAvatarExpanded { - items.append(ActionSheetButtonItem(title: "Message", color: .accent, action: { [weak self] in - dismissAction() - self?.performButtonAction(key: .message) - })) - items.append(ActionSheetButtonItem(title: "Call", color: .accent, action: { [weak self] in - dismissAction() - self?.performButtonAction(key: .call) - })) - items.append(ActionSheetButtonItem(title: "Mute", color: .accent, action: { [weak self] in - dismissAction() - self?.performButtonAction(key: .mute) - })) + if let user = peer as? TelegramUser { + if user.botInfo == nil && !user.flags.contains(.isSupport) { + items.append(ActionSheetButtonItem(title: presentationData.strings.UserInfo_StartSecretChat, color: .accent, action: { [weak self] in + dismissAction() + self?.openStartSecretChat() + })) + } } - items.append(ActionSheetButtonItem(title: presentationData.strings.UserInfo_StartSecretChat, color: .accent, action: { [weak self] in - dismissAction() - self?.openStartSecretChat() - })) actionSheet.setItemGroups([ ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [ActionSheetButtonItem(title: self.presentationData.strings.Common_Cancel, action: { dismissAction() })]) @@ -3297,9 +1310,9 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD cancelImpl?() })) strongSelf.controller?.present(statusController, in: .window(.root)) - return ActionDisposable { [weak controller] in + return ActionDisposable { [weak statusController] in Queue.mainQueue().async() { - controller?.dismiss() + statusController?.dismiss() } } } else { @@ -3327,7 +1340,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD return } if let navigationController = (strongSelf.controller?.navigationController as? NavigationController) { - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(strongSelf.peerId))) + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId))) } }, error: { _ in guard let strongSelf = self else { @@ -3636,8 +1649,69 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }) } - func deleteMessages() { - if let messageIds = self.state.selectedMessageIds, !messageIds.isEmpty { + private func openReport() { + guard let controller = self.controller else { + return + } + controller.present(peerReportOptionsController(context: self.context, subject: .peer(self.peerId), present: { [weak controller] c, a in + controller?.present(c, in: .window(.root), with: a) + }, push: { [weak controller] c in + controller?.push(c) + }, completion: { _ in }), in: .window(.root)) + } + + private func openShareBot() { + let _ = (getUserPeer(postbox: self.context.account.postbox, peerId: self.peerId) + |> deliverOnMainQueue).start(next: { [weak self] peer, _ in + guard let strongSelf = self else { + return + } + if let peer = peer as? TelegramUser, let username = peer.username { + let shareController = ShareController(context: strongSelf.context, subject: .url("https://t.me/\(username)")) + strongSelf.controller?.present(shareController, in: .window(.root)) + } + }) + } + + private func openAddBotToGroup() { + guard let controller = self.controller else { + return + } + context.sharedContext.openResolvedUrl(.groupBotStart(peerId: peerId, payload: ""), context: self.context, urlContext: .generic, navigationController: controller.navigationController as? NavigationController, openPeer: { id, navigation in + }, sendFile: nil, + sendSticker: nil, + present: { [weak controller] c, a in + controller?.present(c, in: .window(.root), with: a) + }, dismissInput: { [weak controller] in + controller?.view.endEditing(true) + }, contentContext: nil) + } + + private func performBotCommand(command: PeerInfoBotCommand) { + let _ = (self.context.account.postbox.loadedPeerWithId(peerId) + |> deliverOnMainQueue).start(next: { [weak self] peer in + guard let strongSelf = self else { + return + } + let text: String + switch command { + case .settings: + text = "/settings" + case .privacy: + text = "/privacy" + case .help: + text = "/help" + } + let _ = enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: [.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)]).start() + + if let navigationController = strongSelf.controller?.navigationController as? NavigationController { + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(strongSelf.peerId))) + } + }) + } + + func deleteMessages(messageIds: Set?) { + if let messageIds = messageIds ?? self.state.selectedMessageIds, !messageIds.isEmpty { self.activeActionDisposable.set((self.context.sharedContext.chatAvailableMessageActions(postbox: self.context.account.postbox, accountPeerId: self.context.account.peerId, messageIds: messageIds) |> deliverOnMainQueue).start(next: { [weak self] actions in if let strongSelf = self, let peer = strongSelf.data?.peer, !actions.options.isEmpty { @@ -3696,8 +1770,8 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } } - func forwardMessages() { - if let messageIds = self.state.selectedMessageIds, !messageIds.isEmpty { + func forwardMessages(messageIds: Set?) { + if let messageIds = messageIds ?? self.state.selectedMessageIds, !messageIds.isEmpty { let peerSelectionController = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context, filter: [.onlyWriteable, .excludeDisabled])) peerSelectionController.peerSelected = { [weak self, weak peerSelectionController] peerId in if let strongSelf = self, let _ = peerSelectionController { @@ -3770,15 +1844,6 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD return } - var maybePlaceholderNode: SearchBarPlaceholderNode? - /*if let listNode = historyNode as? ListView { - listNode.forEachItemNode { node in - if let node = node as? ChatListSearchItemNode { - maybePlaceholderNode = node.searchBarNode - } - } - }*/ - if let _ = self.searchDisplayController { return } @@ -3795,7 +1860,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } } - self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, contentNode: ChatHistorySearchContainerNode(context: self.context, peerId: self.peerId, tagMask: tagMask, interfaceInteraction: self.chatInterfaceInteraction), cancel: { [weak self] in + self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, placeholder: self.presentationData.strings.Common_Search, contentNode: ChatHistorySearchContainerNode(context: self.context, peerId: self.peerId, tagMask: tagMask, interfaceInteraction: self.chatInterfaceInteraction), cancel: { [weak self] in self?.deactivateSearch() }) let transition: ContainedViewLayoutTransition = .animated(duration: 0.2, curve: .easeInOut) @@ -3828,6 +1893,18 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } } + func updatePresentationData(_ presentationData: PresentationData) { + self.presentationData = presentationData + + self.backgroundColor = self.presentationData.theme.list.blocksBackgroundColor + + self.updateNavigationExpansionPresentation(isExpanded: self.headerNode.isAvatarExpanded, animated: false) + + if let (layout, navigationHeight) = self.validLayout { + self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate) + } + } + func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition, additive: Bool = false) { self.validLayout = (layout, navigationHeight) @@ -3846,7 +1923,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD var contentHeight: CGFloat = 0.0 - let headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: layout.safeInsets.left, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, contentOffset: self.scrollNode.view.contentOffset.y, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, presence: self.data?.presence, isContact: self.data?.isContact ?? false, state: self.state, transition: transition, additive: additive) + let headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: layout.safeInsets.left, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, contentOffset: self.scrollNode.view.contentOffset.y, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, statusData: self.data?.status, isContact: self.data?.isContact ?? false, state: self.state, transition: transition, additive: additive) let headerFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: headerHeight)) if additive { transition.updateFrameAdditive(node: self.headerNode, frame: headerFrame) @@ -3930,7 +2007,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD guard let strongSelf = self else { return } - strongSelf.deleteMessages() + strongSelf.deleteMessages(messageIds: nil) }, shareMessages: { [weak self] in guard let strongSelf = self, let messageIds = strongSelf.state.selectedMessageIds, !messageIds.isEmpty else { return @@ -3958,7 +2035,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD guard let strongSelf = self else { return } - strongSelf.forwardMessages() + strongSelf.forwardMessages(messageIds: nil) }, reportMessages: { [weak self] in guard let strongSelf = self, let messageIds = strongSelf.state.selectedMessageIds, !messageIds.isEmpty else { return @@ -3973,7 +2050,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self.paneContainerNode.addSubnode(selectionPanelNode) } selectionPanelNode.selectionPanel.selectedMessages = selectedMessageIds - let panelHeight = selectionPanelNode.update(width: layout.size.width, safeInset: layout.safeInsets.left, metrics: layout.metrics, presentationData: self.presentationData, transition: wasAdded ? .immediate : transition) + let panelHeight = selectionPanelNode.update(layout: layout, presentationData: self.presentationData, transition: wasAdded ? .immediate : transition) let panelFrame = CGRect(origin: CGPoint(x: 0.0, y: paneContainerSize.height - panelHeight), size: CGSize(width: layout.size.width, height: panelHeight)) if wasAdded { selectionPanelNode.frame = panelFrame @@ -4022,16 +2099,20 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD let offsetY = self.scrollNode.view.contentOffset.y if self.state.isEditing || offsetY <= 50.0 { - self.scrollNode.view.bounces = true - self.scrollNode.view.alwaysBounceVertical = true + if !self.scrollNode.view.bounces { + self.scrollNode.view.bounces = true + self.scrollNode.view.alwaysBounceVertical = true + } } else { - self.scrollNode.view.bounces = false - self.scrollNode.view.alwaysBounceVertical = false + if self.scrollNode.view.bounces { + self.scrollNode.view.bounces = false + self.scrollNode.view.alwaysBounceVertical = false + } } if let (layout, navigationHeight) = self.validLayout { if !additive { - self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: layout.safeInsets.left, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, contentOffset: offsetY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, presence: self.data?.presence, isContact: self.data?.isContact ?? false, state: self.state, transition: transition, additive: additive) + self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: layout.safeInsets.left, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, contentOffset: offsetY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, notificationSettings: self.data?.notificationSettings, statusData: self.data?.status, isContact: self.data?.isContact ?? false, state: self.state, transition: transition, additive: additive) } let paneAreaExpansionDistance: CGFloat = 32.0 @@ -4051,7 +2132,12 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD let visibleHeight = self.scrollNode.view.contentOffset.y + self.scrollNode.view.bounds.height - self.paneContainerNode.frame.minY - self.paneContainerNode.update(size: self.paneContainerNode.bounds.size, visibleHeight: visibleHeight, expansionFraction: paneAreaExpansionFraction, presentationData: self.presentationData, data: self.data, transition: transition) + var bottomInset = layout.intrinsicInsets.bottom + if let selectionPanelNode = self.paneContainerNode.selectionPanelNode { + bottomInset = max(bottomInset, selectionPanelNode.bounds.height) + } + + self.paneContainerNode.update(size: self.paneContainerNode.bounds.size, sideInset: layout.safeInsets.left, bottomInset: bottomInset, visibleHeight: visibleHeight, expansionFraction: paneAreaExpansionFraction, presentationData: self.presentationData, data: self.data, transition: transition) self.headerNode.navigationButtonContainer.frame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: layout.statusBarHeight ?? 0.0), size: CGSize(width: layout.size.width - layout.safeInsets.left * 2.0, height: 44.0)) self.headerNode.navigationButtonContainer.isWhite = self.headerNode.isAvatarExpanded @@ -4059,7 +2145,9 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD if self.state.isEditing { navigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .done, isForExpandedView: false)) } else { - navigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .edit, isForExpandedView: false)) + if peerInfoCanEdit(peer: self.data?.peer, cachedData: self.data?.cachedData) { + navigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .edit, isForExpandedView: false)) + } if self.state.selectedMessageIds == nil { if let currentPaneKey = self.paneContainerNode.currentPaneKey { switch currentPaneKey { @@ -4068,8 +2156,13 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD default: break } + switch currentPaneKey { + case .media, .files, .music, .links, .voice: + navigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .select, isForExpandedView: true)) + default: + break + } } - navigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .select, isForExpandedView: true)) } else { navigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .selectionDone, isForExpandedView: true)) } @@ -4123,7 +2216,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self.hapticFeedback?.tap() } - self.headerNode.updateIsAvatarExpanded(shouldBeExpanded) + self.headerNode.updateIsAvatarExpanded(shouldBeExpanded, transition: transition) self.updateNavigationExpansionPresentation(isExpanded: shouldBeExpanded, animated: true) if let (layout, navigationHeight) = self.validLayout { @@ -4230,6 +2323,7 @@ public final class PeerInfoScreen: ViewController { private let avatarInitiallyExpanded: Bool private var presentationData: PresentationData + private var presentationDataDisposable: Disposable? fileprivate var controllerNode: PeerInfoScreenNode { return self.displayNode as! PeerInfoScreenNode @@ -4269,6 +2363,9 @@ public final class PeerInfoScreen: ViewController { if strongSelf.controllerNode.scrollNode.view.contentOffset.y > .ulpOfOne { return nil } + if strongSelf.controllerNode.headerNode.isAvatarExpanded { + return nil + } if let tag = other.userInfo as? PeerInfoNavigationSourceTag, tag.peerId == peerId { return PeerInfoNavigationTransitionNode(screenNode: strongSelf.controllerNode, presentationData: strongSelf.presentationData, headerNode: strongSelf.controllerNode.headerNode) } @@ -4280,12 +2377,30 @@ public final class PeerInfoScreen: ViewController { self.scrollToTop = { [weak self] in self?.controllerNode.scrollToTop() } + + self.presentationDataDisposable = (context.sharedContext.presentationData + |> deliverOnMainQueue).start(next: { [weak self] presentationData in + if let strongSelf = self { + let previousTheme = strongSelf.presentationData.theme + let previousStrings = strongSelf.presentationData.strings + + strongSelf.presentationData = presentationData + + if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings { + strongSelf.controllerNode.updatePresentationData(strongSelf.presentationData) + } + } + }) } required init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } + deinit { + self.presentationDataDisposable?.dispose() + } + override public func loadDisplayNode() { self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded) @@ -4457,7 +2572,7 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig self.headerNode.navigationTransition = PeerInfoHeaderNavigationTransition(sourceNavigationBar: bottomNavigationBar, sourceTitleView: previousTitleView, sourceTitleFrame: previousTitleFrame, sourceSubtitleFrame: previousStatusFrame, fraction: fraction) if let (layout, navigationHeight) = self.screenNode.validLayout { - self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: layout.safeInsets.left, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, contentOffset: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, notificationSettings: self.screenNode.data?.notificationSettings, presence: self.screenNode.data?.presence, isContact: self.screenNode.data?.isContact ?? false, state: self.screenNode.state, transition: transition, additive: false) + self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: layout.safeInsets.left, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, contentOffset: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, notificationSettings: self.screenNode.data?.notificationSettings, statusData: self.screenNode.data?.status, isContact: self.screenNode.data?.isContact ?? false, state: self.screenNode.state, transition: transition, additive: false) } let titleScale = (fraction * previousTitleNode.bounds.height + (1.0 - fraction) * self.headerNode.titleNode.bounds.height) / previousTitleNode.bounds.height @@ -4499,3 +2614,32 @@ private func encodeText(_ string: String, _ key: Int) -> String { } return result } + +private final class ContextControllerContentSourceImpl: ContextControllerContentSource { + let controller: ViewController + weak var sourceNode: ASDisplayNode? + + let navigationController: NavigationController? = nil + + let passthroughTouches: Bool = false + + init(controller: ViewController, sourceNode: ASDisplayNode?) { + self.controller = controller + self.sourceNode = sourceNode + } + + func transitionInfo() -> ContextControllerTakeControllerInfo? { + let sourceNode = self.sourceNode + return ContextControllerTakeControllerInfo(contentAreaInScreenSpace: CGRect(origin: CGPoint(), size: CGSize(width: 10.0, height: 10.0)), sourceNode: { [weak sourceNode] in + if let sourceNode = sourceNode { + return (sourceNode, sourceNode.bounds) + } else { + return nil + } + }) + } + + func animatedIn() { + self.controller.didAppearInContextPreview() + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfoFilesPane.swift b/submodules/TelegramUI/TelegramUI/PeerInfoFilesPane.swift deleted file mode 100644 index 1a2b77ee30..0000000000 --- a/submodules/TelegramUI/TelegramUI/PeerInfoFilesPane.swift +++ /dev/null @@ -1,217 +0,0 @@ -import AsyncDisplayKit -import Display -import TelegramCore -import SyncCore -import SwiftSignalKit -import Postbox -import TelegramPresentationData -import AccountContext -import ContextUI -import PhotoResources -import TelegramUIPreferences - -final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode { - private let context: AccountContext - private let peerId: PeerId - private let paneInteraction: PeerInfoPaneInteraction - private let controllerInteraction: ChatControllerInteraction - - private let listNode: ChatHistoryListNode - - private var currentParams: (size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData)? - - private let ready = Promise() - private var didSetReady: Bool = false - var isReady: Signal { - return self.ready.get() - } - - private let selectedMessagesPromise = Promise?>(nil) - private var selectedMessages: Set? { - didSet { - if self.selectedMessages != oldValue { - self.selectedMessagesPromise.set(.single(self.selectedMessages)) - } - } - } - - private var hiddenMediaDisposable: Disposable? - - init(context: AccountContext, openMessage: @escaping (MessageId) -> Bool, peerId: PeerId, tagMask: MessageTags, interaction: PeerInfoPaneInteraction) { - self.context = context - self.peerId = peerId - self.paneInteraction = interaction - - var openMessageImpl: ((MessageId) -> Bool)? - var toggleMessageSelectionImpl: (([MessageId]) -> Void)? - self.controllerInteraction = ChatControllerInteraction(openMessage: { message, _ in - return openMessageImpl?(message.id) ?? false - }, openPeer: { _, _, _ in - }, openPeerMention: { _ in - }, openMessageContextMenu: { _, _, _, _, _ in - }, openMessageContextActions: { _, _, _, _ in - }, navigateToMessage: { _, _ in - }, tapMessage: nil, clickThroughMessage: { - }, toggleMessagesSelection: { ids, _ in - toggleMessageSelectionImpl?(ids) - }, sendCurrentMessage: { _ in - }, sendMessage: { _ in - }, sendSticker: { _, _, _, _ in - return false - }, sendGif: { _, _, _ in - return false - }, requestMessageActionCallback: { _, _, _ in - }, requestMessageActionUrlAuth: { _, _, _ in - }, activateSwitchInline: { _, _ in - }, openUrl: { _, _, _, _ in - }, shareCurrentLocation: { - }, shareAccountContact: { - }, sendBotCommand: { _, _ in - }, openInstantPage: { _, _ in - }, openWallpaper: { _ in - }, openTheme: {_ in - }, openHashtag: { _, _ in - }, updateInputState: { _ in - }, updateInputMode: { _ in - }, openMessageShareMenu: { _ in - }, presentController: { _, _ in - }, navigationController: { - return nil - }, chatControllerNode: { - return nil - }, reactionContainerNode: { - return nil - }, presentGlobalOverlayController: { _, _ in - }, callPeer: { _ in - }, longTap: { _, _ in - }, openCheckoutOrReceipt: { _ in - }, openSearch: { - }, setupReply: { _ in - }, canSetupReply: { _ in - return false - }, navigateToFirstDateMessage: { _ in - }, requestRedeliveryOfFailedMessages: { _ in - }, addContact: { _ in - }, rateCall: { _, _ in - }, requestSelectMessagePollOptions: { _, _ in - }, requestOpenMessagePollResults: { _, _ in - }, openAppStorePage: { - }, displayMessageTooltip: { _, _, _, _ in - }, seekToTimecode: { _, _, _ in - }, scheduleCurrentMessage: { - }, sendScheduledMessagesNow: { _ in - }, editScheduledMessagesTime: { _ in - }, performTextSelectionAction: { _, _, _ in - }, updateMessageReaction: { _, _ in - }, openMessageReactions: { _ in - }, displaySwipeToReplyHint: { - }, dismissReplyMarkupMessage: { _ in - }, openMessagePollResults: { _, _ in - }, openPollCreation: { _ in - }, requestMessageUpdate: { _ in - }, cancelInteractiveKeyboardGestures: { - }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false)) - self.controllerInteraction.selectionState = self.paneInteraction.selectedMessageIds.flatMap { ids in - return ChatInterfaceSelectionState(selectedIds: ids) - } - self.selectedMessages = self.paneInteraction.selectedMessageIds - self.selectedMessagesPromise.set(.single(self.selectedMessages)) - - self.listNode = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), tagMask: tagMask, subject: nil, controllerInteraction: controllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), mode: .list(search: false, reversed: false)) - - super.init() - - openMessageImpl = { id in - return openMessage(id) - } - - toggleMessageSelectionImpl = { [weak self] ids in - for id in ids { - self?.paneInteraction.toggleMessageSelected(id) - } - } - - self.hiddenMediaDisposable = context.sharedContext.mediaManager.galleryHiddenMediaManager.hiddenIds().start(next: { [weak self] ids in - guard let strongSelf = self else { - return - } - var hiddenMedia: [MessageId: [Media]] = [:] - for id in ids { - if case let .chat(accountId, messageId, media) = id, accountId == strongSelf.context.account.id { - hiddenMedia[messageId] = [media] - } - } - strongSelf.controllerInteraction.hiddenMedia = hiddenMedia - strongSelf.listNode.forEachItemNode { itemNode in - if let itemNode = itemNode as? ListMessageNode { - itemNode.updateHiddenMedia() - } - } - }) - - self.listNode.preloadPages = true - self.addSubnode(self.listNode) - - self.ready.set(self.listNode.historyState.get() - |> take(1) - |> map { _ -> Bool in true }) - } - - deinit { - self.hiddenMediaDisposable?.dispose() - } - - func scrollToTop() -> Bool { - let offset = self.listNode.visibleContentOffset() - switch offset { - case let .known(value) where value <= CGFloat.ulpOfOne: - return false - default: - self.listNode.scrollToEndOfHistory() - return true - } - } - - func update(size: CGSize, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { - self.currentParams = (size, isScrollingLockedAtTop, presentationData) - - transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(), size: size)) - let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition) - self.listNode.updateLayout(transition: transition, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: size, insets: UIEdgeInsets(), duration: duration, curve: curve)) - self.listNode.scrollEnabled = !isScrollingLockedAtTop - } - - func findLoadedMessage(id: MessageId) -> Message? { - self.listNode.messageInCurrentHistoryView(id) - } - - func transferVelocity(_ velocity: CGFloat) { - if velocity > 0.0 { - self.listNode.transferVelocity(velocity) - } - } - - func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { - var transitionNode: (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? - self.listNode.forEachItemNode { itemNode in - if let itemNode = itemNode as? ListMessageNode { - if let result = itemNode.transitionNode(id: messageId, media: media) { - transitionNode = result - } - } - } - return transitionNode - } - - func updateSelectedMessages(animated: Bool) { - self.controllerInteraction.selectionState = self.paneInteraction.selectedMessageIds.flatMap { ids in - return ChatInterfaceSelectionState(selectedIds: ids) - } - self.listNode.forEachItemNode { itemNode in - if let itemNode = itemNode as? ChatMessageItemView { - itemNode.updateSelectionState(animated: animated) - } - } - self.selectedMessages = self.paneInteraction.selectedMessageIds - } -} From d6188e21240f2818f903e3c16e326b5a6d01ac40 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Mon, 10 Feb 2020 18:03:13 +0100 Subject: [PATCH 10/30] Temporary --- SiriIntents/IntentHandler.swift | 4 +- buildbox/deploy-appcenter.sh | 83 +++ buildbox/deploy-telegram.sh | 7 +- .../Sources/AccountContext.swift | 4 +- .../AvatarNode/Sources/AvatarNode.swift | 15 +- .../AvatarNode/Sources/PeerAvatar.swift | 44 +- ...teractiveTransitionGestureRecognizer.swift | 3 + .../Navigation/NavigationContainer.swift | 25 +- .../Display/Display/NavigationBar.swift | 2 +- .../Display/NavigationButtonNode.swift | 7 + .../NavigationTransitionCoordinator.swift | 21 +- ...pLongTapOrDoubleTapGestureRecognizer.swift | 5 +- .../Sources/PhotoResources.swift | 12 +- .../Sources/SettingsController.swift | 3 +- .../Sources/TelegramIntents.swift | 3 +- .../TelegramUI/ChatAvatarNavigationNode.swift | 12 +- .../TelegramUI/ChatController.swift | 116 +++- .../ChatMessagePollBubbleContentNode.swift | 3 +- .../TelegramUI/TelegramUI/ChatTitleView.swift | 118 ++-- .../TelegramUI/MultiScaleTextNode.swift | 75 ++ .../TelegramUI/NavigateToChatController.swift | 7 + .../ListItems/PeerInfoScreenCommentItem.swift | 57 ++ .../Panes/PeerInfoVisualMediaPaneNode.swift | 1 + .../TelegramUI/PeerInfo/PeerInfoData.swift | 258 ++++++- .../PeerInfo/PeerInfoHeaderNode.swift | 396 +++++++++-- .../PeerInfo/PeerInfoPaneContainerNode.swift | 9 +- .../TelegramUI/PeerInfo/PeerInfoScreen.swift | 644 +++++++++++++++--- .../TelegramUI/SharedAccountContext.swift | 6 +- 28 files changed, 1650 insertions(+), 290 deletions(-) create mode 100644 buildbox/deploy-appcenter.sh create mode 100644 submodules/TelegramUI/TelegramUI/MultiScaleTextNode.swift create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenCommentItem.swift diff --git a/SiriIntents/IntentHandler.swift b/SiriIntents/IntentHandler.swift index e0d00c1ea1..efc0b4076a 100644 --- a/SiriIntents/IntentHandler.swift +++ b/SiriIntents/IntentHandler.swift @@ -567,9 +567,9 @@ public class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchFo completion(.success(with: .missed)) } - public func resolveCallType(for intent: INSearchCallHistoryIntent, with completion: @escaping (INCallRecordTypeResolutionResult) -> Void) { + /*public func resolveCallType(for intent: INSearchCallHistoryIntent, with completion: @escaping (INCallRecordTypeResolutionResult) -> Void) { completion(.success(with: .missed)) - } + }*/ public func handle(intent: INSearchCallHistoryIntent, completion: @escaping (INSearchCallHistoryIntentResponse) -> Void) { self.actionDisposable.set((self.accountPromise.get() diff --git a/buildbox/deploy-appcenter.sh b/buildbox/deploy-appcenter.sh new file mode 100644 index 0000000000..f738d21718 --- /dev/null +++ b/buildbox/deploy-appcenter.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +set -e +set -x + +API_HOST="https://api.appcenter.ms" +IPA_PATH="build/Telegram_Signed.ipa" +DSYM_PATH="build/DSYM.zip" + +upload_ipa() { + GROUP_DATA=$(curl \ + -X GET \ + --header "X-API-Token: $API_TOKEN" \ + "$API_HOST/v0.1/apps/$API_USER_NAME/$API_APP_NAME/distribution_groups/Internal" \ + ) + + GROUP_ID=$(echo "$GROUP_DATA" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["id"];') + + UPLOAD_TOKEN=$(curl \ + -X POST \ + --header "Content-Type: application/json" \ + --header "Accept: application/json" \ + --header "X-API-Token: $API_TOKEN" \ + "$API_HOST/v0.1/apps/$API_USER_NAME/$API_APP_NAME/release_uploads" \ + ) + + + UPLOAD_URL=$(echo "$UPLOAD_TOKEN" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["upload_url"];') + UPLOAD_ID=$(echo "$UPLOAD_TOKEN" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["upload_id"];') + + curl --progress-bar -F "ipa=@${IPA_PATH}" "$UPLOAD_URL" + + RELEASE_TOKEN=$(curl \ + -X PATCH \ + --header "Content-Type: application/json" \ + --header "Accept: application/json" \ + --header "X-API-Token: $API_TOKEN" \ + -d '{ "status": "committed" }' \ + "$API_HOST/v0.1/apps/$API_USER_NAME/$API_APP_NAME/release_uploads/$UPLOAD_ID" \ + ) + + + RELEASE_URL=$(echo "$RELEASE_TOKEN" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["release_url"];') + RELEASE_ID=$(echo "$RELEASE_TOKEN" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["release_id"];') + + curl \ + -X POST \ + --header "Content-Type: application/json" \ + --header "Accept: application/json" \ + --header "X-API-Token: $API_TOKEN" \ + -d "{ \"id\": \"$GROUP_ID\", \"mandatory_update\": false, \"notify_testers\": false }" \ + "$API_HOST/$RELEASE_URL/groups" +} + +upload_dsym() { + UPLOAD_DSYM_DATA=$(curl \ + -X POST \ + --header "Content-Type: application/json" \ + --header "Accept: application/json" \ + --header "X-API-Token: $API_TOKEN" \ + -d "{ \"symbol_type\": \"Apple\"}" \ + "$API_HOST/v0.1/apps/$API_USER_NAME/$API_APP_NAME/symbol_uploads" \ + ) + + DSYM_UPLOAD_URL=$(echo "$UPLOAD_DSYM_DATA" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["upload_url"];') + DSYM_UPLOAD_ID=$(echo "$UPLOAD_DSYM_DATA" | python -c 'import json,sys; obj=json.load(sys.stdin); print obj["symbol_upload_id"];') + + curl \ + --progress-bar \ + --header "x-ms-blob-type: BlockBlob" \ + --upload-file "${DSYM_PATH}" \ + "$DSYM_UPLOAD_URL" + + curl \ + -X PATCH \ + --header "Content-Type: application/json" \ + --header "Accept: application/json" \ + --header "X-API-Token: $API_TOKEN" \ + -d '{ "status": "committed" }' \ + "$API_HOST/v0.1/apps/$API_USER_NAME/$API_APP_NAME/symbol_uploads/$DSYM_UPLOAD_ID" +} + +upload_ipa diff --git a/buildbox/deploy-telegram.sh b/buildbox/deploy-telegram.sh index 85374f2d68..d76f0a292d 100644 --- a/buildbox/deploy-telegram.sh +++ b/buildbox/deploy-telegram.sh @@ -34,12 +34,10 @@ fi if [ "$CONFIGURATION" == "hockeyapp" ]; then FASTLANE_PASSWORD="" FASTLANE_ITC_TEAM_NAME="" - FASTLANE_BUILD_CONFIGURATION="internalhockeyapp" elif [ "$CONFIGURATION" == "appstore" ]; then FASTLANE_PASSWORD="$TELEGRAM_BUILD_APPSTORE_PASSWORD" FASTLANE_ITC_TEAM_NAME="$TELEGRAM_BUILD_APPSTORE_TEAM_NAME" FASTLANE_ITC_USERNAME="$TELEGRAM_BUILD_APPSTORE_USERNAME" - FASTLANE_BUILD_CONFIGURATION="testflight_llc" else echo "Unknown configuration $CONFIGURATION" exit 1 @@ -62,7 +60,6 @@ fi if [ "$1" == "appstore" ]; then export DELIVER_ITMSTRANSPORTER_ADDITIONAL_UPLOAD_PARAMETERS="-t DAV" FASTLANE_PASSWORD="$FASTLANE_PASSWORD" xcrun altool --upload-app --type ios --file "$IPA_PATH" --username "$FASTLANE_ITC_USERNAME" --password "@env:FASTLANE_PASSWORD" - #FASTLANE_PASSWORD="$FASTLANE_PASSWORD" FASTLANE_ITC_TEAM_NAME="$FASTLANE_ITC_TEAM_NAME" fastlane "$FASTLANE_BUILD_CONFIGURATION" build_number:"$BUILD_NUMBER" commit_hash:"$COMMIT_ID" commit_author:"$COMMIT_AUTHOR" skip_build:1 skip_pilot:1 -else - FASTLANE_PASSWORD="$FASTLANE_PASSWORD" FASTLANE_ITC_TEAM_NAME="$FASTLANE_ITC_TEAM_NAME" fastlane "$FASTLANE_BUILD_CONFIGURATION" build_number:"$BUILD_NUMBER" commit_hash:"$COMMIT_ID" commit_author:"$COMMIT_AUTHOR" skip_build:1 +else if [ "$1" == "hockeyapp" ]; then + API_USER_NAME="$API_USER_NAME" API_APP_NAME="$API_APP_NAME" API_TOKEN="$API_TOKEN" sh buildbox/deploy-appcenter.sh fi diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 966bb8418a..56df2567ab 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -197,12 +197,13 @@ public final class NavigateToChatControllerParams { public let keepStack: NavigateToChatKeepStack public let purposefulAction: (() -> Void)? public let scrollToEndIfExists: Bool + public let activateMessageSearch: Bool public let animated: Bool public let options: NavigationAnimationOptions public let parentGroupId: PeerGroupId? public let completion: () -> Void - public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: ChatLocation, subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: Bool = false, keepStack: NavigateToChatKeepStack = .default, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, completion: @escaping () -> Void = {}) { + public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: ChatLocation, subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: Bool = false, keepStack: NavigateToChatKeepStack = .default, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, activateMessageSearch: Bool = false, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, completion: @escaping () -> Void = {}) { self.navigationController = navigationController self.chatController = chatController self.context = context @@ -214,6 +215,7 @@ public final class NavigateToChatControllerParams { self.keepStack = keepStack self.purposefulAction = purposefulAction self.scrollToEndIfExists = scrollToEndIfExists + self.activateMessageSearch = activateMessageSearch self.animated = animated self.options = options self.parentGroupId = parentGroupId diff --git a/submodules/AvatarNode/Sources/AvatarNode.swift b/submodules/AvatarNode/Sources/AvatarNode.swift index 18f61800f6..b871681a0a 100644 --- a/submodules/AvatarNode/Sources/AvatarNode.swift +++ b/submodules/AvatarNode/Sources/AvatarNode.swift @@ -191,6 +191,8 @@ public final class AvatarNode: ASDisplayNode { private let imageReadyDisposable = MetaDisposable() private var state: AvatarNodeState = .empty + public var unroundedImage: UIImage? + private let imageReady = Promise(false) public var ready: Signal { let imageReady = self.imageReady @@ -283,7 +285,7 @@ public final class AvatarNode: ASDisplayNode { self.imageNode.isHidden = true } - public func setPeer(context: AccountContext, theme: PresentationTheme, peer: Peer?, authorOfMessage: MessageReference? = nil, overrideImage: AvatarNodeImageOverride? = nil, emptyColor: UIColor? = nil, clipStyle: AvatarNodeClipStyle = .round, synchronousLoad: Bool = false, displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0)) { + public func setPeer(context: AccountContext, theme: PresentationTheme, peer: Peer?, authorOfMessage: MessageReference? = nil, overrideImage: AvatarNodeImageOverride? = nil, emptyColor: UIColor? = nil, clipStyle: AvatarNodeClipStyle = .round, synchronousLoad: Bool = false, displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0), storeUnrounded: Bool = false) { var synchronousLoad = synchronousLoad var representation: TelegramMediaImageRepresentation? var icon = AvatarNodeIcon.none @@ -318,11 +320,18 @@ public final class AvatarNode: ASDisplayNode { let parameters: AvatarNodeParameters - if let peer = peer, let signal = peerAvatarImage(account: context.account, peerReference: PeerReference(peer), authorOfMessage: authorOfMessage, representation: representation, displayDimensions: displayDimensions, emptyColor: emptyColor, synchronousLoad: synchronousLoad) { + if let peer = peer, let signal = peerAvatarImage(account: context.account, peerReference: PeerReference(peer), authorOfMessage: authorOfMessage, representation: representation, displayDimensions: displayDimensions, emptyColor: emptyColor, synchronousLoad: synchronousLoad, provideUnrounded: storeUnrounded) { self.contents = nil self.displaySuspended = true self.imageReady.set(self.imageNode.ready) - self.imageNode.setSignal(signal) + self.imageNode.setSignal(signal |> beforeNext { [weak self] next in + Queue.mainQueue().async { + self?.unroundedImage = next?.1 + } + } + |> map { next -> UIImage? in + return next?.0 + }) if case .editAvatarIcon = icon { if self.editOverlayNode == nil { diff --git a/submodules/AvatarNode/Sources/PeerAvatar.swift b/submodules/AvatarNode/Sources/PeerAvatar.swift index f9dee458bd..5419985f9f 100644 --- a/submodules/AvatarNode/Sources/PeerAvatar.swift +++ b/submodules/AvatarNode/Sources/PeerAvatar.swift @@ -64,15 +64,15 @@ public func peerAvatarImageData(account: Account, peerReference: PeerReference?, } } -public func peerAvatarImage(account: Account, peerReference: PeerReference?, authorOfMessage: MessageReference?, representation: TelegramMediaImageRepresentation?, displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0), round: Bool = true, inset: CGFloat = 0.0, emptyColor: UIColor? = nil, synchronousLoad: Bool = false) -> Signal? { +public func peerAvatarImage(account: Account, peerReference: PeerReference?, authorOfMessage: MessageReference?, representation: TelegramMediaImageRepresentation?, displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0), round: Bool = true, inset: CGFloat = 0.0, emptyColor: UIColor? = nil, synchronousLoad: Bool = false, provideUnrounded: Bool = false) -> Signal<(UIImage, UIImage)?, NoError>? { if let imageData = peerAvatarImageData(account: account, peerReference: peerReference, authorOfMessage: authorOfMessage, representation: representation, synchronousLoad: synchronousLoad) { return imageData - |> mapToSignal { data -> Signal in - let generate = deferred { () -> Signal in + |> mapToSignal { data -> Signal<(UIImage, UIImage)?, NoError> in + let generate = deferred { () -> Signal<(UIImage, UIImage)?, NoError> in if emptyColor == nil && data == nil { return .single(nil) } - return .single(generateImage(displayDimensions, contextGenerator: { size, context -> Void in + let roundedImage = generateImage(displayDimensions, contextGenerator: { size, context -> Void in if let data = data { if let imageSource = CGImageSourceCreateWithData(data as CFData, nil), let dataImage = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) { context.clear(CGRect(origin: CGPoint(), size: displayDimensions)) @@ -110,7 +110,41 @@ public func peerAvatarImage(account: Account, peerReference: PeerReference?, aut context.fill(CGRect(origin: CGPoint(), size: displayDimensions).insetBy(dx: inset, dy: inset)) } } - })) + }) + let unroundedImage: UIImage? + if provideUnrounded { + unroundedImage = generateImage(displayDimensions, contextGenerator: { size, context -> Void in + if let data = data { + if let imageSource = CGImageSourceCreateWithData(data as CFData, nil), let dataImage = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) { + context.clear(CGRect(origin: CGPoint(), size: displayDimensions)) + context.setBlendMode(.copy) + + context.draw(dataImage, in: CGRect(origin: CGPoint(), size: displayDimensions).insetBy(dx: inset, dy: inset)) + } else { + if let emptyColor = emptyColor { + context.clear(CGRect(origin: CGPoint(), size: displayDimensions)) + context.setFillColor(emptyColor.cgColor) + context.fill(CGRect(origin: CGPoint(), size: displayDimensions).insetBy(dx: inset, dy: inset)) + } + } + } else if let emptyColor = emptyColor { + context.clear(CGRect(origin: CGPoint(), size: displayDimensions)) + context.setFillColor(emptyColor.cgColor) + if round { + context.fillEllipse(in: CGRect(origin: CGPoint(), size: displayDimensions).insetBy(dx: inset, dy: inset)) + } else { + context.fill(CGRect(origin: CGPoint(), size: displayDimensions).insetBy(dx: inset, dy: inset)) + } + } + }) + } else { + unroundedImage = roundedImage + } + if let roundedImage = roundedImage, let unroundedImage = unroundedImage { + return .single((roundedImage, unroundedImage)) + } else { + return .single(nil) + } } if synchronousLoad { return generate diff --git a/submodules/Display/Display/InteractiveTransitionGestureRecognizer.swift b/submodules/Display/Display/InteractiveTransitionGestureRecognizer.swift index 25b3a4db81..507899560a 100644 --- a/submodules/Display/Display/InteractiveTransitionGestureRecognizer.swift +++ b/submodules/Display/Display/InteractiveTransitionGestureRecognizer.swift @@ -5,6 +5,9 @@ private func hasHorizontalGestures(_ view: UIView, point: CGPoint?) -> Bool { if view.disablesInteractiveTransitionGestureRecognizer { return true } + if let disablesInteractiveTransitionGestureRecognizerNow = view.disablesInteractiveTransitionGestureRecognizerNow, disablesInteractiveTransitionGestureRecognizerNow() { + return true + } if let point = point, let test = view.interactiveTransitionGestureRecognizerTest, test(point) { return true diff --git a/submodules/Display/Display/Navigation/NavigationContainer.swift b/submodules/Display/Display/Navigation/NavigationContainer.swift index fe79956916..282101e452 100644 --- a/submodules/Display/Display/Navigation/NavigationContainer.swift +++ b/submodules/Display/Display/Navigation/NavigationContainer.swift @@ -188,14 +188,14 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { bottomController.viewWillAppear(true) let bottomNode = bottomController.displayNode - let navigationTransitionCoordinator = NavigationTransitionCoordinator(transition: .Pop, container: self, topNode: topNode, topNavigationBar: topController.navigationBar, bottomNode: bottomNode, bottomNavigationBar: bottomController.navigationBar, didUpdateProgress: { [weak self] progress, transition, topFrame, bottomFrame in + let navigationTransitionCoordinator = NavigationTransitionCoordinator(transition: .Pop, isInteractive: true, container: self, topNode: topNode, topNavigationBar: topController.navigationBar, bottomNode: bottomNode, bottomNavigationBar: bottomController.navigationBar, didUpdateProgress: { [weak self, weak bottomController] progress, transition, topFrame, bottomFrame in if let strongSelf = self { if let top = strongSelf.state.top { strongSelf.syncKeyboard(leftEdge: top.value.displayNode.frame.minX, transition: transition) var updatedStatusBarStyle = strongSelf.statusBarStyle - if let childTransition = strongSelf.state.transition, childTransition.coordinator.progress >= 0.3 { - updatedStatusBarStyle = childTransition.previous.value.statusBar.statusBarStyle + if let bottomController = bottomController, progress >= 0.3 { + updatedStatusBarStyle = bottomController.statusBar.statusBarStyle } else { updatedStatusBarStyle = top.value.statusBar.statusBarStyle } @@ -355,8 +355,21 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { } } self.applyLayout(layout: updatedLayout, to: top, isMaster: true, transition: transition) - if let childTransition = self.state.transition, childTransition.coordinator.progress >= 0.3 { - updatedStatusBarStyle = childTransition.previous.value.statusBar.statusBarStyle + if let childTransition = self.state.transition, childTransition.coordinator.isInteractive { + switch childTransition.type { + case .push: + if childTransition.coordinator.progress >= 0.3 { + updatedStatusBarStyle = top.value.statusBar.statusBarStyle + } else { + updatedStatusBarStyle = childTransition.previous.value.statusBar.statusBarStyle + } + case .pop: + if childTransition.coordinator.progress >= 0.3 { + updatedStatusBarStyle = childTransition.previous.value.statusBar.statusBarStyle + } else { + updatedStatusBarStyle = top.value.statusBar.statusBarStyle + } + } } else { updatedStatusBarStyle = top.value.statusBar.statusBarStyle } @@ -399,7 +412,7 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate { } toValue.value.setIgnoreAppearanceMethodInvocations(false) - let topTransition = TopTransition(type: transitionType, previous: fromValue, coordinator: NavigationTransitionCoordinator(transition: mappedTransitionType, container: self, topNode: topController.displayNode, topNavigationBar: topController.navigationBar, bottomNode: bottomController.displayNode, bottomNavigationBar: bottomController.navigationBar, didUpdateProgress: { [weak self] _, transition, topFrame, bottomFrame in + let topTransition = TopTransition(type: transitionType, previous: fromValue, coordinator: NavigationTransitionCoordinator(transition: mappedTransitionType, isInteractive: false, container: self, topNode: topController.displayNode, topNavigationBar: topController.navigationBar, bottomNode: bottomController.displayNode, bottomNavigationBar: bottomController.navigationBar, didUpdateProgress: { [weak self] _, transition, topFrame, bottomFrame in guard let strongSelf = self else { return } diff --git a/submodules/Display/Display/NavigationBar.swift b/submodules/Display/Display/NavigationBar.swift index 2bd04661cd..ff66977045 100644 --- a/submodules/Display/Display/NavigationBar.swift +++ b/submodules/Display/Display/NavigationBar.swift @@ -112,7 +112,7 @@ open class NavigationBar: ASDisplayNode { public var backPressed: () -> () = { } public var userInfo: Any? - public var makeCustomTransitionNode: ((NavigationBar) -> CustomNavigationTransitionNode?)? + public var makeCustomTransitionNode: ((NavigationBar, Bool) -> CustomNavigationTransitionNode?)? private var collapsed: Bool { get { diff --git a/submodules/Display/Display/NavigationButtonNode.swift b/submodules/Display/Display/NavigationButtonNode.swift index b237e14361..a21f37823f 100644 --- a/submodules/Display/Display/NavigationButtonNode.swift +++ b/submodules/Display/Display/NavigationButtonNode.swift @@ -306,6 +306,13 @@ private final class NavigationButtonItemNode: ASTextNode { public final class NavigationButtonNode: ASDisplayNode { private var nodes: [NavigationButtonItemNode] = [] + public var singleCustomNode: ASDisplayNode? { + for node in self.nodes { + return node.node + } + return nil + } + public var pressed: (Int) -> () = { _ in } public var highlightChanged: (Int, Bool) -> () = { _, _ in } diff --git a/submodules/Display/Display/NavigationTransitionCoordinator.swift b/submodules/Display/Display/NavigationTransitionCoordinator.swift index f439a5bc64..48aec470c2 100644 --- a/submodules/Display/Display/NavigationTransitionCoordinator.swift +++ b/submodules/Display/Display/NavigationTransitionCoordinator.swift @@ -35,6 +35,7 @@ final class NavigationTransitionCoordinator { private let container: ASDisplayNode private let transition: NavigationTransition + let isInteractive: Bool let topNode: ASDisplayNode let bottomNode: ASDisplayNode private let topNavigationBar: NavigationBar? @@ -49,8 +50,9 @@ final class NavigationTransitionCoordinator { private var currentCompletion: (() -> Void)? private var didUpdateProgress: ((CGFloat, ContainedViewLayoutTransition, CGRect, CGRect) -> Void)? - init(transition: NavigationTransition, container: ASDisplayNode, topNode: ASDisplayNode, topNavigationBar: NavigationBar?, bottomNode: ASDisplayNode, bottomNavigationBar: NavigationBar?, didUpdateProgress: ((CGFloat, ContainedViewLayoutTransition, CGRect, CGRect) -> Void)? = nil) { + init(transition: NavigationTransition, isInteractive: Bool, container: ASDisplayNode, topNode: ASDisplayNode, topNavigationBar: NavigationBar?, bottomNode: ASDisplayNode, bottomNavigationBar: NavigationBar?, didUpdateProgress: ((CGFloat, ContainedViewLayoutTransition, CGRect, CGRect) -> Void)? = nil) { self.transition = transition + self.isInteractive = isInteractive self.container = container self.didUpdateProgress = didUpdateProgress self.topNode = topNode @@ -65,11 +67,11 @@ final class NavigationTransitionCoordinator { self.shadowNode.image = shadowImage if let topNavigationBar = topNavigationBar, let bottomNavigationBar = bottomNavigationBar { - if let customTransitionNode = topNavigationBar.makeCustomTransitionNode?(bottomNavigationBar) { + if let customTransitionNode = topNavigationBar.makeCustomTransitionNode?(bottomNavigationBar, isInteractive) { self.inlineNavigationBarTransition = false customTransitionNode.setup(topNavigationBar: topNavigationBar, bottomNavigationBar: bottomNavigationBar) self.customTransitionNode = customTransitionNode - } else if let customTransitionNode = bottomNavigationBar.makeCustomTransitionNode?(topNavigationBar) { + } else if let customTransitionNode = bottomNavigationBar.makeCustomTransitionNode?(topNavigationBar, isInteractive) { self.inlineNavigationBarTransition = false customTransitionNode.setup(topNavigationBar: topNavigationBar, bottomNavigationBar: bottomNavigationBar) self.customTransitionNode = customTransitionNode @@ -131,9 +133,16 @@ final class NavigationTransitionCoordinator { let topFrame = CGRect(origin: CGPoint(x: floorToScreenPixels(position * containerSize.width), y: 0.0), size: containerSize) let bottomFrame = CGRect(origin: CGPoint(x: ((position - 1.0) * containerSize.width * 0.3), y: 0.0), size: containerSize) + var canInvokeCompletion = false + var hadEarlyCompletion = false transition.updateFrame(node: self.topNode, frame: topFrame, completion: { _ in - completion() + if canInvokeCompletion { + completion() + } else { + hadEarlyCompletion = true + } }) + canInvokeCompletion = true transition.updateFrame(node: self.dimNode, frame: CGRect(origin: CGPoint(x: 0.0, y: dimInset), size: CGSize(width: max(0.0, topFrame.minX), height: self.container.bounds.size.height - dimInset))) transition.updateFrame(node: self.shadowNode, frame: CGRect(origin: CGPoint(x: self.dimNode.frame.maxX - shadowWidth, y: dimInset), size: CGSize(width: shadowWidth, height: containerSize.height - dimInset))) transition.updateAlpha(node: self.dimNode, alpha: (1.0 - position) * 0.15) @@ -149,6 +158,10 @@ final class NavigationTransitionCoordinator { } self.didUpdateProgress?(self.progress, transition, topFrame, bottomFrame) + + if hadEarlyCompletion { + completion() + } } private func updateNavigationBarTransition(transition: ContainedViewLayoutTransition) { diff --git a/submodules/Display/Display/TapLongTapOrDoubleTapGestureRecognizer.swift b/submodules/Display/Display/TapLongTapOrDoubleTapGestureRecognizer.swift index 62107686ed..35d1372542 100644 --- a/submodules/Display/Display/TapLongTapOrDoubleTapGestureRecognizer.swift +++ b/submodules/Display/Display/TapLongTapOrDoubleTapGestureRecognizer.swift @@ -68,6 +68,7 @@ public enum TapLongTapOrDoubleTapGestureRecognizerAction { case waitForSingleTap case waitForHold(timeout: Double, acceptTap: Bool) case fail + case keepWithSingleTap } public final class TapLongTapOrDoubleTapGestureRecognizer: UIGestureRecognizer, UIGestureRecognizerDelegate { @@ -206,6 +207,8 @@ public final class TapLongTapOrDoubleTapGestureRecognizer: UIGestureRecognizer, } switch tapAction { + case .keepWithSingleTap: + break case .waitForSingleTap, .waitForDoubleTap: self.timer?.invalidate() let timer = Timer(timeInterval: 0.3, target: TapLongTapOrDoubleTapGestureRecognizerTimerTarget(target: self), selector: #selector(TapLongTapOrDoubleTapGestureRecognizerTimerTarget.longTapEvent), userInfo: nil, repeats: false) @@ -284,7 +287,7 @@ public final class TapLongTapOrDoubleTapGestureRecognizer: UIGestureRecognizer, } switch tapAction { - case .waitForSingleTap: + case .waitForSingleTap, .keepWithSingleTap: if let (touchLocation, _) = self.touchLocationAndTimestamp { self.lastRecognizedGestureAndLocation = (.tap, touchLocation) } diff --git a/submodules/PhotoResources/Sources/PhotoResources.swift b/submodules/PhotoResources/Sources/PhotoResources.swift index f7e0f13037..5aa2304795 100644 --- a/submodules/PhotoResources/Sources/PhotoResources.swift +++ b/submodules/PhotoResources/Sources/PhotoResources.swift @@ -2020,10 +2020,10 @@ public func instantPageImageFile(account: Account, fileReference: FileMediaRefer } } -private func avatarGalleryPhotoDatas(account: Account, fileReference: FileMediaReference? = nil, representations: [ImageRepresentationWithReference], autoFetchFullSize: Bool = false) -> Signal, NoError> { +private func avatarGalleryPhotoDatas(account: Account, fileReference: FileMediaReference? = nil, representations: [ImageRepresentationWithReference], autoFetchFullSize: Bool = false, attemptSynchronously: Bool = false) -> Signal, NoError> { if let smallestRepresentation = smallestImageRepresentation(representations.map({ $0.representation })), let largestRepresentation = largestImageRepresentation(representations.map({ $0.representation })), let smallestIndex = representations.firstIndex(where: { $0.representation == smallestRepresentation }), let largestIndex = representations.firstIndex(where: { $0.representation == largestRepresentation }) { - let maybeFullSize = account.postbox.mediaBox.resourceData(largestRepresentation.resource) + let maybeFullSize = account.postbox.mediaBox.resourceData(largestRepresentation.resource, attemptSynchronously: attemptSynchronously) let signal = maybeFullSize |> take(1) @@ -2037,7 +2037,7 @@ private func avatarGalleryPhotoDatas(account: Account, fileReference: FileMediaR let thumbnail = Signal { subscriber in let fetchedDisposable = fetchedThumbnail.start() - let thumbnailDisposable = account.postbox.mediaBox.resourceData(smallestRepresentation.resource).start(next: { next in + let thumbnailDisposable = account.postbox.mediaBox.resourceData(smallestRepresentation.resource, attemptSynchronously: attemptSynchronously).start(next: { next in subscriber.putNext(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: [])) }, error: subscriber.putError, completed: subscriber.putCompletion) @@ -2052,7 +2052,7 @@ private func avatarGalleryPhotoDatas(account: Account, fileReference: FileMediaR if autoFetchFullSize { fullSizeData = Signal, NoError> { subscriber in let fetchedFullSizeDisposable = fetchedFullSize.start() - let fullSizeDisposable = account.postbox.mediaBox.resourceData(largestRepresentation.resource).start(next: { next in + let fullSizeDisposable = account.postbox.mediaBox.resourceData(largestRepresentation.resource, attemptSynchronously: attemptSynchronously).start(next: { next in subscriber.putNext(Tuple(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []), next.complete)) }, error: subscriber.putError, completed: subscriber.putCompletion) @@ -2082,8 +2082,8 @@ private func avatarGalleryPhotoDatas(account: Account, fileReference: FileMediaR } } -public func chatAvatarGalleryPhoto(account: Account, representations: [ImageRepresentationWithReference], autoFetchFullSize: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { - let signal = avatarGalleryPhotoDatas(account: account, representations: representations, autoFetchFullSize: autoFetchFullSize) +public func chatAvatarGalleryPhoto(account: Account, representations: [ImageRepresentationWithReference], autoFetchFullSize: Bool = false, attemptSynchronously: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { + let signal = avatarGalleryPhotoDatas(account: account, representations: representations, autoFetchFullSize: autoFetchFullSize, attemptSynchronously: attemptSynchronously) return signal |> map { value in diff --git a/submodules/SettingsUI/Sources/SettingsController.swift b/submodules/SettingsUI/Sources/SettingsController.swift index 280b6055f8..1a1e15ec0d 100644 --- a/submodules/SettingsUI/Sources/SettingsController.swift +++ b/submodules/SettingsUI/Sources/SettingsController.swift @@ -1476,7 +1476,8 @@ public func settingsController(context: AccountContext, accountManager: AccountM let inset: CGFloat = 3.0 if let signal = peerAvatarImage(account: primary.0, peerReference: PeerReference(primary.1), authorOfMessage: nil, representation: primary.1.profileImageRepresentations.first, displayDimensions: size, inset: 3.0, emptyColor: nil, synchronousLoad: false) { return signal - |> map { image -> (UIImage, UIImage)? in + |> map { imageVersions -> (UIImage, UIImage)? in + let image = imageVersions?.0 if let image = image, let selectedImage = generateImage(size, rotatedContext: { size, context in context.clear(CGRect(origin: CGPoint(), size: size)) context.translateBy(x: size.width / 2.0, y: size.height / 2.0) diff --git a/submodules/TelegramIntents/Sources/TelegramIntents.swift b/submodules/TelegramIntents/Sources/TelegramIntents.swift index 3cf79eb5d8..a06109c8d2 100644 --- a/submodules/TelegramIntents/Sources/TelegramIntents.swift +++ b/submodules/TelegramIntents/Sources/TelegramIntents.swift @@ -135,7 +135,8 @@ public func donateSendMessageIntent(account: Account, sharedContext: SharedAccou signals.append(.single((peer, subject, savedMessagesAvatar))) } else { let peerAndAvatar = (peerAvatarImage(account: account, peerReference: PeerReference(peer), authorOfMessage: nil, representation: peer.smallProfileImage, round: false) ?? .single(nil)) - |> map { avatarImage in + |> map { imageVersions -> (Peer, SendMessageIntentSubject, UIImage?) in + let avatarImage = imageVersions?.0 return (peer, subject, avatarImage) } signals.append(peerAndAvatar) diff --git a/submodules/TelegramUI/TelegramUI/ChatAvatarNavigationNode.swift b/submodules/TelegramUI/TelegramUI/ChatAvatarNavigationNode.swift index 4e63ec7863..1ba556629e 100644 --- a/submodules/TelegramUI/TelegramUI/ChatAvatarNavigationNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatAvatarNavigationNode.swift @@ -70,8 +70,8 @@ final class ChatAvatarNavigationNode: ASDisplayNode { strongSelf.contextAction?(strongSelf.containerNode, gesture) } - self.containerNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 37.0, height: 37.0)) - self.avatarNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 37.0, height: 37.0)) + /*self.containerNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 37.0, height: 37.0)) + self.avatarNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 37.0, height: 37.0))*/ } override func didLoad() { @@ -80,8 +80,8 @@ final class ChatAvatarNavigationNode: ASDisplayNode { (self.view as? ChatAvatarNavigationNodeView)?.targetNode = self (self.view as? ChatAvatarNavigationNodeView)?.chatController = self.chatController - let tapRecognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.avatarTapGesture(_:))) - self.avatarNode.view.addGestureRecognizer(tapRecognizer) + /*let tapRecognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.avatarTapGesture(_:))) + self.avatarNode.view.addGestureRecognizer(tapRecognizer)*/ } @objc private func avatarTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { @@ -106,7 +106,7 @@ final class ChatAvatarNavigationNode: ASDisplayNode { } func onLayout() { - /*let bounds = self.bounds + let bounds = self.bounds if self.bounds.size.height.isLessThanOrEqualTo(26.0) { if !self.avatarNode.bounds.size.equalTo(bounds.size) { self.avatarNode.font = smallFont @@ -119,6 +119,6 @@ final class ChatAvatarNavigationNode: ASDisplayNode { } self.containerNode.frame = bounds.offsetBy(dx: 10.0, dy: 1.0) self.avatarNode.frame = bounds - }*/ + } } } diff --git a/submodules/TelegramUI/TelegramUI/ChatController.swift b/submodules/TelegramUI/TelegramUI/ChatController.swift index b2fa3154bc..968e201390 100644 --- a/submodules/TelegramUI/TelegramUI/ChatController.swift +++ b/submodules/TelegramUI/TelegramUI/ChatController.swift @@ -307,6 +307,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G private var updateSlowmodeStatusTimerValue: Int32? private var isDismissed = false + + private var focusOnSearchAfterAppearance: Bool = false public override var customData: Any? { return self.chatLocation @@ -1869,46 +1871,72 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if case let .peer(peerId) = chatLocation, peerId != context.account.peerId, subject != .scheduledMessages { self.navigationBar?.userInfo = PeerInfoNavigationSourceTag(peerId: peerId) } - self.chatTitleView = ChatTitleView(account: self.context.account, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, displayAvatar: true) - if let avatarNode = self.chatTitleView?.avatarNode { - avatarNode.chatController = self - avatarNode.contextAction = { [weak self] node, gesture in - guard let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer, peer.smallProfileImage != nil else { - return + + self.chatTitleView = ChatTitleView(account: self.context.account, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder) + self.navigationItem.titleView = self.chatTitleView + self.chatTitleView?.pressed = { [weak self] in + if let strongSelf = self { + if strongSelf.chatLocation == .peer(strongSelf.context.account.peerId) { + strongSelf.effectiveNavigationController?.pushViewController(PeerMediaCollectionController(context: strongSelf.context, peerId: strongSelf.context.account.peerId)) + } else { + strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { + return $0.updatedTitlePanelContext { + if let index = $0.firstIndex(where: { + switch $0 { + case .chatInfo: + return true + default: + return false + } + }) { + var updatedContexts = $0 + updatedContexts.remove(at: index) + return updatedContexts + } else { + var updatedContexts = $0 + updatedContexts.append(.chatInfo) + return updatedContexts.sorted() + } + } + }) } - let galleryController = AvatarGalleryController(context: strongSelf.context, peer: peer, remoteEntries: nil, replaceRootController: { controller, ready in - }, synchronousLoad: true) - galleryController.setHintWillBePresentedInPreviewingContext(true) - - let items: [ContextMenuItem] = [ - .action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_LinkDialogOpen, icon: { _ in nil }, action: { _, f in - f(.dismissWithoutContent) - self?.navigationButtonAction(.openChatInfo(expandAvatar: false)) - })) - ] - let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: galleryController, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture) - strongSelf.presentInGlobalOverlay(contextController) - } - avatarNode.tapped = { [weak self] in - guard let strongSelf = self else { - return - } - var expandAvatar = false - if let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer, peer.smallProfileImage != nil { - expandAvatar = true - } - strongSelf.navigationButtonAction(.openChatInfo(expandAvatar: expandAvatar)) } } + + let chatInfoButtonItem: UIBarButtonItem + switch chatLocation { + case .peer: + let avatarNode = ChatAvatarNavigationNode() + avatarNode.chatController = self + avatarNode.contextAction = { [weak self] node, gesture in + guard let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer, peer.smallProfileImage != nil else { + return + } + let galleryController = AvatarGalleryController(context: strongSelf.context, peer: peer, remoteEntries: nil, replaceRootController: { controller, ready in + }, synchronousLoad: true) + galleryController.setHintWillBePresentedInPreviewingContext(true) + + let items: [ContextMenuItem] = [ + .action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_LinkDialogOpen, icon: { _ in nil }, action: { _, f in + f(.dismissWithoutContent) + self?.navigationButtonAction(.openChatInfo(expandAvatar: true)) + })) + ] + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: galleryController, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture) + strongSelf.presentInGlobalOverlay(contextController) + } + chatInfoButtonItem = UIBarButtonItem(customDisplayNode: avatarNode)! + } + chatInfoButtonItem.target = self + chatInfoButtonItem.action = #selector(self.rightNavigationButtonAction) + chatInfoButtonItem.accessibilityLabel = self.presentationData.strings.Conversation_Info + self.chatInfoNavigationButton = ChatNavigationButton(action: .openChatInfo(expandAvatar: true), buttonItem: chatInfoButtonItem) + self.navigationItem.titleView = self.chatTitleView self.chatTitleView?.pressed = { [weak self] in self?.navigationButtonAction(.openChatInfo(expandAvatar: false)) } - let buttonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationMoreIcon(presentationInterfaceState.theme), style: .plain, target: self, action: #selector(self.rightNavigationButtonAction)) - //buttonItem.accessibilityLabel = strings.Conversation_Search - chatInfoNavigationButton = ChatNavigationButton(action: .toggleInfoPanel, buttonItem: buttonItem) - self.updateChatPresentationInterfaceState(animated: false, interactive: false, { state in if let botStart = botStart, case .interactive = botStart.behavior { return state.updatedBotStartPayload(botStart.payload) @@ -1994,8 +2022,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } else { imageOverride = nil } - strongSelf.chatTitleView?.avatarNode?.avatarNode.setPeer(context: strongSelf.context, theme: strongSelf.presentationData.theme, peer: peer, overrideImage: imageOverride) - strongSelf.chatTitleView?.avatarNode?.contextActionIsEnabled = peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil && imageOverride == nil && peer.smallProfileImage != nil + (strongSelf.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.avatarNode.setPeer(context: strongSelf.context, theme: strongSelf.presentationData.theme, peer: peer, overrideImage: imageOverride) + (strongSelf.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.contextActionIsEnabled = peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil } if strongSelf.peerView === peerView && strongSelf.reportIrrelvantGeoNotice == peerReportNotice && strongSelf.hasScheduledMessages == hasScheduledMessages { @@ -4443,6 +4471,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } self.interfaceInteraction = interfaceInteraction + + if self.focusOnSearchAfterAppearance { + self.focusOnSearchAfterAppearance = false + self.interfaceInteraction?.beginMessageSearch(.everything, "") + } + self.chatDisplayNode.interfaceInteraction = interfaceInteraction self.context.sharedContext.mediaManager.galleryHiddenMediaManager.addTarget(self) @@ -4700,6 +4734,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G })]), in: .window(.root)) })) } + + if self.focusOnSearchAfterAppearance { + self.focusOnSearchAfterAppearance = false + if let searchNode = self.navigationBar?.contentNode as? ChatSearchNavigationContentNode { + searchNode.activate() + } + } } override public func viewWillDisappear(_ animated: Bool) { @@ -5081,8 +5122,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.leftNavigationButton = nil } - self.chatTitleView?.displayAvatar = updatedChatPresentationInterfaceState.interfaceState.selectionState == nil - if let button = rightNavigationButtonForChatInterfaceState(updatedChatPresentationInterfaceState, strings: updatedChatPresentationInterfaceState.strings, currentButton: self.rightNavigationButton, target: self, selector: #selector(self.rightNavigationButtonAction), chatInfoNavigationButton: self.chatInfoNavigationButton) { if self.rightNavigationButton != button { var animated = transition.isAnimated @@ -8456,6 +8495,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return nil } } + + func activateSearch() { + self.focusOnSearchAfterAppearance = true + self.interfaceInteraction?.beginMessageSearch(.everything, "") + } } private final class ContextControllerContentSourceImpl: ContextControllerContentSource { diff --git a/submodules/TelegramUI/TelegramUI/ChatMessagePollBubbleContentNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessagePollBubbleContentNode.swift index c1ba412885..8a812fe3e0 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessagePollBubbleContentNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessagePollBubbleContentNode.swift @@ -1628,10 +1628,11 @@ private final class MergedAvatarsNode: ASDisplayNode { if self.disposables[peer.peerId] == nil { if let signal = peerAvatarImage(account: context.account, peerReference: peerReference, authorOfMessage: nil, representation: representation, displayDimensions: CGSize(width: mergedImageSize, height: mergedImageSize), synchronousLoad: synchronousLoad) { let disposable = (signal - |> deliverOnMainQueue).start(next: { [weak self] image in + |> deliverOnMainQueue).start(next: { [weak self] imageVersions in guard let strongSelf = self else { return } + let image = imageVersions?.0 if let image = image { strongSelf.images[peer.peerId] = image strongSelf.setNeedsDisplay() diff --git a/submodules/TelegramUI/TelegramUI/ChatTitleView.swift b/submodules/TelegramUI/TelegramUI/ChatTitleView.swift index d399138c28..e429d1315e 100644 --- a/submodules/TelegramUI/TelegramUI/ChatTitleView.swift +++ b/submodules/TelegramUI/TelegramUI/ChatTitleView.swift @@ -101,8 +101,6 @@ final class ChatTitleView: UIView, NavigationBarTitleView { private let button: HighlightTrackingButtonNode - let avatarNode: ChatAvatarNavigationNode? - private var validLayout: (CGSize, CGRect)? private var titleLeftIcon: ChatTitleIcon = .none @@ -179,15 +177,6 @@ final class ChatTitleView: UIView, NavigationBarTitleView { var pressed: (() -> Void)? - var displayAvatar: Bool = true { - didSet { - if self.displayAvatar != oldValue { - self.avatarNode?.isHidden = !self.displayAvatar - self.setNeedsLayout() - } - } - } - var titleContent: ChatTitleContent? { didSet { if let titleContent = self.titleContent { @@ -480,7 +469,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { } } - init(account: Account, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, displayAvatar: Bool) { + init(account: Account, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder) { self.account = account self.theme = theme self.strings = strings @@ -511,11 +500,6 @@ final class ChatTitleView: UIView, NavigationBarTitleView { self.activityNode = ChatTitleActivityNode() self.button = HighlightTrackingButtonNode() - if displayAvatar { - self.avatarNode = ChatAvatarNavigationNode() - } else { - self.avatarNode = nil - } super.init(frame: CGRect()) @@ -526,7 +510,6 @@ final class ChatTitleView: UIView, NavigationBarTitleView { self.contentContainer.addSubnode(self.titleNode) self.contentContainer.addSubnode(self.activityNode) self.addSubnode(self.button) - self.avatarNode.flatMap(self.contentContainer.addSubnode) self.presenceManager = PeerPresenceStatusManager(update: { [weak self] in self?.updateStatus() @@ -541,16 +524,12 @@ final class ChatTitleView: UIView, NavigationBarTitleView { strongSelf.titleCredibilityIconNode.layer.removeAnimation(forKey: "opacity") strongSelf.titleNode.alpha = 0.4 strongSelf.activityNode.alpha = 0.4 - strongSelf.titleCredibilityIconNode.alpha = 0.4 } else { strongSelf.titleNode.alpha = 1.0 strongSelf.activityNode.alpha = 1.0 strongSelf.titleCredibilityIconNode.alpha = 1.0 strongSelf.titleNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) strongSelf.activityNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) - strongSelf.titleLeftIconNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) - strongSelf.titleRightIconNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) - strongSelf.titleCredibilityIconNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) } } } @@ -587,6 +566,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { let transition: ContainedViewLayoutTransition = .immediate + self.button.frame = clearBounds self.contentContainer.frame = clearBounds var leftIconWidth: CGFloat = 0.0 @@ -604,7 +584,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { if let image = self.titleCredibilityIconNode.image { if self.titleCredibilityIconNode.supernode == nil { - self.contentContainer.addSubnode(self.titleCredibilityIconNode) + self.titleNode.addSubnode(self.titleCredibilityIconNode) } credibilityIconWidth = image.size.width + 3.0 } else if self.titleCredibilityIconNode.supernode != nil { @@ -620,47 +600,67 @@ final class ChatTitleView: UIView, NavigationBarTitleView { self.titleRightIconNode.removeFromSupernode() } - var leftInset: CGFloat = 12.0 - if let avatarNode = self.avatarNode { - let avatarSize = CGSize(width: 37.0, height: 37.0) - let avatarFrame = CGRect(origin: CGPoint(x: leftInset + 10.0, y: floor((size.height - avatarSize.height) / 2.0)), size: avatarSize) - avatarNode.frame = avatarFrame - if self.displayAvatar { - leftInset += avatarSize.width + 10.0 + 8.0 - } - } - - self.button.frame = CGRect(origin: CGPoint(x: leftInset - 20.0, y: 0.0), size: CGSize(width: clearBounds.width - leftInset, height: size.height)) - let titleSideInset: CGFloat = 3.0 - var titleSize = self.titleNode.updateLayout(CGSize(width: clearBounds.width - leftIconWidth - credibilityIconWidth - rightIconWidth - titleSideInset * 2.0 - leftInset, height: size.height)) - titleSize.width += credibilityIconWidth - let activitySize = self.activityNode.updateLayout(clearBounds.size, alignment: .left) - let titleInfoSpacing: CGFloat = 0.0 - - var titleFrame: CGRect - - if activitySize.height.isZero { - titleFrame = CGRect(origin: CGPoint(x: leftInset + leftIconWidth, y: floor((size.height - titleSize.height) / 2.0)), size: titleSize) - self.titleNode.frame = titleFrame + if size.height > 40.0 { + var titleSize = self.titleNode.updateLayout(CGSize(width: clearBounds.width - leftIconWidth - credibilityIconWidth - rightIconWidth - titleSideInset * 2.0, height: size.height)) + titleSize.width += credibilityIconWidth + let activitySize = self.activityNode.updateLayout(clearBounds.size, alignment: .center) + let titleInfoSpacing: CGFloat = 0.0 + + var titleFrame: CGRect + + if activitySize.height.isZero { + titleFrame = CGRect(origin: CGPoint(x: floor((clearBounds.width - titleSize.width) / 2.0), y: floor((size.height - titleSize.height) / 2.0)), size: titleSize) + if titleFrame.size.width < size.width { + titleFrame.origin.x = -clearBounds.minX + floor((size.width - titleFrame.width) / 2.0) + } + self.titleNode.frame = titleFrame + } else { + let combinedHeight = titleSize.height + activitySize.height + titleInfoSpacing + + titleFrame = CGRect(origin: CGPoint(x: floor((clearBounds.width - titleSize.width) / 2.0), y: floor((size.height - combinedHeight) / 2.0)), size: titleSize) + if titleFrame.size.width < size.width { + titleFrame.origin.x = -clearBounds.minX + floor((size.width - titleFrame.width) / 2.0) + } + titleFrame.origin.x = max(titleFrame.origin.x, clearBounds.minX + leftIconWidth) + self.titleNode.frame = titleFrame + + var activityFrame = CGRect(origin: CGPoint(x: floor((clearBounds.width - activitySize.width) / 2.0), y: floor((size.height - combinedHeight) / 2.0) + titleSize.height + titleInfoSpacing), size: activitySize) + if activitySize.width < size.width { + activityFrame.origin.x = -clearBounds.minX + floor((size.width - activityFrame.width) / 2.0) + } + self.activityNode.frame = activityFrame + } + + if let image = self.titleLeftIconNode.image { + self.titleLeftIconNode.frame = CGRect(origin: CGPoint(x: -image.size.width - 3.0 - UIScreenPixel, y: 4.0), size: image.size) + } + if let image = self.titleCredibilityIconNode.image { + self.titleCredibilityIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.width - image.size.width - 1.0, y: 2.0), size: image.size) + } + if let image = self.titleRightIconNode.image { + self.titleRightIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.width + 3.0, y: 6.0), size: image.size) + } } else { - let combinedHeight = titleSize.height + activitySize.height + titleInfoSpacing + let titleSize = self.titleNode.updateLayout(CGSize(width: floor(clearBounds.width / 2.0 - leftIconWidth - credibilityIconWidth - rightIconWidth - titleSideInset * 2.0), height: size.height)) + let activitySize = self.activityNode.updateLayout(CGSize(width: floor(clearBounds.width / 2.0), height: size.height), alignment: .center) - titleFrame = CGRect(origin: CGPoint(x: leftInset + leftIconWidth, y: floor((size.height - combinedHeight) / 2.0)), size: titleSize) + let titleInfoSpacing: CGFloat = 8.0 + let combinedWidth = titleSize.width + leftIconWidth + credibilityIconWidth + rightIconWidth + activitySize.width + titleInfoSpacing + + let titleFrame = CGRect(origin: CGPoint(x: leftIconWidth + floor((clearBounds.width - combinedWidth) / 2.0), y: floor((size.height - titleSize.height) / 2.0)), size: titleSize) self.titleNode.frame = titleFrame + self.activityNode.frame = CGRect(origin: CGPoint(x: floor((clearBounds.width - combinedWidth) / 2.0 + titleSize.width + leftIconWidth + credibilityIconWidth + rightIconWidth + titleInfoSpacing), y: floor((size.height - activitySize.height) / 2.0)), size: activitySize) - var activityFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((size.height - combinedHeight) / 2.0) + titleSize.height + titleInfoSpacing), size: activitySize) - self.activityNode.frame = activityFrame - } - - if let image = self.titleLeftIconNode.image { - self.titleLeftIconNode.frame = CGRect(origin: CGPoint(x: -image.size.width - 3.0 - UIScreenPixel, y: 4.0), size: image.size) - } - if let image = self.titleCredibilityIconNode.image { - self.titleCredibilityIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.maxX - image.size.width - 1.0, y: titleFrame.minY + 2.0), size: image.size) - } - if let image = self.titleRightIconNode.image { - self.titleRightIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.width + 3.0, y: 6.0), size: image.size) + if let image = self.titleLeftIconNode.image { + self.titleLeftIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.minX, y: titleFrame.minY + 4.0), size: image.size) + } + if let image = self.titleCredibilityIconNode.image { + self.titleCredibilityIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.maxX - image.size.width - 1.0, y: titleFrame.minY + 6.0), size: image.size) + } + if let image = self.titleRightIconNode.image { + self.titleRightIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.maxX - image.size.width - 1.0, y: titleFrame.minY + 6.0), size: image.size) + } } } diff --git a/submodules/TelegramUI/TelegramUI/MultiScaleTextNode.swift b/submodules/TelegramUI/TelegramUI/MultiScaleTextNode.swift new file mode 100644 index 0000000000..9eec9f4aa9 --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/MultiScaleTextNode.swift @@ -0,0 +1,75 @@ +import Foundation +import UIKit +import AsyncDisplayKit +import Display + +private final class MultiScaleTextStateNode: ASDisplayNode { + let textNode: ImmediateTextNode + + var currentLayout: MultiScaleTextLayout? + + override init() { + self.textNode = ImmediateTextNode() + + super.init() + + self.addSubnode(self.textNode) + } +} + +final class MultiScaleTextState { + let attributedText: NSAttributedString + let constrainedSize: CGSize + + init(attributedText: NSAttributedString, constrainedSize: CGSize) { + self.attributedText = attributedText + self.constrainedSize = constrainedSize + } +} + +struct MultiScaleTextLayout { + var size: CGSize +} + +final class MultiScaleTextNode: ASDisplayNode { + private let stateNodes: [AnyHashable: MultiScaleTextStateNode] + + init(stateKeys: [AnyHashable]) { + self.stateNodes = Dictionary(stateKeys.map { ($0, MultiScaleTextStateNode()) }, uniquingKeysWith: { lhs, _ in lhs }) + + super.init() + + for (_, node) in self.stateNodes { + self.addSubnode(node) + } + } + + func updateLayout(states: [AnyHashable: MultiScaleTextState]) -> [AnyHashable: MultiScaleTextLayout] { + assert(Set(states.keys) == Set(self.stateNodes.keys)) + + var result: [AnyHashable: MultiScaleTextLayout] = [:] + for (key, state) in states { + if let node = self.stateNodes[key] { + node.textNode.attributedText = state.attributedText + let nodeSize = node.textNode.updateLayout(state.constrainedSize) + let nodeLayout = MultiScaleTextLayout(size: nodeSize) + node.currentLayout = nodeLayout + node.textNode.frame = CGRect(origin: CGPoint(x: -nodeSize.width / 2.0, y: -nodeSize.height / 2.0), size: nodeSize) + result[key] = nodeLayout + } + } + return result + } + + func update(stateFractions: [AnyHashable: CGFloat], transition: ContainedViewLayoutTransition) { + var fractionSum: CGFloat = 0.0 + for (_, fraction) in stateFractions { + fractionSum += fraction + } + for (key, fraction) in stateFractions { + if let node = self.stateNodes[key], let nodeLayout = node.currentLayout { + transition.updateAlpha(node: node, alpha: fraction / fractionSum) + } + } + } +} diff --git a/submodules/TelegramUI/TelegramUI/NavigateToChatController.swift b/submodules/TelegramUI/TelegramUI/NavigateToChatController.swift index 5b05789afd..9d7591e00c 100644 --- a/submodules/TelegramUI/TelegramUI/NavigateToChatController.swift +++ b/submodules/TelegramUI/TelegramUI/NavigateToChatController.swift @@ -33,6 +33,10 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam controller.scrollToEndOfHistory() let _ = params.navigationController.popToViewController(controller, animated: params.animated) params.completion() + } else if params.activateMessageSearch { + controller.activateSearch() + let _ = params.navigationController.popToViewController(controller, animated: params.animated) + params.completion() } else { let _ = params.navigationController.popToViewController(controller, animated: params.animated) params.completion() @@ -65,6 +69,9 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam controller = ChatControllerImpl(context: params.context, chatLocation: params.chatLocation, subject: params.subject, botStart: params.botStart) } controller.purposefulAction = params.purposefulAction + if params.activateMessageSearch { + controller.activateSearch() + } let resolvedKeepStack: Bool switch params.keepStack { case .default: diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenCommentItem.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenCommentItem.swift new file mode 100644 index 0000000000..19937b5c92 --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenCommentItem.swift @@ -0,0 +1,57 @@ +import AsyncDisplayKit +import Display +import TelegramPresentationData + +final class PeerInfoScreenCommentItem: PeerInfoScreenItem { + let id: AnyHashable + let text: String + + init(id: AnyHashable, text: String) { + self.id = id + self.text = text + } + + func node() -> PeerInfoScreenItemNode { + return PeerInfoScreenCommentItemNode() + } +} + +private final class PeerInfoScreenCommentItemNode: PeerInfoScreenItemNode { + private let textNode: ImmediateTextNode + + private var item: PeerInfoScreenCommentItem? + + override init() { + self.textNode = ImmediateTextNode() + self.textNode.displaysAsynchronously = false + self.textNode.isUserInteractionEnabled = false + + super.init() + + self.addSubnode(self.textNode) + } + + override func update(width: CGFloat, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + guard let item = item as? PeerInfoScreenCommentItem else { + return 10.0 + } + + self.item = item + + let sideInset: CGFloat = 16.0 + let verticalInset: CGFloat = 7.0 + + self.textNode.maximumNumberOfLines = 0 + self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(14.0), textColor: presentationData.theme.list.freeTextColor) + + let textSize = self.textNode.updateLayout(CGSize(width: width - sideInset * 2.0, height: .greatestFiniteMagnitude)) + + let textFrame = CGRect(origin: CGPoint(x: sideInset, y: verticalInset), size: textSize) + + let height = textSize.height + verticalInset * 2.0 + + transition.updateFrame(node: self.textNode, frame: textFrame) + + return height + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift index f374730a20..34e7e78ef9 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift @@ -372,6 +372,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro ) self.itemInteraction.selectedMessageIds = chatControllerInteraction.selectionState.flatMap { $0.selectedIds } + self.scrollNode.view.delaysContentTouches = false self.scrollNode.view.showsVerticalScrollIndicator = false if #available(iOS 11.0, *) { self.scrollNode.view.contentInsetAdjustmentBehavior = .never diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift index feb2c71926..a68b93dc2c 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift @@ -9,34 +9,47 @@ import PeerPresenceStatusManager import TelegramStringFormatting import TelegramPresentationData +enum PeerInfoUpdatingAvatar { + case none + case image(TelegramMediaImageRepresentation) +} + final class PeerInfoState { let isEditing: Bool - let isSearching: Bool let selectedMessageIds: Set? + let updatingAvatar: PeerInfoUpdatingAvatar? init( isEditing: Bool, - isSearching: Bool, - selectedMessageIds: Set? + selectedMessageIds: Set?, + updatingAvatar: PeerInfoUpdatingAvatar? ) { self.isEditing = isEditing - self.isSearching = isSearching self.selectedMessageIds = selectedMessageIds + self.updatingAvatar = updatingAvatar } func withIsEditing(_ isEditing: Bool) -> PeerInfoState { return PeerInfoState( isEditing: isEditing, - isSearching: self.isSearching, - selectedMessageIds: self.selectedMessageIds + selectedMessageIds: self.selectedMessageIds, + updatingAvatar: self.updatingAvatar ) } func withSelectedMessageIds(_ selectedMessageIds: Set?) -> PeerInfoState { return PeerInfoState( isEditing: self.isEditing, - isSearching: self.isSearching, - selectedMessageIds: selectedMessageIds + selectedMessageIds: selectedMessageIds, + updatingAvatar: self.updatingAvatar + ) + } + + func withUpdatingAvatar(_ updatingAvatar: PeerInfoUpdatingAvatar?) -> PeerInfoState { + return PeerInfoState( + isEditing: self.isEditing, + selectedMessageIds: self.selectedMessageIds, + updatingAvatar: updatingAvatar ) } } @@ -50,6 +63,7 @@ final class PeerInfoScreenData { let isContact: Bool let availablePanes: [PeerInfoPaneKey] let groupsInCommon: [Peer]? + let linkedDiscussionPeer: Peer? init( peer: Peer?, @@ -59,7 +73,8 @@ final class PeerInfoScreenData { globalNotificationSettings: GlobalNotificationSettings?, isContact: Bool, availablePanes: [PeerInfoPaneKey], - groupsInCommon: [Peer]? + groupsInCommon: [Peer]?, + linkedDiscussionPeer: Peer? ) { self.peer = peer self.cachedData = cachedData @@ -69,12 +84,21 @@ final class PeerInfoScreenData { self.isContact = isContact self.availablePanes = availablePanes self.groupsInCommon = groupsInCommon + self.linkedDiscussionPeer = linkedDiscussionPeer } } +enum PeerInfoScreenInputUserKind { + case user + case bot + case support +} + enum PeerInfoScreenInputData: Equatable { case none - case user(userId: PeerId, secretChatId: PeerId?, isBot: Bool) + case user(userId: PeerId, secretChatId: PeerId?, kind: PeerInfoScreenInputUserKind) + case channel + case group(isSupergroup: Bool) } func peerInfoAvailableMediaPanes(context: AccountContext, peerId: PeerId) -> Signal<[PeerInfoPaneKey], NoError> { @@ -82,7 +106,7 @@ func peerInfoAvailableMediaPanes(context: AccountContext, peerId: PeerId) -> Sig (.photoOrVideo, .media), (.file, .files), (.music, .music), - (.voiceOrInstantVideo, .voice), + //(.voiceOrInstantVideo, .voice), (.webPage, .links) ] return combineLatest(tags.map { tagAndKey -> Signal in @@ -127,9 +151,25 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen return .none } if let user = peer as? TelegramUser { - return .user(userId: user.id, secretChatId: nil, isBot: user.botInfo != nil) + let kind: PeerInfoScreenInputUserKind + if user.flags.contains(.isSupport) { + kind = .support + } else if user.botInfo != nil { + kind = .bot + } else { + kind = .user + } + return .user(userId: user.id, secretChatId: nil, kind: kind) + } else if let channel = peer as? TelegramChannel { + if case .group = channel.info { + return .group(isSupergroup: true) + } else { + return .channel + } + } else if let _ = peer as? TelegramGroup { + return .group(isSupergroup: false) } else { - preconditionFailure() + return .none } } |> distinctUntilChanged @@ -144,23 +184,26 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen globalNotificationSettings: nil, isContact: false, availablePanes: [], - groupsInCommon: nil + groupsInCommon: nil, + linkedDiscussionPeer: nil )) - case let .user(peerId, secretChatId, isBot): + case let .user(peerId, secretChatId, kind): let groupsInCommonSignal: Signal<[Peer]?, NoError> - if isBot { - groupsInCommonSignal = .single([]) - } else { + switch kind { + case .user: groupsInCommonSignal = .single(nil) |> then( groupsInCommon(account: context.account, peerId: peerId) |> map(Optional.init) ) + default: + groupsInCommonSignal = .single([]) } enum StatusInputData: Equatable { case none case presence(TelegramUserPresence) case bot + case support } let status = Signal { subscriber in class Manager { @@ -188,12 +231,12 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen if user.isDeleted { return .none } + if user.flags.contains(.isSupport) { + return .support + } if user.botInfo != nil { return .bot } - if user.flags.contains(.isSupport) { - return .none - } guard let presence = view.peerPresences[peerId] as? TelegramUserPresence else { return .none } @@ -203,6 +246,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen switch inputData { case .bot: subscriber.putNext(PeerInfoStatusData(text: strings.Bot_GenericBotStatus, isActivity: false)) + case .support: + subscriber.putNext(PeerInfoStatusData(text: strings.Bot_GenericSupportStatus, isActivity: false)) default: var presence: TelegramUserPresence? if case let .presence(value) = inputData { @@ -268,13 +313,124 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen globalNotificationSettings: globalNotificationSettings, isContact: peerView.peerIsContact, availablePanes: availablePanes, - groupsInCommon: groupsInCommon + groupsInCommon: groupsInCommon, + linkedDiscussionPeer: nil + ) + } + case .channel: + let status = context.account.viewTracker.peerView(peerId, updateData: false) + |> map { peerView -> PeerInfoStatusData? in + guard let channel = peerView.peers[peerId] as? TelegramChannel else { + return PeerInfoStatusData(text: strings.Channel_Status, isActivity: false) + } + if let cachedChannelData = peerView.cachedData as? CachedChannelData, let memberCount = cachedChannelData.participantsSummary.memberCount, memberCount != 0 { + return PeerInfoStatusData(text: strings.Conversation_StatusSubscribers(memberCount), isActivity: false) + } else { + return PeerInfoStatusData(text: strings.Channel_Status, isActivity: false) + } + } + |> distinctUntilChanged + + let globalNotificationsKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.globalNotifications])) + var combinedKeys: [PostboxViewKey] = [] + combinedKeys.append(globalNotificationsKey) + return combineLatest( + context.account.viewTracker.peerView(peerId, updateData: true), + peerInfoAvailableMediaPanes(context: context, peerId: peerId), + context.account.postbox.combinedView(keys: combinedKeys), + status + ) + |> map { peerView, availablePanes, combinedView, status -> PeerInfoScreenData in + var globalNotificationSettings: GlobalNotificationSettings = .defaultSettings + if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView { + if let settings = preferencesView.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings { + globalNotificationSettings = settings + } + } + + var discussionPeer: Peer? + if let linkedDiscussionPeerId = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] { + discussionPeer = peer + } + + return PeerInfoScreenData( + peer: peerView.peers[peerId], + cachedData: peerView.cachedData, + status: status, + notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings, + globalNotificationSettings: globalNotificationSettings, + isContact: peerView.peerIsContact, + availablePanes: availablePanes, + groupsInCommon: [], + linkedDiscussionPeer: discussionPeer + ) + } + case .group: + let status = context.account.viewTracker.peerView(peerId, updateData: false) + |> map { peerView -> PeerInfoStatusData? in + guard let channel = peerView.peers[peerId] as? TelegramChannel else { + return PeerInfoStatusData(text: strings.Channel_Status, isActivity: false) + } + if let cachedChannelData = peerView.cachedData as? CachedChannelData, let memberCount = cachedChannelData.participantsSummary.memberCount, memberCount != 0 { + return PeerInfoStatusData(text: strings.Conversation_StatusMembers(memberCount), isActivity: false) + } else { + return PeerInfoStatusData(text: strings.Group_Status, isActivity: false) + } + } + |> distinctUntilChanged + + let globalNotificationsKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.globalNotifications])) + var combinedKeys: [PostboxViewKey] = [] + combinedKeys.append(globalNotificationsKey) + return combineLatest( + context.account.viewTracker.peerView(peerId, updateData: true), + peerInfoAvailableMediaPanes(context: context, peerId: peerId), + context.account.postbox.combinedView(keys: combinedKeys), + status + ) + |> map { peerView, availablePanes, combinedView, status -> PeerInfoScreenData in + var globalNotificationSettings: GlobalNotificationSettings = .defaultSettings + if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView { + if let settings = preferencesView.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings { + globalNotificationSettings = settings + } + } + + return PeerInfoScreenData( + peer: peerView.peers[peerId], + cachedData: peerView.cachedData, + status: status, + notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings, + globalNotificationSettings: globalNotificationSettings, + isContact: peerView.peerIsContact, + availablePanes: availablePanes, + groupsInCommon: [], + linkedDiscussionPeer: nil ) } } } } +func canEditPeerInfo(peer: Peer?) -> Bool { + if let channel = peer as? TelegramChannel { + if channel.hasPermission(.changeInfo) { + return true + } + } else if let group = peer as? TelegramGroup { + switch group.role { + case .admin, .creator: + return true + case .member: + break + } + if !group.hasBannedPermission(.banChangeInfo) { + return true + } + } + return false +} + func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?) -> [PeerInfoHeaderButtonKey] { var result: [PeerInfoHeaderButtonKey] = [] if let user = peer as? TelegramUser { @@ -291,6 +447,62 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?) -> [PeerInf if !user.isDeleted, user.botInfo == nil && !user.flags.contains(.isSupport) { result.append(.more) } + } else if let channel = peer as? TelegramChannel { + var canEditGroupInfo = false + var canEditMembers = false + var canAddMembers = false + var isPublic = false + var isCreator = false + + isPublic = channel.username != nil + if !isPublic, let cachedChannelData = cachedData as? CachedChannelData, cachedChannelData.peerGeoLocation != nil { + isPublic = true + } + + isCreator = channel.flags.contains(.isCreator) + if channel.hasPermission(.changeInfo) { + canEditGroupInfo = true + } + if channel.hasPermission(.banMembers) { + canEditMembers = true + } + if channel.hasPermission(.inviteMembers) { + canAddMembers = true + } + + result.append(.mute) + result.append(.more) + } else if let group = peer as? TelegramGroup { + var canEditGroupInfo = false + var canEditMembers = false + var canAddMembers = false + var isPublic = false + var isCreator = false + + if case .creator = group.role { + isCreator = true + } + switch group.role { + case .admin, .creator: + canEditGroupInfo = true + canEditMembers = true + canAddMembers = true + case .member: + break + } + if !group.hasBannedPermission(.banChangeInfo) { + canEditGroupInfo = true + } + if !group.hasBannedPermission(.banAddMembers) { + canAddMembers = true + } + + if canAddMembers { + result.append(.addMember) + } + + result.append(.mute) + result.append(.more) } return result } @@ -301,6 +513,8 @@ func peerInfoCanEdit(peer: Peer?, cachedData: CachedPeerData?) -> Bool { return false } return true + } else if peer is TelegramChannel || peer is TelegramGroup { + return true } return false } diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift index b601a275e4..b44399c74e 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift @@ -12,6 +12,7 @@ import TelegramPresentationData import PhotoResources import PeerAvatarGalleryUI import TelegramStringFormatting +import ActivityIndicator enum PeerInfoHeaderButtonKey: Hashable { case message @@ -154,25 +155,19 @@ enum PeerInfoAvatarListItem: Equatable { } final class PeerInfoAvatarListItemNode: ASDisplayNode { + private let context: AccountContext let imageNode: TransformImageNode let isReady = Promise() private var didSetReady: Bool = false - init(context: AccountContext, item: PeerInfoAvatarListItem) { + init(context: AccountContext) { + self.context = context self.imageNode = TransformImageNode() super.init() self.addSubnode(self.imageNode) - let representations: [ImageRepresentationWithReference] - switch item { - case let .topImage(topRepresentations): - representations = topRepresentations - case let .image(_, imageRepresentations): - representations = imageRepresentations - } - self.imageNode.setSignal(chatAvatarGalleryPhoto(account: context.account, representations: representations, autoFetchFullSize: true), dispatchOnDisplayLink: false) self.imageNode.imageUpdated = { [weak self] _ in guard let strongSelf = self else { @@ -185,6 +180,17 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode { } } + func setup(item: PeerInfoAvatarListItem, synchronous: Bool) { + let representations: [ImageRepresentationWithReference] + switch item { + case let .topImage(topRepresentations): + representations = topRepresentations + case let .image(_, imageRepresentations): + representations = imageRepresentations + } + self.imageNode.setSignal(chatAvatarGalleryPhoto(account: self.context.account, representations: representations, autoFetchFullSize: true, attemptSynchronously: synchronous), attemptSynchronously: synchronous, dispatchOnDisplayLink: false) + } + func update(size: CGSize, transition: ContainedViewLayoutTransition) { let imageSize = CGSize(width: min(size.width, size.height), height: min(size.width, size.height)) let makeLayout = self.imageNode.asyncLayout() @@ -198,13 +204,23 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { private let context: AccountContext let controlsContainerNode: ASDisplayNode - let controlsContainerTransformNode: ASDisplayNode - let shadowNode: ASDisplayNode + let controlsClippingNode: ASDisplayNode + let controlsClippingOffsetNode: ASDisplayNode + let shadowNode: ASImageNode let contentNode: ASDisplayNode + let leftHighlightNode: ASImageNode + let rightHighlightNode: ASImageNode + var highlightedSide: Bool? + let stripContainerNode: ASDisplayNode + let highlightContainerNode: ASDisplayNode private(set) var galleryEntries: [AvatarGalleryEntry] = [] private var items: [PeerInfoAvatarListItem] = [] private var itemNodes: [WrappedMediaResourceId: PeerInfoAvatarListItemNode] = [:] + private var stripNodes: [ASImageNode] = [] + private let inactiveStripImage: UIImage + private let activeStripImage: UIImage + private var appliedStripNodeCurrentIndex: Int? private var currentIndex: Int = 0 private var transitionFraction: CGFloat = 0.0 @@ -229,14 +245,99 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { self.contentNode = ASDisplayNode() + self.leftHighlightNode = ASImageNode() + self.leftHighlightNode.displaysAsynchronously = false + self.leftHighlightNode.displayWithoutProcessing = true + self.leftHighlightNode.contentMode = .scaleToFill + self.leftHighlightNode.image = generateImage(CGSize(width: 88.0, height: 1.0), contextGenerator: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + + let topColor = UIColor(rgb: 0x000000, alpha: 0.5) + let bottomColor = UIColor(rgb: 0x000000, alpha: 0.0) + + var locations: [CGFloat] = [0.0, 1.0] + let colors: [CGColor] = [topColor.cgColor, bottomColor.cgColor] + + let colorSpace = CGColorSpaceCreateDeviceRGB() + let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)! + + context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: 0.0), options: [.drawsBeforeStartLocation, .drawsAfterEndLocation]) + }) + self.leftHighlightNode.isHidden = true + + self.rightHighlightNode = ASImageNode() + self.rightHighlightNode.displaysAsynchronously = false + self.rightHighlightNode.displayWithoutProcessing = true + self.rightHighlightNode.contentMode = .scaleToFill + self.rightHighlightNode.image = generateImage(CGSize(width: 88.0, height: 1.0), contextGenerator: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + + let topColor = UIColor(rgb: 0x000000, alpha: 0.5) + let bottomColor = UIColor(rgb: 0x000000, alpha: 0.0) + + var locations: [CGFloat] = [0.0, 1.0] + let colors: [CGColor] = [topColor.cgColor, bottomColor.cgColor] + + let colorSpace = CGColorSpaceCreateDeviceRGB() + let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)! + + context.drawLinearGradient(gradient, start: CGPoint(x: size.width, y: 0.0), end: CGPoint(x: 0.0, y: 0.0), options: [.drawsBeforeStartLocation, .drawsAfterEndLocation]) + }) + self.rightHighlightNode.isHidden = true + + self.stripContainerNode = ASDisplayNode() + self.contentNode.addSubnode(self.stripContainerNode) + self.inactiveStripImage = generateStretchableFilledCircleImage(diameter: 3.0, color: UIColor(white: 1.0, alpha: 0.2))! + self.activeStripImage = generateStretchableFilledCircleImage(diameter: 3.0, color: .white)! + + self.highlightContainerNode = ASDisplayNode() + self.highlightContainerNode.addSubnode(self.leftHighlightNode) + self.highlightContainerNode.addSubnode(self.rightHighlightNode) + self.controlsContainerNode = ASDisplayNode() self.controlsContainerNode.isUserInteractionEnabled = false - self.controlsContainerTransformNode = ASDisplayNode() - self.controlsContainerTransformNode.isUserInteractionEnabled = false + self.controlsClippingOffsetNode = ASDisplayNode() - self.shadowNode = ASDisplayNode() - //self.shadowNode.backgroundColor = .green + self.controlsClippingNode = ASDisplayNode() + self.controlsClippingNode.isUserInteractionEnabled = false + self.controlsClippingNode.clipsToBounds = true + + self.shadowNode = ASImageNode() + self.shadowNode.displaysAsynchronously = false + self.shadowNode.displayWithoutProcessing = true + self.shadowNode.contentMode = .scaleToFill + + do { + let size = CGSize(width: 88.0, height: 88.0) + UIGraphicsBeginImageContextWithOptions(size, false, 0.0) + if let context = UIGraphicsGetCurrentContext() { + context.clip(to: CGRect(origin: CGPoint(), size: size)) + + let topColor = UIColor(rgb: 0x000000, alpha: 0.4) + let bottomColor = UIColor(rgb: 0x000000, alpha: 0.0) + + var locations: [CGFloat] = [0.0, 1.0] + let colors: [CGColor] = [topColor.cgColor, bottomColor.cgColor] + + let colorSpace = CGColorSpaceCreateDeviceRGB() + let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)! + + context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: 0.0), options: [.drawsBeforeStartLocation, .drawsAfterEndLocation]) + + let image = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + if let image = image { + self.shadowNode.image = generateImage(image.size, contextGenerator: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + context.translateBy(x: size.width / 2.0, y: size.height / 2.0) + context.rotate(by: -CGFloat.pi / 2.0) + context.translateBy(x: -size.width / 2.0, y: -size.height / 2.0) + context.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: size)) + }) + } + } + } super.init() @@ -244,12 +345,52 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { self.addSubnode(self.contentNode) + self.controlsContainerNode.addSubnode(self.highlightContainerNode) self.controlsContainerNode.addSubnode(self.shadowNode) - self.controlsContainerTransformNode.addSubnode(self.controlsContainerNode) - self.addSubnode(self.controlsContainerTransformNode) + self.controlsContainerNode.addSubnode(self.stripContainerNode) + self.controlsClippingNode.addSubnode(self.controlsContainerNode) + self.controlsClippingOffsetNode.addSubnode(self.controlsClippingNode) - self.view.disablesInteractiveTransitionGestureRecognizer = true + self.view.disablesInteractiveTransitionGestureRecognizerNow = { [weak self] in + guard let strongSelf = self else { + return false + } + return strongSelf.currentIndex != 0 + } self.view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))) + + let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:))) + recognizer.tapActionAtPoint = { _ in + return .keepWithSingleTap + } + recognizer.highlight = { [weak self] point in + guard let strongSelf = self, let size = strongSelf.validLayout else { + return + } + var highlightedSide: Bool? + if let point = point { + if point.x < size.width * 1.0 / 5.0 { + if strongSelf.currentIndex != 0 { + highlightedSide = false + } + } else if point.x > size.width * 4.0 / 5.0 { + if strongSelf.currentIndex < strongSelf.items.count - 1 || strongSelf.items.count > 1 { + highlightedSide = true + } + } + } + if strongSelf.highlightedSide != highlightedSide { + strongSelf.highlightedSide = highlightedSide + if let highlightedSide = highlightedSide { + strongSelf.leftHighlightNode.isHidden = highlightedSide + strongSelf.rightHighlightNode.isHidden = !highlightedSide + } else { + strongSelf.leftHighlightNode.isHidden = true + strongSelf.rightHighlightNode.isHidden = true + } + } + } + self.view.addGestureRecognizer(recognizer) } deinit { @@ -267,6 +408,32 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { } } + @objc private func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { + switch recognizer.state { + case .ended: + if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation { + if let size = self.validLayout, case .tap = gesture { + if location.x < size.width * 1.0 / 5.0 { + if self.currentIndex != 0 { + self.currentIndex -= 1 + self.updateItems(size: size, transition: .immediate) + } + } else if location.x > size.width * 4.0 / 5.0 { + if self.currentIndex < self.items.count - 1 { + self.currentIndex += 1 + self.updateItems(size: size, transition: .immediate) + } else if self.items.count > 1 { + self.currentIndex = 0 + self.updateItems(size: size, transition: .immediate, synchronous: true) + } + } + } + } + default: + break + } + } + @objc private func panGesture(_ recognizer: UIPanGestureRecognizer) { switch recognizer.state { case .changed: @@ -309,6 +476,10 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { func update(size: CGSize, peer: Peer?, transition: ContainedViewLayoutTransition) { self.validLayout = size + + self.leftHighlightNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: floor(size.width * 1.0 / 5.0), height: size.height)) + self.rightHighlightNode.frame = CGRect(origin: CGPoint(x: size.width - floor(size.width * 1.0 / 5.0), y: 0.0), size: CGSize(width: floor(size.width * 1.0 / 5.0), height: size.height)) + if let peer = peer, !self.initializedList { self.initializedList = true self.disposable.set((fetchedAvatarGalleryEntries(account: self.context.account, peer: peer) @@ -341,7 +512,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { self.updateItems(size: size, transition: transition) } - private func updateItems(size: CGSize, transition: ContainedViewLayoutTransition) { + private func updateItems(size: CGSize, transition: ContainedViewLayoutTransition, synchronous: Bool = false) { var validIds: [WrappedMediaResourceId] = [] var addedItemNodesForAdditiveTransition: [PeerInfoAvatarListItemNode] = [] var additiveTransitionOffset: CGFloat = 0.0 @@ -354,7 +525,8 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { itemNode = current } else { wasAdded = true - itemNode = PeerInfoAvatarListItemNode(context: self.context, item: self.items[i]) + itemNode = PeerInfoAvatarListItemNode(context: self.context) + itemNode.setup(item: self.items[i], synchronous: synchronous && i == self.currentIndex) self.itemNodes[self.items[i].id] = itemNode self.contentNode.addSubnode(itemNode) } @@ -387,6 +559,52 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { } } + if self.stripNodes.count != self.items.count { + if self.stripNodes.count < self.items.count { + for _ in 0 ..< self.items.count - self.stripNodes.count { + let stripNode = ASImageNode() + stripNode.displaysAsynchronously = false + stripNode.displayWithoutProcessing = true + if stripNodes.count == self.currentIndex { + stripNode.image = self.activeStripImage + } else { + stripNode.image = self.inactiveStripImage + } + self.stripNodes.append(stripNode) + self.stripContainerNode.addSubnode(stripNode) + } + } else { + for i in (self.items.count ..< self.stripNodes.count).reversed() { + self.stripNodes[i].removeFromSupernode() + self.stripNodes.remove(at: i) + } + } + } + if self.appliedStripNodeCurrentIndex != self.currentIndex { + if let appliedStripNodeCurrentIndex = self.appliedStripNodeCurrentIndex { + if appliedStripNodeCurrentIndex >= 0 && appliedStripNodeCurrentIndex < self.stripNodes.count { + self.stripNodes[appliedStripNodeCurrentIndex].image = self.inactiveStripImage + } + } + self.appliedStripNodeCurrentIndex = self.currentIndex + if self.currentIndex >= 0 && self.currentIndex < self.stripNodes.count { + self.stripNodes[self.currentIndex].image = self.activeStripImage + } + } + let stripInset: CGFloat = 5.0 + let stripSpacing: CGFloat = 4.0 + let stripWidth: CGFloat = floor((size.width - stripInset * 2.0 - stripSpacing * CGFloat(self.stripNodes.count - 1)) / CGFloat(self.stripNodes.count)) + var stripX: CGFloat = stripInset + for i in 0 ..< self.stripNodes.count { + if i == 0 && self.stripNodes.count == 1 { + self.stripNodes[i].isHidden = true + } else { + self.stripNodes[i].isHidden = false + } + self.stripNodes[i].frame = CGRect(origin: CGPoint(x: stripX, y: 0.0), size: CGSize(width: stripWidth, height: 3.0)) + stripX += stripWidth + stripSpacing + } + if let item = self.items.first, let itemNode = self.itemNodes[item.id] { if !self.didSetReady { self.didSetReady = true @@ -429,7 +647,7 @@ final class PeerInfoAvatarTransformContainerNode: ASDisplayNode { if peer.isDeleted { overrideImage = .deletedIcon } - self.avatarNode.setPeer(context: self.context, theme: theme, peer: peer, overrideImage: overrideImage, synchronousLoad: self.isFirstAvatarLoading, displayDimensions: CGSize(width: 100.0, height: 100.0)) + self.avatarNode.setPeer(context: self.context, theme: theme, peer: peer, overrideImage: overrideImage, synchronousLoad: self.isFirstAvatarLoading, displayDimensions: CGSize(width: 100.0, height: 100.0), storeUnrounded: true) self.isFirstAvatarLoading = false } } @@ -439,6 +657,9 @@ final class PeerInfoEditingAvatarNode: ASDisplayNode { let context: AccountContext let avatarNode: AvatarNode + private let updatingAvatarOverlay: ASImageNode + private let activityIndicator: ActivityIndicator + var tapped: (() -> Void)? init(context: AccountContext) { @@ -446,10 +667,24 @@ final class PeerInfoEditingAvatarNode: ASDisplayNode { let avatarFont = avatarPlaceholderFont(size: floor(100.0 * 16.0 / 37.0)) self.avatarNode = AvatarNode(font: avatarFont) + self.updatingAvatarOverlay = ASImageNode() + self.updatingAvatarOverlay.displayWithoutProcessing = true + self.updatingAvatarOverlay.displaysAsynchronously = false + self.updatingAvatarOverlay.isHidden = true + + self.activityIndicator = ActivityIndicator(type: .custom(.white, 22.0, 1.0, false)) + self.activityIndicator.isHidden = true + super.init() self.addSubnode(self.avatarNode) self.avatarNode.frame = CGRect(origin: CGPoint(x: -50.0, y: -50.0), size: CGSize(width: 100.0, height: 100.0)) + self.updatingAvatarOverlay.frame = self.avatarNode.frame + let indicatorSize = self.activityIndicator.measure(CGSize(width: 100.0, height: 100.0)) + self.activityIndicator.frame = CGRect(origin: CGPoint(x: floorToScreenPixels(self.avatarNode.frame.midX - indicatorSize.width / 2.0), y: floorToScreenPixels(self.avatarNode.frame.midY - indicatorSize.height / 2.0)), size: indicatorSize) + + self.addSubnode(self.updatingAvatarOverlay) + self.addSubnode(self.activityIndicator) self.avatarNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))) } @@ -460,11 +695,42 @@ final class PeerInfoEditingAvatarNode: ASDisplayNode { } } - func update(peer: Peer?, theme: PresentationTheme) { + func update(peer: Peer?, updatingAvatar: PeerInfoUpdatingAvatar?, theme: PresentationTheme) { if let peer = peer { - self.avatarNode.setPeer(context: self.context, theme: theme, peer: peer, synchronousLoad: false, displayDimensions: CGSize(width: 100.0, height: 100.0)) + let overrideImage: AvatarNodeImageOverride? + if canEditPeerInfo(peer: peer) { + if let updatingAvatar = updatingAvatar { + switch updatingAvatar { + case let .image(representation): + overrideImage = .image(representation) + case .none: + overrideImage = .none + } + self.activityIndicator.isHidden = false + self.updatingAvatarOverlay.isHidden = false + if self.updatingAvatarOverlay.image == nil { + self.updatingAvatarOverlay.image = generateFilledCircleImage(diameter: 100.0, color: UIColor(white: 0.0, alpha: 0.4), backgroundColor: nil) + } + } else { + overrideImage = .editAvatarIcon + self.activityIndicator.isHidden = true + self.updatingAvatarOverlay.isHidden = true + } + } else { + overrideImage = nil + self.activityIndicator.isHidden = true + self.updatingAvatarOverlay.isHidden = true + } + self.avatarNode.setPeer(context: self.context, theme: theme, peer: peer, overrideImage: overrideImage, synchronousLoad: false, displayDimensions: CGSize(width: 100.0, height: 100.0)) } } + + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + if self.avatarNode.frame.contains(point) { + return self.avatarNode.view + } + return super.hitTest(point, with: event) + } } final class PeerInfoAvatarListNode: ASDisplayNode { @@ -534,7 +800,10 @@ final class PeerInfoAvatarListNode: ASDisplayNode { } func animateAvatarCollapse(transition: ContainedViewLayoutTransition) { - if let currentItemNode = self.listContainerNode.currentItemNode, let avatarCopyView = self.avatarContainerNode.avatarNode.view.snapshotContentTree(), case let .animated(duration, curve) = transition { + if let currentItemNode = self.listContainerNode.currentItemNode, let unroundedImage = self.avatarContainerNode.avatarNode.unroundedImage, case let .animated(duration, curve) = transition { + let avatarCopyView = UIImageView() + avatarCopyView.image = unroundedImage + avatarCopyView.frame = self.avatarContainerNode.avatarNode.frame avatarCopyView.center = currentItemNode.imageNode.position currentItemNode.view.addSubview(avatarCopyView) let scale = currentItemNode.imageNode.bounds.height / avatarCopyView.bounds.height @@ -854,7 +1123,7 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode { return self.itemNodes[key]?.text } - func update(width: CGFloat, safeInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, peer: Peer?, isContact: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) -> CGFloat { + func update(width: CGFloat, safeInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, peer: Peer?, cachedData: CachedPeerData?, isContact: Bool, presentationData: PresentationData, transition: ContainedViewLayoutTransition) -> CGFloat { let avatarSize: CGFloat = 100.0 let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 10.0), size: CGSize(width: avatarSize, height: avatarSize)) transition.updateFrameAdditiveToCenter(node: self.avatarNode, frame: CGRect(origin: avatarFrame.center, size: CGSize())) @@ -869,6 +1138,16 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode { fieldKeys.append(.lastName) } } + } else if let _ = peer as? TelegramGroup { + fieldKeys.append(.title) + if canEditPeerInfo(peer: peer) { + fieldKeys.append(.description) + } + } else if let _ = peer as? TelegramChannel { + fieldKeys.append(.title) + if canEditPeerInfo(peer: peer) { + fieldKeys.append(.description) + } } var hasPrevious = false for key in fieldKeys { @@ -883,9 +1162,15 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode { case .lastName: updateText = (peer as? TelegramUser)?.lastName ?? "" case .title: - updateText = (peer as? TelegramUser)?.debugDisplayTitle ?? "" + updateText = peer?.debugDisplayTitle ?? "" case .description: - break + if let cachedData = cachedData as? CachedChannelData { + updateText = cachedData.about ?? "" + } else if let cachedData = cachedData as? CachedGroupData { + updateText = cachedData.about ?? "" + } else { + updateText = "" + } } itemNode = PeerInfoHeaderSingleLineTextFieldNode() self.itemNodes[key] = itemNode @@ -902,8 +1187,10 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode { isEnabled = isContact case .title: placeholder = "Title" + isEnabled = canEditPeerInfo(peer: peer) case .description: placeholder = "Description" + isEnabled = canEditPeerInfo(peer: peer) } let itemHeight = itemNode.update(width: width, safeInset: safeInset, hasPrevious: hasPrevious, placeholder: placeholder, isEnabled: isEnabled, presentationData: presentationData, updateText: updateText) transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: itemHeight))) @@ -951,6 +1238,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { var performButtonAction: ((PeerInfoHeaderButtonKey) -> Void)? var requestAvatarExpansion: (([AvatarGalleryEntry], (ASDisplayNode, CGRect, () -> (UIView?, UIView?))) -> Void)? + var requestOpenAvatarForEditing: (() -> Void)? var navigationTransition: PeerInfoHeaderNavigationTransition? @@ -999,6 +1287,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.subtitleNodeContainer.addSubnode(self.subtitleNode) self.regularContentNode.addSubnode(self.subtitleNodeContainer) self.regularContentNode.addSubnode(self.avatarListNode) + self.regularContentNode.addSubnode(self.avatarListNode.listContainerNode.controlsClippingOffsetNode) self.addSubnode(self.regularContentNode) self.addSubnode(self.editingContentNode) self.addSubnode(self.navigationButtonContainer) @@ -1012,6 +1301,12 @@ final class PeerInfoHeaderNode: ASDisplayNode { return (avatarNode?.view.snapshotContentTree(unhide: true), nil) })) } + self.editingContentNode.avatarNode.tapped = { [weak self] in + guard let strongSelf = self else { + return + } + strongSelf.requestOpenAvatarForEditing?() + } } func updateAvatarIsHidden(_ isHidden: Bool) { @@ -1029,7 +1324,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.regularContentNode.alpha = state.isEditing ? 0.0 : 1.0 self.editingContentNode.alpha = state.isEditing ? 1.0 : 0.0 - let editingContentHeight = self.editingContentNode.update(width: width, safeInset: containerInset, statusBarHeight: statusBarHeight, navigationHeight: navigationHeight, peer: state.isEditing ? peer : nil, isContact: isContact, presentationData: presentationData, transition: transition) + let editingContentHeight = self.editingContentNode.update(width: width, safeInset: containerInset, statusBarHeight: statusBarHeight, navigationHeight: navigationHeight, peer: state.isEditing ? peer : nil, cachedData: cachedData, isContact: isContact, presentationData: presentationData, transition: transition) transition.updateFrame(node: self.editingContentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -contentOffset), size: CGSize(width: width, height: editingContentHeight))) var transitionSourceHeight: CGFloat = 0.0 @@ -1041,7 +1336,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.backgroundNode.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor self.expandedBackgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.backgroundColor - if let navigationTransition = self.navigationTransition, let sourceAvatarNode = navigationTransition.sourceTitleView.avatarNode?.avatarNode { + if let navigationTransition = self.navigationTransition, let sourceAvatarNode = (navigationTransition.sourceNavigationBar.rightButtonNode.singleCustomNode as? ChatAvatarNavigationNode)?.avatarNode { transitionSourceHeight = navigationTransition.sourceNavigationBar.bounds.height transitionFraction = navigationTransition.fraction transitionSourceAvatarFrame = sourceAvatarNode.view.convert(sourceAvatarNode.view.bounds, to: navigationTransition.sourceNavigationBar.view) @@ -1049,6 +1344,10 @@ final class PeerInfoHeaderNode: ASDisplayNode { transitionSourceSubtitleFrame = navigationTransition.sourceSubtitleFrame transition.updateAlpha(node: self.expandedBackgroundNode, alpha: transitionFraction) + + if self.isAvatarExpanded, case .animated = transition, transitionFraction == 1.0 { + self.avatarListNode.animateAvatarCollapse(transition: transition) + } } else { let backgroundTransitionFraction: CGFloat = max(0.0, min(1.0, contentOffset / (212.0))) transition.updateAlpha(node: self.expandedBackgroundNode, alpha: backgroundTransitionFraction) @@ -1139,10 +1438,13 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.avatarListNode.listContainerNode.isHidden = false if !transitionSourceAvatarFrame.width.isZero { transition.updateCornerRadius(node: self.avatarListNode.listContainerNode, cornerRadius: transitionFraction * transitionSourceAvatarFrame.width / 2.0) + transition.updateCornerRadius(node: self.avatarListNode.listContainerNode.controlsClippingNode, cornerRadius: transitionFraction * transitionSourceAvatarFrame.width / 2.0) } else { transition.updateCornerRadius(node: self.avatarListNode.listContainerNode, cornerRadius: 0.0) + transition.updateCornerRadius(node: self.avatarListNode.listContainerNode.controlsClippingNode, cornerRadius: 0.0) } } else if self.avatarListNode.listContainerNode.cornerRadius != 50.0 { + transition.updateCornerRadius(node: self.avatarListNode.listContainerNode.controlsClippingNode, cornerRadius: 50.0) transition.updateCornerRadius(node: self.avatarListNode.listContainerNode, cornerRadius: 50.0, completion: { [weak self] _ in guard let strongSelf = self else { return @@ -1152,18 +1454,26 @@ final class PeerInfoHeaderNode: ASDisplayNode { } self.avatarListNode.update(size: CGSize(), isExpanded: self.isAvatarExpanded, peer: peer, theme: presentationData.theme, transition: transition) - self.editingContentNode.avatarNode.update(peer: peer, theme: presentationData.theme) + self.editingContentNode.avatarNode.update(peer: peer, updatingAvatar: state.updatingAvatar, theme: presentationData.theme) if additive { transition.updateSublayerTransformScaleAdditive(node: self.avatarListNode.avatarContainerNode, scale: avatarScale) } else { transition.updateSublayerTransformScale(node: self.avatarListNode.avatarContainerNode, scale: avatarScale) } let apparentAvatarFrame: CGRect + let controlsClippingFrame: CGRect if self.isAvatarExpanded { let expandedAvatarCenter = CGPoint(x: expandedAvatarListSize.width / 2.0, y: expandedAvatarListSize.height / 2.0 - contentOffset / 2.0) apparentAvatarFrame = CGRect(origin: CGPoint(x: expandedAvatarCenter.x * (1.0 - transitionFraction) + transitionFraction * avatarCenter.x, y: expandedAvatarCenter.y * (1.0 - transitionFraction) + transitionFraction * avatarCenter.y), size: CGSize()) + if !transitionSourceAvatarFrame.width.isZero { + let expandedFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: expandedAvatarListSize) + controlsClippingFrame = CGRect(origin: CGPoint(x: transitionFraction * transitionSourceAvatarFrame.minX + (1.0 - transitionFraction) * expandedFrame.minX, y: transitionFraction * transitionSourceAvatarFrame.minY + (1.0 - transitionFraction) * expandedFrame.minY), size: CGSize(width: transitionFraction * transitionSourceAvatarFrame.width + (1.0 - transitionFraction) * expandedFrame.width, height: transitionFraction * transitionSourceAvatarFrame.height + (1.0 - transitionFraction) * expandedFrame.height)) + } else { + controlsClippingFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: expandedAvatarListSize) + } } else { apparentAvatarFrame = CGRect(origin: CGPoint(x: avatarCenter.x - avatarFrame.width / 2.0, y: -contentOffset + avatarOffset + avatarCenter.y - avatarFrame.height / 2.0), size: avatarFrame.size) + controlsClippingFrame = apparentAvatarFrame } if case let .animated(duration, curve) = transition, !transitionSourceAvatarFrame.width.isZero, false { let previousFrame = self.avatarListNode.frame @@ -1205,10 +1515,14 @@ final class PeerInfoHeaderNode: ASDisplayNode { transition.updateSublayerTransformScale(node: self.avatarListNode.listContainerNode, scale: innerScale) transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.contentNode, frame: CGRect(origin: CGPoint(x: innerDeltaX + expandedAvatarListSize.width / 2.0, y: innerDeltaY + expandedAvatarListSize.height / 2.0), size: CGSize())) - transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.controlsContainerTransformNode, frame: CGRect(origin: CGPoint(x: expandedAvatarListSize.width / 2.0, y: expandedAvatarListSize.height / 2.0 - innerDeltaY), size: CGSize())) - transition.updateSublayerTransformScale(node: self.avatarListNode.listContainerNode.controlsContainerNode, scale: 1.0 / innerScale) - transition.updateSublayerTransformScaleAdditive(node: self.avatarListNode.listContainerNode.controlsContainerTransformNode, scale: 1.0 / avatarListContainerScale) - transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.shadowNode, frame: CGRect(origin: CGPoint(x: -apparentAvatarFrame.minX, y: -apparentAvatarFrame.minY), size: CGSize(width: expandedAvatarListSize.width, height: navigationHeight))) + transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.controlsClippingOffsetNode, frame: CGRect(origin: controlsClippingFrame.center, size: CGSize())) + transition.updateFrame(node: self.avatarListNode.listContainerNode.controlsClippingNode, frame: CGRect(origin: CGPoint(x: -controlsClippingFrame.width / 2.0, y: -controlsClippingFrame.height / 2.0), size: controlsClippingFrame.size)) + transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.controlsContainerNode, frame: CGRect(origin: CGPoint(x: -controlsClippingFrame.minX, y: -controlsClippingFrame.minY), size: CGSize(width: expandedAvatarListSize.width, height: expandedAvatarListSize.height))) + + transition.updateFrame(node: self.avatarListNode.listContainerNode.shadowNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: expandedAvatarListSize.width, height: navigationHeight + 20.0))) + transition.updateFrame(node: self.avatarListNode.listContainerNode.stripContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: statusBarHeight + 2.0), size: CGSize(width: expandedAvatarListSize.width, height: 3.0))) + transition.updateFrame(node: self.avatarListNode.listContainerNode.highlightContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: expandedAvatarListSize.width, height: expandedAvatarListSize.height))) + transition.updateAlpha(node: self.avatarListNode.listContainerNode.controlsContainerNode, alpha: self.isAvatarExpanded ? (1.0 - transitionFraction) : 0.0) if additive { transition.updateSublayerTransformScaleAdditive(node: self.avatarListNode.listContainerTransformNode, scale: avatarListContainerScale) @@ -1247,16 +1561,16 @@ final class PeerInfoHeaderNode: ASDisplayNode { let titleScale = (transitionFraction * transitionSourceTitleFrame.height + (1.0 - transitionFraction) * titleFrame.height * neutralTitleScale) / (titleFrame.height) let subtitleScale = max(0.01, min(10.0, (transitionFraction * transitionSourceSubtitleFrame.height + (1.0 - transitionFraction) * subtitleFrame.height * neutralSubtitleScale) / (subtitleFrame.height))) - let titleOrigin = CGPoint(x: transitionFraction * transitionSourceTitleFrame.minX + (1.0 - transitionFraction) * titleFrame.minX, y: transitionFraction * transitionSourceTitleFrame.minY + (1.0 - transitionFraction) * titleFrame.minY) - let subtitleOrigin = CGPoint(x: transitionFraction * transitionSourceSubtitleFrame.minX + (1.0 - transitionFraction) * subtitleFrame.minX, y: transitionFraction * transitionSourceSubtitleFrame.minY + (1.0 - transitionFraction) * subtitleFrame.minY) + let titleCenter = CGPoint(x: transitionFraction * transitionSourceTitleFrame.midX + (1.0 - transitionFraction) * titleFrame.midX, y: transitionFraction * transitionSourceTitleFrame.midY + (1.0 - transitionFraction) * titleFrame.midY) + let subtitleCenter = CGPoint(x: transitionFraction * transitionSourceSubtitleFrame.midX + (1.0 - transitionFraction) * subtitleFrame.midX, y: transitionFraction * transitionSourceSubtitleFrame.midY + (1.0 - transitionFraction) * subtitleFrame.midY) - let rawTitleFrame = CGRect(origin: titleOrigin, size: titleFrame.size) + let rawTitleFrame = CGRect(origin: CGPoint(x: titleCenter.x - titleFrame.size.width * titleScale / 2.0, y: titleCenter.y - titleFrame.size.height * titleScale / 2.0), size: CGSize(width: titleFrame.size.width * titleScale, height: titleFrame.size.height * titleScale)) self.titleNodeRawContainer.frame = rawTitleFrame - transition.updateFrameAdditiveToCenter(node: self.titleNodeContainer, frame: rawTitleFrame.offsetBy(dx: rawTitleFrame.width * 0.5 * (titleScale - 1.0), dy: titleOffset + rawTitleFrame.height * 0.5 * (titleScale - 1.0))) - transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(), size: titleFrame.size)) - let rawSubtitleFrame = CGRect(origin: subtitleOrigin, size: subtitleFrame.size) + transition.updateFrameAdditiveToCenter(node: self.titleNodeContainer, frame: CGRect(origin: rawTitleFrame.center, size: CGSize())) + transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: -titleFrame.size.width * 1.0 / titleScale / 2.0, y: -titleFrame.size.height * 1.0 / titleScale / 2.0), size: titleFrame.size)) + let rawSubtitleFrame = CGRect(origin: CGPoint(x: subtitleCenter.x - subtitleFrame.size.width / 2.0, y: subtitleCenter.y - subtitleFrame.size.height / 2.0), size: subtitleFrame.size) self.subtitleNodeRawContainer.frame = rawSubtitleFrame - transition.updateFrameAdditiveToCenter(node: self.subtitleNodeContainer, frame: rawSubtitleFrame.offsetBy(dx: rawSubtitleFrame.width * 0.5 * (subtitleScale - 1.0), dy: titleOffset + rawSubtitleFrame.height * 0.5 * (subtitleScale - 1.0))) + transition.updateFrameAdditiveToCenter(node: self.subtitleNodeContainer, frame: rawSubtitleFrame) transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(), size: subtitleFrame.size)) transition.updateSublayerTransformScale(node: self.titleNodeContainer, scale: titleScale) transition.updateSublayerTransformScale(node: self.subtitleNodeContainer, scale: subtitleScale) diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift index 976036603b..4efc5d5bcd 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift @@ -128,7 +128,12 @@ final class PeerInfoPaneTabsContainerNode: ASDisplayNode { super.init() - self.scrollNode.view.disablesInteractiveTransitionGestureRecognizer = true + self.scrollNode.view.disablesInteractiveTransitionGestureRecognizerNow = { [weak self] in + guard let strongSelf = self else { + return false + } + return strongSelf.scrollNode.view.contentOffset.x > .ulpOfOne + } self.scrollNode.view.showsHorizontalScrollIndicator = false self.scrollNode.view.scrollsToTop = false if #available(iOS 11.0, *) { @@ -249,7 +254,7 @@ final class PeerInfoPaneTabsContainerNode: ASDisplayNode { } leftOffset += paneNodeSize.width + spacing } - self.scrollNode.view.contentSize = CGSize(width: leftOffset + sideInset, height: size.height) + self.scrollNode.view.contentSize = CGSize(width: leftOffset - spacing + sideInset, height: size.height) } if let selectedFrame = selectedFrame { diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift index 26aa03313d..5466014007 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift @@ -28,6 +28,10 @@ import ContextUI import OpenInExternalAppUI import SafariServices import GalleryUI +import LegacyUI +import MapResourceToAvatarSizes +import LegacyComponents +import WebSearchUI protocol PeerInfoScreenItem: class { var id: AnyHashable { get } @@ -77,6 +81,7 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor var contentHeight: CGFloat = 0.0 + var contentWithBackgroundHeight: CGFloat = 0.0 for i in 0 ..< items.count { let item = items[i] @@ -100,13 +105,28 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { let itemTransition: ContainedViewLayoutTransition = wasAdded ? .immediate : transition - let itemHeight = itemNode.update(width: width, presentationData: presentationData, item: item, topItem: i == 0 ? nil : items[i - 1], bottomItem: (i == items.count - 1) ? nil : items[i + 1], transition: itemTransition) + let bottomItem: PeerInfoScreenItem? + if i == items.count - 1 { + bottomItem = nil + } else if items[i + 1] is PeerInfoScreenCommentItem { + bottomItem = nil + } else { + bottomItem = items[i + 1] + } + + let itemHeight = itemNode.update(width: width, presentationData: presentationData, item: item, topItem: i == 0 ? nil : items[i - 1], bottomItem: bottomItem, transition: itemTransition) let itemFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: itemHeight)) itemTransition.updateFrame(node: itemNode, frame: itemFrame) if wasAdded { itemNode.alpha = 0.0 transition.updateAlpha(node: itemNode, alpha: 1.0) } + + if item is PeerInfoScreenCommentItem { + + } else { + contentWithBackgroundHeight += itemHeight + } contentHeight += itemHeight } @@ -124,9 +144,9 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { } } - transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: contentHeight))) + transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: contentWithBackgroundHeight))) transition.updateFrame(node: self.topSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel))) - transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: UIScreenPixel))) + transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentWithBackgroundHeight), size: CGSize(width: width, height: UIScreenPixel))) if contentHeight.isZero { transition.updateAlpha(node: self.topSeparatorNode, alpha: 0.0) @@ -280,6 +300,12 @@ private enum PeerInfoBotCommand { case privacy } +private enum PeerInfoParticipantsSection { + case members + case admins + case banned +} + private final class PeerInfoInteraction { let openUsername: (String) -> Void let openPhone: (String) -> Void @@ -293,6 +319,10 @@ private final class PeerInfoInteraction { let openShareBot: () -> Void let openAddBotToGroup: () -> Void let performBotCommand: (PeerInfoBotCommand) -> Void + let editingOpenPublicLinkSetup: () -> Void + let editingOpenDiscussionGroupSetup: () -> Void + let editingToggleMessageSignatures: (Bool) -> Void + let openParticipantsSection: (PeerInfoParticipantsSection) -> Void init( openUsername: @escaping (String) -> Void, @@ -306,7 +336,11 @@ private final class PeerInfoInteraction { openReport: @escaping () -> Void, openShareBot: @escaping () -> Void, openAddBotToGroup: @escaping () -> Void, - performBotCommand: @escaping (PeerInfoBotCommand) -> Void + performBotCommand: @escaping (PeerInfoBotCommand) -> Void, + editingOpenPublicLinkSetup: @escaping () -> Void, + editingOpenDiscussionGroupSetup: @escaping () -> Void, + editingToggleMessageSignatures: @escaping (Bool) -> Void, + openParticipantsSection: @escaping (PeerInfoParticipantsSection) -> Void ) { self.openUsername = openUsername self.openPhone = openPhone @@ -320,6 +354,10 @@ private final class PeerInfoInteraction { self.openShareBot = openShareBot self.openAddBotToGroup = openAddBotToGroup self.performBotCommand = performBotCommand + self.editingOpenPublicLinkSetup = editingOpenPublicLinkSetup + self.editingOpenDiscussionGroupSetup = editingOpenDiscussionGroupSetup + self.editingToggleMessageSignatures = editingToggleMessageSignatures + self.openParticipantsSection = openParticipantsSection } } @@ -341,38 +379,11 @@ private func peerInfoSectionItems(data: PeerInfoScreenData?, presentationData: P } if let cachedData = data.cachedData as? CachedUserData { if let about = cachedData.about { - items.append(PeerInfoScreenLabeledValueItem(id: 0, label: "bio", text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) + items.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) } } if !data.isContact { - if let botInfo = user.botInfo { - if botInfo.flags.contains(.worksWithGroups) { - items.append(PeerInfoScreenActionItem(id: 6, text: presentationData.strings.UserInfo_InviteBotToGroup, action: { - interaction.openAddBotToGroup() - })) - } - items.append(PeerInfoScreenActionItem(id: 7, text: presentationData.strings.UserInfo_ShareBot, action: { - interaction.openShareBot() - })) - - if let cachedData = data.cachedData as? CachedUserData, let botInfo = cachedData.botInfo { - for command in botInfo.commands { - if command.text == "settings" { - items.append(PeerInfoScreenActionItem(id: 8, text: presentationData.strings.UserInfo_BotSettings, action: { - interaction.performBotCommand(.settings) - })) - } else if command.text == "help" { - items.append(PeerInfoScreenActionItem(id: 9, text: presentationData.strings.UserInfo_BotHelp, action: { - interaction.performBotCommand(.help) - })) - } else if command.text == "privacy" { - items.append(PeerInfoScreenActionItem(id: 10, text: presentationData.strings.UserInfo_BotPrivacy, action: { - interaction.performBotCommand(.privacy) - })) - } - } - } - } else { + if user.botInfo == nil { items.append(PeerInfoScreenActionItem(id: 3, text: "Add Contact", action: { interaction.openAddContact() })) @@ -397,6 +408,54 @@ private func peerInfoSectionItems(data: PeerInfoScreenData?, presentationData: P })) } } + } else if let channel = data.peer as? TelegramChannel { + let ItemUsername = 1 + let ItemAbout = 2 + let ItemAdmins = 3 + let ItemMembers = 4 + let ItemBanned = 5 + let ItemReport = 6 + + if let username = channel.username { + items.append(PeerInfoScreenLabeledValueItem(id: ItemUsername, label: presentationData.strings.Channel_LinkItem, text: "https://t.me/\(username)", textColor: .accent, action: { + interaction.openUsername(username) + })) + } + if let cachedData = data.cachedData as? CachedChannelData { + if let about = cachedData.about { + items.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Profile_About, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) + } + + if case .broadcast = channel.info { + var canEditMembers = false + if channel.hasPermission(.banMembers) { + canEditMembers = true + } + if canEditMembers { + if channel.adminRights != nil || channel.flags.contains(.isCreator) { + let adminCount = cachedData.participantsSummary.adminCount ?? 0 + let memberCount = cachedData.participantsSummary.memberCount ?? 0 + let bannedCount = cachedData.participantsSummary.kickedCount ?? 0 + + items.append(PeerInfoScreenDisclosureItem(id: ItemAdmins, label: "\(adminCount == 0 ? "" : "\(presentationStringsFormattedNumber(adminCount, presentationData.dateTimeFormat.groupingSeparator))")", text: presentationData.strings.GroupInfo_Administrators, action: { + interaction.openParticipantsSection(.admins) + })) + items.append(PeerInfoScreenDisclosureItem(id: ItemMembers, label: "\(memberCount == 0 ? "" : "\(presentationStringsFormattedNumber(memberCount, presentationData.dateTimeFormat.groupingSeparator))")", text: presentationData.strings.Channel_Info_Subscribers, action: { + interaction.openParticipantsSection(.members) + })) + items.append(PeerInfoScreenDisclosureItem(id: ItemBanned, label: "\(bannedCount == 0 ? "" : "\(presentationStringsFormattedNumber(bannedCount, presentationData.dateTimeFormat.groupingSeparator))")", text: presentationData.strings.GroupInfo_Permissions_Removed, action: { + interaction.openParticipantsSection(.banned) + })) + } + } + } + } + } else if let group = data.peer as? TelegramGroup { + if let cachedData = data.cachedData as? CachedGroupData { + if let about = cachedData.about { + items.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) + } + } } return items } @@ -407,34 +466,32 @@ private func editingInfoSectionItems(data: PeerInfoScreenData?, presentationData } var items: [PeerInfoScreenItem] = [] - if let _ = data.peer as? TelegramUser { - if let notificationSettings = data.notificationSettings { - let notificationsLabel: String - let soundLabel: String - let notificationSettings = notificationSettings as? TelegramPeerNotificationSettings ?? TelegramPeerNotificationSettings.defaultSettings - if case let .muted(until) = notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) { - if until < Int32.max - 1 { - notificationsLabel = stringForRemainingMuteInterval(strings: presentationData.strings, muteInterval: until) - } else { - notificationsLabel = presentationData.strings.UserInfo_NotificationsDisabled - } + if let notificationSettings = data.notificationSettings { + let notificationsLabel: String + let soundLabel: String + let notificationSettings = notificationSettings as? TelegramPeerNotificationSettings ?? TelegramPeerNotificationSettings.defaultSettings + if case let .muted(until) = notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) { + if until < Int32.max - 1 { + notificationsLabel = stringForRemainingMuteInterval(strings: presentationData.strings, muteInterval: until) } else { - notificationsLabel = presentationData.strings.UserInfo_NotificationsEnabled + notificationsLabel = presentationData.strings.UserInfo_NotificationsDisabled } - - let globalNotificationSettings: GlobalNotificationSettings = data.globalNotificationSettings ?? GlobalNotificationSettings.defaultSettings - soundLabel = localizedPeerNotificationSoundString(strings: presentationData.strings, sound: notificationSettings.messageSound, default: globalNotificationSettings.effective.privateChats.sound) - - items.append(PeerInfoScreenDisclosureItem(id: 0, label: notificationsLabel, text: "Notifications", action: { - interaction.editingOpenNotificationSettings() - })) - items.append(PeerInfoScreenDisclosureItem(id: 1, label: soundLabel, text: "Sound", action: { - interaction.editingOpenSoundSettings() - })) - items.append(PeerInfoScreenSwitchItem(id: 2, text: "Show Message Text", value: notificationSettings.displayPreviews != .hide, toggled: { value in - interaction.editingToggleShowMessageText(value) - })) + } else { + notificationsLabel = presentationData.strings.UserInfo_NotificationsEnabled } + + let globalNotificationSettings: GlobalNotificationSettings = data.globalNotificationSettings ?? GlobalNotificationSettings.defaultSettings + soundLabel = localizedPeerNotificationSoundString(strings: presentationData.strings, sound: notificationSettings.messageSound, default: globalNotificationSettings.effective.privateChats.sound) + + items.append(PeerInfoScreenDisclosureItem(id: 0, label: notificationsLabel, text: "Notifications", action: { + interaction.editingOpenNotificationSettings() + })) + items.append(PeerInfoScreenDisclosureItem(id: 1, label: soundLabel, text: "Sound", action: { + interaction.editingOpenSoundSettings() + })) + items.append(PeerInfoScreenSwitchItem(id: 2, text: "Show Message Text", value: notificationSettings.displayPreviews != .hide, toggled: { value in + interaction.editingToggleShowMessageText(value) + })) } return items @@ -443,10 +500,62 @@ private func editingInfoSectionItems(data: PeerInfoScreenData?, presentationData private func editingActionsSectionItems(data: PeerInfoScreenData?, presentationData: PresentationData, interaction: PeerInfoInteraction) -> [PeerInfoScreenItem] { var items: [PeerInfoScreenItem] = [] if let data = data { - if data.isContact { - items.append(PeerInfoScreenActionItem(id: 0, text: "Delete Contact", color: .destructive, action: { - interaction.requestDeleteContact() - })) + if let user = data.peer as? TelegramUser { + if data.isContact { + items.append(PeerInfoScreenActionItem(id: 0, text: presentationData.strings.UserInfo_DeleteContact, color: .destructive, action: { + interaction.requestDeleteContact() + })) + } + } else if let channel = data.peer as? TelegramChannel { + if channel.flags.contains(.isCreator) { + let linkText: String + if let username = channel.username { + linkText = "@\(username)" + } else { + linkText = presentationData.strings.Channel_Setup_TypePrivate + } + items.append(PeerInfoScreenDisclosureItem(id: 1, label: linkText, text: presentationData.strings.Channel_TypeSetup_Title, action: { + interaction.editingOpenPublicLinkSetup() + })) + + let discussionGroupTitle: String + if let cachedData = data.cachedData as? CachedChannelData { + if let peer = data.linkedDiscussionPeer { + if let addressName = peer.addressName, !addressName.isEmpty { + discussionGroupTitle = "@\(addressName)" + } else { + discussionGroupTitle = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + } + } else { + discussionGroupTitle = presentationData.strings.Channel_DiscussionGroupAdd + } + } else { + discussionGroupTitle = "..." + } + + items.append(PeerInfoScreenDisclosureItem(id: 2, label: discussionGroupTitle, text: presentationData.strings.Channel_DiscussionGroup, action: { + interaction.editingOpenDiscussionGroupSetup() + })) + //items.append(PeerInfoScreenCommentItem(id: 3, text: presentationData.strings.Channel_DiscussionGroupInfo)) + + let messagesShouldHaveSignatures: Bool + switch channel.info { + case let .broadcast(info): + messagesShouldHaveSignatures = info.flags.contains(.messagesShouldHaveSignatures) + default: + messagesShouldHaveSignatures = false + } + items.append(PeerInfoScreenSwitchItem(id: 4, text: presentationData.strings.Channel_SignMessages, value: messagesShouldHaveSignatures, toggled: { value in + interaction.editingToggleMessageSignatures(value) + })) + items.append(PeerInfoScreenCommentItem(id: 5, text: presentationData.strings.Channel_SignMessages_Help)) + } + } else if let group = data.peer as? TelegramGroup { + if case .creator = group.role { + items.append(PeerInfoScreenDisclosureItem(id: 1, label: presentationData.strings.Group_Setup_TypePrivate, text: presentationData.strings.Channel_TypeSetup_Title, action: { + interaction.editingOpenPublicLinkSetup() + })) + } } } return items @@ -486,13 +595,17 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD private(set) var data: PeerInfoScreenData? private(set) var state = PeerInfoState( isEditing: false, - isSearching: false, - selectedMessageIds: nil + selectedMessageIds: nil, + updatingAvatar: nil ) private var dataDisposable: Disposable? private let activeActionDisposable = MetaDisposable() private let resolveUrlDisposable = MetaDisposable() + private let toggleShouldChannelMessagesSignaturesDisposable = MetaDisposable() + + private let updateAvatarDisposable = MetaDisposable() + private let currentAvatarMixin = Atomic(value: nil) private let _ready = Promise() var ready: Promise { @@ -507,6 +620,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self.presentationData = context.sharedContext.currentPresentationData.with { $0 } self.scrollNode = ASScrollNode() + self.scrollNode.view.delaysContentTouches = false self.headerNode = PeerInfoHeaderNode(context: context, avatarInitiallyExpanded: avatarInitiallyExpanded) self.infoSection = PeerInfoScreenItemSectionContainerNode(id: 0) @@ -552,6 +666,18 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }, performBotCommand: { [weak self] command in self?.performBotCommand(command: command) + }, + editingOpenPublicLinkSetup: { [weak self] in + self?.editingOpenPublicLinkSetup() + }, + editingOpenDiscussionGroupSetup: { [weak self] in + self?.editingOpenDiscussionGroupSetup() + }, + editingToggleMessageSignatures: { [weak self] value in + self?.editingToggleMessageSignatures(value: value) + }, + openParticipantsSection: { [weak self] section in + self?.openParticipantsSection(section: section) } ) @@ -950,6 +1076,10 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD })) } + self.headerNode.requestOpenAvatarForEditing = { [weak self] in + self?.openAvatarForEditing() + } + self.headerNode.navigationButtonContainer.performAction = { [weak self] key in guard let strongSelf = self else { return @@ -970,8 +1100,12 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD strongSelf.controller?.navigationItem.setLeftBarButton(UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, style: .plain, target: strongSelf, action: #selector(strongSelf.editingCancelPressed)), animated: true) case .done, .cancel: if case .done = key { - if let data = strongSelf.data, data.isContact { - if let peer = data.peer as? TelegramUser { + guard let data = strongSelf.data else { + strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel) + return + } + if let peer = data.peer as? TelegramUser { + if data.isContact { let firstName = strongSelf.headerNode.editingContentNode.editingTextForKey(.firstName) ?? "" let lastName = strongSelf.headerNode.editingContentNode.editingTextForKey(.lastName) ?? "" @@ -1012,7 +1146,44 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } else { strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel) } + } else { + strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel) } + } else if let group = data.peer as? TelegramGroup, canEditPeerInfo(peer: group) { + let title = strongSelf.headerNode.editingContentNode.editingTextForKey(.title) ?? "" + + } else if let channel = data.peer as? TelegramChannel, canEditPeerInfo(peer: channel) { + let title = strongSelf.headerNode.editingContentNode.editingTextForKey(.title) ?? "" + let description = strongSelf.headerNode.editingContentNode.editingTextForKey(.description) ?? "" + + var updateDataSignals: [Signal] = [] + + if title != channel.title { + updateDataSignals.append( + updatePeerTitle(account: strongSelf.context.account, peerId: channel.id, title: title) + |> ignoreValues + |> mapError { _ in return Void() } + ) + } + if description != (data.cachedData as? CachedChannelData)?.about { + updateDataSignals.append( + updatePeerDescription(account: strongSelf.context.account, peerId: channel.id, description: description.isEmpty ? nil : description) + |> ignoreValues + |> mapError { _ in return Void() } + ) + } + strongSelf.activeActionDisposable.set((combineLatest(updateDataSignals) + |> deliverOnMainQueue).start(error: { _ in + guard let strongSelf = self else { + return + } + strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel) + }, completed: { + guard let strongSelf = self else { + return + } + strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel) + })) } else { strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel) } @@ -1060,6 +1231,8 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self.activeActionDisposable.dispose() self.resolveUrlDisposable.dispose() self.hiddenAvatarRepresentationDisposable.dispose() + self.toggleShouldChannelMessagesSignaturesDisposable.dispose() + self.updateAvatarDisposable.dispose() } override func didLoad() { @@ -1242,16 +1415,86 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD let dismissAction: () -> Void = { [weak actionSheet] in actionSheet?.dismissAnimated() } - var reportSpam = false - var deleteChat = false var items: [ActionSheetItem] = [] + items.append(ActionSheetButtonItem(title: presentationData.strings.ChatSearch_SearchPlaceholder, color: .accent, action: { [weak self] in + dismissAction() + self?.openChatWithMessageSearch() + })) if let user = peer as? TelegramUser { + if let botInfo = user.botInfo { + if botInfo.flags.contains(.worksWithGroups) { + items.append(ActionSheetButtonItem(title: presentationData.strings.UserInfo_InviteBotToGroup, color: .accent, action: { [weak self] in + dismissAction() + self?.openAddBotToGroup() + })) + } + if user.username != nil { + items.append(ActionSheetButtonItem(title: presentationData.strings.UserInfo_ShareBot, color: .accent, action: { [weak self] in + dismissAction() + self?.openShareBot() + })) + } + + if let cachedData = data.cachedData as? CachedUserData, let botInfo = cachedData.botInfo { + for command in botInfo.commands { + if command.text == "settings" { + items.append(ActionSheetButtonItem(title: presentationData.strings.UserInfo_BotSettings, color: .accent, action: { [weak self] in + dismissAction() + self?.performBotCommand(command: .settings) + })) + } else if command.text == "help" { + items.append(ActionSheetButtonItem(title: presentationData.strings.UserInfo_BotHelp, color: .accent, action: { [weak self] in + dismissAction() + self?.performBotCommand(command: .help) + })) + } else if command.text == "privacy" { + items.append(ActionSheetButtonItem(title: presentationData.strings.UserInfo_BotPrivacy, color: .accent, action: { [weak self] in + dismissAction() + self?.performBotCommand(command: .privacy) + })) + } + } + } + } + if user.botInfo == nil && !user.flags.contains(.isSupport) { items.append(ActionSheetButtonItem(title: presentationData.strings.UserInfo_StartSecretChat, color: .accent, action: { [weak self] in dismissAction() self?.openStartSecretChat() })) } + } else if let channel = peer as? TelegramChannel { + var canReport = true + if channel.isVerified { + canReport = false + } + if channel.adminRights != nil { + canReport = false + } + if channel.flags.contains(.isCreator) { + canReport = false + } + if canReport { + items.append(ActionSheetButtonItem(title: presentationData.strings.ReportPeer_Report, color: .destructive, action: { [weak self] in + dismissAction() + self?.openReport() + })) + } + if channel.flags.contains(.isCreator) { + items.append(ActionSheetButtonItem(title: presentationData.strings.ChannelInfo_DeleteChannel, color: .destructive, action: { [weak self] in + dismissAction() + self?.openDeleteChannel() + })) + } else { + if case .member = channel.participationStatus { + items.append(ActionSheetButtonItem(title: presentationData.strings.Channel_LeaveChannel, color: .destructive, action: { [weak self] in + dismissAction() + self?.openLeaveChannel() + })) + } + } + } else if let group = peer as? TelegramGroup { + } actionSheet.setItemGroups([ ActionSheetItemGroup(items: items), @@ -1263,6 +1506,12 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } } + private func openChatWithMessageSearch() { + if let navigationController = (self.controller?.navigationController as? NavigationController) { + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(self.peerId), activateMessageSearch: true)) + } + } + private func openStartSecretChat() { let peerId = self.peerId let _ = (self.context.account.postbox.transaction { transaction -> (Peer?, PeerId?) in @@ -1710,6 +1959,235 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }) } + private func editingOpenPublicLinkSetup() { + self.controller?.push(channelVisibilityController(context: self.context, peerId: self.peerId, mode: .generic, upgradedToSupergroup: { _, f in f() })) + } + + private func editingOpenDiscussionGroupSetup() { + self.controller?.push(channelDiscussionGroupSetupController(context: self.context, peerId: self.peerId)) + } + + private func editingToggleMessageSignatures(value: Bool) { + self.toggleShouldChannelMessagesSignaturesDisposable.set(toggleShouldChannelMessagesSignatures(account: self.context.account, peerId: self.peerId, enabled: value).start()) + } + + private func openParticipantsSection(section: PeerInfoParticipantsSection) { + switch section { + case .members: + self.controller?.push(channelMembersController(context: self.context, peerId: self.peerId)) + case .admins: + self.controller?.push(channelAdminsController(context: self.context, peerId: self.peerId)) + case .banned: + self.controller?.push(channelBlacklistController(context: self.context, peerId: self.peerId)) + } + } + + private func openDeleteChannel() { + let peerId = self.peerId + let _ = (self.context.account.postbox.transaction { transaction -> Peer? in + return transaction.getPeer(peerId) + } + |> deliverOnMainQueue).start(next: { [weak self] peer in + guard let strongSelf = self, let peer = peer else { + return + } + let presentationData = strongSelf.presentationData + let actionSheet = ActionSheetController(presentationData: presentationData) + let dismissAction: () -> Void = { [weak actionSheet] in + actionSheet?.dismissAnimated() + } + actionSheet.setItemGroups([ + ActionSheetItemGroup(items: [ + ActionSheetTextItem(title: presentationData.strings.ChannelInfo_DeleteChannelConfirmation), + ActionSheetButtonItem(title: presentationData.strings.ChannelInfo_DeleteChannel, color: .destructive, action: { + dismissAction() + self?.deletePeerChat(peer: peer, globally: true) + }), + ]), + ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })]) + ]) + strongSelf.controller?.present(actionSheet, in: .window(.root)) + }) + } + + private func openLeaveChannel() { + let peerId = self.peerId + let _ = (self.context.account.postbox.transaction { transaction -> Peer? in + return transaction.getPeer(peerId) + } + |> deliverOnMainQueue).start(next: { [weak self] peer in + guard let strongSelf = self, let peer = peer else { + return + } + let presentationData = strongSelf.presentationData + let actionSheet = ActionSheetController(presentationData: presentationData) + let dismissAction: () -> Void = { [weak actionSheet] in + actionSheet?.dismissAnimated() + } + actionSheet.setItemGroups([ + ActionSheetItemGroup(items: [ + ActionSheetButtonItem(title: presentationData.strings.Channel_LeaveChannel, color: .destructive, action: { + dismissAction() + self?.deletePeerChat(peer: peer, globally: false) + }), + ]), + ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })]) + ]) + strongSelf.controller?.present(actionSheet, in: .window(.root)) + }) + } + + private func deletePeerChat(peer: Peer, globally: Bool) { + guard let controller = self.controller, let navigationController = controller.navigationController as? NavigationController else { + return + } + guard let tabController = navigationController.viewControllers.first as? TabBarController else { + return + } + for childController in tabController.controllers { + if let chatListController = childController as? ChatListController { + chatListController.maybeAskForPeerChatRemoval(peer: RenderedPeer(peer: peer), deleteGloballyIfPossible: globally, completion: { [weak navigationController] deleted in + if deleted { + navigationController?.popToRoot(animated: true) + } + }, removed: { + }) + break + } + } + } + + private func openAvatarForEditing() { + guard let peer = self.data?.peer, canEditPeerInfo(peer: peer) else { + return + } + + let peerId = self.peerId + let _ = (self.context.account.postbox.transaction { transaction -> (Peer?, SearchBotsConfiguration) in + return (transaction.getPeer(peerId), currentSearchBotsConfiguration(transaction: transaction)) + } + |> deliverOnMainQueue).start(next: { [weak self] peer, searchBotsConfiguration in + guard let strongSelf = self, let peer = peer else { + return + } + + let presentationData = strongSelf.presentationData + + let legacyController = LegacyController(presentation: .custom, theme: presentationData.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) + + strongSelf.controller?.present(legacyController, in: .window(.root)) + + var hasPhotos = false + if !peer.profileImageRepresentations.isEmpty { + hasPhotos = true + } + + let completedImpl: (UIImage) -> Void = { image in + guard let strongSelf = self, let data = image.jpegData(compressionQuality: 0.6) else { + return + } + + let resource = LocalFileMediaResource(fileId: arc4random64()) + strongSelf.context.account.postbox.mediaBox.storeResourceData(resource.id, data: data) + let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: resource) + + strongSelf.state = strongSelf.state.withUpdatingAvatar(.image(representation)) + if let (layout, navigationHeight) = strongSelf.validLayout { + strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false) + } + + let postbox = strongSelf.context.account.postbox + strongSelf.updateAvatarDisposable.set((updatePeerPhoto(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, stateManager: strongSelf.context.account.stateManager, accountPeerId: strongSelf.context.account.peerId, peerId: strongSelf.peerId, photo: uploadedPeerPhoto(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, resource: resource), mapResourceToAvatarSizes: { resource, representations in + return mapResourceToAvatarSizes(postbox: postbox, resource: resource, representations: representations) + }) + |> deliverOnMainQueue).start(next: { result in + guard let strongSelf = self else { + return + } + switch result { + case .complete: + strongSelf.state = strongSelf.state.withUpdatingAvatar(nil) + if let (layout, navigationHeight) = strongSelf.validLayout { + strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false) + } + case .progress: + break + } + })) + } + + let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: hasPhotos, hasViewButton: false, personalPhoto: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: false)! + let _ = strongSelf.currentAvatarMixin.swap(mixin) + mixin.requestSearchController = { assetsController in + guard let strongSelf = self else { + return + } + let controller = WebSearchController(context: strongSelf.context, peer: peer, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), completion: { result in + assetsController?.dismiss() + completedImpl(result) + })) + strongSelf.controller?.present(controller, in: .window(.root)) + } + mixin.didFinishWithImage = { image in + if let image = image { + completedImpl(image) + } + } + mixin.didFinishWithDelete = { + guard let strongSelf = self else { + return + } + + let _ = strongSelf.currentAvatarMixin.swap(nil) + if let profileImage = peer.smallProfileImage { + strongSelf.state = strongSelf.state.withUpdatingAvatar(.none) + if let (layout, navigationHeight) = strongSelf.validLayout { + strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false) + } + } + let postbox = strongSelf.context.account.postbox + strongSelf.updateAvatarDisposable.set((updatePeerPhoto(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, stateManager: strongSelf.context.account.stateManager, accountPeerId: strongSelf.context.account.peerId, peerId: strongSelf.peerId, photo: nil, mapResourceToAvatarSizes: { resource, representations in + return mapResourceToAvatarSizes(postbox: postbox, resource: resource, representations: representations) + }) + |> deliverOnMainQueue).start(next: { result in + guard let strongSelf = self else { + return + } + switch result { + case .complete: + strongSelf.state = strongSelf.state.withUpdatingAvatar(nil) + if let (layout, navigationHeight) = strongSelf.validLayout { + strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false) + } + case .progress: + break + } + })) + } + mixin.didDismiss = { [weak legacyController] in + guard let strongSelf = self else { + return + } + let _ = strongSelf.currentAvatarMixin.swap(nil) + legacyController?.dismiss() + } + let menuController = mixin.present() + if let menuController = menuController { + menuController.customRemoveFromParentViewController = { [weak legacyController] in + legacyController?.dismiss() + } + } + }) + } + func deleteMessages(messageIds: Set?) { if let messageIds = messageIds ?? self.state.selectedMessageIds, !messageIds.isEmpty { self.activeActionDisposable.set((self.context.sharedContext.chatAvailableMessageActions(postbox: self.context.account.postbox, accountPeerId: self.context.account.peerId, messageIds: messageIds) @@ -2353,7 +2831,7 @@ public final class PeerInfoScreen: ViewController { badgeStrokeColor: baseNavigationBarPresentationData.theme.badgeStrokeColor, badgeTextColor: baseNavigationBarPresentationData.theme.badgeTextColor ), strings: baseNavigationBarPresentationData.strings)) - self.navigationBar?.makeCustomTransitionNode = { [weak self] other in + self.navigationBar?.makeCustomTransitionNode = { [weak self] other, isInteractive in guard let strongSelf = self else { return nil } @@ -2363,7 +2841,10 @@ public final class PeerInfoScreen: ViewController { if strongSelf.controllerNode.scrollNode.view.contentOffset.y > .ulpOfOne { return nil } - if strongSelf.controllerNode.headerNode.isAvatarExpanded { + if isInteractive && strongSelf.controllerNode.headerNode.isAvatarExpanded { + return nil + } + if other.contentNode != nil { return nil } if let tag = other.userInfo as? PeerInfoNavigationSourceTag, tag.peerId == peerId { @@ -2456,7 +2937,6 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig private var previousBackButtonArrow: ASDisplayNode? private var currentBackButtonArrow: ASDisplayNode? private var previousBackButtonBadge: ASDisplayNode? - private var previousRightButton: ASDisplayNode? private var currentBackButton: ASDisplayNode? private var previousTitleNode: (ASDisplayNode, TextNode)? @@ -2500,10 +2980,6 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig self.previousBackButtonBadge = previousBackButtonBadge self.addSubnode(previousBackButtonBadge) } - if let previousRightButton = bottomNavigationBar.makeTransitionRightButtonNode(accentColor: self.presentationData.theme.rootController.navigationBar.accentTextColor) { - self.previousRightButton = previousRightButton - self.addSubnode(previousRightButton) - } if let currentBackButton = topNavigationBar.makeTransitionBackButtonNode(accentColor: self.screenNode.headerNode.isAvatarExpanded ? .white : self.presentationData.theme.rootController.navigationBar.accentTextColor) { self.currentBackButton = currentBackButton self.addSubnode(currentBackButton) @@ -2512,12 +2988,14 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig let previousTitleNode = previousTitleView.titleNode.makeCopy() let previousTitleContainerNode = ASDisplayNode() previousTitleContainerNode.addSubnode(previousTitleNode) + previousTitleNode.frame = previousTitleNode.frame.offsetBy(dx: -previousTitleNode.frame.width / 2.0, dy: -previousTitleNode.frame.height / 2.0) self.previousTitleNode = (previousTitleContainerNode, previousTitleNode) self.addSubnode(previousTitleContainerNode) let previousStatusNode = previousTitleView.activityNode.makeCopy() let previousStatusContainerNode = ASDisplayNode() previousStatusContainerNode.addSubnode(previousStatusNode) + previousStatusNode.frame = previousStatusNode.frame.offsetBy(dx: -previousStatusNode.frame.width / 2.0, dy: -previousStatusNode.frame.height / 2.0) self.previousStatusNode = (previousStatusContainerNode, previousStatusNode) self.addSubnode(previousStatusContainerNode) } @@ -2553,12 +3031,6 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig transition.updateAlpha(node: previousBackButtonBadge, alpha: fraction) } - if let previousRightButton = self.previousRightButton { - let previousRightButtonFrame = bottomNavigationBar.rightButtonNode.view.convert(bottomNavigationBar.rightButtonNode.view.bounds, to: bottomNavigationBar.view) - previousRightButton.frame = previousRightButtonFrame - transition.updateAlpha(node: previousRightButton, alpha: fraction) - } - if let currentBackButton = self.currentBackButton { let currentBackButtonFrame = topNavigationBar.backButtonNode.view.convert(topNavigationBar.backButtonNode.view.bounds, to: topNavigationBar.view) transition.updateFrame(node: currentBackButton, frame: currentBackButtonFrame.offsetBy(dx: fraction * 12.0, dy: 0.0)) @@ -2566,7 +3038,7 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig transition.updateAlpha(node: currentBackButton, alpha: (1.0 - fraction)) } - if let previousTitleView = bottomNavigationBar.titleView as? ChatTitleView, let avatarNode = previousTitleView.avatarNode, let (previousTitleContainerNode, previousTitleNode) = self.previousTitleNode, let (previousStatusContainerNode, previousStatusNode) = self.previousStatusNode { + if let previousTitleView = bottomNavigationBar.titleView as? ChatTitleView, let _ = (bottomNavigationBar.rightButtonNode.singleCustomNode as? ChatAvatarNavigationNode)?.avatarNode, let (previousTitleContainerNode, previousTitleNode) = self.previousTitleNode, let (previousStatusContainerNode, previousStatusNode) = self.previousStatusNode { let previousTitleFrame = previousTitleView.titleNode.view.convert(previousTitleView.titleNode.bounds, to: bottomNavigationBar.view) let previousStatusFrame = previousTitleView.activityNode.view.convert(previousTitleView.activityNode.bounds, to: bottomNavigationBar.view) @@ -2578,10 +3050,10 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig let titleScale = (fraction * previousTitleNode.bounds.height + (1.0 - fraction) * self.headerNode.titleNode.bounds.height) / previousTitleNode.bounds.height let subtitleScale = max(0.01, min(10.0, (fraction * previousStatusNode.bounds.height + (1.0 - fraction) * self.headerNode.subtitleNode.bounds.height) / previousStatusNode.bounds.height)) - transition.updateFrame(node: previousTitleContainerNode, frame: CGRect(origin: self.headerNode.titleNodeRawContainer.frame.origin.offsetBy(dx: previousTitleFrame.size.width * 0.5 * (titleScale - 1.0), dy: previousTitleFrame.size.height * 0.5 * (titleScale - 1.0)), size: previousTitleFrame.size)) - transition.updateFrame(node: previousTitleNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: previousTitleFrame.size)) - transition.updateFrame(node: previousStatusContainerNode, frame: CGRect(origin: self.headerNode.subtitleNodeRawContainer.frame.origin.offsetBy(dx: previousStatusFrame.size.width * 0.5 * (subtitleScale - 1.0), dy: previousStatusFrame.size.height * 0.5 * (subtitleScale - 1.0)), size: previousStatusFrame.size)) - transition.updateFrame(node: previousStatusNode, frame: CGRect(origin: CGPoint(), size: previousStatusFrame.size)) + transition.updateFrame(node: previousTitleContainerNode, frame: CGRect(origin: self.headerNode.titleNodeRawContainer.frame.center, size: CGSize())) + transition.updateFrame(node: previousTitleNode, frame: CGRect(origin: CGPoint(x: -previousTitleFrame.width / 2.0, y: -previousTitleFrame.height / 2.0), size: previousTitleFrame.size)) + transition.updateFrame(node: previousStatusContainerNode, frame: CGRect(origin: self.headerNode.subtitleNodeRawContainer.frame.center, size: CGSize())) + transition.updateFrame(node: previousStatusNode, frame: CGRect(origin: CGPoint(x: -previousStatusFrame.size.width / 2.0, y: -previousStatusFrame.size.height / 2.0), size: previousStatusFrame.size)) transition.updateSublayerTransformScale(node: previousTitleContainerNode, scale: titleScale) transition.updateSublayerTransformScale(node: previousStatusContainerNode, scale: subtitleScale) diff --git a/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift b/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift index 50cdd8a69d..8a475cb359 100644 --- a/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift +++ b/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift @@ -1246,9 +1246,13 @@ public final class SharedAccountContextImpl: SharedAccountContext { private let defaultChatControllerInteraction = ChatControllerInteraction.default private func peerInfoControllerImpl(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool) -> ViewController? { - if let _ = peer as? TelegramGroup { + if let _ = peer as? TelegramGroup { + return PeerInfoScreen(context: context, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded) + return groupInfoController(context: context, peerId: peer.id) } else if let channel = peer as? TelegramChannel { + return PeerInfoScreen(context: context, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded) + if case .group = channel.info { return groupInfoController(context: context, peerId: peer.id) } else { From 0f0bb05cc547adff24f4b0177583e6cd5a7b2886 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Mon, 10 Feb 2020 18:35:38 +0100 Subject: [PATCH 11/30] Fix typo --- buildbox/deploy-telegram.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildbox/deploy-telegram.sh b/buildbox/deploy-telegram.sh index d76f0a292d..744c99ea44 100644 --- a/buildbox/deploy-telegram.sh +++ b/buildbox/deploy-telegram.sh @@ -60,6 +60,6 @@ fi if [ "$1" == "appstore" ]; then export DELIVER_ITMSTRANSPORTER_ADDITIONAL_UPLOAD_PARAMETERS="-t DAV" FASTLANE_PASSWORD="$FASTLANE_PASSWORD" xcrun altool --upload-app --type ios --file "$IPA_PATH" --username "$FASTLANE_ITC_USERNAME" --password "@env:FASTLANE_PASSWORD" -else if [ "$1" == "hockeyapp" ]; then +elif [ "$1" == "hockeyapp" ]; then API_USER_NAME="$API_USER_NAME" API_APP_NAME="$API_APP_NAME" API_TOKEN="$API_TOKEN" sh buildbox/deploy-appcenter.sh fi From fd9be238d2500d61d673cce63498f2a32f4c3e28 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Mon, 10 Feb 2020 18:41:06 +0100 Subject: [PATCH 12/30] Fix script --- buildbox/deploy-appcenter.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildbox/deploy-appcenter.sh b/buildbox/deploy-appcenter.sh index f738d21718..58376b2c20 100644 --- a/buildbox/deploy-appcenter.sh +++ b/buildbox/deploy-appcenter.sh @@ -4,8 +4,8 @@ set -e set -x API_HOST="https://api.appcenter.ms" -IPA_PATH="build/Telegram_Signed.ipa" -DSYM_PATH="build/DSYM.zip" +IPA_PATH="build/artifacts/Telegram.ipa" +DSYM_PATH="build/artifacts/Telegram.DSYMs.zip" upload_ipa() { GROUP_DATA=$(curl \ From 76893115f6cbdce49956499fb0549a91edbe9348 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 11 Feb 2020 01:53:12 +0100 Subject: [PATCH 13/30] Temp --- .../AvatarNode/Sources/AvatarNode.swift | 14 +- .../Display/Display/GenerateImage.swift | 31 + .../Sources/ItemListAddressItem.swift | 17 +- .../Sources/ItemListPeerItem.swift | 11 +- .../ChannelPermissionsController.swift | 2 +- .../Contents.json | 12 + .../ic_camera.pdf | Bin 0 -> 4149 bytes .../TelegramUI/ChatController.swift | 6 +- .../ListItems/PeerInfoScreenAddressItem.swift | 122 +++ .../ListItems/PeerInfoScreenHeaderItem.swift | 57 ++ .../ListItems/PeerInfoScreenMemberItem.swift | 124 +++ .../PeerInfo/Panes/PeerInfoMembersPane.swift | 196 ++++ .../TelegramUI/PeerInfo/PeerInfoData.swift | 103 ++- .../PeerInfo/PeerInfoHeaderNode.swift | 29 +- .../TelegramUI/PeerInfo/PeerInfoMembers.swift | 153 ++++ .../PeerInfo/PeerInfoPaneContainerNode.swift | 9 + .../TelegramUI/PeerInfo/PeerInfoScreen.swift | 863 +++++++++++++++--- 17 files changed, 1542 insertions(+), 207 deletions(-) create mode 100644 submodules/TelegramUI/Images.xcassets/Avatar/EditAvatarIconLarge.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Avatar/EditAvatarIconLarge.imageset/ic_camera.pdf create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenAddressItem.swift create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenHeaderItem.swift create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoMembersPane.swift create mode 100644 submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoMembers.swift diff --git a/submodules/AvatarNode/Sources/AvatarNode.swift b/submodules/AvatarNode/Sources/AvatarNode.swift index b871681a0a..2f4e502e6a 100644 --- a/submodules/AvatarNode/Sources/AvatarNode.swift +++ b/submodules/AvatarNode/Sources/AvatarNode.swift @@ -150,8 +150,14 @@ public final class AvatarEditOverlayNode: ASDisplayNode { context.setBlendMode(.normal) - if let editAvatarIcon = generateTintedImage(image: UIImage(bundleImageName: "Avatar/EditAvatarIcon"), color: .white) { - context.draw(editAvatarIcon.cgImage!, in: CGRect(origin: CGPoint(x: floor((bounds.size.width - editAvatarIcon.size.width) / 2.0) + 0.5, y: floor((bounds.size.height - editAvatarIcon.size.height) / 2.0) + 1.0), size: editAvatarIcon.size)) + if bounds.width > 90.0 { + if let editAvatarIcon = generateTintedImage(image: UIImage(bundleImageName: "Avatar/EditAvatarIconLarge"), color: .white) { + context.draw(editAvatarIcon.cgImage!, in: CGRect(origin: CGPoint(x: floor((bounds.size.width - editAvatarIcon.size.width) / 2.0) + 0.5, y: floor((bounds.size.height - editAvatarIcon.size.height) / 2.0) + 1.0), size: editAvatarIcon.size)) + } + } else { + if let editAvatarIcon = generateTintedImage(image: UIImage(bundleImageName: "Avatar/EditAvatarIcon"), color: .white) { + context.draw(editAvatarIcon.cgImage!, in: CGRect(origin: CGPoint(x: floor((bounds.size.width - editAvatarIcon.size.width) / 2.0) + 0.5, y: floor((bounds.size.height - editAvatarIcon.size.height) / 2.0) + 1.0), size: editAvatarIcon.size)) + } } } } @@ -501,7 +507,9 @@ public final class AvatarNode: ASDisplayNode { context.scaleBy(x: 1.0, y: -1.0) context.translateBy(x: -bounds.size.width / 2.0, y: -bounds.size.height / 2.0) - if let editAvatarIcon = generateTintedImage(image: UIImage(bundleImageName: "Avatar/EditAvatarIcon"), color: theme.list.itemAccentColor) { + if bounds.width > 90.0, let editAvatarIcon = generateTintedImage(image: UIImage(bundleImageName: "Avatar/EditAvatarIconLarge"), color: theme.list.itemAccentColor) { + context.draw(editAvatarIcon.cgImage!, in: CGRect(origin: CGPoint(x: floor((bounds.size.width - editAvatarIcon.size.width) / 2.0) + 0.5, y: floor((bounds.size.height - editAvatarIcon.size.height) / 2.0) + 1.0), size: editAvatarIcon.size)) + } else if let editAvatarIcon = generateTintedImage(image: UIImage(bundleImageName: "Avatar/EditAvatarIcon"), color: theme.list.itemAccentColor) { context.draw(editAvatarIcon.cgImage!, in: CGRect(origin: CGPoint(x: floor((bounds.size.width - editAvatarIcon.size.width) / 2.0) + 0.5, y: floor((bounds.size.height - editAvatarIcon.size.height) / 2.0) + 1.0), size: editAvatarIcon.size)) } } else if case .archivedChatsIcon = parameters.icon { diff --git a/submodules/Display/Display/GenerateImage.swift b/submodules/Display/Display/GenerateImage.swift index cabf6f5c54..4b7f38fbe9 100644 --- a/submodules/Display/Display/GenerateImage.swift +++ b/submodules/Display/Display/GenerateImage.swift @@ -238,6 +238,8 @@ public func generateStretchableFilledCircleImage(diameter: CGFloat, color: UICol let cap: Int if intDiameter == 3 { cap = 1 + } else if intDiameter == 2 { + cap = 3 } else if intRadius == 1 { cap = 2 } else { @@ -266,6 +268,35 @@ public func generateVerticallyStretchableFilledCircleImage(radius: CGFloat, colo })?.stretchableImage(withLeftCapWidth: Int(radius), topCapHeight: Int(radius)) } +public func generateSmallHorizontalStretchableFilledCircleImage(diameter: CGFloat, color: UIColor?, backgroundColor: UIColor? = nil) -> UIImage? { + return generateImage(CGSize(width: diameter + 1.0, height: diameter), contextGenerator: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + + if let subImage = generateImage(CGSize(width: diameter + 1.0, height: diameter), contextGenerator: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + context.setFillColor(UIColor.black.cgColor) + context.fillEllipse(in: CGRect(origin: CGPoint(), size: CGSize(width: diameter, height: diameter))) + context.fill(CGRect(origin: CGPoint(x: diameter / 2.0, y: 0.0), size: CGSize(width: 1.0, height: diameter))) + context.fillEllipse(in: CGRect(origin: CGPoint(x: 1.0, y: 0.0), size: CGSize(width: diameter, height: diameter))) + }) { + if let backgroundColor = backgroundColor { + context.setFillColor(backgroundColor.cgColor) + context.fill(CGRect(origin: CGPoint(), size: size)) + } + + if let color = color { + context.setFillColor(color.cgColor) + } else { + context.setFillColor(UIColor.clear.cgColor) + context.setBlendMode(.copy) + } + + context.clip(to: CGRect(origin: CGPoint(), size: size), mask: subImage.cgImage!) + context.fill(CGRect(origin: CGPoint(), size: size)) + } + })?.stretchableImage(withLeftCapWidth: Int(diameter / 2), topCapHeight: Int(diameter / 2)) +} + public func generateTintedImage(image: UIImage?, color: UIColor, backgroundColor: UIColor? = nil) -> UIImage? { guard let image = image else { return nil diff --git a/submodules/ItemListAddressItem/Sources/ItemListAddressItem.swift b/submodules/ItemListAddressItem/Sources/ItemListAddressItem.swift index 9ad3ec1d6d..929a0d82ca 100644 --- a/submodules/ItemListAddressItem/Sources/ItemListAddressItem.swift +++ b/submodules/ItemListAddressItem/Sources/ItemListAddressItem.swift @@ -18,13 +18,14 @@ public final class ItemListAddressItem: ListViewItem, ItemListItem { let selected: Bool? public let sectionId: ItemListSectionId let style: ItemListStyle + let displayDecorations: Bool let action: (() -> Void)? let longTapAction: (() -> Void)? let linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)? public let tag: Any? - public init(theme: PresentationTheme, label: String, text: String, imageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>?, selected: Bool? = nil, sectionId: ItemListSectionId, style: ItemListStyle, action: (() -> Void)?, longTapAction: (() -> Void)? = nil, linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)? = nil, tag: Any? = nil) { + public init(theme: PresentationTheme, label: String, text: String, imageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>?, selected: Bool? = nil, sectionId: ItemListSectionId, style: ItemListStyle, displayDecorations: Bool = true, action: (() -> Void)?, longTapAction: (() -> Void)? = nil, linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)? = nil, tag: Any? = nil) { self.theme = theme self.label = label self.text = text @@ -32,6 +33,7 @@ public final class ItemListAddressItem: ListViewItem, ItemListItem { self.selected = selected self.sectionId = sectionId self.style = style + self.displayDecorations = displayDecorations self.action = action self.longTapAction = longTapAction self.linkItemAction = linkItemAction @@ -157,7 +159,7 @@ public class ItemListAddressItemNode: ListViewItemNode { updatedTheme = item.theme } - let insets: UIEdgeInsets + var insets: UIEdgeInsets let leftInset: CGFloat = 16.0 + params.leftInset let rightInset: CGFloat = 8.0 + params.rightInset let separatorHeight = UIScreenPixel @@ -175,6 +177,10 @@ public class ItemListAddressItemNode: ListViewItemNode { insets = itemListNeighborsGroupedInsets(neighbors) } + if !item.displayDecorations { + insets = UIEdgeInsets() + } + var leftOffset: CGFloat = 0.0 var selectionNodeWidthAndApply: (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode)? if let selected = item.selected { @@ -226,6 +232,11 @@ public class ItemListAddressItemNode: ListViewItemNode { strongSelf.highlightedBackgroundNode.backgroundColor = item.theme.list.itemHighlightedBackgroundColor } + strongSelf.topStripeNode.isHidden = !item.displayDecorations + strongSelf.bottomStripeNode.isHidden = !item.displayDecorations + strongSelf.backgroundNode.isHidden = !item.displayDecorations + strongSelf.highlightedBackgroundNode.isHidden = !item.displayDecorations + let _ = labelApply() let _ = textApply() let _ = imageApply() @@ -293,7 +304,7 @@ public class ItemListAddressItemNode: ListViewItemNode { case .sameSection(false): strongSelf.topStripeNode.isHidden = true default: - strongSelf.topStripeNode.isHidden = false + strongSelf.topStripeNode.isHidden = !item.displayDecorations } let bottomStripeInset: CGFloat let bottomStripeOffset: CGFloat diff --git a/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift b/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift index 59d93c72ca..ce2f1c397a 100644 --- a/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift +++ b/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift @@ -334,8 +334,9 @@ public final class ItemListPeerItem: ListViewItem, ItemListItem { public let tag: ItemListItemTag? let header: ListViewItemHeader? let shimmering: ItemListPeerItemShimmering? + let displayDecorations: Bool - public init(presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, context: AccountContext, peer: Peer, height: ItemListPeerItemHeight = .peerList, aliasHandling: ItemListPeerItemAliasHandling = .standard, nameColor: ItemListPeerItemNameColor = .primary, nameStyle: ItemListPeerItemNameStyle = .distinctBold, presence: PeerPresence?, text: ItemListPeerItemText, label: ItemListPeerItemLabel, editing: ItemListPeerItemEditing, revealOptions: ItemListPeerItemRevealOptions? = nil, switchValue: ItemListPeerItemSwitch?, enabled: Bool, selectable: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, removePeer: @escaping (PeerId) -> Void, toggleUpdated: ((Bool) -> Void)? = nil, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? = nil, hasTopStripe: Bool = true, hasTopGroupInset: Bool = true, noInsets: Bool = false, tag: ItemListItemTag? = nil, header: ListViewItemHeader? = nil, shimmering: ItemListPeerItemShimmering? = nil) { + public init(presentationData: ItemListPresentationData, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, context: AccountContext, peer: Peer, height: ItemListPeerItemHeight = .peerList, aliasHandling: ItemListPeerItemAliasHandling = .standard, nameColor: ItemListPeerItemNameColor = .primary, nameStyle: ItemListPeerItemNameStyle = .distinctBold, presence: PeerPresence?, text: ItemListPeerItemText, label: ItemListPeerItemLabel, editing: ItemListPeerItemEditing, revealOptions: ItemListPeerItemRevealOptions? = nil, switchValue: ItemListPeerItemSwitch?, enabled: Bool, selectable: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, removePeer: @escaping (PeerId) -> Void, toggleUpdated: ((Bool) -> Void)? = nil, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? = nil, hasTopStripe: Bool = true, hasTopGroupInset: Bool = true, noInsets: Bool = false, tag: ItemListItemTag? = nil, header: ListViewItemHeader? = nil, shimmering: ItemListPeerItemShimmering? = nil, displayDecorations: Bool = true) { self.presentationData = presentationData self.dateTimeFormat = dateTimeFormat self.nameDisplayOrder = nameDisplayOrder @@ -365,6 +366,7 @@ public final class ItemListPeerItem: ListViewItem, ItemListItem { self.tag = tag self.header = header self.shimmering = shimmering + self.displayDecorations = displayDecorations } public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, (ListViewItemApply) -> Void)) -> Void) { @@ -932,7 +934,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo strongSelf.topStripeNode.isHidden = true default: hasTopCorners = true - strongSelf.topStripeNode.isHidden = hasCorners || !item.hasTopStripe + strongSelf.topStripeNode.isHidden = !item.displayDecorations || hasCorners || !item.hasTopStripe } let bottomStripeInset: CGFloat let bottomStripeOffset: CGFloat @@ -944,7 +946,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo bottomStripeInset = 0.0 bottomStripeOffset = 0.0 hasBottomCorners = true - strongSelf.bottomStripeNode.isHidden = hasCorners + strongSelf.bottomStripeNode.isHidden = hasCorners || !item.displayDecorations } strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil @@ -1087,6 +1089,9 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo shimmerNode.removeFromSupernode() } + strongSelf.backgroundNode.isHidden = !item.displayDecorations + strongSelf.highlightedBackgroundNode.isHidden = !item.displayDecorations + strongSelf.updateLayout(size: layout.contentSize, leftInset: params.leftInset, rightInset: params.rightInset) strongSelf.setRevealOptions((left: [], right: peerRevealOptions)) diff --git a/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift b/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift index 05e6b55824..85d9837112 100644 --- a/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift @@ -335,7 +335,7 @@ func compactStringForGroupPermission(strings: PresentationStrings, right: Telegr } } -let allGroupPermissionList: [(TelegramChatBannedRightsFlags, TelegramChannelPermission)] = [ +public let allGroupPermissionList: [(TelegramChatBannedRightsFlags, TelegramChannelPermission)] = [ (.banSendMessages, .sendMessages), (.banSendMedia, .sendMessages), (.banSendGifs, .sendMessages), diff --git a/submodules/TelegramUI/Images.xcassets/Avatar/EditAvatarIconLarge.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Avatar/EditAvatarIconLarge.imageset/Contents.json new file mode 100644 index 0000000000..868e9f5048 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Avatar/EditAvatarIconLarge.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_camera.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Avatar/EditAvatarIconLarge.imageset/ic_camera.pdf b/submodules/TelegramUI/Images.xcassets/Avatar/EditAvatarIconLarge.imageset/ic_camera.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6b39b47bbb0836616233b848db889f51e3b47534 GIT binary patch literal 4149 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 igjYaeFsk7HF8LWC5}Dr19~%u DrawingContext?, NoError>? + let action: (() -> Void)? + let longTapAction: (() -> Void)? + let linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)? + + init( + id: AnyHashable, + label: String, + text: String, + imageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>?, + action: (() -> Void)?, + longTapAction: (() -> Void)? = nil, + linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)? = nil + ) { + self.id = id + self.label = label + self.text = text + self.imageSignal = imageSignal + self.action = action + self.longTapAction = longTapAction + self.linkItemAction = linkItemAction + } + + func node() -> PeerInfoScreenItemNode { + return PeerInfoScreenAddressItemNode() + } +} + +private final class PeerInfoScreenAddressItemNode: PeerInfoScreenItemNode { + private let selectionNode: PeerInfoScreenSelectableBackgroundNode + private let bottomSeparatorNode: ASDisplayNode + + private var item: PeerInfoScreenAddressItem? + private var itemNode: ItemListAddressItemNode? + + override init() { + var bringToFrontForHighlightImpl: (() -> Void)? + self.selectionNode = PeerInfoScreenSelectableBackgroundNode(bringToFrontForHighlight: { bringToFrontForHighlightImpl?() }) + + self.bottomSeparatorNode = ASDisplayNode() + self.bottomSeparatorNode.isLayerBacked = true + + super.init() + + bringToFrontForHighlightImpl = { [weak self] in + self?.bringToFrontForHighlight?() + } + + self.addSubnode(self.bottomSeparatorNode) + self.addSubnode(self.selectionNode) + } + + override func update(width: CGFloat, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + guard let item = item as? PeerInfoScreenAddressItem else { + return 10.0 + } + + self.item = item + + self.selectionNode.pressed = item.action + + let sideInset: CGFloat = 16.0 + + self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + + let addressItem = ItemListAddressItem(theme: presentationData.theme, label: item.label, text: item.text, imageSignal: item.imageSignal, sectionId: 0, style: .blocks, displayDecorations: false, action: nil, longTapAction: item.longTapAction, linkItemAction: item.linkItemAction) + + let params = ListViewItemLayoutParams(width: width, leftInset: 0.0, rightInset: 0.0, availableHeight: 1000.0) + + let itemNode: ItemListAddressItemNode + if let current = self.itemNode { + itemNode = current + addressItem.updateNode(async: { $0() }, node: { + return itemNode + }, params: params, previousItem: nil, nextItem: nil, animation: .None, completion: { (layout, apply) in + let nodeFrame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: layout.size.height)) + + itemNode.contentSize = layout.contentSize + itemNode.insets = layout.insets + itemNode.frame = nodeFrame + + apply(ListViewItemApply(isOnScreen: true)) + }) + } else { + var itemNodeValue: ListViewItemNode? + addressItem.nodeConfiguredForParams(async: { $0() }, params: params, synchronousLoads: false, previousItem: nil, nextItem: nil, completion: { node, apply in + itemNodeValue = node + apply().1(ListViewItemApply(isOnScreen: true)) + }) + itemNode = itemNodeValue as! ItemListAddressItemNode + itemNode.isUserInteractionEnabled = false + self.itemNode = itemNode + self.addSubnode(itemNode) + } + + let height = itemNode.contentSize.height + + transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(), size: itemNode.bounds.size)) + + let highlightNodeOffset: CGFloat = topItem == nil ? 0.0 : UIScreenPixel + self.selectionNode.update(size: CGSize(width: width, height: height + highlightNodeOffset), theme: presentationData.theme, transition: transition) + transition.updateFrame(node: self.selectionNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -highlightNodeOffset), size: CGSize(width: width, height: height + highlightNodeOffset))) + + transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: sideInset, y: height - UIScreenPixel), size: CGSize(width: width - sideInset, height: UIScreenPixel))) + transition.updateAlpha(node: self.bottomSeparatorNode, alpha: bottomItem == nil ? 0.0 : 1.0) + + return height + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenHeaderItem.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenHeaderItem.swift new file mode 100644 index 0000000000..6ab8aab21e --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenHeaderItem.swift @@ -0,0 +1,57 @@ +import AsyncDisplayKit +import Display +import TelegramPresentationData + +final class PeerInfoScreenHeaderItem: PeerInfoScreenItem { + let id: AnyHashable + let text: String + + init(id: AnyHashable, text: String) { + self.id = id + self.text = text + } + + func node() -> PeerInfoScreenItemNode { + return PeerInfoScreenHeaderItemNode() + } +} + +private final class PeerInfoScreenHeaderItemNode: PeerInfoScreenItemNode { + private let textNode: ImmediateTextNode + + private var item: PeerInfoScreenHeaderItem? + + override init() { + self.textNode = ImmediateTextNode() + self.textNode.displaysAsynchronously = false + self.textNode.isUserInteractionEnabled = false + + super.init() + + self.addSubnode(self.textNode) + } + + override func update(width: CGFloat, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + guard let item = item as? PeerInfoScreenHeaderItem else { + return 10.0 + } + + self.item = item + + let sideInset: CGFloat = 16.0 + let verticalInset: CGFloat = 7.0 + + self.textNode.maximumNumberOfLines = 0 + self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(13.0), textColor: presentationData.theme.list.freeTextColor) + + let textSize = self.textNode.updateLayout(CGSize(width: width - sideInset * 2.0, height: .greatestFiniteMagnitude)) + + let textFrame = CGRect(origin: CGPoint(x: sideInset, y: verticalInset), size: textSize) + + let height = textSize.height + verticalInset * 2.0 + + transition.updateFrame(node: self.textNode, frame: textFrame) + + return height + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift new file mode 100644 index 0000000000..246861f33d --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift @@ -0,0 +1,124 @@ +import Foundation +import UIKit +import AsyncDisplayKit +import Display +import TelegramPresentationData +import ItemListPeerItem +import SwiftSignalKit +import AccountContext +import Postbox +import SyncCore +import TelegramCore +import ItemListUI + +final class PeerInfoScreenMemberItem: PeerInfoScreenItem { + let id: AnyHashable + let context: AccountContext + let peer: Peer + let presence: TelegramUserPresence? + let action: (() -> Void)? + + init( + id: AnyHashable, + context: AccountContext, + peer: Peer, + presence: TelegramUserPresence?, + action: (() -> Void)? + ) { + self.id = id + self.context = context + self.peer = peer + self.presence = presence + self.action = action + } + + func node() -> PeerInfoScreenItemNode { + return PeerInfoScreenMemberItemNode() + } +} + +private final class PeerInfoScreenMemberItemNode: PeerInfoScreenItemNode { + private let selectionNode: PeerInfoScreenSelectableBackgroundNode + private let bottomSeparatorNode: ASDisplayNode + + private var item: PeerInfoScreenMemberItem? + private var itemNode: ItemListPeerItemNode? + + override init() { + var bringToFrontForHighlightImpl: (() -> Void)? + self.selectionNode = PeerInfoScreenSelectableBackgroundNode(bringToFrontForHighlight: { bringToFrontForHighlightImpl?() }) + + self.bottomSeparatorNode = ASDisplayNode() + self.bottomSeparatorNode.isLayerBacked = true + + super.init() + + bringToFrontForHighlightImpl = { [weak self] in + self?.bringToFrontForHighlight?() + } + + self.addSubnode(self.bottomSeparatorNode) + self.addSubnode(self.selectionNode) + } + + override func update(width: CGFloat, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { + guard let item = item as? PeerInfoScreenMemberItem else { + return 10.0 + } + + self.item = item + + self.selectionNode.pressed = item.action + + let sideInset: CGFloat = 16.0 + + self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + + let peerItem = ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: item.context, peer: item.peer, height: .peerList, presence: item.presence, text: .presence, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: false, sectionId: 0, action: nil, setPeerIdWithRevealedOptions: { lhs, rhs in + + }, removePeer: { _ in + + }, contextAction: nil, hasTopStripe: false, hasTopGroupInset: false, noInsets: true, displayDecorations: false) + + let params = ListViewItemLayoutParams(width: width, leftInset: 0.0, rightInset: 0.0, availableHeight: 1000.0) + + let itemNode: ItemListPeerItemNode + if let current = self.itemNode { + itemNode = current + peerItem.updateNode(async: { $0() }, node: { + return itemNode + }, params: params, previousItem: nil, nextItem: nil, animation: .None, completion: { (layout, apply) in + let nodeFrame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: layout.size.height)) + + itemNode.contentSize = layout.contentSize + itemNode.insets = layout.insets + itemNode.frame = nodeFrame + + apply(ListViewItemApply(isOnScreen: true)) + }) + } else { + var itemNodeValue: ListViewItemNode? + peerItem.nodeConfiguredForParams(async: { $0() }, params: params, synchronousLoads: false, previousItem: nil, nextItem: nil, completion: { node, apply in + itemNodeValue = node + apply().1(ListViewItemApply(isOnScreen: true)) + }) + itemNode = itemNodeValue as! ItemListPeerItemNode + itemNode.isUserInteractionEnabled = false + self.itemNode = itemNode + self.addSubnode(itemNode) + } + + let height = itemNode.contentSize.height + + transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(), size: itemNode.bounds.size)) + + let highlightNodeOffset: CGFloat = topItem == nil ? 0.0 : UIScreenPixel + self.selectionNode.update(size: CGSize(width: width, height: height + highlightNodeOffset), theme: presentationData.theme, transition: transition) + transition.updateFrame(node: self.selectionNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -highlightNodeOffset), size: CGSize(width: width, height: height + highlightNodeOffset))) + + transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: sideInset, y: height - UIScreenPixel), size: CGSize(width: width - sideInset, height: UIScreenPixel))) + transition.updateAlpha(node: self.bottomSeparatorNode, alpha: bottomItem == nil ? 0.0 : 1.0) + + return height + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoMembersPane.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoMembersPane.swift new file mode 100644 index 0000000000..243a95f6a9 --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoMembersPane.swift @@ -0,0 +1,196 @@ +import AsyncDisplayKit +import Display +import TelegramCore +import SyncCore +import SwiftSignalKit +import Postbox +import TelegramPresentationData +import AccountContext +import ContextUI +import PhotoResources +import TelegramUIPreferences +import ItemListPeerItem +import MergeLists +import ItemListUI + +private struct PeerMembersListTransaction { + let deletions: [ListViewDeleteItem] + let insertions: [ListViewInsertItem] + let updates: [ListViewUpdateItem] +} + +private struct PeerMembersListEntry: Comparable, Identifiable { + var index: Int + var member: PeerInfoMember + + var stableId: PeerId { + return self.member.id + } + + static func ==(lhs: PeerMembersListEntry, rhs: PeerMembersListEntry) -> Bool { + return lhs.member == rhs.member + } + + static func <(lhs: PeerMembersListEntry, rhs: PeerMembersListEntry) -> Bool { + return lhs.index < rhs.index + } + + func item(context: AccountContext, presentationData: PresentationData, openPeer: @escaping (Peer) -> Void) -> ListViewItem { + let member = self.member + return ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: context, peer: member.peer, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: nil, enabled: true, selectable: true, sectionId: 0, action: { + openPeer(member.peer) + }, setPeerIdWithRevealedOptions: { _, _ in + }, removePeer: { _ in + }, contextAction: nil/*{ node, gesture in + openPeerContextAction(peer, node, gesture) + }*/, hasTopStripe: false, noInsets: true) + } +} + +private func preparedTransition(from fromEntries: [PeerMembersListEntry], to toEntries: [PeerMembersListEntry], context: AccountContext, presentationData: PresentationData, openPeer: @escaping (Peer) -> Void) -> PeerMembersListTransaction { + 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(context: context, presentationData: presentationData, openPeer: openPeer), directionHint: nil) } + let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, openPeer: openPeer), directionHint: nil) } + + return PeerMembersListTransaction(deletions: deletions, insertions: insertions, updates: updates) +} + +final class PeerInfoMembersPaneNode: ASDisplayNode, PeerInfoPaneNode { + private let context: AccountContext + private let membersContext: PeerInfoMembersContext + + private let listNode: ListView + private var currentEntries: [PeerMembersListEntry] = [] + private var currentState: PeerInfoMembersState? + private var canLoadMore: Bool = false + private var enqueuedTransactions: [PeerMembersListTransaction] = [] + + private var currentParams: (size: CGSize, isScrollingLockedAtTop: Bool, presentationData: PresentationData)? + + private let ready = Promise() + private var didSetReady: Bool = false + var isReady: Signal { + return self.ready.get() + } + + private var disposable: Disposable? + + init(context: AccountContext, membersContext: PeerInfoMembersContext) { + self.context = context + self.membersContext = membersContext + + self.listNode = ListView() + + super.init() + + self.listNode.preloadPages = true + self.addSubnode(self.listNode) + + self.disposable = (membersContext.state + |> deliverOnMainQueue).start(next: { [weak self] state in + guard let strongSelf = self else { + return + } + strongSelf.currentState = state + if let (_, _, presentationData) = strongSelf.currentParams { + strongSelf.updateState(state: state, presentationData: presentationData) + } + }) + + self.listNode.visibleBottomContentOffsetChanged = { [weak self] offset in + guard let strongSelf = self, let state = strongSelf.currentState, case .ready(true) = state.dataState else { + return + } + if case let .known(value) = offset, value < 100.0 { + strongSelf.membersContext.loadMore() + } + } + } + + deinit { + } + + func scrollToTop() -> Bool { + if !self.listNode.scrollToOffsetFromTop(0.0) { + self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Spring(duration: 0.4), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) + return true + } else { + return false + } + } + + func update(size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition) { + let isFirstLayout = self.currentParams == nil + self.currentParams = (size, isScrollingLockedAtTop, presentationData) + + transition.updateFrame(node: self.listNode, frame: CGRect(origin: CGPoint(), size: size)) + let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition) + + self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: size, insets: UIEdgeInsets(top: 0.0, left: sideInset, bottom: bottomInset, right: sideInset), duration: duration, curve: curve), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) + + self.listNode.scrollEnabled = !isScrollingLockedAtTop + + if isFirstLayout, let state = self.currentState { + self.updateState(state: state, presentationData: presentationData) + } + } + + private func updateState(state: PeerInfoMembersState, presentationData: PresentationData) { + var entries: [PeerMembersListEntry] = [] + for member in state.members { + entries.append(PeerMembersListEntry(index: entries.count, member: member)) + } + let transaction = preparedTransition(from: self.currentEntries, to: entries, context: self.context, presentationData: presentationData, openPeer: { [weak self] peer in + + }) + self.currentEntries = entries + self.enqueuedTransactions.append(transaction) + self.dequeueTransaction() + } + + private func dequeueTransaction() { + guard let (layout, _, _) = self.currentParams, let transaction = self.enqueuedTransactions.first else { + return + } + + self.enqueuedTransactions.remove(at: 0) + + var options = ListViewDeleteAndInsertOptions() + options.insert(.Synchronous) + + self.listNode.transaction(deleteIndices: transaction.deletions, insertIndicesAndItems: transaction.insertions, updateIndicesAndItems: transaction.updates, options: options, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { [weak self] _ in + guard let strongSelf = self else { + return + } + if !strongSelf.didSetReady { + strongSelf.didSetReady = true + strongSelf.ready.set(.single(true)) + } + }) + } + + func findLoadedMessage(id: MessageId) -> Message? { + return nil + } + + func updateHiddenMedia() { + } + + func transferVelocity(_ velocity: CGFloat) { + if velocity > 0.0 { + self.listNode.transferVelocity(velocity) + } + } + + func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { + return nil + } + + func addToTransitionSurface(view: UIView) { + } + + func updateSelectedMessages(animated: Bool) { + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift index a68b93dc2c..09bbdafd90 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift @@ -64,6 +64,7 @@ final class PeerInfoScreenData { let availablePanes: [PeerInfoPaneKey] let groupsInCommon: [Peer]? let linkedDiscussionPeer: Peer? + let members: PeerInfoMembersData? init( peer: Peer?, @@ -74,7 +75,8 @@ final class PeerInfoScreenData { isContact: Bool, availablePanes: [PeerInfoPaneKey], groupsInCommon: [Peer]?, - linkedDiscussionPeer: Peer? + linkedDiscussionPeer: Peer?, + members: PeerInfoMembersData? ) { self.peer = peer self.cachedData = cachedData @@ -85,6 +87,7 @@ final class PeerInfoScreenData { self.availablePanes = availablePanes self.groupsInCommon = groupsInCommon self.linkedDiscussionPeer = linkedDiscussionPeer + self.members = members } } @@ -98,7 +101,7 @@ enum PeerInfoScreenInputData: Equatable { case none case user(userId: PeerId, secretChatId: PeerId?, kind: PeerInfoScreenInputUserKind) case channel - case group(isSupergroup: Bool) + case group(isSupergroup: Bool, membersContext: PeerInfoMembersContext) } func peerInfoAvailableMediaPanes(context: AccountContext, peerId: PeerId) -> Signal<[PeerInfoPaneKey], NoError> { @@ -144,6 +147,11 @@ struct PeerInfoStatusData: Equatable { var isActivity: Bool } +enum PeerInfoMembersData: Equatable { + case shortList([PeerInfoMember]) + case longList(PeerInfoMembersContext) +} + func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) -> Signal { return context.account.postbox.combinedView(keys: [.basicPeer(peerId)]) |> map { view -> PeerInfoScreenInputData in @@ -162,12 +170,12 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen return .user(userId: user.id, secretChatId: nil, kind: kind) } else if let channel = peer as? TelegramChannel { if case .group = channel.info { - return .group(isSupergroup: true) + return .group(isSupergroup: true, membersContext: PeerInfoMembersContext(context: context, peerId: channel.id)) } else { return .channel } - } else if let _ = peer as? TelegramGroup { - return .group(isSupergroup: false) + } else if let group = peer as? TelegramGroup { + return .group(isSupergroup: false, membersContext: PeerInfoMembersContext(context: context, peerId: group.id)) } else { return .none } @@ -185,7 +193,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen isContact: false, availablePanes: [], groupsInCommon: nil, - linkedDiscussionPeer: nil + linkedDiscussionPeer: nil, + members: nil )) case let .user(peerId, secretChatId, kind): let groupsInCommonSignal: Signal<[Peer]?, NoError> @@ -301,8 +310,14 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen } var availablePanes = availablePanes - if let groupsInCommon = groupsInCommon, !groupsInCommon.isEmpty { - availablePanes.append(.groupsInCommon) + if let groupsInCommon = groupsInCommon { + if !groupsInCommon.isEmpty { + availablePanes.append(.groupsInCommon) + } + } else if let cachedData = peerView.cachedData as? CachedUserData { + if cachedData.commonGroupCount != 0 { + availablePanes.append(.groupsInCommon) + } } return PeerInfoScreenData( @@ -314,7 +329,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen isContact: peerView.peerIsContact, availablePanes: availablePanes, groupsInCommon: groupsInCommon, - linkedDiscussionPeer: nil + linkedDiscussionPeer: nil, + members: nil ) } case .channel: @@ -362,10 +378,11 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen isContact: peerView.peerIsContact, availablePanes: availablePanes, groupsInCommon: [], - linkedDiscussionPeer: discussionPeer + linkedDiscussionPeer: discussionPeer, + members: nil ) } - case .group: + case let .group(_, membersContext): let status = context.account.viewTracker.peerView(peerId, updateData: false) |> map { peerView -> PeerInfoStatusData? in guard let channel = peerView.peers[peerId] as? TelegramChannel else { @@ -379,6 +396,16 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen } |> distinctUntilChanged + let membersData: Signal = membersContext.state + |> map { state -> PeerInfoMembersData? in + if state.members.count > 5 { + return .longList(membersContext) + } else { + return .shortList(state.members) + } + } + |> distinctUntilChanged + let globalNotificationsKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.globalNotifications])) var combinedKeys: [PostboxViewKey] = [] combinedKeys.append(globalNotificationsKey) @@ -386,9 +413,10 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen context.account.viewTracker.peerView(peerId, updateData: true), peerInfoAvailableMediaPanes(context: context, peerId: peerId), context.account.postbox.combinedView(keys: combinedKeys), - status + status, + membersData ) - |> map { peerView, availablePanes, combinedView, status -> PeerInfoScreenData in + |> map { peerView, availablePanes, combinedView, status, membersData -> PeerInfoScreenData in var globalNotificationSettings: GlobalNotificationSettings = .defaultSettings if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView { if let settings = preferencesView.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings { @@ -396,6 +424,16 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen } } + var discussionPeer: Peer? + if let linkedDiscussionPeerId = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] { + discussionPeer = peer + } + + var availablePanes = availablePanes + if let membersData = membersData, case .longList = membersData { + availablePanes.insert(.members, at: 0) + } + return PeerInfoScreenData( peer: peerView.peers[peerId], cachedData: peerView.cachedData, @@ -405,7 +443,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen isContact: peerView.peerIsContact, availablePanes: availablePanes, groupsInCommon: [], - linkedDiscussionPeer: nil + linkedDiscussionPeer: discussionPeer, + members: membersData ) } } @@ -443,31 +482,19 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?) -> [PeerInf result.append(.call) } result.append(.mute) - - if !user.isDeleted, user.botInfo == nil && !user.flags.contains(.isSupport) { - result.append(.more) - } + result.append(.more) } else if let channel = peer as? TelegramChannel { - var canEditGroupInfo = false - var canEditMembers = false - var canAddMembers = false - var isPublic = false - var isCreator = false - - isPublic = channel.username != nil - if !isPublic, let cachedChannelData = cachedData as? CachedChannelData, cachedChannelData.peerGeoLocation != nil { - isPublic = true - } - - isCreator = channel.flags.contains(.isCreator) - if channel.hasPermission(.changeInfo) { - canEditGroupInfo = true - } - if channel.hasPermission(.banMembers) { - canEditMembers = true - } - if channel.hasPermission(.inviteMembers) { - canAddMembers = true + switch channel.info { + case .broadcast: + if let cachedData = cachedData as? CachedChannelData { + if cachedData.linkedDiscussionPeerId != nil { + result.append(.discussion) + } + } + case .group: + if channel.flags.contains(.isCreator) || channel.hasPermission(.inviteMembers) { + result.append(.addMember) + } } result.append(.mute) diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift index b44399c74e..606947df54 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift @@ -16,6 +16,7 @@ import ActivityIndicator enum PeerInfoHeaderButtonKey: Hashable { case message + case discussion case call case mute case more @@ -252,7 +253,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { self.leftHighlightNode.image = generateImage(CGSize(width: 88.0, height: 1.0), contextGenerator: { size, context in context.clear(CGRect(origin: CGPoint(), size: size)) - let topColor = UIColor(rgb: 0x000000, alpha: 0.5) + let topColor = UIColor(rgb: 0x000000, alpha: 0.1) let bottomColor = UIColor(rgb: 0x000000, alpha: 0.0) var locations: [CGFloat] = [0.0, 1.0] @@ -272,7 +273,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { self.rightHighlightNode.image = generateImage(CGSize(width: 88.0, height: 1.0), contextGenerator: { size, context in context.clear(CGRect(origin: CGPoint(), size: size)) - let topColor = UIColor(rgb: 0x000000, alpha: 0.5) + let topColor = UIColor(rgb: 0x000000, alpha: 0.1) let bottomColor = UIColor(rgb: 0x000000, alpha: 0.0) var locations: [CGFloat] = [0.0, 1.0] @@ -287,8 +288,8 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { self.stripContainerNode = ASDisplayNode() self.contentNode.addSubnode(self.stripContainerNode) - self.inactiveStripImage = generateStretchableFilledCircleImage(diameter: 3.0, color: UIColor(white: 1.0, alpha: 0.2))! - self.activeStripImage = generateStretchableFilledCircleImage(diameter: 3.0, color: .white)! + self.inactiveStripImage = generateSmallHorizontalStretchableFilledCircleImage(diameter: 2.0, color: UIColor(white: 1.0, alpha: 0.2))! + self.activeStripImage = generateSmallHorizontalStretchableFilledCircleImage(diameter: 2.0, color: .white)! self.highlightContainerNode = ASDisplayNode() self.highlightContainerNode.addSubnode(self.leftHighlightNode) @@ -370,11 +371,11 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { var highlightedSide: Bool? if let point = point { if point.x < size.width * 1.0 / 5.0 { - if strongSelf.currentIndex != 0 { + if strongSelf.items.count > 1 { highlightedSide = false } } else if point.x > size.width * 4.0 / 5.0 { - if strongSelf.currentIndex < strongSelf.items.count - 1 || strongSelf.items.count > 1 { + if strongSelf.items.count > 1 { highlightedSide = true } } @@ -417,6 +418,9 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { if self.currentIndex != 0 { self.currentIndex -= 1 self.updateItems(size: size, transition: .immediate) + } else if self.items.count > 1 { + self.currentIndex = self.items.count - 1 + self.updateItems(size: size, transition: .immediate) } } else if location.x > size.width * 4.0 / 5.0 { if self.currentIndex < self.items.count - 1 { @@ -559,6 +563,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { } } + let hadOneStripNode = self.stripNodes.count == 1 if self.stripNodes.count != self.items.count { if self.stripNodes.count < self.items.count { for _ in 0 ..< self.items.count - self.stripNodes.count { @@ -591,9 +596,12 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { self.stripNodes[self.currentIndex].image = self.activeStripImage } } + if hadOneStripNode && self.stripNodes.count > 1 { + self.stripContainerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) + } let stripInset: CGFloat = 5.0 let stripSpacing: CGFloat = 4.0 - let stripWidth: CGFloat = floor((size.width - stripInset * 2.0 - stripSpacing * CGFloat(self.stripNodes.count - 1)) / CGFloat(self.stripNodes.count)) + let stripWidth: CGFloat = max(5.0, floor((size.width - stripInset * 2.0 - stripSpacing * CGFloat(self.stripNodes.count - 1)) / CGFloat(self.stripNodes.count))) var stripX: CGFloat = stripInset for i in 0 ..< self.stripNodes.count { if i == 0 && self.stripNodes.count == 1 { @@ -601,7 +609,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { } else { self.stripNodes[i].isHidden = false } - self.stripNodes[i].frame = CGRect(origin: CGPoint(x: stripX, y: 0.0), size: CGSize(width: stripWidth, height: 3.0)) + self.stripNodes[i].frame = CGRect(origin: CGPoint(x: stripX, y: 0.0), size: CGSize(width: stripWidth, height: 2.0)) stripX += stripWidth + stripSpacing } @@ -1520,7 +1528,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.controlsContainerNode, frame: CGRect(origin: CGPoint(x: -controlsClippingFrame.minX, y: -controlsClippingFrame.minY), size: CGSize(width: expandedAvatarListSize.width, height: expandedAvatarListSize.height))) transition.updateFrame(node: self.avatarListNode.listContainerNode.shadowNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: expandedAvatarListSize.width, height: navigationHeight + 20.0))) - transition.updateFrame(node: self.avatarListNode.listContainerNode.stripContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: statusBarHeight + 2.0), size: CGSize(width: expandedAvatarListSize.width, height: 3.0))) + transition.updateFrame(node: self.avatarListNode.listContainerNode.stripContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: statusBarHeight + 2.0), size: CGSize(width: expandedAvatarListSize.width, height: 2.0))) transition.updateFrame(node: self.avatarListNode.listContainerNode.highlightContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: expandedAvatarListSize.width, height: expandedAvatarListSize.height))) transition.updateAlpha(node: self.avatarListNode.listContainerNode.controlsContainerNode, alpha: self.isAvatarExpanded ? (1.0 - transitionFraction) : 0.0) @@ -1681,6 +1689,9 @@ final class PeerInfoHeaderNode: ASDisplayNode { case .message: buttonText = "Message" buttonIcon = .message + case .discussion: + buttonText = "Discussion" + buttonIcon = .message case .call: buttonText = "Call" buttonIcon = .call diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoMembers.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoMembers.swift new file mode 100644 index 0000000000..ecc921a2c0 --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoMembers.swift @@ -0,0 +1,153 @@ +import Foundation +import SwiftSignalKit +import Postbox +import SyncCore +import TelegramCore +import AccountContext +import TemporaryCachedPeerDataManager + +enum PeerInfoMember: Equatable { + case channelMember(RenderedChannelParticipant) + + var id: PeerId { + switch self { + case let .channelMember(channelMember): + return channelMember.peer.id + } + } + + var peer: Peer { + switch self { + case let .channelMember(channelMember): + return channelMember.peer + } + } + + var presence: TelegramUserPresence? { + switch self { + case let .channelMember(channelMember): + return channelMember.presences[channelMember.peer.id] as? TelegramUserPresence + } + } +} + +enum PeerInfoMembersDataState: Equatable { + case loading(isInitial: Bool) + case ready(canLoadMore: Bool) +} + +struct PeerInfoMembersState: Equatable { + var members: [PeerInfoMember] + var dataState: PeerInfoMembersDataState +} + +private final class PeerInfoMembersContextImpl { + private let queue: Queue + private let context: AccountContext + private let peerId: PeerId + + private var members: [PeerInfoMember] = [] + private var dataState: PeerInfoMembersDataState = .loading(isInitial: true) + + private let stateValue = Promise() + var state: Signal { + return self.stateValue.get() + } + private let disposable = MetaDisposable() + + private var channelMembersControl: PeerChannelMemberCategoryControl? + + init(queue: Queue, context: AccountContext, peerId: PeerId) { + self.queue = queue + self.context = context + self.peerId = peerId + + self.pushState() + + if peerId.namespace == Namespaces.Peer.CloudChannel { + let (disposable, control) = context.peerChannelMemberCategoriesContextsManager.recent(postbox: context.account.postbox, network: context.account.network, accountPeerId: context.account.peerId, peerId: peerId, updated: { [weak self] state in + queue.async { + guard let strongSelf = self else { + return + } + strongSelf.members = state.list.map(PeerInfoMember.channelMember) + switch state.loadingState { + case let .loading(initial): + strongSelf.dataState = .loading(isInitial: initial) + case let .ready(hasMore): + strongSelf.dataState = .ready(canLoadMore: hasMore) + } + strongSelf.pushState() + } + }) + self.disposable.set(disposable) + self.channelMembersControl = control + } else if peerId.namespace == Namespaces.Peer.CloudGroup { + disposable.set((context.account.postbox.peerView(id: peerId) + |> deliverOn(self.queue)).start(next: { [weak self] view in + guard let strongSelf = self, let cachedData = view.cachedData as? CachedGroupData, let participantsData = cachedData.participants else { + return + } + var members: [PeerInfoMember] = [] + for participant in participantsData.participants { + if let peer = view.peers[participant.peerId] { + + } + } + strongSelf.dataState = .ready(canLoadMore: false) + strongSelf.pushState() + })) + } else { + self.dataState = .ready(canLoadMore: false) + self.pushState() + } + } + + deinit { + self.disposable.dispose() + } + + private func pushState() { + self.stateValue.set(.single(PeerInfoMembersState(members: self.members, dataState: self.dataState))) + } + + func loadMore() { + if case .ready(true) = self.dataState, let channelMembersControl = self.channelMembersControl { + self.context.peerChannelMemberCategoriesContextsManager.loadMore(peerId: self.peerId, control: channelMembersControl) + } + } +} + +final class PeerInfoMembersContext: Equatable { + private let queue = Queue.mainQueue() + private let impl: QueueLocalObject + + var state: Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + self.impl.with { impl in + disposable.set(impl.state.start(next: { value in + subscriber.putNext(value) + })) + } + return disposable + } + } + + init(context: AccountContext, peerId: PeerId) { + let queue = self.queue + self.impl = QueueLocalObject(queue: queue, generate: { + return PeerInfoMembersContextImpl(queue: queue, context: context, peerId: peerId) + }) + } + + func loadMore() { + self.impl.with { impl in + impl.loadMore() + } + } + + static func ==(lhs: PeerInfoMembersContext, rhs: PeerInfoMembersContext) -> Bool { + return lhs === rhs + } +} diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift index 4efc5d5bcd..9eb080c548 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift @@ -51,6 +51,7 @@ enum PeerInfoPaneKey { case voice case music case groupsInCommon + case members } final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode { @@ -449,6 +450,12 @@ final class PeerInfoPaneContainerNode: ASDisplayNode { paneNode = PeerInfoListPaneNode(context: self.context, chatControllerInteraction: self.chatControllerInteraction!, peerId: self.peerId, tagMask: .music) case .groupsInCommon: paneNode = PeerInfoGroupsInCommonPaneNode(context: self.context, peerId: peerId, chatControllerInteraction: self.chatControllerInteraction!, openPeerContextAction: self.openPeerContextAction!, peers: data?.groupsInCommon ?? []) + case .members: + if case let .longList(membersContext) = data?.members { + paneNode = PeerInfoMembersPaneNode(context: self.context, membersContext: membersContext) + } else { + preconditionFailure() + } } let disposable = MetaDisposable() @@ -533,6 +540,8 @@ final class PeerInfoPaneContainerNode: ASDisplayNode { title = "Audio" case .groupsInCommon: title = "Groups" + case .members: + title = "Members" } return PeerInfoPaneSpecifier(key: key, title: title) }, selectedPane: self.currentPaneKey, transition: transition) diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift index 5466014007..346f706c01 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift @@ -32,6 +32,9 @@ import LegacyUI import MapResourceToAvatarSizes import LegacyComponents import WebSearchUI +import LocationResources +import LocationUI +import Geocoding protocol PeerInfoScreenItem: class { var id: AnyHashable { get } @@ -47,8 +50,6 @@ class PeerInfoScreenItemNode: ASDisplayNode { } private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { - let id: AnyHashable - private let backgroundNode: ASDisplayNode private let topSeparatorNode: ASDisplayNode private let bottomSeparatorNode: ASDisplayNode @@ -56,9 +57,7 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { private var currentItems: [PeerInfoScreenItem] = [] private var itemNodes: [AnyHashable: PeerInfoScreenItemNode] = [:] - init(id: AnyHashable) { - self.id = id - + override init() { self.backgroundNode = ASDisplayNode() self.backgroundNode.isLayerBacked = true @@ -82,6 +81,7 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { var contentHeight: CGFloat = 0.0 var contentWithBackgroundHeight: CGFloat = 0.0 + var contentWithBackgroundOffset: CGFloat = 0.0 for i in 0 ..< items.count { let item = items[i] @@ -105,6 +105,15 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { let itemTransition: ContainedViewLayoutTransition = wasAdded ? .immediate : transition + let topItem: PeerInfoScreenItem? + if i == 0 { + topItem = nil + } else if items[i - 1] is PeerInfoScreenHeaderItem { + topItem = nil + } else { + topItem = items[i - 1] + } + let bottomItem: PeerInfoScreenItem? if i == items.count - 1 { bottomItem = nil @@ -114,7 +123,7 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { bottomItem = items[i + 1] } - let itemHeight = itemNode.update(width: width, presentationData: presentationData, item: item, topItem: i == 0 ? nil : items[i - 1], bottomItem: bottomItem, transition: itemTransition) + let itemHeight = itemNode.update(width: width, presentationData: presentationData, item: item, topItem: topItem, bottomItem: bottomItem, transition: itemTransition) let itemFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: itemHeight)) itemTransition.updateFrame(node: itemNode, frame: itemFrame) if wasAdded { @@ -123,11 +132,14 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { } if item is PeerInfoScreenCommentItem { - } else { contentWithBackgroundHeight += itemHeight } contentHeight += itemHeight + + if item is PeerInfoScreenHeaderItem { + contentWithBackgroundOffset = contentHeight + } } var removeIds: [AnyHashable] = [] @@ -144,8 +156,8 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { } } - transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: contentWithBackgroundHeight))) - transition.updateFrame(node: self.topSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel))) + transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentWithBackgroundOffset), size: CGSize(width: width, height: max(0.0, contentWithBackgroundHeight - contentWithBackgroundOffset)))) + transition.updateFrame(node: self.topSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentWithBackgroundOffset - UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel))) transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentWithBackgroundHeight), size: CGSize(width: width, height: UIScreenPixel))) if contentHeight.isZero { @@ -160,6 +172,133 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { } } +private final class PeerInfoScreenDynamicItemSectionContainerNode: ASDisplayNode { + private let backgroundNode: ASDisplayNode + private let topSeparatorNode: ASDisplayNode + private let bottomSeparatorNode: ASDisplayNode + + private var currentItems: [PeerInfoScreenItem] = [] + private var itemNodes: [AnyHashable: PeerInfoScreenItemNode] = [:] + + override init() { + self.backgroundNode = ASDisplayNode() + self.backgroundNode.isLayerBacked = true + + self.topSeparatorNode = ASDisplayNode() + self.topSeparatorNode.isLayerBacked = true + + self.bottomSeparatorNode = ASDisplayNode() + self.bottomSeparatorNode.isLayerBacked = true + + super.init() + + self.addSubnode(self.backgroundNode) + self.addSubnode(self.topSeparatorNode) + self.addSubnode(self.bottomSeparatorNode) + } + + func update(width: CGFloat, presentationData: PresentationData, items: [PeerInfoScreenItem], transition: ContainedViewLayoutTransition) -> CGFloat { + self.backgroundNode.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor + self.topSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + + var contentHeight: CGFloat = 0.0 + var contentWithBackgroundHeight: CGFloat = 0.0 + var contentWithBackgroundOffset: CGFloat = 0.0 + + for i in 0 ..< items.count { + let item = items[i] + + let itemNode: PeerInfoScreenItemNode + var wasAdded = false + if let current = self.itemNodes[item.id] { + itemNode = current + } else { + wasAdded = true + itemNode = item.node() + self.itemNodes[item.id] = itemNode + self.addSubnode(itemNode) + itemNode.bringToFrontForHighlight = { [weak self, weak itemNode] in + guard let strongSelf = self, let itemNode = itemNode else { + return + } + strongSelf.view.bringSubviewToFront(itemNode.view) + } + } + + let itemTransition: ContainedViewLayoutTransition = wasAdded ? .immediate : transition + + let topItem: PeerInfoScreenItem? + if i == 0 { + topItem = nil + } else if items[i - 1] is PeerInfoScreenHeaderItem { + topItem = nil + } else { + topItem = items[i - 1] + } + + let bottomItem: PeerInfoScreenItem? + if i == items.count - 1 { + bottomItem = nil + } else if items[i + 1] is PeerInfoScreenCommentItem { + bottomItem = nil + } else { + bottomItem = items[i + 1] + } + + let itemHeight = itemNode.update(width: width, presentationData: presentationData, item: item, topItem: topItem, bottomItem: bottomItem, transition: itemTransition) + let itemFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: width, height: itemHeight)) + itemTransition.updateFrame(node: itemNode, frame: itemFrame) + if wasAdded { + itemNode.alpha = 0.0 + transition.updateAlpha(node: itemNode, alpha: 1.0) + } + + if item is PeerInfoScreenCommentItem { + } else { + contentWithBackgroundHeight += itemHeight + } + contentHeight += itemHeight + + if item is PeerInfoScreenHeaderItem { + contentWithBackgroundOffset = contentHeight + } + } + + var removeIds: [AnyHashable] = [] + for (id, _) in self.itemNodes { + if !items.contains(where: { $0.id == id }) { + removeIds.append(id) + } + } + for id in removeIds { + if let itemNode = self.itemNodes.removeValue(forKey: id) { + transition.updateAlpha(node: itemNode, alpha: 0.0, completion: { [weak itemNode] _ in + itemNode?.removeFromSupernode() + }) + } + } + + transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentWithBackgroundOffset), size: CGSize(width: width, height: max(0.0, contentWithBackgroundHeight - contentWithBackgroundOffset)))) + transition.updateFrame(node: self.topSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentWithBackgroundOffset - UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel))) + transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentWithBackgroundHeight), size: CGSize(width: width, height: UIScreenPixel))) + + if contentHeight.isZero { + transition.updateAlpha(node: self.topSeparatorNode, alpha: 0.0) + transition.updateAlpha(node: self.bottomSeparatorNode, alpha: 0.0) + } else { + transition.updateAlpha(node: self.topSeparatorNode, alpha: 1.0) + transition.updateAlpha(node: self.bottomSeparatorNode, alpha: 1.0) + } + + return contentHeight + } + + func updateVisibleItems(in rect: CGRect) { + + } +} + final class PeerInfoSelectionPanelNode: ASDisplayNode { private let context: AccountContext private let peerId: PeerId @@ -323,6 +462,12 @@ private final class PeerInfoInteraction { let editingOpenDiscussionGroupSetup: () -> Void let editingToggleMessageSignatures: (Bool) -> Void let openParticipantsSection: (PeerInfoParticipantsSection) -> Void + let editingOpenPreHistorySetup: () -> Void + let openPermissions: () -> Void + let editingOpenStickerPackSetup: () -> Void + let openLocation: () -> Void + let editingOpenSetupLocation: () -> Void + let openPeerInfo: (Peer) -> Void init( openUsername: @escaping (String) -> Void, @@ -340,7 +485,13 @@ private final class PeerInfoInteraction { editingOpenPublicLinkSetup: @escaping () -> Void, editingOpenDiscussionGroupSetup: @escaping () -> Void, editingToggleMessageSignatures: @escaping (Bool) -> Void, - openParticipantsSection: @escaping (PeerInfoParticipantsSection) -> Void + openParticipantsSection: @escaping (PeerInfoParticipantsSection) -> Void, + editingOpenPreHistorySetup: @escaping () -> Void, + openPermissions: @escaping () -> Void, + editingOpenStickerPackSetup: @escaping () -> Void, + openLocation: @escaping () -> Void, + editingOpenSetupLocation: @escaping () -> Void, + openPeerInfo: @escaping (Peer) -> Void ) { self.openUsername = openUsername self.openPhone = openPhone @@ -358,52 +509,71 @@ private final class PeerInfoInteraction { self.editingOpenDiscussionGroupSetup = editingOpenDiscussionGroupSetup self.editingToggleMessageSignatures = editingToggleMessageSignatures self.openParticipantsSection = openParticipantsSection + self.editingOpenPreHistorySetup = editingOpenPreHistorySetup + self.openPermissions = openPermissions + self.editingOpenStickerPackSetup = editingOpenStickerPackSetup + self.openLocation = openLocation + self.editingOpenSetupLocation = editingOpenSetupLocation + self.openPeerInfo = openPeerInfo } } -private func peerInfoSectionItems(data: PeerInfoScreenData?, presentationData: PresentationData, interaction: PeerInfoInteraction) -> [PeerInfoScreenItem] { +private func infoItems(data: PeerInfoScreenData?, context: AccountContext, presentationData: PresentationData, interaction: PeerInfoInteraction) -> [(AnyHashable, [PeerInfoScreenItem])] { guard let data = data else { return [] } - var items: [PeerInfoScreenItem] = [] + + enum Section: Int, CaseIterable { + case groupLocation + case peerInfo + case peerMembers + } + + var items: [Section: [PeerInfoScreenItem]] = [:] + for section in Section.allCases { + items[section] = [] + } + if let user = data.peer as? TelegramUser { if let phone = user.phone { - items.append(PeerInfoScreenLabeledValueItem(id: 2, label: "mobile", text: "\(formatPhoneNumber(phone))", textColor: .accent, action: { + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 2, label: "mobile", text: "\(formatPhoneNumber(phone))", textColor: .accent, action: { interaction.openPhone(phone) })) } if let username = user.username { - items.append(PeerInfoScreenLabeledValueItem(id: 1, label: "username", text: "@\(username)", textColor: .accent, action: { + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 1, label: "username", text: "@\(username)", textColor: .accent, action: { interaction.openUsername(username) })) } if let cachedData = data.cachedData as? CachedUserData { - if let about = cachedData.about { - items.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) + if user.isScam { + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: user.botInfo != nil ? presentationData.strings.UserInfo_ScamBotWarning : presentationData.strings.UserInfo_ScamUserWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) + } else if let about = cachedData.about, !about.isEmpty { + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) } } if !data.isContact { if user.botInfo == nil { - items.append(PeerInfoScreenActionItem(id: 3, text: "Add Contact", action: { + items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 3, text: "Add Contact", action: { interaction.openAddContact() })) } if let cachedData = data.cachedData as? CachedUserData { if cachedData.isBlocked { - items.append(PeerInfoScreenActionItem(id: 4, text: user.botInfo != nil ? "Restart Bot" : "Unblock", action: { + items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 4, text: user.botInfo != nil ? "Restart Bot" : "Unblock", action: { interaction.updateBlocked(false) })) } else { if user.flags.contains(.isSupport) { } else { - items.append(PeerInfoScreenActionItem(id: 4, text: user.botInfo != nil ? "Stop Bot" : "Block User", color: .destructive, action: { + items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 4, text: user.botInfo != nil ? "Stop Bot" : "Block User", color: .destructive, action: { interaction.updateBlocked(true) })) } } } if user.botInfo != nil, !user.isVerified { - items.append(PeerInfoScreenActionItem(id: 5, text: presentationData.strings.ReportPeer_Report, action: { + items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 5, text: presentationData.strings.ReportPeer_Report, action: { interaction.openReport() })) } @@ -415,15 +585,34 @@ private func peerInfoSectionItems(data: PeerInfoScreenData?, presentationData: P let ItemMembers = 4 let ItemBanned = 5 let ItemReport = 6 + let ItemLocationHeader = 7 + let ItemLocation = 8 + + if let location = (data.cachedData as? CachedChannelData)?.peerGeoLocation { + items[.groupLocation]!.append(PeerInfoScreenHeaderItem(id: ItemLocationHeader, text: presentationData.strings.GroupInfo_Location.uppercased())) + + let imageSignal = chatMapSnapshotImage(account: context.account, resource: MapSnapshotMediaResource(latitude: location.latitude, longitude: location.longitude, width: 90, height: 90)) + items[.groupLocation]!.append(PeerInfoScreenAddressItem( + id: ItemLocation, + label: "", + text: location.address.replacingOccurrences(of: ", ", with: "\n"), + imageSignal: imageSignal, + action: { + interaction.openLocation() + } + )) + } if let username = channel.username { - items.append(PeerInfoScreenLabeledValueItem(id: ItemUsername, label: presentationData.strings.Channel_LinkItem, text: "https://t.me/\(username)", textColor: .accent, action: { + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemUsername, label: presentationData.strings.Channel_LinkItem, text: "https://t.me/\(username)", textColor: .accent, action: { interaction.openUsername(username) })) } if let cachedData = data.cachedData as? CachedChannelData { - if let about = cachedData.about { - items.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Profile_About, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) + if channel.isScam { + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Profile_About, text: presentationData.strings.GroupInfo_ScamGroupWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) + } else if let about = cachedData.about, !about.isEmpty { + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Profile_About, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) } if case .broadcast = channel.info { @@ -437,13 +626,13 @@ private func peerInfoSectionItems(data: PeerInfoScreenData?, presentationData: P let memberCount = cachedData.participantsSummary.memberCount ?? 0 let bannedCount = cachedData.participantsSummary.kickedCount ?? 0 - items.append(PeerInfoScreenDisclosureItem(id: ItemAdmins, label: "\(adminCount == 0 ? "" : "\(presentationStringsFormattedNumber(adminCount, presentationData.dateTimeFormat.groupingSeparator))")", text: presentationData.strings.GroupInfo_Administrators, action: { + items[.peerInfo]!.append(PeerInfoScreenDisclosureItem(id: ItemAdmins, label: "\(adminCount == 0 ? "" : "\(presentationStringsFormattedNumber(adminCount, presentationData.dateTimeFormat.groupingSeparator))")", text: presentationData.strings.GroupInfo_Administrators, action: { interaction.openParticipantsSection(.admins) })) - items.append(PeerInfoScreenDisclosureItem(id: ItemMembers, label: "\(memberCount == 0 ? "" : "\(presentationStringsFormattedNumber(memberCount, presentationData.dateTimeFormat.groupingSeparator))")", text: presentationData.strings.Channel_Info_Subscribers, action: { + items[.peerInfo]!.append(PeerInfoScreenDisclosureItem(id: ItemMembers, label: "\(memberCount == 0 ? "" : "\(presentationStringsFormattedNumber(memberCount, presentationData.dateTimeFormat.groupingSeparator))")", text: presentationData.strings.Channel_Info_Subscribers, action: { interaction.openParticipantsSection(.members) })) - items.append(PeerInfoScreenDisclosureItem(id: ItemBanned, label: "\(bannedCount == 0 ? "" : "\(presentationStringsFormattedNumber(bannedCount, presentationData.dateTimeFormat.groupingSeparator))")", text: presentationData.strings.GroupInfo_Permissions_Removed, action: { + items[.peerInfo]!.append(PeerInfoScreenDisclosureItem(id: ItemBanned, label: "\(bannedCount == 0 ? "" : "\(presentationStringsFormattedNumber(bannedCount, presentationData.dateTimeFormat.groupingSeparator))")", text: presentationData.strings.GroupInfo_Permissions_Removed, action: { interaction.openParticipantsSection(.banned) })) } @@ -452,21 +641,49 @@ private func peerInfoSectionItems(data: PeerInfoScreenData?, presentationData: P } } else if let group = data.peer as? TelegramGroup { if let cachedData = data.cachedData as? CachedGroupData { - if let about = cachedData.about { - items.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) + if group.isScam { + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: presentationData.strings.GroupInfo_ScamGroupWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) + } else if let about = cachedData.about, !about.isEmpty { + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) } } } - return items + + if let members = data.members, case let .shortList(memberList) = members { + for member in memberList { + var presence = member.presence + if member.id == context.account.peerId { + presence = TelegramUserPresence(status: .present(until: Int32.max - 1), lastActivity: 0) + } + items[.peerMembers]!.append(PeerInfoScreenMemberItem(id: member.id, context: context, peer: member.peer, presence: presence, action: { + interaction.openPeerInfo(member.peer) + })) + } + } + + var result: [(AnyHashable, [PeerInfoScreenItem])] = [] + for section in Section.allCases { + if let sectionItems = items[section], !sectionItems.isEmpty { + result.append((section, sectionItems)) + } + } + return result } -private func editingInfoSectionItems(data: PeerInfoScreenData?, presentationData: PresentationData, interaction: PeerInfoInteraction) -> [PeerInfoScreenItem] { - guard let data = data else { - return [] +private func editingItems(data: PeerInfoScreenData?, context: AccountContext, presentationData: PresentationData, interaction: PeerInfoInteraction) -> [(AnyHashable, [PeerInfoScreenItem])] { + enum Section: Int, CaseIterable { + case notifications + case groupLocation + case peerPublicSettings + case peerSettings } - var items: [PeerInfoScreenItem] = [] - if let notificationSettings = data.notificationSettings { + var items: [Section: [PeerInfoScreenItem]] = [:] + for section in Section.allCases { + items[section] = [] + } + + if let data = data, let notificationSettings = data.notificationSettings { let notificationsLabel: String let soundLabel: String let notificationSettings = notificationSettings as? TelegramPeerNotificationSettings ?? TelegramPeerNotificationSettings.defaultSettings @@ -483,82 +700,230 @@ private func editingInfoSectionItems(data: PeerInfoScreenData?, presentationData let globalNotificationSettings: GlobalNotificationSettings = data.globalNotificationSettings ?? GlobalNotificationSettings.defaultSettings soundLabel = localizedPeerNotificationSoundString(strings: presentationData.strings, sound: notificationSettings.messageSound, default: globalNotificationSettings.effective.privateChats.sound) - items.append(PeerInfoScreenDisclosureItem(id: 0, label: notificationsLabel, text: "Notifications", action: { + items[.notifications]!.append(PeerInfoScreenDisclosureItem(id: 0, label: notificationsLabel, text: "Notifications", action: { interaction.editingOpenNotificationSettings() })) - items.append(PeerInfoScreenDisclosureItem(id: 1, label: soundLabel, text: "Sound", action: { + items[.notifications]!.append(PeerInfoScreenDisclosureItem(id: 1, label: soundLabel, text: "Sound", action: { interaction.editingOpenSoundSettings() })) - items.append(PeerInfoScreenSwitchItem(id: 2, text: "Show Message Text", value: notificationSettings.displayPreviews != .hide, toggled: { value in + items[.notifications]!.append(PeerInfoScreenSwitchItem(id: 2, text: "Show Message Text", value: notificationSettings.displayPreviews != .hide, toggled: { value in interaction.editingToggleShowMessageText(value) })) } - return items -} - -private func editingActionsSectionItems(data: PeerInfoScreenData?, presentationData: PresentationData, interaction: PeerInfoInteraction) -> [PeerInfoScreenItem] { - var items: [PeerInfoScreenItem] = [] if let data = data { if let user = data.peer as? TelegramUser { + let ItemDelete = 0 if data.isContact { - items.append(PeerInfoScreenActionItem(id: 0, text: presentationData.strings.UserInfo_DeleteContact, color: .destructive, action: { + items[.peerSettings]!.append(PeerInfoScreenActionItem(id: ItemDelete, text: presentationData.strings.UserInfo_DeleteContact, color: .destructive, action: { interaction.requestDeleteContact() })) } } else if let channel = data.peer as? TelegramChannel { - if channel.flags.contains(.isCreator) { - let linkText: String - if let username = channel.username { - linkText = "@\(username)" - } else { - linkText = presentationData.strings.Channel_Setup_TypePrivate - } - items.append(PeerInfoScreenDisclosureItem(id: 1, label: linkText, text: presentationData.strings.Channel_TypeSetup_Title, action: { - interaction.editingOpenPublicLinkSetup() - })) - - let discussionGroupTitle: String - if let cachedData = data.cachedData as? CachedChannelData { - if let peer = data.linkedDiscussionPeer { - if let addressName = peer.addressName, !addressName.isEmpty { - discussionGroupTitle = "@\(addressName)" + let ItemUsername = 1 + let ItemDiscussionGroup = 2 + let ItemSignMessages = 3 + let ItemSignMessagesHelp = 4 + + switch channel.info { + case .broadcast: + if channel.flags.contains(.isCreator) { + let linkText: String + if let username = channel.username { + linkText = "@\(username)" + } else { + linkText = presentationData.strings.Channel_Setup_TypePrivate + } + items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemUsername, label: linkText, text: presentationData.strings.Channel_TypeSetup_Title, action: { + interaction.editingOpenPublicLinkSetup() + })) + + let discussionGroupTitle: String + if let cachedData = data.cachedData as? CachedChannelData { + if let peer = data.linkedDiscussionPeer { + if let addressName = peer.addressName, !addressName.isEmpty { + discussionGroupTitle = "@\(addressName)" + } else { + discussionGroupTitle = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + } } else { - discussionGroupTitle = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + discussionGroupTitle = presentationData.strings.Channel_DiscussionGroupAdd } } else { - discussionGroupTitle = presentationData.strings.Channel_DiscussionGroupAdd + discussionGroupTitle = "..." } - } else { - discussionGroupTitle = "..." + + items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemDiscussionGroup, label: discussionGroupTitle, text: presentationData.strings.Channel_DiscussionGroup, action: { + interaction.editingOpenDiscussionGroupSetup() + })) + + let messagesShouldHaveSignatures: Bool + switch channel.info { + case let .broadcast(info): + messagesShouldHaveSignatures = info.flags.contains(.messagesShouldHaveSignatures) + default: + messagesShouldHaveSignatures = false + } + items[.peerSettings]!.append(PeerInfoScreenSwitchItem(id: ItemSignMessages, text: presentationData.strings.Channel_SignMessages, value: messagesShouldHaveSignatures, toggled: { value in + interaction.editingToggleMessageSignatures(value) + })) + items[.peerSettings]!.append(PeerInfoScreenCommentItem(id: ItemSignMessagesHelp, text: presentationData.strings.Channel_SignMessages_Help)) } + case .group: + let ItemUsername = 1 + let ItemLinkedChannel = 2 + let ItemPreHistory = 3 + let ItemStickerPack = 4 + let ItemPermissions = 5 + let ItemAdmins = 6 + let ItemLocationHeader = 7 + let ItemLocation = 8 + let ItemLocationSetup = 9 - items.append(PeerInfoScreenDisclosureItem(id: 2, label: discussionGroupTitle, text: presentationData.strings.Channel_DiscussionGroup, action: { - interaction.editingOpenDiscussionGroupSetup() - })) - //items.append(PeerInfoScreenCommentItem(id: 3, text: presentationData.strings.Channel_DiscussionGroupInfo)) + let isCreator = channel.flags.contains(.isCreator) + let isPublic = channel.username != nil - let messagesShouldHaveSignatures: Bool - switch channel.info { - case let .broadcast(info): - messagesShouldHaveSignatures = info.flags.contains(.messagesShouldHaveSignatures) - default: - messagesShouldHaveSignatures = false + if let cachedData = data.cachedData as? CachedChannelData { + if isCreator, let location = cachedData.peerGeoLocation { + items[.groupLocation]!.append(PeerInfoScreenHeaderItem(id: ItemLocationHeader, text: presentationData.strings.GroupInfo_Location.uppercased())) + + let imageSignal = chatMapSnapshotImage(account: context.account, resource: MapSnapshotMediaResource(latitude: location.latitude, longitude: location.longitude, width: 90, height: 90)) + items[.groupLocation]!.append(PeerInfoScreenAddressItem( + id: ItemLocation, + label: "", + text: location.address.replacingOccurrences(of: ", ", with: "\n"), + imageSignal: imageSignal, + action: { + interaction.openLocation() + } + )) + if cachedData.flags.contains(.canChangePeerGeoLocation) { + items[.groupLocation]!.append(PeerInfoScreenActionItem(id: ItemLocationSetup, text: presentationData.strings.Group_Location_ChangeLocation, action: { + interaction.editingOpenSetupLocation() + })) + } + } + + if isCreator || (channel.adminRights != nil && channel.hasPermission(.pinMessages)) { + if cachedData.peerGeoLocation != nil { + if isCreator { + let linkText: String + if let username = channel.username { + linkText = "@\(username)" + } else { + linkText = presentationData.strings.GroupInfo_PublicLinkAdd + } + items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemUsername, label: linkText, text: presentationData.strings.GroupInfo_PublicLink, action: { + interaction.editingOpenPublicLinkSetup() + })) + } + } else { + if cachedData.flags.contains(.canChangeUsername) { + items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemUsername, label: isPublic ? presentationData.strings.Channel_Setup_TypePublic : presentationData.strings.Channel_Setup_TypePrivate, text: presentationData.strings.GroupInfo_GroupType, action: { + interaction.editingOpenPublicLinkSetup() + })) + + if let linkedDiscussionPeer = data.linkedDiscussionPeer { + let peerTitle: String + if let addressName = linkedDiscussionPeer.addressName, !addressName.isEmpty { + peerTitle = "@\(addressName)" + } else { + peerTitle = linkedDiscussionPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + } + items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemLinkedChannel, label: peerTitle, text: presentationData.strings.Group_LinkedChannel, action: { + interaction.editingOpenDiscussionGroupSetup() + })) + } + } + if !isPublic && cachedData.linkedDiscussionPeerId == nil { + items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPreHistory, label: cachedData.flags.contains(.preHistoryEnabled) ? presentationData.strings.GroupInfo_GroupHistoryVisible : presentationData.strings.GroupInfo_GroupHistoryHidden, text: presentationData.strings.GroupInfo_GroupHistory, action: { + interaction.editingOpenPreHistorySetup() + })) + } + } + } + + if cachedData.flags.contains(.canSetStickerSet) && canEditPeerInfo(peer: channel) { + items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemStickerPack, label: cachedData.stickerPack?.title ?? presentationData.strings.GroupInfo_SharedMediaNone, text: presentationData.strings.Stickers_GroupStickers, action: { + interaction.editingOpenStickerPackSetup() + })) + } + + var canViewAdminsAndBanned = false + if let adminRights = channel.adminRights, !adminRights.isEmpty { + canViewAdminsAndBanned = true + } else if channel.flags.contains(.isCreator) { + canViewAdminsAndBanned = true + } + + if canViewAdminsAndBanned { + var activePermissionCount: Int? + if let defaultBannedRights = channel.defaultBannedRights { + var count = 0 + for (right, _) in allGroupPermissionList { + if !defaultBannedRights.flags.contains(right) { + count += 1 + } + } + activePermissionCount = count + } + + items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPermissions, label: activePermissionCount.flatMap({ "\($0)/\(allGroupPermissionList.count)" }) ?? "", text: presentationData.strings.GroupInfo_Permissions, action: { + interaction.openPermissions() + })) + + items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemAdmins, label: cachedData.participantsSummary.adminCount.flatMap { "\(presentationStringsFormattedNumber($0, presentationData.dateTimeFormat.groupingSeparator))" } ?? "", text: presentationData.strings.GroupInfo_Administrators, action: { + interaction.openParticipantsSection(.admins) + })) + } } - items.append(PeerInfoScreenSwitchItem(id: 4, text: presentationData.strings.Channel_SignMessages, value: messagesShouldHaveSignatures, toggled: { value in - interaction.editingToggleMessageSignatures(value) - })) - items.append(PeerInfoScreenCommentItem(id: 5, text: presentationData.strings.Channel_SignMessages_Help)) } } else if let group = data.peer as? TelegramGroup { + let ItemUsername = 1 + let ItemPreHistory = 2 + let ItemPermissions = 3 + let ItemAdmins = 4 + if case .creator = group.role { - items.append(PeerInfoScreenDisclosureItem(id: 1, label: presentationData.strings.Group_Setup_TypePrivate, text: presentationData.strings.Channel_TypeSetup_Title, action: { - interaction.editingOpenPublicLinkSetup() + if let cachedData = data.cachedData as? CachedGroupData { + if cachedData.flags.contains(.canChangeUsername) { + items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemUsername, label: presentationData.strings.Group_Setup_TypePrivate, text: presentationData.strings.GroupInfo_GroupType, action: { + interaction.editingOpenPublicLinkSetup() + })) + } + } + items[.peerPublicSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPreHistory, label: presentationData.strings.GroupInfo_GroupHistoryHidden, text: presentationData.strings.GroupInfo_GroupHistory, action: { + interaction.editingOpenPreHistorySetup() + })) + var activePermissionCount: Int? + if let defaultBannedRights = group.defaultBannedRights { + var count = 0 + for (right, _) in allGroupPermissionList { + if !defaultBannedRights.flags.contains(right) { + count += 1 + } + } + activePermissionCount = count + } + + items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPermissions, label: activePermissionCount.flatMap({ "\($0)/\(allGroupPermissionList.count)" }) ?? "", text: presentationData.strings.GroupInfo_Permissions, action: { + interaction.openPermissions() + })) + + items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemAdmins, label: "", text: presentationData.strings.GroupInfo_Administrators, action: { + interaction.openParticipantsSection(.admins) })) } } } - return items + + var result: [(AnyHashable, [PeerInfoScreenItem])] = [] + for section in Section.allCases { + if let sectionItems = items[section], !sectionItems.isEmpty { + result.append((section, sectionItems)) + } + } + return result } private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate { @@ -570,9 +935,8 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD let scrollNode: ASScrollNode let headerNode: PeerInfoHeaderNode - private let infoSection: PeerInfoScreenItemSectionContainerNode - private let editingInfoSection: PeerInfoScreenItemSectionContainerNode - private let editingActionsSection: PeerInfoScreenItemSectionContainerNode + private var regularSections: [AnyHashable: PeerInfoScreenItemSectionContainerNode] = [:] + private var editingSections: [AnyHashable: PeerInfoScreenItemSectionContainerNode] = [:] private let paneContainerNode: PeerInfoPaneContainerNode private var ignoreScrolling: Bool = false private var hapticFeedback: HapticFeedback? @@ -623,9 +987,6 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self.scrollNode.view.delaysContentTouches = false self.headerNode = PeerInfoHeaderNode(context: context, avatarInitiallyExpanded: avatarInitiallyExpanded) - self.infoSection = PeerInfoScreenItemSectionContainerNode(id: 0) - self.editingInfoSection = PeerInfoScreenItemSectionContainerNode(id: 1) - self.editingActionsSection = PeerInfoScreenItemSectionContainerNode(id: 2) self.paneContainerNode = PeerInfoPaneContainerNode(context: context, peerId: peerId) super.init() @@ -678,6 +1039,24 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }, openParticipantsSection: { [weak self] section in self?.openParticipantsSection(section: section) + }, + editingOpenPreHistorySetup: { [weak self] in + self?.editingOpenPreHistorySetup() + }, + openPermissions: { [weak self] in + self?.openPermissions() + }, + editingOpenStickerPackSetup: { [weak self] in + self?.editingOpenStickerPackSetup() + }, + openLocation: { [weak self] in + self?.openLocation() + }, + editingOpenSetupLocation: { [weak self] in + self?.editingOpenSetupLocation() + }, + openPeerInfo: { [weak self] peer in + self?.openPeerInfo(peer: peer) } ) @@ -940,6 +1319,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }) } }) + strongSelf.view.endEditing(true) strongSelf.controller?.present(actionSheet, in: .window(.root)) } else { strongSelf.context.sharedContext.applicationBindings.openUrl(url) @@ -961,6 +1341,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD actionSheet?.dismissAnimated() }) ])]) + strongSelf.view.endEditing(true) strongSelf.controller?.present(actionSheet, in: .window(.root)) default: break @@ -1017,9 +1398,6 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self.scrollNode.view.scrollsToTop = false self.scrollNode.view.delegate = self self.addSubnode(self.scrollNode) - self.scrollNode.addSubnode(self.infoSection) - self.scrollNode.addSubnode(self.editingInfoSection) - self.scrollNode.addSubnode(self.editingActionsSection) self.scrollNode.addSubnode(self.paneContainerNode) self.addSubnode(self.headerNode) @@ -1070,6 +1448,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self?.headerNode.updateAvatarIsHidden(false) } })) + strongSelf.view.endEditing(true) strongSelf.controller?.present(galleryController, in: .window(.root), with: AvatarGalleryControllerPresentationArguments(transitionArguments: { _ in return GalleryTransitionArguments(transitionNode: transitionNode, addToTransitionSurface: { _ in }) @@ -1369,6 +1748,12 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD if let navigationController = controller.navigationController as? NavigationController { self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(self.peerId))) } + case .discussion: + if let cachedData = self.data?.cachedData as? CachedChannelData, let linkedDiscussionPeerId = cachedData.linkedDiscussionPeerId { + if let navigationController = controller.navigationController as? NavigationController { + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(linkedDiscussionPeerId))) + } + } case .call: self.requestCall() case .mute: @@ -1480,26 +1865,50 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self?.openReport() })) } - if channel.flags.contains(.isCreator) { - items.append(ActionSheetButtonItem(title: presentationData.strings.ChannelInfo_DeleteChannel, color: .destructive, action: { [weak self] in - dismissAction() - self?.openDeleteChannel() - })) - } else { - if case .member = channel.participationStatus { - items.append(ActionSheetButtonItem(title: presentationData.strings.Channel_LeaveChannel, color: .destructive, action: { [weak self] in + + switch channel.info { + case .broadcast: + if channel.flags.contains(.isCreator) { + items.append(ActionSheetButtonItem(title: presentationData.strings.ChannelInfo_DeleteChannel, color: .destructive, action: { [weak self] in dismissAction() - self?.openLeaveChannel() + self?.openDeletePeer() })) + } else { + if case .member = channel.participationStatus { + items.append(ActionSheetButtonItem(title: presentationData.strings.Channel_LeaveChannel, color: .destructive, action: { [weak self] in + dismissAction() + self?.openLeavePeer() + })) + } + } + case .group: + if channel.flags.contains(.isCreator) { + items.append(ActionSheetButtonItem(title: presentationData.strings.ChannelInfo_DeleteGroup, color: .destructive, action: { [weak self] in + dismissAction() + self?.openDeletePeer() + })) + } else { + if case .member = channel.participationStatus { + items.append(ActionSheetButtonItem(title: presentationData.strings.Group_LeaveGroup, color: .destructive, action: { [weak self] in + dismissAction() + self?.openLeavePeer() + })) + } } } } else if let group = peer as? TelegramGroup { - + if case .Member = group.membership { + items.append(ActionSheetButtonItem(title: presentationData.strings.Group_LeaveGroup, color: .destructive, action: { [weak self] in + dismissAction() + self?.openLeavePeer() + })) + } } actionSheet.setItemGroups([ ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [ActionSheetButtonItem(title: self.presentationData.strings.Common_Cancel, action: { dismissAction() })]) ]) + self.view.endEditing(true) controller.present(actionSheet, in: .window(.root)) case .addMember: break @@ -1604,6 +2013,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD private func openUsername(value: String) { let shareController = ShareController(context: context, subject: .url("\(value)")) + self.view.endEditing(true) self.controller?.present(shareController, in: .window(.root)) } @@ -1669,6 +2079,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD ]), ActionSheetItemGroup(items: [ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, action: { dismissAction() })]) ]) + strongSelf.view.endEditing(true) strongSelf.controller?.present(actionSheet, in: .window(.root)) } else { strongSelf.context.sharedContext.applicationBindings.openUrl("tel:\(formatPhoneNumber(value).replacingOccurrences(of: " ", with: ""))") @@ -1710,6 +2121,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } let _ = updatePeerMuteSetting(account: strongSelf.context.account, peerId: strongSelf.peerId, muteInterval: value).start() }) + strongSelf.view.endEditing(true) strongSelf.controller?.present(muteSettingsController, in: .window(.root)) }) } @@ -1814,6 +2226,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD ]), ActionSheetItemGroup(items: [ActionSheetButtonItem(title: self.presentationData.strings.Common_Cancel, action: { dismissAction() })]) ]) + self.view.endEditing(true) self.controller?.present(actionSheet, in: .window(.root)) } @@ -1879,6 +2292,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD ]), ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })]) ]) + strongSelf.view.endEditing(true) strongSelf.controller?.present(actionSheet, in: .window(.root)) } else { let text: String @@ -1902,6 +2316,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD guard let controller = self.controller else { return } + self.view.endEditing(true) controller.present(peerReportOptionsController(context: self.context, subject: .peer(self.peerId), present: { [weak controller] c, a in controller?.present(c, in: .window(.root), with: a) }, push: { [weak controller] c in @@ -1917,6 +2332,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } if let peer = peer as? TelegramUser, let username = peer.username { let shareController = ShareController(context: strongSelf.context, subject: .url("https://t.me/\(username)")) + strongSelf.view.endEditing(true) strongSelf.controller?.present(shareController, in: .window(.root)) } }) @@ -1964,7 +2380,10 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } private func editingOpenDiscussionGroupSetup() { - self.controller?.push(channelDiscussionGroupSetupController(context: self.context, peerId: self.peerId)) + guard let data = self.data, let peer = data.peer else { + return + } + self.controller?.push(channelDiscussionGroupSetupController(context: self.context, peerId: peer.id)) } private func editingToggleMessageSignatures(value: Bool) { @@ -1972,17 +2391,103 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } private func openParticipantsSection(section: PeerInfoParticipantsSection) { + guard let data = self.data, let peer = data.peer else { + return + } switch section { case .members: self.controller?.push(channelMembersController(context: self.context, peerId: self.peerId)) case .admins: - self.controller?.push(channelAdminsController(context: self.context, peerId: self.peerId)) + if peer is TelegramGroup { + self.controller?.push(channelAdminsController(context: self.context, peerId: self.peerId)) + } else if peer is TelegramChannel { + self.controller?.push(channelAdminsController(context: self.context, peerId: self.peerId)) + } case .banned: self.controller?.push(channelBlacklistController(context: self.context, peerId: self.peerId)) } } - private func openDeleteChannel() { + private func editingOpenPreHistorySetup() { + guard let data = self.data, let peer = data.peer else { + return + } + self.controller?.push(groupPreHistorySetupController(context: self.context, peerId: peer.id, upgradedToSupergroup: { _, f in f() })) + } + + private func openPermissions() { + guard let data = self.data, let peer = data.peer else { + return + } + self.controller?.push(channelPermissionsController(context: self.context, peerId: peer.id)) + } + + private func editingOpenStickerPackSetup() { + guard let data = self.data, let peer = data.peer, let cachedData = data.cachedData as? CachedChannelData else { + return + } + self.controller?.push(groupStickerPackSetupController(context: self.context, peerId: peer.id, currentPackInfo: cachedData.stickerPack)) + } + + private func openLocation() { + guard let data = self.data, let peer = data.peer, let cachedData = data.cachedData as? CachedChannelData, let location = cachedData.peerGeoLocation else { + return + } + let context = self.context + let presentationData = self.presentationData + let mapMedia = TelegramMediaMap(latitude: location.latitude, longitude: location.longitude, geoPlace: nil, venue: MapVenue(title: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), address: location.address, provider: nil, id: nil, type: nil), liveBroadcastingTimeout: nil) + let locationController = legacyLocationController(message: nil, mapMedia: mapMedia, context: context, openPeer: { _ in }, sendLiveLocation: { _, _ in }, stopLiveLocation: {}, openUrl: { url in + context.sharedContext.applicationBindings.openUrl(url) + }) + self.controller?.push(locationController) + } + + private func editingOpenSetupLocation() { + guard let data = self.data, let peer = data.peer else { + return + } + let presentationData = self.presentationData + let locationController = legacyLocationPickerController(context: self.context, selfPeer: peer, peer: peer, sendLocation: { [weak self] coordinate, _, address in + guard let strongSelf = self else { + return + } + let addressSignal: Signal + if let address = address { + addressSignal = .single(address) + } else { + addressSignal = reverseGeocodeLocation(latitude: coordinate.latitude, longitude: coordinate.longitude) + |> map { placemark in + if let placemark = placemark { + return placemark.fullAddress + } else { + return "\(coordinate.latitude), \(coordinate.longitude)" + } + } + } + + let context = strongSelf.context + let _ = (addressSignal + |> mapToSignal { address -> Signal in + return updateChannelGeoLocation(postbox: context.account.postbox, network: context.account.network, channelId: peer.id, coordinate: (coordinate.latitude, coordinate.longitude), address: address) + } + |> deliverOnMainQueue).start(error: { errror in + guard let strongSelf = self else { + return + } + strongSelf.controller?.present(textAlertController(context: context, title: nil, text: strongSelf.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + }) + }, sendLiveLocation: { _, _ in }, theme: presentationData.theme, customLocationPicker: true, presentationCompleted: { + }) + self.controller?.push(locationController) + } + + private func openPeerInfo(peer: Peer) { + if let infoController = self.context.sharedContext.makePeerInfoController(context: self.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + (self.controller?.navigationController as? NavigationController)?.pushViewController(infoController) + } + } + + private func openDeletePeer() { let peerId = self.peerId let _ = (self.context.account.postbox.transaction { transaction -> Peer? in return transaction.getPeer(peerId) @@ -1991,6 +2496,14 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD guard let strongSelf = self, let peer = peer else { return } + var isGroup = false + if let channel = peer as? TelegramChannel { + if case .group = channel.info { + isGroup = true + } + } else if peer is TelegramGroup { + isGroup = true + } let presentationData = strongSelf.presentationData let actionSheet = ActionSheetController(presentationData: presentationData) let dismissAction: () -> Void = { [weak actionSheet] in @@ -1998,19 +2511,20 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } actionSheet.setItemGroups([ ActionSheetItemGroup(items: [ - ActionSheetTextItem(title: presentationData.strings.ChannelInfo_DeleteChannelConfirmation), - ActionSheetButtonItem(title: presentationData.strings.ChannelInfo_DeleteChannel, color: .destructive, action: { + ActionSheetTextItem(title: isGroup ? presentationData.strings.ChannelInfo_DeleteGroupConfirmation : presentationData.strings.ChannelInfo_DeleteChannelConfirmation), + ActionSheetButtonItem(title: isGroup ? presentationData.strings.ChannelInfo_DeleteGroup : presentationData.strings.ChannelInfo_DeleteChannel, color: .destructive, action: { dismissAction() self?.deletePeerChat(peer: peer, globally: true) }), ]), ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })]) ]) + strongSelf.view.endEditing(true) strongSelf.controller?.present(actionSheet, in: .window(.root)) }) } - private func openLeaveChannel() { + private func openLeavePeer() { let peerId = self.peerId let _ = (self.context.account.postbox.transaction { transaction -> Peer? in return transaction.getPeer(peerId) @@ -2019,6 +2533,14 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD guard let strongSelf = self, let peer = peer else { return } + var isGroup = false + if let channel = peer as? TelegramChannel { + if case .group = channel.info { + isGroup = true + } + } else if peer is TelegramGroup { + isGroup = true + } let presentationData = strongSelf.presentationData let actionSheet = ActionSheetController(presentationData: presentationData) let dismissAction: () -> Void = { [weak actionSheet] in @@ -2026,13 +2548,14 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } actionSheet.setItemGroups([ ActionSheetItemGroup(items: [ - ActionSheetButtonItem(title: presentationData.strings.Channel_LeaveChannel, color: .destructive, action: { + ActionSheetButtonItem(title: isGroup ? presentationData.strings.Group_LeaveGroup : presentationData.strings.Channel_LeaveChannel, color: .destructive, action: { dismissAction() self?.deletePeerChat(peer: peer, globally: false) }), ]), ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })]) ]) + strongSelf.view.endEditing(true) strongSelf.controller?.present(actionSheet, in: .window(.root)) }) } @@ -2083,6 +2606,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD legacyController.bind(controller: navigationController) + strongSelf.view.endEditing(true) strongSelf.controller?.present(legacyController, in: .window(.root)) var hasPhotos = false @@ -2242,6 +2766,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD actionSheet?.dismissAnimated() }) ])]) + strongSelf.view.endEditing(true) strongSelf.controller?.present(actionSheet, in: .window(.root)) } })) @@ -2411,54 +2936,83 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD contentHeight += headerHeight contentHeight += sectionSpacing - let infoSectionHeight = self.infoSection.update(width: layout.size.width, presentationData: self.presentationData, items: peerInfoSectionItems(data: self.data, presentationData: self.presentationData, interaction: self.interaction), transition: transition) - let infoSectionFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: infoSectionHeight)) - if additive { - transition.updateFrameAdditive(node: self.infoSection, frame: infoSectionFrame) - } else { - transition.updateFrame(node: self.infoSection, frame: infoSectionFrame) - } - - let editingInfoSectionHeight = self.editingInfoSection.update(width: layout.size.width, presentationData: self.presentationData, items: editingInfoSectionItems(data: self.data, presentationData: self.presentationData, interaction: self.interaction), transition: transition) - let editingInfoSectionFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: infoSectionHeight)) - if additive { - transition.updateFrameAdditive(node: self.editingInfoSection, frame: editingInfoSectionFrame) - } else { - transition.updateFrame(node: self.editingInfoSection, frame: editingInfoSectionFrame) - } - - if self.state.isEditing { - transition.updateAlpha(node: self.infoSection, alpha: 0.0) - transition.updateAlpha(node: self.editingInfoSection, alpha: 1.0) - transition.updateAlpha(node: self.editingActionsSection, alpha: 1.0) - if !editingInfoSectionHeight.isZero { - contentHeight += editingInfoSectionHeight - contentHeight += sectionSpacing + var validRegularSections: [AnyHashable] = [] + for (sectionId, sectionItems) in infoItems(data: self.data, context: self.context, presentationData: self.presentationData, interaction: self.interaction) { + validRegularSections.append(sectionId) + + let sectionNode: PeerInfoScreenItemSectionContainerNode + if let current = self.regularSections[sectionId] { + sectionNode = current + } else { + sectionNode = PeerInfoScreenItemSectionContainerNode() + self.regularSections[sectionId] = sectionNode + self.scrollNode.addSubnode(sectionNode) } - } else { - transition.updateAlpha(node: self.infoSection, alpha: 1.0) - transition.updateAlpha(node: self.editingInfoSection, alpha: 0.0) - transition.updateAlpha(node: self.editingActionsSection, alpha: 0.0) - if !infoSectionHeight.isZero { - contentHeight += infoSectionHeight + + let sectionHeight = sectionNode.update(width: layout.size.width, presentationData: self.presentationData, items: sectionItems, transition: transition) + let sectionFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: sectionHeight)) + if additive { + transition.updateFrameAdditive(node: sectionNode, frame: sectionFrame) + } else { + transition.updateFrame(node: sectionNode, frame: sectionFrame) + } + + transition.updateAlpha(node: sectionNode, alpha: self.state.isEditing ? 0.0 : 1.0) + if !sectionHeight.isZero && !self.state.isEditing { + contentHeight += sectionHeight contentHeight += sectionSpacing } } - - let editingActionsSectionHeight = self.editingActionsSection.update(width: layout.size.width, presentationData: self.presentationData, items: editingActionsSectionItems(data: self.data, presentationData: self.presentationData, interaction: self.interaction), transition: transition) - let editingActionsSectionFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: editingActionsSectionHeight)) - if additive { - transition.updateFrameAdditive(node: self.editingActionsSection, frame: editingActionsSectionFrame) - } else { - transition.updateFrame(node: self.editingActionsSection, frame: editingActionsSectionFrame) + var removeRegularSections: [AnyHashable] = [] + for (sectionId, sectionNode) in self.regularSections { + if !validRegularSections.contains(sectionId) { + removeRegularSections.append(sectionId) + } + } + for sectionId in removeRegularSections { + if let sectionNode = self.regularSections.removeValue(forKey: sectionId) { + sectionNode.removeFromSupernode() + } } - if self.state.isEditing { - if !editingActionsSectionHeight.isZero { - contentHeight += editingActionsSectionHeight + var validEditingSections: [AnyHashable] = [] + for (sectionId, sectionItems) in editingItems(data: self.data, context: self.context, presentationData: self.presentationData, interaction: self.interaction) { + validEditingSections.append(sectionId) + + let sectionNode: PeerInfoScreenItemSectionContainerNode + if let current = self.editingSections[sectionId] { + sectionNode = current + } else { + sectionNode = PeerInfoScreenItemSectionContainerNode() + self.editingSections[sectionId] = sectionNode + self.scrollNode.addSubnode(sectionNode) + } + + let sectionHeight = sectionNode.update(width: layout.size.width, presentationData: self.presentationData, items: sectionItems, transition: transition) + let sectionFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: sectionHeight)) + if additive { + transition.updateFrameAdditive(node: sectionNode, frame: sectionFrame) + } else { + transition.updateFrame(node: sectionNode, frame: sectionFrame) + } + + transition.updateAlpha(node: sectionNode, alpha: self.state.isEditing ? 1.0 : 0.0) + if !sectionHeight.isZero && self.state.isEditing { + contentHeight += sectionHeight contentHeight += sectionSpacing } } + var removeEditingSections: [AnyHashable] = [] + for (sectionId, sectionNode) in self.editingSections { + if !validEditingSections.contains(sectionId) { + removeEditingSections.append(sectionId) + } + } + for sectionId in removeEditingSections { + if let sectionNode = self.editingSections.removeValue(forKey: sectionId) { + sectionNode.removeFromSupernode() + } + } let paneContainerSize = CGSize(width: layout.size.width, height: layout.size.height - navigationHeight) var restoreContentOffset: CGPoint? @@ -2506,6 +3060,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD let shareController = ShareController(context: strongSelf.context, subject: .messages(messages.sorted(by: { lhs, rhs in return lhs.index < rhs.index })), externalShare: true, immediateExternalShare: true) + strongSelf.view.endEditing(true) strongSelf.controller?.present(shareController, in: .window(.root)) } }) @@ -2518,6 +3073,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD guard let strongSelf = self, let messageIds = strongSelf.state.selectedMessageIds, !messageIds.isEmpty else { return } + strongSelf.view.endEditing(true) strongSelf.controller?.present(peerReportOptionsController(context: strongSelf.context, subject: .messages(Array(messageIds).sorted()), present: { c, a in self?.controller?.present(c, in: .window(.root), with: a) }, push: { c in @@ -2576,7 +3132,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD private func updateNavigation(transition: ContainedViewLayoutTransition, additive: Bool) { let offsetY = self.scrollNode.view.contentOffset.y - if self.state.isEditing || offsetY <= 50.0 { + if self.state.isEditing || offsetY <= 50.0 || self.paneContainerNode.alpha.isZero { if !self.scrollNode.view.bounces { self.scrollNode.view.bounces = true self.scrollNode.view.alwaysBounceVertical = true @@ -2682,7 +3238,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } else if offsetY >= 1.0 { shouldBeExpanded = false } - if let shouldBeExpanded = shouldBeExpanded, self.canUpdateAvatarExpansion, shouldBeExpanded != self.headerNode.isAvatarExpanded { + if let shouldBeExpanded = shouldBeExpanded, shouldBeExpanded != self.headerNode.isAvatarExpanded { let transition: ContainedViewLayoutTransition = .animated(duration: 0.35, curve: .spring) if self.hapticFeedback == nil { @@ -2935,6 +3491,7 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig private let headerNode: PeerInfoHeaderNode private var previousBackButtonArrow: ASDisplayNode? + private var previousBackButton: ASDisplayNode? private var currentBackButtonArrow: ASDisplayNode? private var previousBackButtonBadge: ASDisplayNode? private var currentBackButton: ASDisplayNode? @@ -2972,6 +3529,10 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig self.previousBackButtonArrow = previousBackButtonArrow self.addSubnode(previousBackButtonArrow) } + if let previousBackButton = bottomNavigationBar.makeTransitionBackButtonNode(accentColor: self.presentationData.theme.rootController.navigationBar.accentTextColor) { + self.previousBackButton = previousBackButton + self.addSubnode(previousBackButton) + } if self.screenNode.headerNode.isAvatarExpanded, let currentBackButtonArrow = topNavigationBar.makeTransitionBackArrowNode(accentColor: self.screenNode.headerNode.isAvatarExpanded ? .white : self.presentationData.theme.rootController.navigationBar.accentTextColor) { self.currentBackButtonArrow = currentBackButtonArrow self.addSubnode(currentBackButtonArrow) @@ -3014,6 +3575,12 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig previousBackButtonArrow.frame = previousBackButtonArrowFrame } + if let previousBackButton = self.previousBackButton { + let previousBackButtonFrame = bottomNavigationBar.backButtonNode.view.convert(bottomNavigationBar.backButtonNode.view.bounds, to: bottomNavigationBar.view) + previousBackButton.frame = previousBackButtonFrame + transition.updateAlpha(node: previousBackButton, alpha: fraction) + } + if let currentBackButtonArrow = self.currentBackButtonArrow { let currentBackButtonArrowFrame = topNavigationBar.backButtonArrow.view.convert(topNavigationBar.backButtonArrow.view.bounds, to: topNavigationBar.view) currentBackButtonArrow.frame = currentBackButtonArrowFrame @@ -3033,7 +3600,7 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig if let currentBackButton = self.currentBackButton { let currentBackButtonFrame = topNavigationBar.backButtonNode.view.convert(topNavigationBar.backButtonNode.view.bounds, to: topNavigationBar.view) - transition.updateFrame(node: currentBackButton, frame: currentBackButtonFrame.offsetBy(dx: fraction * 12.0, dy: 0.0)) + //transition.updateFrame(node: currentBackButton, frame: currentBackButtonFrame.offsetBy(dx: fraction * 12.0, dy: 0.0)) transition.updateAlpha(node: currentBackButton, alpha: (1.0 - fraction)) } From f2ca7b00efcafed34c1c76821a1c25db6d678480 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 11 Feb 2020 10:34:00 +0400 Subject: [PATCH 14/30] Various improvements --- NotificationService/Serialization.m | 2 +- Telegram-iOS/Resources/Compass.tgs | Bin 0 -> 11211 bytes Telegram-iOS/Resources/Dice_1.tgs | Bin 0 -> 63935 bytes Telegram-iOS/Resources/Dice_2.tgs | Bin 0 -> 61430 bytes Telegram-iOS/Resources/Dice_3.tgs | Bin 0 -> 64600 bytes Telegram-iOS/Resources/Dice_4.tgs | Bin 0 -> 65388 bytes Telegram-iOS/Resources/Dice_5.tgs | Bin 0 -> 65287 bytes Telegram-iOS/Resources/Dice_6.tgs | Bin 0 -> 65369 bytes Telegram-iOS/en.lproj/Localizable.strings | 19 + .../Sources/AnimatedStickerNode.swift | 27 +- .../Sources/CallListController.swift | 7 +- submodules/Charts/BUCK | 31 + submodules/Charts/Info.plist | 22 + .../Chart Screen/ChartDetailsView.swift | 258 + .../Chart Screen/ChartStackSection.swift | 199 + .../Chart Screen/ChartStackSection.xib | 149 + .../Sources/Chart Screen/ChartView.swift | 158 + .../ChartVisibilityItemView.swift | 95 + .../Chart Screen/ChartVisibilityView.swift | 147 + .../Chart Screen/ChartsDataLoader.swift | 51 + .../ChartsStackViewController.swift | 222 + .../Sources/Chart Screen/RangeChartView.swift | 291 + submodules/Charts/Sources/ChartNode.swift | 48 + .../Charts Reader/ChartsCollection.swift | 91 + .../Charts Reader/ChartsDataManager.swift | 191 + .../Sources/Charts Reader/ChartsError.swift | 14 + .../Sources/Charts Reader/Convert.swift | 42 + submodules/Charts/Sources/Charts.h | 19 + .../Controllers/BaseChartController.swift | 166 + .../GeneralChartComponentController.swift | 328 + .../Lines/BaseLinesChartController.swift | 236 + .../Lines/GeneralLinesChartController.swift | 247 + .../Lines/TwoAxisLinesChartController.swift | 306 + .../PercentChartComponentController.swift | 195 + .../PercentPieChartController.swift | 281 + .../PieChartComponentController.swift | 198 + .../BarsComponentController.swift | 226 + .../DailyBarsChartController.swift | 249 + .../LinesComponentController.swift | 210 + .../StackedBarsChartController.swift | 243 + .../Charts/Renderes/BarChartRenderer.swift | 293 + .../Charts/Renderes/BaseChartRenderer.swift | 116 + .../Renderes/ChartDetailsRenderer.swift | 147 + .../Renderes/HorizontalScalesRenderer.swift | 99 + .../Charts/Renderes/LineBulletsRenerer.swift | 67 + .../Charts/Renderes/LinesChartRenderer.swift | 538 ++ .../Charts/Renderes/PecentChartRenderer.swift | 132 + .../PercentPieAnimationRenderer.swift | 202 + .../Charts/Renderes/PerformanceRenderer.swift | 31 + .../Charts/Renderes/PieChartRenderer.swift | 191 + .../Renderes/VerticalLinesRenderer.swift | 42 + .../Renderes/VerticalScalesRenderer.swift | 162 + .../Sources/Helpers/AnimationController.swift | 178 + .../Charts/Sources/Helpers/Array+Utils.swift | 18 + .../Charts/Sources/Helpers/CGFloat.swift | 17 + .../Sources/Helpers/CGPoint+Extensions.swift | 219 + .../Sources/Helpers/ClosedRange+Utils.swift | 15 + .../Helpers/CustomNavigationController.swift | 19 + .../Sources/Helpers/DisplayLinkService.swift | 114 + .../Sources/Helpers/GlobalHelpers.swift | 12 + .../Helpers/NumberFormatter+Utils.swift | 19 + .../Sources/Helpers/OnePixelConstraint.swift | 17 + .../Helpers/ScalesNumberFormatter.swift | 32 + .../Sources/Helpers/TimeInterval+Utils.swift | 27 + .../Charts/Sources/Helpers/TimeZone.swift | 36 + .../Sources/Helpers/UIColor+Utils.swift | 64 + .../Sources/Helpers/UIImage+Utils.swift | 28 + .../Sources/Helpers/UIImageView+Utils.swift | 24 + .../Sources/Helpers/UILabel+Utils.swift | 37 + .../Sources/Helpers/UIView+Extensions.swift | 57 + .../Charts/Sources/Models/ChartLineData.swift | 76 + .../Charts/Sources/Models/ColorMode.swift | 175 + .../Sources/Models/LinesChartLabel.swift | 25 + .../Sources/Models/LinesSelectionLabel.swift | 15 + .../Sources/ChatListController.swift | 8 +- .../Sources/ChatListSearchContainerNode.swift | 27 +- .../Sources/ContactsController.swift | 7 +- submodules/Display/Display/TabBarNode.swift | 2 +- .../GalleryUI/Sources/GalleryController.swift | 6 +- .../Sources/GalleryControllerNode.swift | 8 +- .../GalleryControllerPresentationState.swift | 11 +- .../Sources/GalleryFooterContentNode.swift | 17 + .../GalleryUI/Sources/GalleryFooterNode.swift | 70 +- .../GalleryUI/Sources/GalleryItemNode.swift | 6 +- .../GalleryUI/Sources/GalleryPagerNode.swift | 16 +- .../Items/ChatAnimationGalleryItem.swift | 4 +- .../Items/ChatDocumentGalleryItem.swift | 4 +- .../Items/ChatExternalFileGalleryItem.swift | 4 +- .../Sources/Items/ChatImageGalleryItem.swift | 4 +- .../Items/UniversalVideoGalleryItem.swift | 91 +- .../ZoomableContentGalleryItemNode.swift | 117 +- .../Sources/InstantImageGalleryItem.swift | 4 +- .../InstantPageGalleryController.swift | 4 +- .../Sources/ItemListPeerActionItem.swift | 19 +- .../Sources/ItemListStickerPackItem.swift | 7 + .../SecureIdDocumentGalleryController.swift | 4 +- .../SecureIdDocumentImageGalleryItem.swift | 4 +- .../Sources/AvatarGalleryController.swift | 4 +- .../Sources/PeerAvatarImageGalleryItem.swift | 4 +- submodules/PeerInfoUI/BUCK | 1 + submodules/PeersNearbyUI/BUCK | 2 + .../Sources/PeersNearbyController.swift | 214 +- .../Sources/PeersNearbyHeaderItem.swift | 37 +- .../Sources/SpecialTabBarIcons.swift | 5 + .../Sources/SettingsController.swift | 8 +- submodules/StatisticsUI/BUCK | 31 + submodules/StatisticsUI/Info.plist | 22 + .../StatisticsUI/Sources/StatisticsUI.h | 19 + .../Sources/StatsController.swift | 351 + .../StatisticsUI/Sources/StatsGraphItem.swift | 205 + .../Sources/StatsOverviewItem.swift | 292 + .../SyncCore/Sources/CachedChannelData.swift | 51 +- .../TextEntitiesMessageAttribute.swift | 5 + submodules/TelegramApi/Sources/Api0.swift | 33 +- submodules/TelegramApi/Sources/Api1.swift | 294 + submodules/TelegramApi/Sources/Api2.swift | 304 +- submodules/TelegramApi/Sources/Api3.swift | 105 +- .../Sources/AccountStateManagementUtils.swift | 9 +- .../TelegramCore/Sources/BankCards.swift | 34 + .../Sources/ChannelStatistics.swift | 424 + submodules/TelegramCore/Sources/JSON.swift | 3 +- .../ManagedSecretChatOutgoingOperations.swift | 4 + .../TelegramCore/Sources/PeersNearby.swift | 101 +- .../TelegramCore/Sources/Serialization.swift | 2 +- .../Sources/StoreMessage_Telegram.swift | 2 + .../TextEntitiesMessageAttribute.swift | 2 + .../Sources/UpdateCachedPeerData.swift | 1 + .../Sources/PresentationStrings.swift | 7882 +++++++++-------- .../Resources/PresentationResourceKey.swift | 2 + .../PresentationResourcesItemList.swift | 12 + .../Sources/PresenceStrings.swift | 20 +- .../Images.xcassets/Chart/Contents.json | 9 + .../Chart/arrow_left.imageset/Contents.json | 12 + .../Chart/arrow_left.imageset/arrow_left.pdf | Bin 0 -> 4081 bytes .../Chart/arrow_right.imageset/Contents.json | 12 + .../arrow_right.imageset/arrow_right.pdf | Bin 0 -> 874 bytes .../Contents.json | 23 + .../selection_frame_dark.pdf | 61 + .../Contents.json | 23 + .../selection_frame_light.pdf | 62 + .../Chat List/Tabs/Holiday/Contents.json | 9 + .../Holiday/IconCalls.imageset/Contents.json | 12 + .../Holiday/IconCalls.imageset/ic_calls.pdf | Bin 0 -> 4945 bytes .../Holiday/IconChats.imageset/Contents.json | 12 + .../IconChats.imageset/ic_messages.pdf | Bin 0 -> 4626 bytes .../IconContacts.imageset/Contents.json | 12 + .../IconContacts.imageset/ic_contacts.pdf | Bin 0 -> 5894 bytes .../IconSettings.imageset/Contents.json | 12 + .../IconSettings.imageset/ic_settings.pdf | Bin 0 -> 4550 bytes .../MakeInvisibleIcon.imageset/Contents.json | 12 + .../ic_stopshowme.pdf | Bin 0 -> 4829 bytes .../MakeVisibleIcon.imageset/Contents.json | 12 + .../MakeVisibleIcon.imageset/ic_showme.pdf | Bin 0 -> 4748 bytes .../SoundOff.imageset/Contents.json | 12 + .../SoundOff.imageset/soundoff (2).pdf | Bin 0 -> 4533 bytes .../SoundOn.imageset/Contents.json | 12 + .../SoundOn.imageset/soundon (2).pdf | Bin 0 -> 4774 bytes .../TelegramUI/ChatBotInfoItem.swift | 2 +- .../TelegramUI/ChatController.swift | 27 + .../ChatControllerInteraction.swift | 2 + .../TelegramUI/ChatHistoryListNode.swift | 23 +- .../ChatMessageAnimatedStickerItemNode.swift | 114 +- .../ChatMessageAttachedContentNode.swift | 3 +- .../ChatMessageBubbleContentNode.swift | 1 + .../ChatMessageBubbleItemNode.swift | 10 +- .../TelegramUI/ChatMessageItem.swift | 4 +- .../ChatMessageTextBubbleContentNode.swift | 5 +- .../ChatRecentActionsControllerNode.swift | 2 + .../ChatScheduleTimeControllerNode.swift | 2 +- .../TelegramUI/GifPaneSearchContentNode.swift | 2 +- .../TelegramUI/ListMessageDateHeader.swift | 1 - .../Resources/PresentationStrings.mapping | Bin 144219 -> 144524 bytes .../Sources/StringWithAppliedEntities.swift | 9 + .../Sources/TelegramAttributes.swift | 1 + .../UrlHandling/Sources/UrlHandling.swift | 7 +- .../Sources/WebSearchGalleryController.swift | 4 +- .../Sources/WebSearchVideoGalleryItem.swift | 4 +- submodules/ffmpeg/gas-preprocessor.pl | 1210 +++ 178 files changed, 16610 insertions(+), 4271 deletions(-) create mode 100644 Telegram-iOS/Resources/Compass.tgs create mode 100644 Telegram-iOS/Resources/Dice_1.tgs create mode 100644 Telegram-iOS/Resources/Dice_2.tgs create mode 100644 Telegram-iOS/Resources/Dice_3.tgs create mode 100644 Telegram-iOS/Resources/Dice_4.tgs create mode 100644 Telegram-iOS/Resources/Dice_5.tgs create mode 100644 Telegram-iOS/Resources/Dice_6.tgs create mode 100644 submodules/Charts/BUCK create mode 100644 submodules/Charts/Info.plist create mode 100644 submodules/Charts/Sources/Chart Screen/ChartDetailsView.swift create mode 100644 submodules/Charts/Sources/Chart Screen/ChartStackSection.swift create mode 100644 submodules/Charts/Sources/Chart Screen/ChartStackSection.xib create mode 100644 submodules/Charts/Sources/Chart Screen/ChartView.swift create mode 100644 submodules/Charts/Sources/Chart Screen/ChartVisibilityItemView.swift create mode 100644 submodules/Charts/Sources/Chart Screen/ChartVisibilityView.swift create mode 100644 submodules/Charts/Sources/Chart Screen/ChartsDataLoader.swift create mode 100644 submodules/Charts/Sources/Chart Screen/ChartsStackViewController.swift create mode 100644 submodules/Charts/Sources/Chart Screen/RangeChartView.swift create mode 100644 submodules/Charts/Sources/ChartNode.swift create mode 100644 submodules/Charts/Sources/Charts Reader/ChartsCollection.swift create mode 100644 submodules/Charts/Sources/Charts Reader/ChartsDataManager.swift create mode 100644 submodules/Charts/Sources/Charts Reader/ChartsError.swift create mode 100644 submodules/Charts/Sources/Charts Reader/Convert.swift create mode 100644 submodules/Charts/Sources/Charts.h create mode 100644 submodules/Charts/Sources/Charts/Controllers/BaseChartController.swift create mode 100644 submodules/Charts/Sources/Charts/Controllers/GeneralChartComponentController.swift create mode 100644 submodules/Charts/Sources/Charts/Controllers/Lines/BaseLinesChartController.swift create mode 100644 submodules/Charts/Sources/Charts/Controllers/Lines/GeneralLinesChartController.swift create mode 100644 submodules/Charts/Sources/Charts/Controllers/Lines/TwoAxisLinesChartController.swift create mode 100644 submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PercentChartComponentController.swift create mode 100644 submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PercentPieChartController.swift create mode 100644 submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PieChartComponentController.swift create mode 100644 submodules/Charts/Sources/Charts/Controllers/Stacked Bars/BarsComponentController.swift create mode 100644 submodules/Charts/Sources/Charts/Controllers/Stacked Bars/DailyBarsChartController.swift create mode 100644 submodules/Charts/Sources/Charts/Controllers/Stacked Bars/LinesComponentController.swift create mode 100644 submodules/Charts/Sources/Charts/Controllers/Stacked Bars/StackedBarsChartController.swift create mode 100644 submodules/Charts/Sources/Charts/Renderes/BarChartRenderer.swift create mode 100644 submodules/Charts/Sources/Charts/Renderes/BaseChartRenderer.swift create mode 100644 submodules/Charts/Sources/Charts/Renderes/ChartDetailsRenderer.swift create mode 100644 submodules/Charts/Sources/Charts/Renderes/HorizontalScalesRenderer.swift create mode 100644 submodules/Charts/Sources/Charts/Renderes/LineBulletsRenerer.swift create mode 100644 submodules/Charts/Sources/Charts/Renderes/LinesChartRenderer.swift create mode 100644 submodules/Charts/Sources/Charts/Renderes/PecentChartRenderer.swift create mode 100644 submodules/Charts/Sources/Charts/Renderes/PercentPieAnimationRenderer.swift create mode 100644 submodules/Charts/Sources/Charts/Renderes/PerformanceRenderer.swift create mode 100644 submodules/Charts/Sources/Charts/Renderes/PieChartRenderer.swift create mode 100644 submodules/Charts/Sources/Charts/Renderes/VerticalLinesRenderer.swift create mode 100644 submodules/Charts/Sources/Charts/Renderes/VerticalScalesRenderer.swift create mode 100644 submodules/Charts/Sources/Helpers/AnimationController.swift create mode 100644 submodules/Charts/Sources/Helpers/Array+Utils.swift create mode 100644 submodules/Charts/Sources/Helpers/CGFloat.swift create mode 100644 submodules/Charts/Sources/Helpers/CGPoint+Extensions.swift create mode 100644 submodules/Charts/Sources/Helpers/ClosedRange+Utils.swift create mode 100644 submodules/Charts/Sources/Helpers/CustomNavigationController.swift create mode 100644 submodules/Charts/Sources/Helpers/DisplayLinkService.swift create mode 100644 submodules/Charts/Sources/Helpers/GlobalHelpers.swift create mode 100644 submodules/Charts/Sources/Helpers/NumberFormatter+Utils.swift create mode 100644 submodules/Charts/Sources/Helpers/OnePixelConstraint.swift create mode 100644 submodules/Charts/Sources/Helpers/ScalesNumberFormatter.swift create mode 100644 submodules/Charts/Sources/Helpers/TimeInterval+Utils.swift create mode 100644 submodules/Charts/Sources/Helpers/TimeZone.swift create mode 100644 submodules/Charts/Sources/Helpers/UIColor+Utils.swift create mode 100644 submodules/Charts/Sources/Helpers/UIImage+Utils.swift create mode 100644 submodules/Charts/Sources/Helpers/UIImageView+Utils.swift create mode 100644 submodules/Charts/Sources/Helpers/UILabel+Utils.swift create mode 100644 submodules/Charts/Sources/Helpers/UIView+Extensions.swift create mode 100644 submodules/Charts/Sources/Models/ChartLineData.swift create mode 100644 submodules/Charts/Sources/Models/ColorMode.swift create mode 100644 submodules/Charts/Sources/Models/LinesChartLabel.swift create mode 100644 submodules/Charts/Sources/Models/LinesSelectionLabel.swift create mode 100644 submodules/PresentationDataUtils/Sources/SpecialTabBarIcons.swift create mode 100644 submodules/StatisticsUI/BUCK create mode 100644 submodules/StatisticsUI/Info.plist create mode 100644 submodules/StatisticsUI/Sources/StatisticsUI.h create mode 100644 submodules/StatisticsUI/Sources/StatsController.swift create mode 100644 submodules/StatisticsUI/Sources/StatsGraphItem.swift create mode 100644 submodules/StatisticsUI/Sources/StatsOverviewItem.swift create mode 100644 submodules/TelegramCore/Sources/BankCards.swift create mode 100644 submodules/TelegramCore/Sources/ChannelStatistics.swift create mode 100644 submodules/TelegramUI/Images.xcassets/Chart/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chart/arrow_left.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chart/arrow_left.imageset/arrow_left.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Chart/arrow_right.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chart/arrow_right.imageset/arrow_right.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Chart/selection_frame_dark.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chart/selection_frame_dark.imageset/selection_frame_dark.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Chart/selection_frame_light.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chart/selection_frame_light.imageset/selection_frame_light.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconCalls.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconCalls.imageset/ic_calls.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconChats.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconChats.imageset/ic_messages.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconContacts.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconContacts.imageset/ic_contacts.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconSettings.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconSettings.imageset/ic_settings.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Contact List/MakeInvisibleIcon.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Contact List/MakeInvisibleIcon.imageset/ic_stopshowme.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Contact List/MakeVisibleIcon.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Contact List/MakeVisibleIcon.imageset/ic_showme.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOff.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOff.imageset/soundoff (2).pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOn.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOn.imageset/soundon (2).pdf create mode 100755 submodules/ffmpeg/gas-preprocessor.pl diff --git a/NotificationService/Serialization.m b/NotificationService/Serialization.m index 00a0621e3e..f7eea7807e 100644 --- a/NotificationService/Serialization.m +++ b/NotificationService/Serialization.m @@ -3,7 +3,7 @@ @implementation Serialization - (NSUInteger)currentLayer { - return 109; + return 110; } - (id _Nullable)parseMessage:(NSData * _Nullable)data { diff --git a/Telegram-iOS/Resources/Compass.tgs b/Telegram-iOS/Resources/Compass.tgs new file mode 100644 index 0000000000000000000000000000000000000000..d9ec83eb7741d23487187cafe49dc52d7109fca7 GIT binary patch literal 11211 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 literal 0 HcmV?d00001 diff --git a/Telegram-iOS/Resources/Dice_1.tgs b/Telegram-iOS/Resources/Dice_1.tgs new file mode 100644 index 0000000000000000000000000000000000000000..e078e6b6de72e46f09ae9cc14485052b8a73bd18 GIT binary patch literal 63935 zcmYhgV~}P&+i=~sZBDy;+O}=mwykN~wr$(C&9iMxTkl-=Q(x7$f21m@?BqzQlD*fl z2&15Y{(C?`uX?r`0b+@CuQaA_aPxr|x=DU+7Os;8_(q*b8OeLLj%`Gc^ zadpSYL_mLjF@c}#PMEZ`xFtFS1VZ%>)meYNgzbG_1H$+>4~G2xUIAeqkrXe6uXkzs z{GW^&2Sf5duXo~ak5QiuqTly@|Jt``Vly z@_s(ebDxIB;`qPG*S?qh{a+<}-|p)AKCcP)aFPG@`gy-s=bbn8fB(qi4Bz{{93m9% zx*7BT{QL6Lyf+0+=zl!mpXU7iF;w?Dhsble$N%ZbQkFQ$ABOm&;qygdJwtWGrJ*j@ z(mvor!NgB%D#QtH9md$HJSlqwP%>#A&906D{l-zgf9di+RO(YW0qFa`j>UP=V7-U= zf2f9jEZKW4`LB5c0^|I@=IsqSJHx~G^K?=Tiw$M&lda$EUX$S8iuStlWez mrXHn@yj9m=j-4n$$!$un?CKc?tJg(22{|_nFecv~ zE9=P>>3`W0sTXA(06YaXb44TZ^|~Rv_dQ`fgxCPRrJEMcIetq`6p6Y*(asz_D=l1-*j`#e#pJDd#^(s)CDg>rWXX7K3SsANcQaYH% z2!FnWt^kOb`YjX(VSWD=OyBo?J;dL4`2vDItZnJ;(OYz@67*3zz{t%cT~sHF(bhfR zZzl}e#f`&}XA^-7vmT->RoMJM#ofp0yPD$zzpP2Mr_jd-x0Fp#t%mgMhQlvBvjO`pu3~zihINZ3lOnb?1`ZrLNEXON&wJG4-K^f&!wG_3cP% zJDZ>4q_kXj!IZq46p+?xKZ6@u7w*&*eypIK5`U2k}-fJ2h3Y!rE9poQ}`jNbB ziy7G^brvxfVOk2n7u|7H=i0mYnO>G0YlM*O)6pH&_r$;ztQZysCF+oIc8_Ce{Ivi zeZqk1D|VeIU5D0jAo(!9+6!D~8ZY0N?r3^c>|6pH%+Ah0)qgZY-T8kV==;4{M)UtX zO!0s3uXcLY1PAeGWuQKHwVaHgj+ceZLHw|K+q^EfkUrFn0M?f6@KrP?3F2)CM!g<@ zH`Sx{8MU6))8Bx9Z1b*&wqioEKU0jqkDk(9%d8Ifr>Q)`#=#HK9>+yFY{L$g3=(<3T+-gI*M45_^P(_6P}Rrm>S8fj z$@tMtU9Y@c6A`L%Why%Pd6AT`6gdxTo(hgM-U z;m@WBKYebTNt(2I{CHEUNyn07Tk8t(?wzRK0F8O6Q|iBix+&g+#Q4eg(%{;({|cWp z^sl&}_i>{w`Q=t=?o7<6PdDea%0ZlX-sP`2MXe;7Q$M?Ct{VPUCc2%L}t8#4V;#U7;LaHXGM%1dk5JE#i50OjTCoh*4C+yY< zKeNVgZyVVtr$*@fsf>X2SwHtl30UrmcjV9&_~L=^n->p_QpYp5ZRR^v8Bc$fZTwnm zz=Bw->5vT@=l-Iu(3|jRLC&nPh2V(C`4GS(Y#bnKFv*C02(@$Lx%+yILKj_baRBex zEQY8eo*Xi;eeDLfLad`#=S4?tA1-N5gO~TWP>xz*;~bwdBBdC)ub0v8BJMC&hX5nG z8oXJ7ESM=?@^tK_53hC@7VUAaoCq5E(0CPMDIw#ke6X;b%dwnG`B!$wp<%t*jcPIs zU62^kDQin7eJokOM>_kCv<2elslrqW+EgmYrQYfvy&qmL7o-o;i0_dvO>V(Ko4|bp zwP9n)knq!;XktU#fe1;J8g;pvs9NjZX1;8;f#I1`)?Cu{2~9(0>WDpC-!;k{eX%fyswa8@{>HZ))qY z`s!BmVPFxs7V!{FR2|kx?)j@u&u%V*_@x1pJe zE{KYy$}QqNU%b#LaD8GUW@Xs_3+%FLTpy<-8w+D|4?Bpi;pSi zJZ%^tPm+!wW9%A_;~c(G-+8Hccb~CrxM&{F>-(C1dCGdxEe%iD%OF{y`O$YU`;NbP zBc~LTe8zt#*C-DBxvo1t%xdN3^ep>hCy4Q*1K|_fG~ylup{drQT;Q#&cdQ-P#OfX+ zc2#v0Rod8dVH-Sy*GJVDfzR4{H(?Ab6X`%GE7!7gZ1LMIkXL;cJuS*gUEQkJp#veW z?(IV9QB~2i07pB?ChVa>u5$i%)#n+#wxjUj`MF{mUC+-c1k)hgP_%+I$VY34k+eyD~0t^FmJtwWw*()+d&sF zLb2vCig!Y+1fgJ10ieuq* zjWH6z(4cOY#VwOKI4#wii4L>Qy2F8ef?R91tWJLleSz+Yu0`i}kTDWH>_ z!7)DxNzpw#EA9h5mJHNT>BA3g4Mx;zMff#DiCe>8`jltas%976k~a!<%i6zbZBHcK z4NQUoNGn_qrSQhQvtkcPW<(Run z)%?;e5xkK{on~zr1NGPO*U2c=d819=SO z_=bFzDgCdEJ*OP>BUP%_JxzW=X2zBacCu~IkG#9mta>%&f2+#mUEE zb9z_j{Hn_SUvrs%qSJfdXZLY(vfgj{%xGL2X9XR22Ptw)vb0ON2%Kr>Il#Z4#K*Zk zpNh}QskPhNhp$WdpXar_;~)PIj_=l$qmRplaitlplrcuUKaPtF#XMESaRLRlyRqHU zhxhI?PIebRcA@phi*5KDW zJII7~UuPytQ>_EO0^b9DjPRoF_up}TCfO#AHng%hKk4W1yc{IBIH|Br+GCMXS^%9P zg6K0~MB^HCpVwcsuzQ5Ym=sX2wWKoJfBte9v0Lca^XqRQ^O=K}-m*V;ypFVX`~cSU zzX618_Et3IRCcuAx6%a~kX=HK=U!C!u{;l)Q%~SCiTIZ-0jOO1_hZKzW<^_CC3C(s zMcRES6PGyGf-C0%fjPbX+Y#rT+9yj>9$wh;^ni0yo}TEkwEMqIxq72Zj-yH5@%KlM zBifn-<~%hxnLl%OJib4VasF@DA94I&Z)3Ogl_P1^hirE@ImQ|*4OHK}#Zv&ankmZB zh&niz)D;Y~9V)Obpg&1!88>|8vzZ2&ZL2S!F0Qp3Gwi2g%L~W zB#TIOF(*fekF!<}!uT$(*`|)4CU12^ihfL$;c5~)0ycl&RdFlAy_dStI3M-g_<(0WZDUD*~3})(Ar^$yQZ2$CuyYplNuo1TqP?%)DF*me?^ouP; ziM5s;_bK=LZgf^=zCI)o%;^=+G6cjI*Y*!M{NM8FpFiH}`_LJcg(bVv-~@_Y0dNOb zsxT7YswNxNrOF8eGZFgjpAPUh3hG3WT$}Ld2)Cyu&N(UZQL}B1K%s0;hgeOo9fp*F zoC9Grjz@%|kZE2O!%5dLI6j%|=<(FSa1QPTK;-7L= zg~pFUjKZQ#6;2njv#W%~hROI8V$}CdMK;1vQ#@iG;I!t?U+x2d9LG)7Fk-A`=!3IafcRWH?K92iHAzx>r# zYl>X8hm9W_Rs=m`H{a77KNh3xO}9rsMr*!!0IOXOOt$)^*Hg{D8Ljl_-~Yc#&+D;qC8NiOxu7QKyL@1Ele_XtHv-?Ipy94ehCAvsxhuPRTUk_`4^lHrpy5)_sB?uRA)a!$ zHYBPh+x((|f!)6V*rhg*4zw6CWoYa(=zW|Z;Lu5HT@*L!9;|gOQy3DPR3g`aQ*$Sv zXKW{FxQTvfEBFLb0claEz%=`l4nnS~?rzy!zl7(hu3o}D&Z>qwfRlys0f1leZb z!J`1g4IMn+#5ZgXHh_@KfQx1fYCyBOW*Z&>o(+O1_S4!M(u%;@GGwyjqW+dliM(7O zna$IHzAFmxI#@kETkwvXj!e}&IWls!>Z?M z{_;=2?3HQu&bS4;ZXKVW9Fi0;Rvc@NlP6erc<5LL)x@piX%@LcMf`9o4+u`eq{?-z z0imbZz$pLCG3v4JGrGq=Tqt2q^z#&{7#^2Oh=^rNRx_$E=&h)qjB!1 zEQm3(d-8iVcwifS0+wGZFK@;dM%<0__Fg-5Z=N_6j%Pl}oxJT&U1g&W&j`w~pm#uX|HXknfBQkx=j+n$ z)&Z@hPm6F0{CN&#klC;nTmUrEPU*@OJ4981z6N_-jMaxaH!+YueHge5vak9FFbQr@ zGckw!mOeJ>=dfJlRWCmbpK!1`Qih#iKBl=#oPp(p@km}247XYX2mBHCihN+=nQ+E2 z0HlF#+XWuo87&UHiVn3-!TR?Yxg-J$TCs9$)a`!*?d|>FKzG^(GbZpXC&{y%3@6DX zWmxAh0$JI2{UY}tKKW_x2y}knbx9E5nUiij?MO=M0$OE(zAdrcpr_Im;6GSm)TGi?(IUFyI(z( z^6gQKv{>5&`lck#R-T2-*W*$W$S^mHIWR+|j_y8Stoo$1F0#%M+^dR@N6JjHEYujk zh51s#%S2d`W`q;%;h!43oEjezoI^##aoXiq()_&6%jnDU{&Z*P5%3Z%CWH&-PVXO&{q=f__#5* zaJa$RLx)_>EP;Hd=lA(^{B-@?-N^B?P%%lF%HV2XW$c{-!&_$pi4ZLPE;+n=SLYUw z(t(MgW<~AnkLq?GbU1CB`)jK;@r!zt{Xw73W|D4EURv_gA6H-}skvveUWGP%s;F9Y zWBgPF*Eh^>_92W{PF4@i-7v|t?-0s*iB~LSD@okjb^vkac8`QDP6yXhu9S@oir#dL zygOdkeC9cq{R(H!Q<6#g2nakY`LMV@TzDf`sa7SUqj=yW0AipAmRbeacNRA!@= z+0CBm@V7_M%BYy9{d|{GZRk;)=UTSjl>L}Qfrrr?Mvv!@piRIi)bJ7Bkz*b5AXNt? zy(G(n+V~i4*~E{IWOhl~&po&M3pz#A4yL}_D&rvBV0DcrP6f`r9q8r0uHBvV-brQ| z%dT6>sCDn+pehbFo7pmB#W5X17hOc4DWj4nZ*VS+&>X&}plGA$&kLqwdcAK0oA3a< z+HO1n{?i?6nk6yI_Iu#tHrPf#OSmaiJTXDZlx^A(0lS$yN=}8~*)}7Kj##pqoHx?S z<{~~d3zz_t2AdBZFW1F^_3o;WMf(%zX)|wW|AKeqq!Q#a=dyL7Sm8xc@H`R$*#;x7 zy9TMW$j+e1SvLbrswsE+$UqKtfR8DjTIlgI3BISr)tDGBN2giD_ae!=x@lJX-O${yNAD1M)!mj$K(PJhy*qvKm;R`R;zy1Pv}$I#+CfaaWes>P z!bzo&N9%}qteYHeTbBdHE^%VINC_mpc9k)T7FWlO0MVczL_=$K(Avm0k?uL=uDohT z*>wO}ldk_5Hk=DMDG5dI?5S^;F~<hMw!En*2UFl+rQ!x2)BZ;O zC3}OAVVtS#8K*hI7O=>&NZLq?j{#b&o=VU+R46dE4%{&3t!IvkpVo-`4e-+a?*w4Y zc&gSz2FlT;twaPS~ok;@XT9uB{(L9{T^Bf{35PDD}bNCukeqdSpZNN_kFORvYgDlMu zz^j(`5RATm+J6_7o-(S;SNiJo(HFd>|K7o&I?K_Jc7W1CN3u*Hb*mFo2>(alkq9Cd0ArT zI8{ttVCw5|`Bv{(lHL1Bopu0RpiYDnOQh3Lh?CGP-0hOB9)-GzHqhU5mZjFBtsuVb z6PhH_G8anc`KQ?KxV+gj7&3ZpKTyp$IC(Nhgwn2?S3uTAwqL=QAgyFV zmSllsE7WO@q{RX|7`En@Nm?(l11}D#4#Be@VYR>(P11nEzb_QnxOC*L7B7qFAZFg~ z{#I%FwTrc>c%N1v>dBH{ACx_9g>ECb9_}oyQg}Ghgxqj6b76+7UZBEpT8rLS4G+%C z^*n^zqQNc_s*Rb4><;d^hD_83*Fho(V~+V%nVo*7Q4mCFT}m3dt9GSSs61ytQ3sP_ z-yG^tXWFeR)xO5mt8^a?CwACW2~I^ycl^XYD+sxc8Y8p{Et5xRL~+{|U6+i0(;8j3 z%u}W;R#qV+L@gKO9-cu2QCkr21me-@{y;)e<6kc^;n5GAHl{K8VGE!s3GcE6Tq}u~ zBM)LD9h|5B0y54o#|8zjXU?Oi6EhXAFyC|bh_CROVRK`@)??30@NK=He8}|)18Nj& z^`d}h)@}fiJT9A6O=h16$^lXb@=G5KEg8d_%rn5QtKPK~de$DTx}1Y?Lgk|TLzz_` zz(koV^oH1k0&IqQJ(MrnV&_D-)(BU|15!aijJGC8c(XqBL3dR0)&)1c(-yaumP;dRQ!?J$A|!BGUqiIj zZ(XR(!}d`aV&XH}6&hUboiRo4{6;rp%IGWT$;=*enx|<@{yx`S&pdtk{6-~fnhY8B z^Sjo@^bs$nJbFA`QF`NmPV73+*pLB4wB017jgP0SfHo2~C4J<%@NYO4qQH}s9oZSi zgiXM$M@iH~IWXg!itl%0=|d0Fy<(|TqB#X8%FMi)7&OV`go3spD2%TxrN4kdLPrFi zR+cve()y#;w5afurk%3z6ch7APV8SO<1^Bl37x!ZIN?uF zNE}oZ@&@;Au0c}J2o2P8(Oh)tEv2mF;TM>81R1%X;SwxlG!mvdXabd>#X3q!%s%3V zA7EE5Cz|Mt#bT6&V1_CmMP9@_Br{iL0-(FIrY zX7&y~XF3$HgYToXPM$@X8}k-T2z<>*;GW~`YKa8IScQnbcxsWgZ>rf1$iVn5SWEYF zm+Tc!#T%LCx! z8@>QYeZzu?>WmOfvqhC?<%j=CPO<`5Lwl952((B0b>_{TXc# z%ZI-h8T{Q2g>+mRFsEe;k0wL|gExNE;3L=`PBR~})sD#B5BrkGafLn4seva!1H^$? z)=HP{}^jm&nicd zbQV*~t@1!LG*UU}xcVI)5%U;|U&I;Yx~WX`nW}s{G@uH8Cvpy@Z^UN>o70O*Of09a z2#ND-AdPli)d*Zq8(acLM~Dja)DG6a*btN&KHu!bY?%r4TBK*WGKps;5t7ze1VeAK zcG>XKZMfz!dn;jx4{ap5SwwW32w}DSAU;p^i?U?66V-vS@V7RBlbiQuYD!`V!xsr-c#M({ zHeRE!U}F(|gmiZ(A4&a1L9>DZeB==%x>A7`w`1PljahSk@3EZv+5JC6orx*~8QV^R z&pFIjIAdsxROKv5EwHw3sF`^wgbNN!l)$pN7XEH7jpLJ~X<>8IZl3vPNDc%CGx@tL z1<_W*79uqmo0r+wfx<+~`{JZ(4~iq&>%w%x6n1RThhyqIelZ3O_Vq}*QkDBUb{#k$ zv)FDi063j+ERGotw9a#t0(in2kdOw4U%u;9C^$mMED7EGyRCXUS5Rj|W?hb}rP)Bf z=e9JQe-nTfs@se_(X)4~EUE=(Qg~U7vj~6&A$~!)GVVM8tJwW+E!^00o~$=Va&FZH z?HLk^F6PCoZLy@RR|YXivOPCl0m#9Z&y&Cig#8hvj!L6MMq+rh`7)dGCaXi|NUYf$ zL5`=9%=`N}=;y`pyd;<%a;Gr7Jj=$-=oh$b23oozIET%VP2OQaL+y$9W=KTt524`d z&FakGG3gS1Amyq$yZhz(^I? z9!R}M)5lTgu*2i#X@#J2i19D(R+&iSCOX=fa%Zx#aCU6D)fZ3baQ}vjJ3;)d#sG** z(hnkKxhlLof@?_j4|%(AxHfwK)=CBn0%-Trc=&@nlR}-K!0G;AF|tB?JFW&qB-s17 zLAJqkplxXSisdL71MW>kz1DmkbSyi4FQ;hG{X-r=0FF0oqiKC_t|L)K6;^_9UF!-W z_E0XnKOXGwZL9Z*p6yxNg~7rcV6{u>r+}r@ z)XE@%p~{46ZdM^!Z-sB4q`h_DkO4b9TSv5aFVI29w$t}>LOmV;5~b1U%+E0Xdr1^u zLIfG2G1H$~vh}B3E!?AI+VQEAP4_R|M*n>4$%lzNor6(kU|rbQc{{;sQPXTm71L0T zetK>OT#sP5;A}q0>*5Z4bR)S&^!7{gjd~VYjT$>XE4!)a1Rw|(h@k{rHGFC6c@eFT z0RO}AKmMg!@RI(If0H7Kx8NIIn-Y=1L~#CuQV;WvWChdpSnTc!gbighjj?`lHeH0G z#c%{T)FMmwcaI^K>J^Ee${}7ZC?d{v64$}PxB2Z~MS%QKqS;Thn|^3D!J>q6RAj|2 z*Y&!p^wr&}fb9arW@bgPS%X4uZEX@fNfl%6O>RJ)uEbslF6(xQ0^VE;4o08KGAbOp z!->?CqP~ufcX}rR-?g1GoP+W zV`IPS|H}tdTO4%GJ6uA}lEdXsgFQjNHu3&=v!B z%bTffg}U+L1A1*Mjbc}3I}60e{50ZXy*$+RU3CB38Rn1QKr+7L_bg;#$Yp~139GSz znYda0WZf{m0q+(2?W~?n;)};mW}uPw#SFI0!iwtT2;iimJRHwOUjLGRr!^;?(+qvR z+WP+Aeqf%~z?~JY4Iw4@{nRxua|&o4q0t#q*(C1KLgXDv4RxC-_BD4OId8XxbAdTl z3FV6OoGiL3t6;&BRT0pVo78!%|Q7#zioA=z8rg4JR%t}Fa;IGxY;PtvMQ~(AJ z{R6Voz?-T!u^?-nE(Bxn9z@ z{IAU0vl-K1*{-+p8gpamNXfYnLE4Wk@MZ70*^d*<9nQED^>XGPsOnqH`heE^;(1l> zb_@Qs;-hIJa+yvwC0hW%+sxHv6?33?CoO2SV>$JUl+&1okPA+u7m!dXn4e(fiuaThy~8(6@}%vvpR-) zUJPBjg0X5ARp%cM{6RDKzMh@qY21W$Xh@NNkf7Dh{iz> z7G{~W+kN{(K)P?mf)gbmBD>cV!N{7(|{^)*G99{2>B#ZZ48$el$4_OTiqOljZXw*G10nyO@G+ry9G zXnH(w`_%sLg-`U&(?|L`zh|Wk8L}M^R;%OOXgOqAQ3jmwY}wz;FtTWL#bKPc-n!Q< z^!(1d?%bbKgc>$tO!SO@ZbO)-e1`fr%bq!>whwuioWR!yQUn{k3|xh@ZkM=uuUlyN z_sU-0KmNsIZeex8cg+eMgjE68ET#a|ss)CI^#@6ej<-J37{JzSdGm3Tw{KOa^LEbn z()IBlgu~N1C$!Ux5)QHpe3&OSKeUqKhD-=xakkOVuV*8F(9lDEF6#JksU;Oa~zq0Nk%)rumywF~rClJ-!V(_KahpEkNtupVy&4ZvKU;A$vmmY#pg zL<9MS&-5H1Q2rLt)C#(;_qTdD3XxYoy zi`C)2LAE^ECORi=EYCq3Azg`ubFrnYL3s0WVe*z+etf@Ph;IggHl+)23pN$@g|MAR zNkB){U#6zT);LU$n>~);b?dL^d_xfuY`_DWz~x3FFKAB0*C5QrJ;P#Q#__QAbt>y= zrLLRrhBMirOHM(71BS#s$#k807aQax8U&^srg+|D)@Y`CyN5G2K$eT_j(vDu56#<; zY-F}RtY+ynTi6~MGk4no9u!iF4_%;$RA(f}l%#*h7y$%?koF@WnptWHCa?k^qOLkx1%4Z+fb{US(9pl=Nm`H~2II_w*Xs{&S-wFdd3w&O|K>#!;yq#J z34`Q%ypb>`*a5NN5R#9uqEkd8_-YXR5K6KzQhQ7e^^@dr{Yw~>I@n_owhNDDGN0?q zXZqsxyu^l995n|9j=kD1vVzP%l)_EvPR;pS^wxO$n(sd`;QWh=C0Hz=u~oJyaV-B? zeKFBDhsa%3*L6XCl|!J=($8GPm7H1+^~$;iQ5=f9iI1nE&%#h2`x*Zi-AH7JZ6*=% zBO;9^Wu^QPn{`i&OIf1yKo^5Mw>-`>+>s722{!~rl&!>!WO=z0SZn5NsYY(i)j}m~ z3<`fg4#)~+^Ku`>a&v<7@|2qmAECkBNvo9J8kjC=hbwagvdkR=fIyArK!X{P_Iks( zE5?1zB(3n};KnVF?Fx66vpsA%np8Vqm7FT0bChQGHO*#|U|&H)tFtED`@mIVmd(Xi z8faW9uZcA`{c1zipqU6hw>2c_VaXMyQ<}&!8F!Bf0uQ_k;)75+3r+wC^v9=YTd>l%%TuJ z3I#XJ4oO4@tqGxf6-wN}k&Y^sS;87W%Bk`bgKI;?F?6+ze6=td3jN?cQ{epIIucCy z?6t~C)u8#T1z&wo)-4;hj!5PI2sqih|Jh&x7+bq^j#2?6(rekrb_&SJz>TV8 z@__-Vs6vQ2)b%Vl>V_jx1H8ZTVz9uHVN38au#%Kcb6asWo&ZflWWF}>l@qfq8=^rw z5+iiBe}>|6l&%yLY@GQ(`t?1B0>K-?MGiV+P|aJ^Lcr5{%d@)>VVoUe3JvH-&8yPs zig}U>LGzvjG|1fteB2jYnw|y7PQxKTn07J-j;Ajhs_7xUoIIi}f8)~VT@VDM*{YZ> zmGU{T()agH@L0%Si14pj<}h7jF78AEiEWw33$qvklvM_@EgXA`9TJ@67SOD2rE#Q5 zug=tq!Z@%8tVomQdloQ71esklvB{&uN_b|-B#;CrLR1xSl?;xq`6Xw21U15FZ2glx zF_K|A6IBg_d-q3 z4G*TA1t1-JF_iS*5!fN#wumA}7_l+ma!|BeLa(>&(_hrd)`4Oi!K3azY$CAeKAE<3 z|6LcVPT5hl`YAbO@GoIZRdzzO98Ka}EfTbEej0ZwPPtl__q!RRTTvm?#U)YrAz<2( zig??L7fRVm-A#VpFm*s&m>V!;(e*Hww%faQzabMze#KubMv%9vl{=eb{{bi^{s9O% zagKS<;kZScu#JU0QLfvLa9b0J?*j7^IJDt7x>rxfTdI&^ba_NXg5;oo5)a6M#`c_b z5hR%_@VV)ACpHrZc67Hp&8J+2BX0EehxZXM9Gb|+!;ch2A`!-5*~z7LJs8U}4e9A= zbn`+6A(vSdMgWUN`B0CRXz0KPlROv7$2>Ad`Ei`MOaJUlmyMcl1l$j4`naSOb#tep z-WEj*R_7=jVuNqwD8|R2M^R7Z(<#R1&`FX{1;jzPF%c)*nkrm|{Q3M~ruNKGl-&Cn zxD^weEo`opLEW&~6=ouQysho@Ict~NGysA2`2n> za#ezjTt|w^Yp;WqTc^zO^$Yyu2E9h_|4^`2f@e)MwCC*q(4{oOu~>+NwG~1J^>)i0 z16d<6y~6-VrP7q;mtemLJ{AsZRrGiEm9wgG`_V&pHPaRL*QL-<4PkoZJ&#>Hd!;4E zuR2R)($sB?9H5N%|YU-v##~J!k^m6|ADs32%Nay z3hTIj{bW2uQ$Bc-a}Whgr%Wz`D<%>nNHf(N0|AEo42#VH$ilXsI_|}R-`~Q``h;}- zH0+zt!EP3uohct%9nhk-=`Xa@FbgDL8^!Prs|H^tTG}w~3&POvsB*6nzQp%Qx=Mtn zf7D!8iLmwPtok2tI}c7-D3<%w^mG*#jbz{DJo8R;k>7;#Flia7qHwDqZ`Q>P{*c+y zKGgbE9VsBjUY}JS)&mpiC1Kg=c`pbA(;^Gw;}0&WtI;g0g(L$ZFaveWtYN!Zf)yMV zc_HA_KpWc^>Z#)Ysso1=nGSz9HOG}{?b`oT5#|wNp`{Vz)08IZq8O}Z3(tay z+PpSAZ`7{im7GA6{5D)E?OXQ61W+=>!s)XVYAtBRKUUv4ga1!@&9!9c z!HxjiY)IV=?~4-P-EU*uHDwMtBV5hWg_%np5TqOWpdb4h199Gt@j9=cw2<(!@zD3v zGf0(PB^mjdeU*!Jf@3S>#>Wn|`ug8&tP30%U1{hAocF6tu%)$_LKJ5ddx$~$S+6{n zABxuh7@pDJ4hRPk=P-s4=SN0rA&jaN>?t}!A~;8VFzpgy5HX1guQH_xkOz8O!syK{i~+<7`sPh6B6%|ncEx+2AQ>j zEDC8)Ui7#x8h4np+?vPGfG~q~P?eN2R`Kx;odz-0ps#^BJy{CwsrhWq8)Xs`E zyYm`n`lo`Yb&D1K6A@0ACd<^-V{^GYRRcz(j@CxNz`&pSbe(G+@r~Vl-|tKvVO}yS z=0{X-Q-tIE2>Q?>VHh*vRU=ZHsyW+PBdU^_y2v4$HM=YD5Bo`*KI=oL2kusFa}{l?aTmyy)%5?Ge)+zC27B3-vsl$8=Gd*iBjA_soVc35U!ZiB1Fi(_U2un zGL-ZWr@~T~0h?DYBRkSBdsbEJxTdUK^eR-*Y^3o6xOe%f=fYFT_v@*%u&m^8ss z%eYqsu4LN%oKCCqra$+Ahil8#q%L4%+tgtZk2UkF9U&bHd&Q$?3DZ@#O}&hf?-MP~ z9TAbw{SfYSaKUTvlY}#y@0*3g$hOy`Po92a`Y|qrT1_d<2JpK6pAb;xwdmd)hgsvG zB?_(n)Ifz;e^1iW?_AxB5^v$@`ryFyX|_0$NmU zMNVqd1WhX!Y)|`;WWW68u3==qC|+$*yW6^JMK(m&xu`2;gWn;&0tXGEcBL|XWP(Sc z;CCoZRu6oLGv9Y+x6ljUt!{h+k> z`jF(m{OYb@0Ka@pam#{0f}cwCIx34=?xY z8*&RN|3<}Yb!JsFed0H8*M;>1;-G+&S|3nH4Hsu=v~pf3yeR{-pVg17{6^(zwN`n` zJ8YoiU`=}N=-d>HjuK!8S^L zenC`xLp(PrKr?pDiErI1*6_A=9Ijuk(fJ!Ts>{KN0xj1Y%5WP)KcC}JkjQYj6ikek zjMP6+-em{d^`yl;+fpp;E{fw0aEJd%fVS4Irbu56;8#~gV2I9_p{z*hFuxWM3c7Yo zUc8-?3@Q+@fpzT3wvrPFZC*Bdv?v_gt!Ve_ZFycmP99MN$LbEoVCp zl%dO7e;Bz24yW0Y5l}|ow&1bLd1w<`~0Jt1thX%jBIIM}hI z2}x5H5Hzl*+>}kvk7g3L&CG472VFH^S*|ocepm>Ms(;x^osSZ>oh3cIPi%Ac_-@WX zZ+cBLeKB7tut51+Ufg!F8wu@~_ep_j*Vd8ZL~5*cs$bkqMir%jvAK~9J}8?gdw_le zZ+i+uvp|CSH-&h+5Q$mx-{u=^BMd=kacgPGB8n-RMK5QSo^tK8s$5$kLeD{;O_Ah_ zx*@@#@&y2VTJ;4Q1>}*J&|98$aA0pg_mTl(HLeL#;79lGZ%wW`CX}a@R+cTU2R5-;Nnt46=C`fveI2EuiJS{=DBYe08Huo0Jy++w zYKlF2^tp|jM1Asdv5ojL>eN{gX~My^eT-^K=AID^*tjD#<*e*oKuYBV0ww78Fcfcwm=Q*K(WdqSvc#*ctb-*kYQ=r%qoYIJ-Ovg&@ zAm*09yEc25LVbrg`{*cvi6+!JQ}k#P27ZfR2>J?|l(e|!IPwg8nAX($ij2dz@ z5q71cbjP7>Ho0a!XelT-YGtW^u@c4Z@y8N3`ZV zL4>nFr@9q&hm3@mxbpE(8ljz)6j|r*l7{1`y6M2!*YoIN8Gp#(KEs(U@MsM?REFcX zTj~QT)lull?+saF>yY8r41Qw?TM?H$f*}7U&sndLL`ESQcL(;f!Od--@c4f`eFJ-7 zUC(Z9+qP|+Q`@#ZwQbwBZQJg&o!T}}=Xt;D{D8f}mA#YP$!69rEfJyz#jF}KZH*Ob zPRIKuv}N2v{;Dv_J(M<0(VYAo-FWSN(GR1FY_mC*1+GIt!86C*6(6%i%WS zHPkc86XkI>g&R7hS#O6f=N=7@wAygFprxHrAG;M&N3( z_pfcfG5ryOG|m--Gp6AR@XdN^$Q5j+!RX4_JPa6V9%MY6EmjH#CT><#JA5<@lA(6z zehV$=@(cfYJ^U0cP$L#7zz#->0^PZ_wCjzWV_DUWmW9UU(VeDacn~0WVPPQyxV^SH`#o?N9Hufm8r*?h?d(+saZ7n*U9`ww>rM*9WM*$nR zGga<2zm=rW!h7}j?5IS=O&8>5Qrhwh=g06uuydx`GV-S)&4`u8T;`7cf7nPkPMZ(` zxslVVJibiml_P$2DXG#-MrliUh5~g7Cbi`+6aCUF9q^%!6uO+#D?RYLuCz}VXb?_!E30biv|#kB~en5zIEV8dn4q5Wn;_VU+qQjRrbgCIv@x1`K3Q6=NV zu<`eUG*8O$!#Jf1aFf!GUyN(xfpUn4ePt&VY-&bvoI)cMs<*I?v=}2|5fEVRuAIy2 z^+KFuU?8XIy9D5$j5hxUXfX{=pUYu$bs#vKChg;fs43Wvqj@qPya{mm)u~WGx_s=7 zon^ahnzmd_)Cqd#&ToNjv0h#s&;OeqD#Xii(bqx8vihgqfPg{I9P z0sKVAO{cP=v{^c1Kv^abpmf#VCq^LVtH)%*XD74;J)cSCZ$jq=T*t8U1ui=Lj|U@l z0)-uve=NYPBhLu|lF(Imtr8>1FN=UBvP)tA^|mZXUa>w7C8#x&Tlj9Z1i4Zg(Y5qu+?J~}BN6L6Lu_pyxg-%Oq zwz6;{>Esh7n5;wEtoikr=TN{s|7Zd4@r8w+y*MPZmoYOFs1(y>sF;^9f59qDvoLqA zYvPGC*s*UbzGDg>o%RO(Q@5wj940~^CJ=WQt0wj0?qBWeuR`oB`EkdR{XM&>W=JR6 zlEpPht+`kqi3KBXH!cB<+eS4Cv{@$PM&^McWYwRI0~Lk75qM7ASSE2 zEtxl2?Du41vZ=99`hnmx;$eAM=fM3*!Kl%7dnz-wrr$-jLrCyr`g@r=2jxqHXyqj5 z>9Kt}*0pA^7_VC1dm!MUYUIh50MiwiAM@M!BJ{u4!+7uiO1xSOzt%@Fl;Nu$<>8DE zS!o1TL?Xl3?#B3L#i2v?3?kU8qW?f?=M-f0F0={?2o73t{2)8!v{X@(!*LR#LM-))-=2d|v4PGNFr8GfX+G-9$aiKDmfB|4O| z!@7T&GbU4l#pI=}zKQViJndiJl#P~Vc2Tl!eMH~eB=ASdF4w$9Z3L&Wq889-xp!fe zC_AE}0$Cj;&B~#w(eAg<6-I4Zy0A73T72HBKs00e2~~jtmKnN&t7N!Clg4>rflzZ#)B+f5$ujFy!w=zdD*|H5y#cD(m7EVmdl z=qVH?_}Zi`HncIoMAq0yjH?YQ1Yy|@O5mHWym@u*FCVyVS0MrTYt$#lD##}>9b|n! zk&LB~$uyKrcpQWl9*U*V8w5vJm-0M65GAe4x7SUfj;oG2rlF|xNL{LGo&S10qa98& z@B&p1N@krHUDk1`evTN6hCYNdTRRX;)??d>U08SKDkLKy+^15CE8O5^N~L-S5qVOE z#j*y>;EpAu{hn0?Q7S$R;S(*?G(;HU_H>It+kj)(((7bgGbU=4_3vEG3yPzb|Dhyd+Eu&9jBp1l$rp8mCmv=*3van!CZ698>j)5F;tbip| z6g>sbYRXP`o#2l7wL)3p$trgVZ-+5|5pt{VZC#Ro@>43#8BsOqhUccgU-C1_dH@%- zWx_F}u0ovG%gyE|RLKb9$^vZWj|~l`fp-a7zARGR0icFw6CqU}WKFn28>1%-Jit~JOu7V? zY<|eIr<1|;2$9z?LVwQ9vobkwY9srX;*fErYNLu@@%+niILV0ty4PrBu{Qu{oB+(5 zt?bj7veya|3T(zc23V-J`cUHvxxgreEc2{}>nni(P%m7>apSu(^sN;`u_>s_b^>)i z$`J0#3a4Nn9l&-DE|a8ARS~bvC^tyV0wy2VJQnKA2#%K}ii(Wli;f%sXs&qHJuCwg zYKFZ0To*zT6V{U;S)?vU1ZeRBNbzogH@6{#yOM?gI2NwsU0zlwC!zgzEPU}-9nt9k zS`k5`GgLUP3xaZ>VO<*S+M-hFL^2Pw?V}-^&x;IZ1!m3(kuh0Xs=N7#u^-~psLgGx z;$CC2gt$^g-pVo>)XZ^{^2w6;$39wZdn2ASc)mlZ!@7_kRD8jQ)fc0t{L_O}!Xe%r z;v96B`N<|Jv~@HKgM@i#BQXd$k+m%ZC*R3jwI3;a{a1V0P>&4^$|$lZZJ6d(=gUm#n5ZQt$vGo044$63@nNjjmf? zVp@HV(}}3~QB*VD`!B2~*hA|(vcqG5Kumn|TofhVhqufqHrClsL5nH~N1mmXMR?d0 z*qt!Ejh37wRk2T0#-#YWv#}(Am>_V<5KT^7&b^FjAU;IHm56b!{>fqaWrInlN{E7e zMOD$`gv!G;kCi$rn)_|!z)7&pDK&xBycJjovyEy1XW0{}2gsH*6vwNRUj~;-3eSUu zuEOX7^%}PyqmV8Po@-0GP7MIPfnT7UHx9cl^Ey?MRPF(&gDy<`;XTn(Il-#{^A41i z1y19Utm`iSs2sEU8#ca)G1wx_8|;N^l~R?0ID(vH%#GG*i-m#_c9q;wQFqqs{sl~aO`q#3bqCrP*1Fh2gPf)yVecX3ZTKDItXDvp{h ztxGqa(-@*-l>y2P_^##g*E%w&M05 zk@l$~3Or{JDW~&=+p!KO^f^A{l)Sngf<_6*Push&_pJ!?ep>?Rgv>v|5;A=mm`R`Z zvQ+1FfRyEb_k&pcR4rQtjuEXAriL@>3`cU(kG*-I1)S6V{wmR zxWyRd_K(X16EHNxw(Ox>VHeTaPy{a3=c){z0)BG}uz7}9`VI{<|sA|GO!s2$>CD zVE`aDdxD1HVX$S1u8BIsO%8u^@MsMU)*2ISNO7lRBB*OcWta5_?Nqur{@e`HMLS4k zO;u&8a@ADP21g#wiRxWcS0B-}hCQ;>|ER0wuB-iE*zw}OQ2~u~f_V!QR%g*l!_)$X zcFV|S!M5;v@53q}MKq!pM;F#E=G6hKUELXYLp}{4i>F5ckEoRA77qH~r6=JbgL~?y z3v#m$X4o_$ZiU4CD}X?3&x?c|NjNIbbRK_8um7V_zN$c`wG)G|2{t1@kF--?I?#>{ zxY2tCcXen1lBZ#m60jOQzWm^+Qs!j6>#+xIepuAZD6HxTGZ(=Dw@;HCiR$2g8x$;O zi;~m}yeF3kz24?nr{YTYyPoV{r3u!o!a*P^wzA+h6-wZ!FJZi@UwF#G*il%^BJM0% zR5IHi65$B7au4f*KQP>!xX?_n09Meb*uV{X6;TO{pq=4n!5Ua(Cdvv7E=BqwBrFJ4 zmk~vA?R1S$cY&y#dKz1z$SjLh93r20zQ=J)A;|QVp-KQ-$`B5E-u_%BuP?K#oqq1P zwzGAE(|n}Ly4yyb9miq?fi{wblS>q(@DQvbZVLxdmmQjcV<@2=SqkZqu1CUf8g$yd zY6KM;vp)Z?=Ih%$G{>qrOO9!M)d%fVudLLx!QqZNL$(&KdnXqNu4l=3PCfLW5%*Ct zZuD;TRPTSaQ08js`Mc~BY;_*8=Dqor{M$4`Rh_3h>bHkLHh@V*scVk@o`8z>1+`+X zKBndqwAoTd8_z#9Qp52qF+Kb0I1MzXM3RckoevSM(f}yc2O0xQ0$au~$--BN3#1b9APrxGaVjq( zBjlMDXt16KRJx90;hhv5+hug;zl9_W_z>Gw)Z05G^hA^HlT|oXRW7z zEnOCE-MulCv0ENFb!Qo`bj~K0z9>>gSLpaaH+M=jvdy<29HLxv{`+)T2T6oMV&2OA zfjw4+57R?P8ylW)LEQ}{aIv?R-<_p%^UInU4z0hP@=9D5)Yu@aN@m?Ou5>f-^5Omj zEYmIwvS}V*;^0!ZbWH?U=IyNwQ?aA#3s{S&EflKeaHc-3Du~ zwS<`0zaQ)B&%Mn(fwLU%%hR`=otz&HnZ!Qd;LqA|_vZy{m>LGt8q~a+Y?S9eiD{$o zYsi@W`(0un%zh6HWcys%@Gl8wV`V#rJI#3Q0@iY!h;)!(fL$IqNn;gFG9PgQ$U;?+ z+V{jqd;X3;xn4iHoX00*5=XxSh(t~YooJ?Hl z#ZZWGedmST%HZdTtLL2xrtQ00Ex)kpsImWH&r_8Of)*6ZQI!fsm4Dwpa`Up9G$E2? z0-my!NisC5Lc8;PX4Ox1uX_8S5@|4+TF#HT%pwI6H8Flhqsm%9Gm+hJ6 z86>}zn6b-Kxft296H2TaRO5Wxn0G7Iwv}ur4%1fGHzK3}LZ${m)0rP+1tsu7?sN+2 zlT0RS1{rBeYWNUdgqNZ+!uCnLaD&F0h5Y=lk8>sGYsJ4om_+K_u`LCqK`#+?XhJt6 zaxU34^;@2bDT;2Wrjc+(!N*Qt`9HCOl`K22n>aq(;PoVQD& zGa!MERfl6K#?S*DZg#>=yue=5$NZd^C$${AjY*419PeE*yM>{^f)iy%LV)OtYrSD~Iq~O^y~GNzy~|NJPt&=uv*|;=pza zbe&Fn&^CLA7VhL(%gKR{OS^a1gHC=*CholDNRzg*NL^EISESw4B%TE;+>(j4!1+=T z6zo2~usM;yu>El64Uso*M{j2Mb^kq4u}X6bBlL0)(gpiN|dq%p;0l#1Jk0$S({B9^3b zIwc)?b8i7YZ%)V2J8Z2FOEerR_nXHR78&r+N;Ph|ATMbWZ~a!rYric)1&U9x?LCK* z{i8i)Sr$wVwjLgea9;e5l6CQb4|-D}_><>UB}V>#;U(B`8T)0?ZFg2>h)u zrB#rOiI6i+$G&Wt2%FW5Js+RB8Zkbo^6}7^2JJas)ly=_#i`M~8%?i8N|MzTpCeaU1 zml0Z@o2oNJMTjRoWbR!Vm?A}CDIZ<}S+H}?p}tSsRyOb!$9?A9BkqUXk%)|V=s7x% z9H<2Fr9e*o(iJlz6`BoUi~nLCE^bU@$V7&OAhgOx{HIpT0D4bud6gYB_``ekCKo<# zjh?-amg+@QgrnNdh_<^D*{G`$lY2KcHW}nrq9-Gzx0Q&0YI{U>d$`Mm!FekhP-t2|)-!7>?0YBG6`B{T@(Q6w70URrqP_ki$Re5h`c}a+Bo7RI01Fhz@Z(6f9q|nlVxm z;%ZE$0;h~Dm>5+cAV>p`64-d7V=nV-UGxTw%vfeh4fIA1J!eUf!8(-JQWIwm2$Pam zxPnqwoH_s)T`((!`*5bLYtjv#>VsE3LBq-8YsvL(SunLNEz@yMQo|!lq9V|+g1{Ld z+X%z{a##U^fCf|WR;hnd>(+9jy)h#v*X{j)2CV^rd#Qj4HJfdwthF%7AX%CgR| zZ8&WX6{;(^7f`X0>#6k|I3dS2<0@BMpE&LO1!sx)-o$aT z4bQ4GL8<|6{`y!$Xp}jI2QupKb*4j|k`dDyZJEVuX@JIO2~^`7d6No)#F;@|A2r8! z1c)+$utMA{6bp5M9s2;EtCzmqjwqRpb;OeOjPQm+VkG2DeaA}o_tu_hUe}p<5P3+N z_{Kc`4#*HTj|%G%-jos1>1*kQYZ;LO9{^LqrZ4r&Smq$}IU}aq*W!!TG9dNUCpL3zsG|+}!9Ua~CQ}aWn0`vRnEWhxW*M7#WWVK|)@xXX zkF+l)l&q&i+_P=iw9j#X;!}^Un|!Y5h#Ti2@&l~t!xItVtZ}8#7lbCMq7sHVDkUTd#wbCe5BIW*B+~BH1dFpOTu!K3&kpA}53g8rBw!Al zQ%r}_!c-WtRh4jeM$uQ3A~yO@NY@>rbyhlAs0|q2&$yb~V`kFQB4MzL79G z?E5d@U(@@?0|3fRc?Js$-h&b-eMnmHLR|61b%p1X-i8h*h3w;8>^Gv{x|z`r9GlP^ z{{d_VFO{%5@|QILum5Q@5{lKQ&W zPpM;oDI&yNAH=&W$oCdaYxjkZcoL&I!ZVC7iov0N54}PW!R2+$yOE#@WZWlPy3qLP zBVr@Nhbk)n-m8Ewh?j1XORf``18AN{y@9UbR1lqFTX(?*Qc9FK(6Y1U_7eksGIy^C z0u@}z5~g%kuA^65OHLF#vef!SCz+c_bpjrSb!Yim*Ha_%phH3fP>ri?fLSLbpl=t? z{8N<3kPYbfbTL2~XAFf~d|Ec6kr%>kx>!#7f&h3(J{w?vk&*xi&@N=E(^nGkCC*UJ zAvF@TS6SbKvcHj50>PW@NiB!O^-&=yFjrj^ywv$YeDLwh%?PmtVC4ZsZdgEyrLC2j ziz?t~LiMpNhM6pnm6W30~b^VcZEUEC8zbLlA8B} zxGR?=KvocNu)t~;NR2CJpzWYniXV~&5w)+rW+qpN_o{8HMtOS!Qpf8SJQHGtjNKcv z2xcZ=UbN8Jdz6ykVI%yzZ6dUH`7?G6k4H0cos@}&cr+HE^5_HzA1uTJybu&}ZPc9D zvqm1`D};wT*1XN?1j-^zBhV1ts(|C2xF)l$&KN0#km*IyG@B~y2gQw;*JPNST)80u zW)mVsLlUQv3W5i!8W@RmtOO!+52h2pgWv)SpFanU3fXh{Rd%+(UfFS1Brgw9n}Xx9 zs!_Qi5UbeSv}j5S_pBd&|DqdcB^BU>)3e1r6aa(_H%35PU-uETJum{aqq!_7(f`&0 zmUwY6AI_ByPByUvPNFQ$nFpaQx#+11G|ccb%#qSoM}peogz1hx>XC8{j9zhwtA1I& zZ6qywLY!c_4$UKq)t71PMWD5zWFXwU1&kHT^0L){d?I5RDTHH@#JeF;p3rtW!O5zu3 z!uqk|h$bIjBig`PY0$mZN@U`KDP0nGEEslX0SO?a0=sE(1Z4B~?Cg09OvdRl|C)$` zgsTSe*aorSw=K}dETvX)3BC0Vz*xSoDzaw z&q9SIWiT3fRywT)U{lv+zAQRJsC|=bB$^5{DtohhR7Z0*V7C(MR^Gqpq?{D%AfAX?W9g9?C% zhyA^oKtWV>M~l0FL^@dB)-4ue=EAB+Q<^9C-0xGTu*%$E>7fv#>c^mQ7kz#*QW%<; zBP1F27G7TIu1H3-v#Eaod@^3ZPclf*(bEECMRB#tq+Wu>i5nCA9}L`+jG^LHSY~A$ zQs3t^$1T0sX&_RWR^yFz{-D%5e zl7x|n&!w;<^J;cC#L8u@3f!|!?k8y?sgoCcRGh}bwJjl2jV84)cz{s?nqcHm=g-UM zGErbHV4_tNKyzk06dw31NWHo8c%)G9C=nGB@}V+e=Md%_7e-s3*`+CzH6Jn0#~1~` z6$N_0L&Au968$R8%op_cOM{7rrI&iJGA(L>Eb@vtlr*Oedl<@Qo65^WNH_8;_ZJ1U zOy6`y7HIaMn@wymmyj#IM_?zRn5$;0UC%4<6PW3X#!H1=O(WlHFei`$ z<=gTrfMPTBMEf!KGml3E*eyttWOM@?0>#|zf|)`Rg>`{}D^LC2!MU6~i*u=V>DLe# zfQbaM>quAvWSwO(8{`4)RH89C$_Awz1sm>%BwJ|CAPFBzZU9fB#OoNy(Iz<=Ru!@) z!Y9xxq&8Z2bI^%AXkL>o8IclVjBu& z$1d>g5hvuZlh6X;8s;AIO_q0>zYrm5p+g>7e1eRDcZ{{jpyR|E)db8{`2Zw6vq+iZ zX66d1yqNLeJqa;Z46>y^3RArxum7H?bRHHKO8?HJ3=tykmp2&^R#@UzGLgMo7I_eH zGgcj;;NO~udOM^x>UW|V_jkHTG0>Q;K3l4rx+0+ORD8ZKjxR1BJ=Z(`$mu#>6>>3~ zy-s6b^h!3uRm2QIeGJV80KjCMuJx&qdP#^F>2U?o(cp{M&-bSPARtDX=^>1x6rP|s z9mMyVru+h;q;6tUvrdyW6AO@wbmmupMbN<8E~WMA4E+U55=mSdB_`D13$a#$XFw=x zd8m1Oyigd_K$flqU*ldaYiEAi;}6A9G18JyG0@|OmjBRvj0qZ>QZ!I77D+^)stSs# z^eH5HD1u&Q9I45G>L@qHz-nDhM>02IBDW)5Hf=)`m8>%9luvXgb02+g3SN#<*g>*^OP;gV<(&d z9C5+vo56^LMdAe2hC^%{0hA#4t7|PYMgM=pllrIO`9tZ5kUtVjO9M%khxjFQjeLM( z;*O>g4YfgeQe|E=*d4uc#%of5=t@B|4}uC7)|_HN85{9a{i0LF5N;zZ{;`ITuVNG; zk*Gu2DdLd_R(H~OZrL#>i>wnxW!!*JIS_pe95e>L*wqYp{AVH$q zrHp|jj^#)-jVA@{7(UVZ&9wPC;W~%B5DA}_jqy;yFvL1~k~$;RA)t)^8^>ANP=ja^ z|7!aPLvmo{Y1cH{e+{F3A=hSx&RJ~NXfwQTeGkiK+Rd0U`ik~Qikb^8L7^qwJ{id0 zxA}E~&&I^+QC*im-N>O3Ojh`EWNsp^+_>t4;|gJeLJIUi!wU|xHufOS+ZK$12Cy856+p>r8tyn!VQWh?T8v+0O-)ar1U$*R0<(UU zc~liT$d`6d=GriqmI4+QUZviE!{+c)$)S@fV>Ce$E8DsuQ2}AaOWi7Mo)h+NAjfV`tYP8r_* z!Mrt-??4Z5vWE#Nc+}n*^yXfbpwW|X;@ah+0_&R}#SkgM10bb=WZoR)cmFke#vRki>t%}0r z05F6_$X6~?p*_v!RRyQ~dI!>CWR>M6&U+E&mNFa#qK85Uc>xizT2E3s-pOMo#ZyCS z0K-iBx7*dNdaS(#f~qB@qaDig7v@!ren^`LuTsV`@OPw@{L7N3$C;phG^gD0ECic{ zxriJB_@?EC4jnj*#UHFNae|gA>$&`-SN4>!#n_3?{Uh8$qbQd@89rgv#aA-lpGqN} z#A&VSU>Lj&-DK68geSqwCqB1OzY*t@$KK%FzJP2xA1EI{SazFjBV0upE1N_Y7n1Ek z;H(zwWR-O2lJM~xQW~Af(ksjvkh9!!%R?VFPKO~ z+fUz#+Fzn?paVQB1nSN9ahd0P_nO*5a~8l?L==YDzOj4pA_*0*}r1e{TSYR|>+a1&DedS}p4h_M33 z5>no!3c+uE37}wJ=ZDf-KthIO&O_U7W|gmRUYcfIbNc6(_h@>COo%}ZysdY#yHw_2 zib+0{ccQ1BUhhIF`7SIiN_~XI8V^1yL2+38`Gt_@ag#Lnc5~VnvDD+5fm)g=&_;N_ zr~8_d|6@?$s>r`pv353MM=t^ED^=aV!m{yHC!yh7C!0J#R` zcQQktS#-jWi)I>No+%;88+Z?{ydK$2Z2>lmWe&jXl3Bh+*=D=9f@?Wwkku>*I47!G zLjOE`RsTN^r+L2|w}n1>T>IGtq~t4T&={`}rX4)j;e3NxsegYFB%cA6MW@Mi16i`E z?)o=K6?dhlKi~j3KXlT>l0x;DaCbKX!jFA5!ruScw@y7QEJ!=(yK>mLtXQYYI< z+uTNN&-am#vNeuEk*Y-#ANGwyK?_mw8_Y9ujHGafg{N?|q z|4LT_`kejF?RHyl)?S}^&@IN(XA&FyaR{)c1p zeYWFDWxMF2mlfDf&+B*5z;~v;`6FhC>X#egR!@L{aAC~{$*-Fg4Y4mU2J`dywzP!K z*T+$2A1#^p&ChFkq78mdulMnHow0g0{ASB_u6O(Z8+@R#6VUS@qh*lpS$2-1fjd6O zuPVKq^x+JzDcMuZ)sEM`$LCdykC&TE@@u!@KD1aNqO$6>ka|1NlP?E$f06J(sr*Kk z>8N%jHY~eJS}V_d#8oBkFI_!bQ2cg$_vk^nm>r*|6!gsBDdrI($$ocHLv&{hY~9no zVa!J{b^)v;3uL&BJlp7D$4k_+RK9aATII8-5dWTq9s0j#!(wrK%6Q6Fa(*#H7Q>vg ztDBMB&~h}GvM*Lce>ANuM+eALi0v_FGui5pRZ`E~XB_GphOL^YJ<9W@L&M2DXYCbcy8urm63(^J4o^&I=zL zKhHlIb>k(f(8VAsP&wEE@)1l)mOj+U515IRmRVNwP!85Rx$sA&2|7%N3%%U9olU3D zuXjTKivK4ivCao~Pbmuq+h>A>sC`&LK}x_FW3WA(cg%6}?_ z`9GBoRE3ttbo!7{h)moiPN=quXT|r|gNJlT&fj{GyXG&aO8hLqPVs-1i{Bml?0b%X z`Fp!LyM5P>?-9h{u23Q&O+t;J!(8S9ga*fEdg63#f%ZmoeGbu*DsWJAzN*V?`JZqI z|0kS3fzW!Oxf~DRDlQhkyHMlI7(jpO#8|n&55pPe{UkHRC@M zAGPE6oD9WhMd$b|TLEHP=-(0QLhP`~jyFqA8b|{M5fKD6Px+R3j0zvhPGNTw=#{~7Wmo^t8){~IO%!9-kB zP?Vn1vu39-ADgyzWIv4?+SF4-sPkFL3dA?StQNpeqpnVwyi<}RZrg2T?@g7BTZcZo zS!DqCy*b+Ndyx`7`I|*iw}GKol#w4moNT@zsTOFHkA|9pKo&>N>sX&K<&{}+(fZ1b z;t(8W#=k5Rkq6geygyoDCA!Z6?B^e3BT4}QVf@|jGxwpYcY!;)wp2^M-Y4fTi@aK& z6Jw$K9Yi2TXu}42g;8fSQo*!O45^&@x5{RUYDdKS4Bj-3-#)vcuhYaoZKz%VU-Yao z3jO=~9JH3=dLs89n(o3FvQFbXZ?K_T_#1ri?h#MQ2WHOIo)X3Gn}>gfmOfa}pm%e9p*pm4i}we=OhY^dDSMNRTHUCz`B zUyD^7)#UeXw81>DBlCS(o@UrHz`y>Qyh|+HagMfEJ6%oax#bZd*GkzO1O&= zi!*$YSv{rSK7AgbFTV(4$f_8p5fL6Sd{Q>wy^4kv&gd!YGWYUBKke)gyfo{7SFQNe z{OLv4dQ&|8lCPV!8)7bX<~eg>sajTve#5o7{`|{f-OZk$a6SuklYI6G4)`K<`xTd= z5Cq&;d)zH1&PW=Wh|0?IsDbzBBW5La;w!uU<A0I_A7@xefKRc z7sijq4yO&5A9`rD;sqaM&r0-z7olc2e?en@rI{-L9?dq)P&cV9=h|$SiP2}7;A?T< zy*=(*5Ti$NbSH4vGOM#-)uDFvHkw9ivmo#IYwYlE6ku!ncLC7X;>LS>%C`XuAN?VI zA;W>At;H3^nm<0z(tW^*`u*4_c-QJ%B-M*t8B9}#T23u=H5px4^<5=Hsty zZ^bsd(Ai4nuYC7C-hcU?U*;Y2fC%i~%72VbD*luIYzAGs$`P}%_TDk=Ywm$x_nI+} z)V_Z5NRX<_>9z(J1z#k=IUePNni!bro7!n~Ua60;{!dLLp3~1*H{9K!4 zo1*?sT=m{RAvI;YP5y!T{=_YcH@nZ7-~B3K_Y=3my>S1SHV$MM;^BjWPz?3vO=Id> z%5DF}Bdq^}8|BtN%1*q=5r`|6sXb4^zdBbspnTlnV~Y74yH^$zzwTwEcEW9|>tW*_ zS51y?ZsPMrJlA3_e~*OWp138TZ|NCts<9F6#WV?G*|Fs;|7SH z|Bc4x99MqF)4g!SVM%`{RP|%f>Zxxa@ve*jzK+K=YT=VH4bO8ov@ngar*{53RP7uv zFxA4UWANZ~o2ncF#~YuJ26J>ak#1(kI3EwgeO!H&TTJ&2&kct6h*7*3KZpP1#R=fM zbstyw^uuJ~>(%Hw?TOoC)C>HQf1z)k)R*K}+iTNmBi};k>w>gxuGd#!^BZ8-dtWOP z2f%5QuvmHIw%vT!*2X71N2^5z2EE^F4J+3+BH%qCC%bmfT)z;bV}8`D@cGU*M_LVi z-&B<_X=`hEi_?*aX2CIr3cwckM zpu>Gs4^?nz^gb=ya9#7ZY5n0avAr>P-@HdfUln*0GV)IC=$OyKoA-Zw!hEagI=&y= z*WSQOG98NwWD1IEoaBu(q*8XozUU_nzdhq)l}J3JA0+3zz_!mVy=dm+>_oIL`sbBmnX)*gFdyv*v^zuzQY>%3{y0j&8!RB8PNb7?j9V)V!X zDUoV#Z_|9j-v~<>qaWjSeq7DBWC-S3-hsatopS;O(ZV;@wCCGdEvcr zu7N-DNloAGefRpjhVDhddRrkhTh|+awcsvp6B1=|4D$s6J^3=I9iOn3yoY)S@tXRW zgORNX5evBK|8V3*h4)SCxpw~|T3zuP<|0b)7+d2f=gE6MNPY7^ZI;esPmGz+QF2xl zuGx-um7;b>)jZ|X>Z^UTe+jH!mp!XZohR6cquRC8c1{Zm1u+|Zki=tjpIy~0G0yxiq5dfEK$TT1S&@q8KKwlv zhROkY-m<)+HBgsPM&t%2;x*B8XxQ;1czW-$-cqTEtGj7IS|{%5zI2~QZK<~_B%kl} zWn=A)J7fb5phi-r$#W@k{c5^S?-$fOMB$w>OtW=j`o-YDZ059D zUmbANU#5SKzFH4z-#@*IaQ2X1aIG$AMR4d59?a>P+0p}dW9v%wmP&>*m3gdTXqJ*Mg$S*3ZLKeom)#^^c63+i@Z9$J;!_gQ z3hA?!6x8D<{DH8`2UW<*$1Uw-v-8rO!vp6JgR=wQuU59X-oc~LdCE;So8C3^k1`!V zXBSgrhX`QXn~!#qz{l^W4=0lyKwSorBP~FD(x9$-$w=ov=aKq~8evB7w_DvP@!jQa z?scs$@Ca-#hoFA(dH2jp`Y@$T1+Hye4Gd?A%vDtq?^-O!LIFB|LFJ6>hpJ9cA zo_IvYdb98Bey>Zng{KvJ@MlFHZQU^NH9i-?*A`~Nzn=uk&&bWTd*6JWhWne3O4Dni zm^kTRP%1mFWt+hT0o%YXDEty5^$ttRc?aSDdSM}jo; zXUBi+w|e}3rEHDe`2uWeo28cu6o6)C{;lf6L2-s<<*(XFjXf7yTSnG)DqJxRZxoO` z==*FGBJgp$C&-{g%i7_lqfkKSZqT3}9#a#T8T+;iH40w3#pm-5-Q)^U49X(Q$t2d2 zB36UuGsRR>3~7bk%@sM8PWpU1W5{#7+J|!=ZuVwEx7F%!wvD%~<>HLH<+TKU?f-iE zA4@>aw~t(7xS2zV2x_25$~{R%wFEN@r@Bjo&=Tt1pWgoEwea%y>T?WS5o3baRO{5* z;;a4B;)|Mydw_5MJ0jzIQ3b*2mVx5wBgJdfxs%-2XmU$y&23B#s84Cy&I<4N2@93? zG5_GEnq)dzdMN0T=mXSyD)b8RbsVxacH3Pv@B+4nO4Z(T*J$3CXGXw%+ySK#FN(bh zf}9n{Unu5T)cC{vH*WyE&^;jVOS@R|JH&6?KYKSv`|wmQ4lB>cTX=kbA3y1@kz@!( z>}vnogD*h`fDm3M)U-tW&Htc5pV(zv9 zHq-*=Pzs!DnJ~wpaPZAFGJn-Qkyl$zv38QCxKqcqP#|j~^s>L7pAOAsf%kR&cS@U9 zQ7)4d(7M5(ei^6};gy+;A|s|P1cAaSwW`3p!?zL7OABqeSL)HskeWr=1`i4NeMFF8 z3fxHj^pEd(%Q*VF{wGyt%B(1e%rG7gc4&S-8$%xK{*K0YK2odntT%8@yr~@tv@rmAe)OCPTYtY-a2~m$T*jKuFKcb$&kqzM@+RuSi?t=-yNYpkPxOTDRHe zC3bTjxG3oASH?s_v_ABnU6eLD(c*htt`t~i&Oe!>iCJU#&+AZ5Br0R;U)LpnW&6GX zKCi_k+;B9jS6AT7b+SM{gldTU&GF-M22o-SWwW0ZFYgn-srG!Pbthl*RN>FJ-T|MV zi(k93uhWGQg%=kpnx8l6Q7`vtd>+&hnQ-6^KI>-z+8I3HHv{ZbUJGHApxO3h{Qro0$0)&?rU|fZPusR_+cu_c+qP}nc2C>3ZQI;_ z-f#Ep?|ZJQ@>FIdA|#`-oFbt_(u!Q_qN21=7~_e=Dy7P)z{(@Qq86;K*{iVt@kopte_tffQ)4g5pZau&avFqKg_V5V^PYas> zXf~pFgC&V|=S0EiINmFJv}!PK@BkA1Q}P|D$);z!)b*@iGx~`#m2m>!R>Hw#HAyNb zdPK`?J?{6D=v*JG;kDY*ms4P#V!Ix7(-S^lik& zkF!k_|4WXemb@4Aa<@uDX#jYY{%7tW-E|(T{en&>i;m4E=biDz_+_FxGqkn4fDm$0 ziB~^WsX_b>bD2PJW2WYs9OsalsvfUAyt_2};R$To(eZdM{M`WfrYX7*!)*qqrHwQIL>ke*V^P5OL>w2cADZiLR_^b-XqEA@CXQ1nTSi=7Vd z_V8*m!oS$`S=aS41bW8v^pVDEp4YZ_STTvp7`fx7J-er@_~D6k+A;9BZ+16QChNr2 zH*E4PI{A4XbkhtIZI(i6%qxPpVzVFQf>*NR+ zHvl-Q-119&&$PP`BG)#c00%K^5tI6BeI>&?Em>>fE;55l@9gw*lIEl_W%`A4Z6j}B z@6E`?H53ohsGPd+g6%-z~YCxj~II*VmO(0Yw z%5iMncVRh((WFFK0^?D;)N{qDq+%66JZs6!V3P&abSj1QOh~%#hwp@+7r+6Y9qhe#?|JO(DUR`UpjLzC~S7#`Hp?YK1QHEk>*27QTo9>!NR5W~F{VB@GGJKxT6b_p1 z=|hDz;JB_5`7q8Jr(X8~D?6{dC}K;sF}jdu*{^?V6nJRGhZj3I%njIkqG+uAQOC9U zl)bk*TYA?beu5(VQHXiR!3`Q;;ANhJ^RKGX zn6LVC1ZU$FEFw}Ih{(2I!?VMr~^Na(GOIR<&q)>it_t9$A|Kbh4!7XGOs)5Rywat=yFD? z*5BlwgXZ~sq9U9!ObkGm>G4@B@SqLc*{Vh(1HmFc3Qo1sRKqgu$jhcS1cfOF`Vw2j zK)n$x`eLlciC37@n}ra=%}#vx)+$FX$dl}K*Bj9V(~Xu+&V$C{P1Eky*Cw7_PtRk= z23q&jmm)E-wGmr_QrLZrqK&y4#}%6)+3|YTkoxy>QL&* z6Qk>b%&sh{I!jdbb0pDyi|TQ_@YSZrszGh8?ADCj75qwHDQ|B3+v3&T=E}wG(#r2D zT3@daP-!4rO(C@p`2OABK=qeYBM_?(f%AP<7as&~kaL!gJdejk4cMuAb-D!sg#RD~ zB_d$!kRjjr$a>P{ECYY11@FLA^@*zU>p1aI$9(Yo#GUr$b$)2ySQx8CJDi~F@;-v* ziTDN_D-&x|QSEe@-okh0GLdJOa;^;W9xPXYu!*SwIMH(Xh`(7T5Q&4fL&y-zzi&PH zLojdEhi$~70SP}D_Ca^PD>!{&!M$S7ExdmnG=k_s< z=7Ek3gP=zCeMA|HGy!pLO5-I;F@+-RRX5eox3}iI0<{IC-bReQQfE%`{=_4pdUJpC>dh#(lPCN03-oOt+E(vP z5KXp2v(ri!=nq6ZZU$BCx|@HFKtj`)&AbZ^mejUHZb=QUVPqz5Hh*{x%bdp_&N9pe zmeovZyN)oj?|%~IkLKQ;_oO$)?;Ik3&7 zG;taAv=o8?Jqip zOkN31c}g|T@v@y#>Y_HRBPYz zO!ZVqdYs!M)t*PU{RL--qV2p=VQO1)?R*q44%g3K4KrIgvfsKUw~_y|w=MIz(NY!2 z@Dsn3yx1||B#+Sr>(7~xtq#(I3v-IITbjKIG0~6~j_ZESm06|4?n^I&F5^C_(!*9& z;)lGTdy&-S?k+D;�BP%RDld@T0#%*;9MM|6od4QZ8OOeQ(0 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 z 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 literal 0 HcmV?d00001 diff --git a/Telegram-iOS/Resources/Dice_2.tgs b/Telegram-iOS/Resources/Dice_2.tgs new file mode 100644 index 0000000000000000000000000000000000000000..c350c4d88c6e83a4181e3e24466a35744a2c459e GIT binary patch literal 61430 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\CX;!Wla34T; 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∋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%0A(z3a9Rlc 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 literal 0 HcmV?d00001 diff --git a/Telegram-iOS/Resources/Dice_4.tgs b/Telegram-iOS/Resources/Dice_4.tgs new file mode 100644 index 0000000000000000000000000000000000000000..0cc05f7cea2686e3f1ec7bc61ff16552bb9b0969 GIT binary patch literal 65388 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

$W>hNA?ZKI*E9GA7vQtwB4b3 zVioBg7m#^{nZ+%@)`0tg^SvEPNo`$=c(E>it^)h zQUp2sPmIv(j}i$wxDC-Yt4&j!GF_Soh(e%6t1EbmYgZG>K3|#VcPylbZ^3y(r->`m zRFp4c0t9$>+ns4zu38eF)zNu%4WGQ8%4vAuyVC0m|lxi>iIb z6l>b5>%dD-qQWF1G*OC2mkAJI)!9IXIX!o#^g>N{D(eUiBp)R`+-O&6GZbnxw7+ZZ zZne{Bip-bQX4>lBZndk?bhcL8kamTvb{Y-JBiepd3MH&Iv)XAivIDEX+3DmKI}HZx zLwe@UI=Jn1oCbre!I*S~(RJZW32t3=))|~P^^|!A$V|2IxF|HG>xo@8u+^_bs^|-v zR9f(%MX9N!lWVn^#G-F>XS{>^Sv0NJ3eDQj(WZG6ZzZ3Z9To*AQ(WDHSE{wu7(A5W zpodF0ZWtY8W=Z17f#Cty*a#q194(12BsY?m zOS?~%tlRV%8MI!lW@kg^L*xmcxAptO)`y2lF?+uf11ypRNR&mH5IDR!wK6DGu>&q zC^B*70KIJGLnH2Vt3g3bMS4SX-DIc5SY1IVH>+K2gB{yq5>Hgee0so6Bf;b-ve)SV z0A(He6re}iVyhBZs5UivN-By7D{gE{6##>#zmq_j=1$%PbK;v7B!I*>15_7+2aCNG zGf?kI*3>U)y8?EWhxHWR;j$ZyH~H&~p85=RGzP>;55`=#dZ{TmmsOL>nKrtUv5Y`U zrxEnQLl^bla4g+`D+?+0t&Fc+BH$C>Aq6Uc&F{8cpRE39BpX^jCZx2TJ1rNniuzzSnf1j7S}8_w^8D? zI(`}r_ag;92d=oqw!t8YY(AxJ%yee0(^vv<<1Tm6P1I|f96i@vbnAMUwQhYA2;oGD z*0vH=6XO|P@dW!<8$n6swoA_32vwJ+QBJE~u_@}bhS_#u^(6HK9PUgDSat{H^HRb% z$q(4=ZJgqJRJUCK85Ap22vrBG;g^GW4K28;5JM1$GevJMc?uxYj8$?Zahz=>GvuY# zQc_E;NkKMRnGhoPOY#I zS_>uL>ggs2zL*N^v+N}mO4&TB^Mk@v3Yw5^|I)) z1tp%dEvm^v{?oRsH0Zi`3HQ*p4v*5*&}H72jz-es&=(&rA+EKtloa;#D_b%l^Qh_8 zErx2zY@=+Cyt^4yB&*A(RYwr8tzG`x zuvP1y!RPy1ae0GWHfhO_3_T~l@&^|xv8zJfboNDA7rYZJ1ITBq5>$Mh2ZpaAh&(gGvl0y+VdVUD-uX< z(kyjcmXOG&7N*gT(;V_?ROC=EGEDY{;RMKzbGmT@9B@hLfq4P9+cq1)P$GUVC)(TW zcAD*wgt(djCrBT=UCn0jILINbA0wM>lNpidMKb6O<|$mw@ z#CV%(`P`GeK44?26|Ro%(KuAB*`xt|gj4g)7dsKHwPei0gBhzW=$Tarw>C5_>}G0M zTiV;ea#UFzSQ?t)-FJ`N6|`YUbHIBSK20q;7Xa0f%@*Iq^=Ry-N_nQok)5OPWe?~V z8`4f*BM^WmRSl84mlt1=+_D!(0Chlx)jfW-#`r~~Kl%P(hb9O`4vWmqZrf}URmoHY zy$j@aJIzLkO{$sW#g1`V?P@g6&LQcdVgZ(QdEH_R_fZ_o8-Z@-+SW>@TFPoNB^@)> zX(A7I1-{~$tS3s?x+(;N}ag3o-o=WT~!IlPcta9Fiw>-Aih~2(#zTBQ0)%_ zx}07-Y8Nmb!1H>FhJZzj1VnO+2iWG2Ad2Q&#*u3gY^Jhsj>HYP$y}!d1pY493TbB?@DOlDu_MW(AvPp`)cG@*jK`P1m#czO$co^V#7CS5Rs!U^*q-VnCUwXQgs z%$8Gv*Qo6pSSiYjr9QsVt(4=7Pj5jh!H{O&s2A#r_++pYJBpoRA8x7N?Q%YLcXi!j z+h7zZz>^T5=Z&CO6zCQ^tOQ9IVTD(Nt;${|h5~9rhi|uB9aCW`8HV!HioIFr#b?p6 z(>7CgDZu0sL)%KnHWNarf*CpX&aHHuWON=)~ub(!h7+6iTvY&;*mZ?q`to+Rk> zEzTXToWSL%t3I}=O=~%^+GUO`K~q2{8|R^Q#QHSETNxYuZM4Ot&FsFqsTptrLa}UR zv0&;zl03A)uZge6C`BDwQ}KgHSTQ@dpG;A?#yeun=!t}d*0T_zw9izCB-{qSwYE?9 z8E57S);H>OBxJzRM%Rm0mpB%~n>hyH(>C-y@I@T}rOV4s`? z_9kd{L!EXq?nas*!^CG~CfJ?KO006A5#43BSF)?ji6VqOn<>%^P9WoHm0qfNlRQyU zf+41{y@wLWkVFBX-$L2yX4H}rQ1{8~^5ST&yj#wwaj7&b0IQD&*K8*Zr>N&+9JWSO zl+Im`KkCx<+Cp-@*zjb=Nz{6dl0w}R+RlBt2v*tls^eIGB*g}NFMN&GbAjC>vx>Nl zzE2||rHaJ4i?_@etX*qO+V+iqOR zk^B{b&)r1bFY~r{7+AoI^}Y=T1KOf2?MS2`X}q%r{O@}rGV1h&JQSOAsHU;=LWxbX zyDFC3kXIu;x|V)vMfLY=r`5Pw)qLsEq;rl^Hgv0j=6z0g!h2ARx> z3bq(f5w~{1W{}{ z&A==`41{sRBRe*DjnZhPpZxFa3yNtzc4W`>W6x!+qr&ZtTMAqWb~h-@FbAZDjXjps z>L@?Q{U9E`0Jj0`bhXyAiZaY54RyxReiYMSx7ln&+d>L3jGVpfHk)l5`B0-orYnaT zZf7^dhSQNs4#}z%yr=kp*$l}8iWOW+X3PvW+Y3=lj&Ktu20euVK@#B53Kd^7Ne+?s zb`qAO?hV>yq)3cTH!HEuf~s&pg_3wE*YAmppx$W}HT0+089!4i0-a+;ngRxS>YyT% zYH@od5fb(U+JmaX^=5Kq@Rd9@rUg zyq%V@cO(MA=>S3TG{jDzR6m{Ta1*L~CbslXzQ8Fd6oW{05@~pt9KnKBOZF+R+lV}$ zoKzjkXdQT>$#fYROS(_A?hCv2d5fL5o2Kz^BU4nqal_{ zk_G0614kr*kjoqhLf2w)GgW*D9`|!Liy31B)SXyuPu4FN2uO9JDZw6M$(R0i;9-!o zL(a@f)r15Y_${ed3Yy?lF;7Dl_fDwbd09YIIQllo?Mk(eF!)a>5M2ij9VY{#g#=7! z5;0PVlnqZu!2%d2bUev!v)KTEK~W0VYx6`h+-x^i8a=thV;fXEFx+gnt-%8jgr+Rn zCYWw#xd7qajLS?j#u%Dywi*fnogIC_q70dAwiuEgDO1r!(CKLnlQA_J(GeP#Qyh)2 zs_?U!f-F#jFs8BTp)l1j&`VV$e-d(+e{ha@_$jU&6lY-PwzfF<47E*Ux^UbT&{h+) zoKBrUE)GuY7K24HC^A%$wmIB2tM-u~_ehYvQT%#C> zjdoqcwsg$vT*RdbSLCez!Kth&G!7YurCPGx6`=T*%i<%*> zeBMOLSP&~dD5=WApdCk0+fLLDJG> zW9xPkjaI=mRV|}Dwk0&q~J`jL#Q}(3zWns2hDvMx_ zGL~>;mk;~{l6te?cs55f3}+I}jd^&<>(O$v;i$bZ#Y{N!o8lo_ZZ_PO(sdhNhmB5) zmfIPQ(Q`#8d>QRXqj?^g1>OS^v&%b#9LOxQI_AZ{8F95^vnK*QOAKX~t<$@NK3IJ! zr3lf~0RW7ku)tG`d(w&f)!Rjts^Wgg7okUyO2(2>?W|`Nq_D*qi=H01d@6|c(fR|Q zKAk5{`9Fa2SuVr{N2x>9L~4|8uy`_XX~<}eJh9~jQ8g^aAn7c0fS#EPz+-F* zuc{^_n=Ot4IL}H9744zO{$y`j$*cK>qpTr(JcT9(|DiWYVn38!P>rj`K$oo9I7#aQ zNZ)8JKgk>EpurwdCPIr%4!TQp%Q8?8*;0)JQ~+5mHDcaz=^T6>`SeUsPm*2^RCh?9 z(#5^Wo3R_{+Iw6BevC?b7!s%uu$;CVb$bVRy%AA2J>i^eG^t#Wop<5q>=pE+9<=Gg zGkB0w>C$3mqt!<1YMBmYq|9vt$!xRLa2s)nwM6xx$ZWIKw#NL{+VCA_w%KY(g0~GB zG*r2P#fHJKl`^TK2U|L=HH_u0IJiNv*-OA2*(AjDp3A2 zoyx8xr}gvV^gtWc0c;k-->?Bd9sDtx@{4iGIrWI3KY&<{EHyTi<1PakZe}S9NDuOW zK{RL|+|gpm5GKsp8ohH%0Np-#IkB{my+ys<{;r!iHl&7B+?kv=de)7GO2pxmU*Qr1 zMrQ6mn0^WJ4P7BE?tN4<>QVF`88KpHybzW7L2(28DC|VC7=^U42#hLlgk?t6b~4Aq z(?;_PX$V7FB(s`dIBMW6eQ>sW6D`fw*Vonf7szkS9E8zmebc!OfHCfVdJG%wTIUvawtqF}rn{5VS z^hVUZ^*j%Yv9I4G%`&M0OuP~OOHc|VTq=e^$>9t~VWgata---O?&agQ)J*hjj&{%{ z2s|2F`}d)>s6Q40IjV8lZgC!GHWE5OY|Gp=>&ctr2U4q$xQVdtrluM`z@7wqe$Gci zSI87Upga@OjHN{vHWC!7U!oaqvINlMU7G_76iEgi$L}@vX(JComP6Z!J<>x?)As{3 z3fhgzoWt}mn;MEEwI|>hxT#ndt>t!oiUVTOgtKJrW5D#lH3BtlO2XNDrKsS@=(nIK z&Au2?Ge3mlOLPJL>yDw_f#WjQI21M_Quc<{0RifUP7A0vb!GrwcY~DjrajRU52G9gxBmtgRaD5|SLERRL_4Eh+M068H$lQZM#P z3I%T5kXUPl_zOmDeTNyKltUg#!^S3|5gX#D=c&a<=@?o&qUYK>mP0tP3K7xM|I*ag|%>k$nA&73a+L=`|cr`n{5#lhG1MSBs8#~;J znSw%F`|KI8*D0%l*21oc!X|bmF>7B;H->;u$IjC5kb5J>^tes zHf&fN4?Hyq(VeSGi@AjkOOv`}_=QA(0(CkLMm1Cq{1r|chvXC_oU4qJsgV%w| zEzF^a3KnW%9`GUapvXW*^eZIhH?oNFIZSjpu0qGmloQCkW0rn_D zlLiBfNo%3$+H!YbThVIt(Ns&NGj_XGosXHF|8AgS&^2339n}e=gJ*@jFEd*_K`7|c zOJ%@!Aq9jLRi7nJri$;Yk{){M+BRmQmFMv-Q4ug#HRtv1*5mG zB94HR7+w(Tm)WjvXu7IC31HYk@12 z(KzqRpGHeX)wC0Y28_ZhnV=29?lSR|AW7*-43B49qQ-{iiHN0#ECe7vC`Nfw{)5{-m%wJ81`{v@O$<%Jz_xRhZS|L&wd zf4QI?4n~hIfhqRMt>MbW`ff`R>6pxKYnr02Hf?(3ZGKo7`u`lgHof$I`k*lV^WXeO zW8z5v@a5C(PuE9=pQiEdBmQ&>o^J7Zv9L%QUPaYaLbe^{6XR+i}z8T$KT8n4iKyb4~J)y{Cs3U^^^QXUa3i&e%Z{kXKDjn zDeSTsxN~Z-CvTTuxOmjK(HUttQwa9~&FK`dd)^Un)w3%EVmoI0M;l6DoW`y&iL(ad zk;VzE<^ZqyGPp_vub%#w4ZWSqY%G?2a~}+|#y*<_-`vx)2Nnz^6LZ#R--rzQ;%J!O zlB_Wg(j3a#=b1ch3Xx6UhtZhb@goV2lw-D&dqMyJ9lsF;blL(!RekV&mi}R6S zD4UZgE}IVov{(-vkjF9adD>eO=c&8~S!|b!abo~8Y=KK45n7`s=~O0u|f zmMsG+Ht&nQW3dGF1os+2ux(C4)d0@@=!Vc0a$G}RC~ky4tb~L5xf;&ig@BT3GyOel zZ8q6=DsaY_Mo0l3(H8XG^bx3CNoIz)!$God8C#>jY3p?|xWj4$*vJfbVjZ`r$Yk;I z2Cu??F)4=lRY6*bKSg;a$zPz+jygj~kqe3l_$6)^+EFpSt~DPnMqe!vhCc#D` z#^N?e;=I&Z5WIscUXSL^#ba?cVq?*0q^g_GmeaP5u5QH*)T|AYMa|D{wU;JpJZCgk z*pFg+0+fNJ*myZ4$qBqkd342jUeS3(6qUiOF&^3~5)?o&IT#34ZE)yws=!+YWHJu05Bf(3+JIZ zLQZ2ezZ4Z40K_gM&(jLK~B=!RdEiRW97 z%h?^W!=b}d#Ij8a(7l;durWD%+r41K&X%BzRt`e#!`ej=T3W<2)3Z=FGP3Ake0lKX zj){#rgUJdR%T0JxHv&AAWVe{Sw^#lZMGoe;>(B#7LbeX72aiHZi(J18hF6z(J&gxydO_e1bIKm*fyLn#J2 zyehjs0;P$A5%B}DRw!6T&jU^b*9nRlm7`{$5>dNAYcQFaXiGrGC6aCz9(EB@$pBuY z4)rBcX9kwTcVR!{Tb0F(NuEhs^%Q~zA!5BD{Uc88?j$-!HA+RfI8K2~3WH1y-n>I` zYW&T{#Ox8>5faA34&KPoSs+s7mD9RIytLBYM(I>bVB7VG*~|4hGTf0$CmvdaS!!Sh ze27`wrrI~ub~1@%b)F%8m!!=qrA%inK9tZKRa3{JycfgX7D`d1XbO@^g?Dqn>ql#! z0lsJY9;r_W*dS{U&b}xt3AADGG^8jE0fZ5t2{ipZ#Gs)QNjp%>C|Va136^+3YX~ag zIsynJS3#qN?w~TNhTs_wyww&pUgDCEfImo?h@=UITVU<5AA0iJ?vyySGIsiO<52|j>NVHiS!hJUP0l-1-6TTy>Ngf^ccq8%`1l?BH$wSTrFQF-Oyv9P|^coHYuehJQ zBMeC+fr=*N(ZnXh_Xi^yBoA7XM0Mf1c%f5pQzI_l*^Y^1S(n&zG#c`4gGO0j4;1B& z^f8MeT(Si2P|h?l32qiFh32?Y(!HSR~i(z-D(uB4zg=Q&b3+Y7`hSsB@ZF# zA#R-Zm@`;uM5`~ZPg%vd$Y#{BNzvUw3BzbAa%1(zrVP}qv+iJ%U&rSHx{f4WIe0=y z?~7WBjvelPh`sC7ArUw-UUB9LO61^FH-=q*aixjo=PIu*(R%QVZyTN-@p2L=K(unD zF$+mO7_h`&EnwSoc@%TRJLkm`F#>bWIx(&ktC07I3pfG3P>irQ>b_{5Yh!sC_fY& zn>5p1AC+zrmVzElzMM@H$sPkMh><@AwJuSR;?A1MX(d5>HdA^sQVwO8#@1APwm6kh zO{!4{6122WpMe^VQ3;?IBlCc;J}sOBiRz!YeD2bkXp^pnH7~Oi71=GQG&Pv7(A`%C zF3cO#2r6Kf33i$O8c7;4K0`5r?R1t1Kx((sGZ>Eq@{#QJ0Ed>biDG}*Wmck(ooOV% zBZUA!5Xr*w%#RHKHy|iv)>U4h2Xi`P%d*O%leZw%{f@i}yH%YpaEvT%l{~U=R_pSk zr3XaagP{s+9wRRlCwE^3Oeqvjtz!FX%~)ruYDVm>pO(mCbxf4hr2FgaD2P-=Rx!c?q;6ZNidetCWS<@2lk`ckMz1*Y3O);wGp zUvW$yExTvps?y*I)df${*pAejLf%xs@pzhte=rn0u2S)L6`3> z3!-$!bvUdEPJ1*=x44V9)4%R;BH5;~%}ev>e;@PkUt16FUid_^CZZKtT#zYFec2Q7 zT9Tk8@ylxxUiwtDC_#(jmscge@Tml?O4O=^9eJWa&s8tEetCC;%RH9ZTX;tF# zs+5;L6|G9rs>J10sV{sgX&jDPm9)GnFa4NLT9vF-Nz1G9(og!VRViAPytpdi#h>+B zl`;%r7lh-yzr@%WK(I$rh@MmrV?NHRHnD#RJymR z;QNKCq?bMwHC}ezit+uzRPs7gxn1gs{N5QK6f)cT|6bPnduN>J`YHZ@)EmkB% zfAiR~RMjWgyT|$Mw=JCT{*N7fdEVi--SEBp>ih4nk=tZ;jXycL6^_DQ?DY4yw;vDV zt8g4(g=0@~=dnaHSGoI8!uR8$ticAljk*CUdleT4+Rr;sIS(COi=HF8^A1xnoR>Wp zL%8VAJ5E2Gu?*^$EgH@|QkgW!q<-0^@yuIPHVtEwF55Jnd8D#wlug63P4jt28fDWc zo5p3EmNSo3Hchf=T()UF??{tunq6wqGESqN8G%wmTo%w_s zX@(NNmS#w2KBJ0kT4d9*Y|}HJQDvlVWYe;2(=(q@RW_|72e53@GoMjaHfdge1~Bnw8aYB^VsRyw2B&b9P@PpZWqq*|VAoN>!= zTF1V;jz{O>?>~Nd_u<`NuV4R|4-+W|#))59#sCtve0QW7*NC_J_plYG%{A<0xVJmR zd%t=2%l4sk&rzES&@$z|1QxXeFBkGxaryyT!e0pX`w;ub`~$y^&cTCMOvpVL6}Bha zOO-TjCmS$$%iD9|QXVt7NE{O=w@jBDWN|G};QpDQ0*@ILnre+{?lO~4gY0|Y5Xosp z9A`awU{rbv)F~Dw2TX>UG-x5LIJEwRp`m-62tpB}lFXaIDW<0{OOMX@Rk6) zLL0$VNeM#>dIMr;aNw>sxOnp5C|^b9{@jPsG>Ov)vt17|6a2|T>(N-DK`R@E=YX66 zbREKaRtu*uDVnyyPh5w(HZ*mCn*rr)T@P^@PWK+{bcUWrq`-xtVjLe0qQ6!fS~-2M zb+*c5L8}DS0|9e+jck<9G$UV{q3Nh6P zoE*X5n^3^Fy55qe(;oyfF9xdc8cqW^cEG;ief@e5LOT6Hn0zcy=U`I{92#)dcmas{ z6~Tb%^vwoE-%My+?|x_pLO3r_nc|s*;2$+IQu09&)DbZ>xwV#Pvalj^Z94scMEka2`8utp9knBIMIbb{dfb_ zl~UvVe1fMxY7hy9$aBj=UE>2m+XvMB>ByA(K^*-M#L;WWsZUQh*dg&C&8Uv}SP(~S zr-L{iM$fp%gJ+yG*ul4f&iny4#`~c&Gb|-Mn)uA$y$SpOXE))~kMV%$$HeEHQ2Zd7 z;6qdLbFoxC>Vg8)Fak5ub!co5D}|)RiXv$)KH**m3@e1hs$hkapY@Z~sD|6mnLGee zwv|pbk!9--64bfA$W$2#@-1!5S;5&gnlNV_v4Iq>B4l3$3e9Z_~vxt zfPz1^b7l}g|CtbAG>B&#Ra+v_r->e~c1J(mb5P+KBo~lpG~Qv5y_>dXS&`w+r>Dea zpvniqi8CqnX@vn&c4Ts1Z)i`r05~HUfn<|W<`9z(HQ!uUT+k<6HtQwz#KK^K0?au< zX zdhriIcEZ@=%H-5K#p=(Qrh)<>m{UW@BKU(`NTJ_I;hb42vVMWpDTT}I#QYAP8{(g* z^WmIns!q<@jj{U;2?8h(dukT1Xt>iKQIK3<*SA?<64Gj*uz-4eU+q;+xx^>bdq9+rFr#GAC4`4oB&2*of{zN+pp3~u^l~8h z0+|}}q$>t&Pss71_5^}T$hVgwHeX6GfMh4HsK)z*H4Xj}1s@P^cG0d$6U#eeqa8v)F(Y~3Dni4 ziYpWxli)#vI;^WNF$K9EXi6bYY-?bC=DvWu(%Z>J6}QgY^;IW3F5`N;{R00K6>z8g zmLFc~m0HdZhr|5v=eJj{uMcU99)!mEd^bA`{hP+F1XMKcv*Xs8co1&Uy&W3$zK3mE z==qEG#^jjx9^857Z1%qH@1pVgA^Hw-rExR*>JE44X7B6%Zq@6@pWWbA^kw|IfL{B! zw&FI$-S>%8I68k>Wr}6}IZk2G{Nx1Z$* z^Sj&h-F{_gad$BLRi5iNbA>0%r}*z)+424A`zbKHbU#eq<;IYLA8w|f|HD83@amNrdu52k=24($h#eZJ^>C4s4pWk0UOa^_@KH2@?p`=0K zMXJo!xO)YQydK5f!W`!Zc3W??cOGdhG;p-E<~xVy8+3fOL8s>%bbfHq$Cu?(-nl$H z=m+lMOF4kMxBq*1ww`97M|{TElaR6U_36`jVAt<9XMmp4?119&^uARV_3iDacYmEi rnXC8D=$7_QuZ-0YVeLvUp`@P5eeZlMfdOHsz*87>% z`x&tNe%rL;`=&kpx#{KmqR#VvTaEMkeFi52_I9?o`~BXX&Sy(f{$lffb-cZCSxr+MajL7yHn;VA z(;4|{$No7+uEH5Plci`S=%opZUP(`Kap>zEQU3b;=5wfs!+zY{_5FG#>qgQ32=n_S zPWybk^<4a&^EwRJ{dp&xBfnT-gt9ll|L={9{T=lkbd%{zKAtQp<4f! zAUCqokSz%(FfVIcc_@BFx`%r15-Ox4QbYj!;X|hRj20@e9pxu)9A2XhzZ@N(&G#ndaP-PG$l^!l03qgOS1q07YkdORY? zR))77k?nLgqLac@%{t@H?b!R@Tdl{?Ln@(mogw#%{+#MsmVgtsxsR1#zHC3IORKn7 zXVaC|t@RIFk7r*KpGh`LpX+g<7t~(j-AmG4FJLDYY(wWs zA?&NPsP+2xTmtg;O{y8~+vXT3o`&1G?abCgNo^ado5TIC|FO%c`i`T4`{LrAZf(DV zt1a4ouEm}i=3C@COPVR0_i)5sRMaonR1L?-mF~gJz~Ysz9DtLnt*QU^C1c<3bE)6^ z+avnF+x;qEd$Wx$);@lm>PhgoL8Zq%$b-dxWB+d^53BdZ2Eu#o@Zsu|EzXkq1a7=F z?uh3D;EGzdo`dG|TKYTqPwTe{__{6i$at^gR9+WuI_*`kC= zS-ROI^vL)S^l}0zlm0|4FQudTBA&G4e%ab zA(ncf)hG>_b7_8ekL|M&Q?~bS&&mzD93{?8J}AfGX-eaKw4WC3-p7n%UWI(-PqRm# ziTkcmKM5Yx_AENXx3I%ad8d}DZjO&AOxLB=Nl=g6?sJyy!$r<21pft%%o|6aF=P{bGb)}Zi3Mr-Y>-{T9G3p!|0c*A*Xf@eg?CuR; zyc{~bx($mq<~^Yic1p=E4Ik-;e8>L%aGz6r$DGf!N1WNT`9C~hKLv5nXtnG!8|FSk zY78Sya*5ZyvBUK2cGEVT#$AhXi5n@=YFOp#8>aqfiblQgqhZ$e65JZ8MO_BzIB?#- zUxp$HE;QN#wY=s1mf`pG>R7yX0V{)-lPYq zE4Jb{Ybk(#AUf~7o(0UA&Yg9$Z=ndOupJa{vo#;|?|D&s;HS+aVk)>bH=N8ioJ=;H z$Zm;n?Lx0m&ndZ}DY4fii-3fwjUmSr>Vfbwd3qfg( z(s8kLrEC5vlBFeS9{daYFon8RrEbPB;ofd$SA{O-L4V|sNy^If{P&lBii0Gn?$25U zS^r{zsJicV)N`tuj2>EL94KvEivn)k(em9&@og`r>FJe+3yh!qPQgZrce06V8~LS_ zAF;lFR1dhQn>E#Bv=kba5_j!Mu~g+M;xol$&8!vEhJ~i(=9P}hVVCX})4}n1>DIj5 zyRR5`7mm_!wjitFN%kmMmNcyZ?&uZa?-apH+r@Euh2KgbYNbHb*W;_+TaWK!{bVx3 z1D8~>=gBWr|5V_P1giIoX}^e69FlKUyT-(f5PS8ZZ^r zXC(tKCEaDMxJMQ@otQVZaWoneujWnhEDm2qV6|wg2oh#e@o3%MrM=}su-O#bJ3}V-ov!-+AiLc~)Yx$GXCSyb_nsV$ zO5Es(?ZpG0%weci8eMPuD6_Bpef#I2Sv!k6OLXk*&TKGb^4*0s5f)e6KYS;6-hZo; z;Hp~fEHCx~8EQn~V}3bD<_KV}STaXsnS$?{9N|ol4_v6wbg3I6QXbDQTOCELrF^8Q z(kA!PgCz}buCTN?$kOI6@DMWQ-$GMip3$_WAqGqCf2k``qYjjZ+=3K3)jvulK09PI zJ8T!eg0h&^J|;Ik5q8$n@dY57V!JE`)#Dx$zAkAZhKg%anD2J~6^!YavXe~(x?iTP z&6T(4bjftbY!_#;^WgG$g1g;CP-Q!O+rPrrY`s%p5N!|OHg9uhVzX&ptqp{zFy^9x z-q9K@n($*p1b#Q575i+K!Fn&IpuKv*N`=mvb6F{O_<}xCt<7fpl6Ak`r*c=aZ+>8A zgt^iMsJAx8i5|~2HEz}xmw6obt+~UvokloK>5AK)2&^NfA73N$vRLQ49ooDDvc$Ll zB$vK{B>Nk@_+QBW{r`nQedoU)ldAHHoZ7n77;I~(`E8i+$^6x5XwSMiBtF3t7Dq!Cqi@iTTkA6SS852F$%D*ntrbIJ>!Fld3K!>0{=r_cy zf1?d`!wa?^9Qk~{zDIZYELXl)@%X-<;!b{ddM@PHFgJbNRg60A>gOQd6v%>awr|G3 zejgj{TtHvHH)nreTJ?^8eSdAfd@BFtn$OmwiG>$JfHlZF=hn+*UnY7B*yN5%adK&R zH|q$wHG@0DgYo#ZZc{!>;8K2p-V1SjE6RlaK0G~-<2x{P4$Lszm~Hp^(aw_??Eyji zisEC=vOoj8PFeLecj{p*DZ&!m$!m3g59)rR6zyMsYGPh5@sssn`?|FpYQt=hUFoLx zZhJ0Lsw2YUbTfa4`@ve2U+TU1osWxNRL91W!ixD#zaH>H*JXX-rJcIju8s7A@Ad2V z`~j>%8S=HNyvrC_Yj0~A?jNFQNFjPTFBy29OzHk`Qq}+Pb^`uZgdO|+IY0FK^874m zS(tX+`~6k?I_R%?bLr5L409Uro^kXM2y+s<7KY~3m?eSC7x&7E0X^zh`AlRG^>=jO>NJp_%x&`8Xi7^yVIR=Ru% zx}HYMWJB9qg}bsgQ9H71vXaCG+pOMu<#X_;Tgu^SIM}Co&T& zFK?>`O6I<6F|;(zrtK3Ni&ifEYuAfy?+?pRA^z82z&QStd{-{76rhO)lxMlh5L@IL zrvq@>-R(dweBL2>u}*^lgzs$Y8YcVRHE%5Nx~xUoSO%$VtWZSt>h4YiF%xxb`|>nV zZjXHF2W(va4U$ZXQvC)H>nPy832;9(rdWNsskh;f!UsNpIQqe|v7->fuxOLHz4`3y zN+Hn^lAZZzHTn$U^)RFu_m~H0O$eO#JLUtuMg+H3!-(36{^u01(g7YLDtB&_tamqW zy&oESf!vw&QoqYBil|xjVG}R68yjB0jX)`tTUBj)hvDOIKee6eA~!8!!^e7pCGOgd zk5Z@4rYO7Pt&_AItxu1cYPaL_4PKqiQmapAn>^C5|L?)|ezLvgIMeDg;`eiXxHWKM zlk3IC0OI<@3q&g1b^bUi`L5~&5Os5~x__4u@*@0&U#;F+*Ah~V7Da~D!l#^}KoC9Z zisp)4l8i1(I*{+kR>xw?3a%9$dJnhcItm#aq57vXDtJ#9eW+Ze6M4vdK{}&j7c-Kf zisuHplB+jIp9n|*w*&=Gs1nSLAKslFnfma{^lj7kc}^2NnN{nfyUqTh%A8a)kRcZoBho- zK`U2uq0e=c?^kQ+^7eWgXrVE*k-7=s%zoO!*yyjEqwa>y+^PBz`l3AFO>|M_PP*Er z6D3$*e^$|8BlTgqWcKAj&W=G^mUWp!W5ul=WjZvJl{CmT6-w8;vzw6PnrGyp(D%rx zGaMSXIyD-%l*{!FX)Sw=lqEWqmLd5teA-u(`vf8D)-UMXcJkFp7ImhI~49=Sz5-XGpe^)!yJr$xQr*>b&Kk`+I>_g1B?Y|cK8%X3X&-ZGId`yV%h zr(=YNhB?0^zY8n7IUJ85f_S@%u2QTgu^oJKFG13N(Xv}hoWX?Fh|n_q-PIsWI2|$W za+Dbf0ozZWZ8Od%UIGCokk?#Wdr&|KzAkc_{5F*@yYT&q9wE-6*KvI zFif~$d&3;U#!lx!OF%4CjLE09HMobh^wi^uOQBFLvb+v%NREX*wNxHbdUIc)uRUVk zojV-yu|k}oQn)8>o=Dj}A0Un$QoiMdeVl%fQvqUAtaV*Lx_yb`M|bNh@aMI$pl>ic zXbjsNZ&JC7;ojhGQ_k&N?SycVKqR@psl;q2M=+tMQnvSJ#?1_bMKylNG|FTl6Ez2( zcHi$Z3xe0?%Aa6YN~vOKiXf~x*vsb?DP)<)4wJq0`|74IL(2!i+oF2`w8MNQ2@`uE z$!dsQ5gcbSUPz&kS8L)mNB*&W zFyM}>q0;I@02aol$L{PHNO`OmQXAy2H`YtIP)v>LNGXT7L9V>J!8D4cW1`HV2ir<{ z6JW)k1M5~mOh)oMVxB7a&CSExqk`A06jWX;)5E$+Eu8Pn6#5@1wc^@hIYM<3N|nnA zs>-G$xsDOe!qiZofZlbCc0KWNA0kN2nJ|G-UhQ%$6W*5L>RG|- zI+PYPTU#aLpktlkni3Um^z5Z4HG-xFHiWz}OWEuTQm=Xo>VFSDYW_~B#t-4frt>;4_R;KmPcinB8 zHRI7Vt(@R==(?da9tuV+qi2QiFA7ez8jx^h8_Fj{Ss&TeOHaJi_?f+jwRFXx@hJ)I z`HC|5(e94-FZnwet8?`FX;HHPV_V#lT`_~vjmFyC8D3R@b$)sc)?9MXNtlA-eK|{D z+($|4fIf&}d{jT@A zQddwi{|IiU%oNRb6W!mqi?_7Yn`MX$E`j@s$-qv6c1(g`R^flnH@SNB+n&fSH9L0* zcXLA(Z~d_^XW&LaomAuKlqxG}^1j3R;(#+#b&x$te|pGK)`6-NgC(GHDV~y(^}#8T zg+6=^Cw~V|r^z=52vAqjhZOicIdIc-GsR_`Q7@&?C>*m-IWS-Jy~jCV(dghZX8-xL zI3z3#isB%|NGS`nj21~l!V|--D=}sKJdJ{hbW}{pqLbJghY3eg6(}i}GWjMR_Y!pZ z7Ov!E^dI;Xw$}eFQNvvoOzfVFI5$AC*gBaz4nzsInQ2Is68aD!E&`^Z(YGfAD}IH| zvZ%$YGCRwf<6$=+?MoJ}nTQB3#`DTMX;l=OZHAl3lz)hRvFca*0Y}8T z=8DWD_^M#jTADE-7Rh|*6JTY6MPMwa$s^pB`ihd2YQKhE6qQ|&Nw_WN^>@g>F$BpM zoTg*LuQua3Fa8I<(dC)u(xOS`DK4j;k?zP{+(H_l-ZIf&Tx%aq`@62o?@*ie0E>vA z;yOyUHS6VA6V{EmBT;Hbi}-LCX_%|)KDbNaligXG0qazh(b-X5Z32&fnzW6EE4lI= z$go@zz4onheq4nMtVZXe?>6WG8ubn|%$|tqCWA0HtO_GV zP+!7dP`LZF(Lq>k0xcV53<=`F7Lwwki@VC&! zpW{G*2D}D>VTBmXFNtBcS1(Nb#n`p-LR0PDJ&>*J<-FytO%*Z>+%2ch2ovsH0eG^L zZ$SO#mjlVSU#V^TYC4$p&7?CQ)(Qn7hY`z{mMa7hM-bvD)qpUvjR;}|;T9U=zP@wo_WmqaI#zo_o8*w5euS{KS*kSBq^ym9i-*NW}EsrM zHA@$4h2061)e0AlwKKwWJG3j7jiJ`6?AWM)HR%BXC z$AEqqbPLC@Y)*hkN^pH}fmnIhj4^(tTvRGF4aL$YUSF>iuDg-Q+ho0=<(7g&$15;F z*KS&`Ubd^YOb-%r{H<`<{bJd+D$xWqfS#Bh65XKWA^9pY4H?QkGwG4mx2EJkdKtgP zKv4V#ol20dcl>#Ee8km;t9Zb+l-@}SyJ8Ev7nhqjL7?Dko>OdN8KgncO0Kc%p_~D%DZ(2GKHUF zo{u;Z`Pt0g93V5pA5>bN(Rr=#4~)&=Tx)|!jZ-iHMB#K5jIDdZZ=UDY;;M_hWXGx* z24foKtmpL|rtb2_RBnr7eiEm;KbI_2R};FjGKx$N17en0zQzx z)eqv1$E|Qb=M~^C=Xpt5N1)ke`R<#PIWOT&^g}p>2tv85WVuq3&{GK_YUP}gjzTI> zP&CotvQRoF%5oFAS2OBC8J!@+l2FU+&96p9ahHsgR-cy<2A3aa-oh(!_+R?&#DP{b zF6RbT(A&AtyES zWkm42hyatQ%^(VtVA0UMcxu9)&zKq5{;#e&3Fg!-0PGf{&v0%``Za>=^euk4;z7}D zEh^JM3yk;#T8~C2knA)mFrar3LPxCS5QVtd?>o_m{eS<#%6KUcN?eO~_y?|2jX9u5 zUDO8}85kyQf6@^v6TDD2awoDR+)swI4`T7vLo{94A+IgKwkzj06CX!lf_Cn5sB3;{ z*UwP9psOBd$W?IePft`{*Dg~Je(Yx(sQ2cjo7^H$u*wNB@ik%DSy}(Cf)c?o$h73` zk%;WZzKw$0J$dm~Icv)a>}0o?X{NSLwg1vD*Lx9is~eg}eCid9%UP6n2Q0K)Ga6 zRklN&@x!PW9w8AviXX?WQJCeRW%Sk zk8AkGcy&4Z%&up2&)k1pHMWkD6~7!a#w>~v^H(B2l(m583NUGeD&Z2qMKbQHTE9qJTZd|l5=}Mr|pgC zq^_ZpXK-3||6$8Ei^~0*>Kf{`{o^aHh5;gu*bDC5vUDSCVmuP#Fy-au|DB)(B8>1H}B#;cOoTUGg`82Lu7#!+B3 ztFW8Z;|Sphml~cb2oCx5>CcB>Kehovjx8`5fY=QacgcVzLj%lFQ*M%xaTKQ6^biG7 z2?&SH7)3p$#(V<)1g)ZkJ7rRn(WawVA3uXM#MozN+~d`pn>?=EcypG>I3kpM+SU{0 zc1Djz?#p?cZ?w>jc}<247g4M2@({hJ!=WL=s`Q-W&+L>f;t>Yhn4U0pL{+R+p{m>9 zAU%ZqQ9Pay?*+06{yps<-RUi)TYB9R<#s~HgGkB;&1%!Doa=`~;gLQ|V(fc_mMCTh^6NuVK+QmDvwAX$}-ZbG1vo}ej9EGs$yO??KCz()%KOj{?0B}=>p@}rlp z4eRMpAxY$wCUGMNr_?ommU6?m3La!2?!A{!1Y?XSQALR!NU*xa5fjBtmD*!cjFYfN zwa0DG@eM4*K**eJqKiaWR^kQ+iqv#O`oafLn$&P2eXck@7tCDgEwALO&kS}WXIeNH zvUJ<$1k#+$Yk?rV$Eb3qSe9ACPr<|YyWcutqc}00W`VAYcBgD)G<{wOC8+*D}gkL zH3uOO-M!JdW@*+92u0{&U7ggr!&9=${ja4somQ5OE*t`cgJ34rq4`3h(;AIY?zw$P zY22F&xCj-^UvZ}eI(YSS6A3v4cteu+lUL$fF}{;?@?acwrA&`DdFF2?#uIr;BRBm1L4-BVj^s_Fa}oaA~6i3mJGV?_f=GybM!EEJHnk9>lC=! z2xEJcQZ)21`Y2P@K5i%Nx~AajKb%;8pb$m0Rn#_3z1K+UULtE@KWQ(!*!LzVK*%r= zojH;9pcY|hOHUj^%kt7A9u|PHW0FF2oDp!f*8u&fHZZNrRiW7_OeWEaquK~(TBbki zgmP_u(ZYDpoMlnL-?2V*OxD%BwOIGX_llxL``(hoshWxL)5x@nqm1f1*9Z$iOhimJ zq7yyyH80B-O&faU+?&TQ;+ss3kJ}^Z7^I^)-FaQnhKEL8LvhrcQi+;M`7LQn=fi}` zAP*uI#@mN{mQXo;$nf!RBw{NKQRp0`kgqF&WYUTVnjTin0rPRy0Mx-;>ktuARc%RS zko?`3oPd}y=1*0?|EYOScLvvP-2Z4@NA4q+VmOfit%Mh{IK=2s^h31>V@0@vPa%HhqkY^e9=ribUC25Q%R7I?Y9+`9k zFc>*En8p~9e_1Z(hR2pOufA65E;UOah%Ch<5|5*FrBJ|f#85+MzijXyf+Q`Ts*@2A z8~}C(-0&ySEQ=>9BHAgG1d&SHL>D4S93oEV#DbGs@9+w>qkFYZ0p~U&K8t5vc|X^= zZh~Dz(Si#q6FBWzZQJqxZ9`Wbu@pv%{>)hX@->ZFb6?TZy3o9AF^F?V9P;Ibj*dt! z{0K~qI=IxFtV;MSb(cc1@e^gNv7-9TbGl?J^(3(U@f>Gkt#x6VC9+%Ah{UnA z?q2{B**10P9oXf-r-!MP^|xIAED-ibI3jRaHdubP9LlEsB9(l4wAey8E)hW^@<5Wn zg94lGwl##guxZ!BDj5#>*#Xw#cp*HB0I9B&1ukG&le4P+sT7{{`e_IN3t;E(Ty5!A zLjW8$yq4@u9X*T}?V^Y`&@XSbVDzPC+{Q2I1>Euz-jx$7Mqq^a&(;_iPIK#cE{c{b z2UJ-&73l7%y3!2FJA?a7==_ zV)BAY6$uLKeGsblB{c#CHEXk%Q|+FO#!_P_c5Vq^;)zOkJr36MUIxMU#eaNmb|=2= zBK4@Iy-C_4nwp%7s7hG&AV;vbz*WHbiLPjQkDdR5(_1s;d8~uK1ypyiqNY^r9~$F7 z^vk(fb>|)6@VF|b8n|6TMTTVqe@<$AAv7jrj`u@)iS}jpKzdXr?v6EseTdw*hyvU{ zD2BED|12COt1Mw;!yv>+U(A9*NHmCePZNHBO;FAdGV68jKYbBopB}9ctivCX?-9iH46`c zjN)||y*Mi3G?t#paV1C=_02lJK7;_UX3>r{HTO%HC85EoKFLu3UIR| zN1OjlC9^eIfpMHy88;Ci2YI@|57f~7F$ay0ckg-lamPWf*vti;{2l&lP-G9G>V#$~ z-_{E$We+6oihpMH6-o!AVVlQIh&*uQr9bsBt-q#V5O7IotmGA#l{2JxBDlHFq^e)K zhXYz28<8DX_GqZmV?bFDJo0;Jkr7|je@%UJ{a;hfOgOp>6>b(Q1q2_3mJ>Bs9t4D8 zwQW-E*d^$@CTfl!9Z;s7>t&*fLaJ2HEp&-rhh{vsOZJPO|7*ug%ej?M=w>Njl!8bT zBrI%~aDfD^C7lZr0028CyB%Dr5)8_agy^Dgc@{fL8r_^VK&${=*a)9~fPDWFpM(9C zm>5r$n3;J?rBP_sDc|m2vzbVf;x${yAp%3Xs*c8nQ^t85O>hw2GQ;fQ>E>a+ddgkQ zIj*XFS1+O`sLZf9EKQNl!Cxm%tS5p8ePDI9th>KM7yUu7l@^LBqYyapAhmeNf%n>m z0cW%bpEvN|iI@9_p)K<>Abs4kaN&Q2^%H(tN*WS6!uJrIU~mBq`az6rmpfL+TJYed zwjyW_Py{|mR)x&w*RYE99%Ps~bR6Q2Sg9`joB5dT*p(~+!L2!1rRmu#Dglou!_Sq+ z_IU+9f9Ssh-wXaSy?|d(twf}rQ1s;s8ftX*)SUxj#l1^>Ad*h%MqYGcL$JT&XU0aB zwW9?M{fPSn{q7r4tz5@0)3K9#N*2k>=v*nPh!Fy-4@vqck0LO$@XM`1TcUDSF;tMR zZOeCm9zMf>h0FFea2fXM7n~Jat!Sip6;VYf>MxhiPo$EeT>ua%HxPQn+fGjal{<`V+0GXYW5tKboAVI4z#Y=bT&f_`?Arc!CEIGo7PS?v-f z?&5XS9z1x|uFTB&xO`}E`SBA3I-6I05xNCbPmO|U28;+^1voFiXryK9=nO% zPOg1r@2+8W)6Mb-NE~SZfJiL{XyVL9t2r&Eh_bR!#w!n^oY6HWc5=ijzcHrnVs+IL zJ~~nNa=Gi}{9N5d^oIR;T2zHuLr)f`wzfC_$mCV3EFK^6`l}{Fc{HXhrnyS^0(Mt< z_N5)OhSOIo>qmRleh&KQnnpU4{JIm@U2uLNl?zI*qHe~Un2q&zGThe<;&x^K-MV%i zYoK<|9*WBo}OMxRaGiT)r_( z8fy*5-X+4vRO6T#C;l}UH1i0TJrga+CJ7O}MbQbc4lQ)66PHVj94;q&wGR!KI3J3Y z*PIv*#HQ>@el=}+(JX%ju~cJ#?av0qwQe&LnE!@9{Th!wG+v(-k^;2~-nd1Y2#Dlg z=ZfzEQ}7Xkhy@|{7E5tB>|Qcs#&ithITZMzhEVO!9r!grfWZ~}-zv|UVBO+Nj;n}@L%wOAd zqCml~_xNs*d$`Rh1X^B1Ct-Ci`sMoVkrcGd1DB&V><>q&ubWyJFWM9A&@j<60NAwD zmYQOos+eA|eRJ3iBs~>?jyVK$bwDe4&?b_^Bt4V_u@>OdXdveW_gTUe8eX@%?X6Kk zLJIrT&%;b#wHI8FapYRr<{jJU)r83aI@jUbuZ6l(!ISds@ZmsZdmCHdm;~b+T{EQv zeQ$rmNU;5bK$JTC{6CCMJ+Pt7h*0jwJw^;lD>PBNshgA@I!M;s?HK032tq>Lj_Tj&5`Yn#8&pxHBa3BY}DO4&h&G?Qwunk zds6}yP?ifwE9pebWD67=0d(mTg@xOgOXJ|So6YUGhjb&ub->jgUqC=*k>bj{0S1qc zl^otKuM>8nC)+6!HL}k}k-1G#JW6&Fh14Hf+GBCyb-eVt`r53yaVUKzr{h53%NXxq zDp!wDmNyn>NG7SQkxxbCEgaUkGZW`aG$K;g1fq zpaI-3=99Ti-Pomc?S93a!>o%+$ir=}ojZ!~p;;vyQ&(ug zWFagUc0d;b8=Y~&r83xS#~$@LFgS9IdiAngwI!}&qaDc9ZAvAsiuPN zi#p0eiqh#4CW)CCZ|?DjhNNw>Z}t6STpG9bFY5bZrtUs`XU=rchainW4`jp*PZj0#yx|E3Ck&B z{+|2DP3m`hs&vE*&tp`>&^fKBiz^lBwn#h3ovUDo$s&;}i4=nhS0y#7g;>V1g*by6 z_(St;+*rFIMWUL_VgawVY{*1p_~)*ary1D{$0EsEG7E_%u?d|86aZsKNZ}Y&)Pdx! zeh7~il&=Lo5~@Gp(kvG!M)FHg-{@~*ZXz-Yo;fxk8#z)=u0}ibkMdp@P)+U^S^!zi z60hpmVDr`}DYwI44#z`q(xD97po7D5@rc3mKGdPEKqXe=w--px*AwK*!x2wx_#;+! zhw?Xv0B-GZU+Y1nv`iv4-#zW6(h}H*$7)j|2a{0x;HhLaaNR*1aW_wy>H>)zh(d2{ z)FW1L2a2!y5xkldK30K9s`mseK6)|ug3l-y+MMjYWZ~rkhbjYY7*0KW+jC5L_-;sE z=dJtigh;9TI2H(p>Yw@uWo?Q0t+xQDBkD;#`d(5?^=P;8K=-Nwo4riS#i+snDk$lr zP#*dI2Uc~4%E~A=52&iLFfkrql&Us#maVTCCV$+fZCIM^nWwsuV90w)Q1XgCffeV< zg@k%A$l8%&IuLb`OSIPbp@U1vn6iJ00j2N2`#;^{1vI^B#1ys_K|BO&< zbi|Et59bGJ?HW{hWcbY(E+Rfz*K)xI5ak&^TC;~@M)Z&0^R{}E`BEmqKO+N9yP#-m zIanqIE}`iUwlLv;0Nnv4FZ4pIA}C+IaTV^~0#%p&(>bh~4!nl$`&Uj2LVt)9tmR1v z4b|>1(8n$R(nfF7%z z?E5OiUDRhRw=w>g|5S^GtOT+zyog;onVFIRQo#-Thz^p!@*w}rSowvX$mW=jtiC>G zq7rj^GJ2r7VWJBPUsv<@{i=Kunm`GP;PvjNget%5PCUO0CzCwOznW@+6f3^k=U=Q| zi$-Tw6Cs%EGDgcXJUnJeT8G%Z43A|n)Hh>@2rtFY&i^V2Ko{tHU|x&g8{ke%s8>CV zg5oHYAaa?cuW)jEau_c6LSAHD)Z79p+cKxwnXJ%apvy&jHg%mJ<3XR^QHR5=FqE|H zisf2VgfYDunjC$$B8CZkfl4_y0x89f2XI2ZGu$U zOySrNvAjVL>j--I{ID$DgqWZ7ug{G9#hNzVW&S&2)8hF(1E~_bj=xo|nX)k;7?}fB z{@DWHawUZj(v|#lM;>)qD|3;v7yxQLy322LRB;V4s~bz4>w?zT@#5`3Pa94gOtw+d zoQrco>05m@?t6cDAcL#>Xe)LT#4k9)0~jwHmqALC23V^Hfao0+@1!!xd#GKC=A(*k zp{%SyNW9W|%Ty;&)>cyQ#!0O&O}dk<%xihlm~QF8W|6SLP+Q}dm#}lL)p_~?=SK>! z&aU`h{Fj^4|5(!;hy^)Ru>dwcqsolY5bxUt4lt0*I6}z*vsmwm>_ibnjImf2UDCQC zb^jGYBWmr_LYq6#*~N6#nZ)kF)DLFV4J)=$!FNf~n1nP31(M@p=&pc3pj0&&pYg?@4JvEZgqMdq1vOt`8T_@^KYfa zPx|a(z3R-yK#(yfbUt3%qMJ;{`NTyb2{5Mf62nmtLw(GeTQM$jty8THG1yIn-x~yi z#3tyl;?Xz19f><`VZM88v^KqD;ml zOsKTOSy~(AV$|+`;Xnj|4eMecQ4jAyqXnuWOum#pUx#x?hw$zntnqOZa1uhjfU9|~ z?=u=&=;(Bi22XkCZr9cm^oikg)rQ^ix7A@c`tP;d(?R<{v2hw4*iI~Npq2wv)>wFz zuJ)VpVJx)M?3qK|35L%KIzf|SVX|w{*0Sdmi0oooDb>QZTDvf64yWfR`kTPWo40Zv zl=0n+EOk|$YztaPSpTKy3AWP#B6IVxS#x4IRdz6bje-4kN%~ zG_ZO>KbwFgagqThvCI{isUfcpG!sfd$>Tzj{-X;TfltH!)10YrmMetQ+}1@TW(xeN zZQQ>&z}Q*QarB6>^1rPO-(^Joaa0pn{K zn$M(be__pEYq%7a1Zd5NROp%-joZVa7}cMTNI+8+e4T~Ps*55#HesFA<8>^uyu^I* zQ+6=gde+DS&9~NupnN1m-X3dP_?gqpgoI#sG=t1P|1I1Xf_NZf)vekTr&Y(U2D#Up=2b#Q6h3hI(%jG87 z#gshZ+<3MleDN~|+%^ixhxKaU2-E8J0N;hTmQ@HO?Tp>-JOy zLuO|#mYsd`-_+*cEi}tb?aXfDR5*bzbm=j<8O8~t%pjEjq6*9K_^dSw!=hOVAP_j> ziuePGMUH+>A%I0u3G|`M#4&iaHt{TR_-t$5Rd-GQB+Vr_>j=ttg!fOt)yg+ZXx8c2 zduBB1|GtLmtTL4r1qYHFGVHpyr2tW~=;E~P4tag7XhvElu~!(&D2M_HTcmhYujD z{35H%p|pxuU?+N;7{>&$kF$aiDx*GL(`*ZP031=gk~ek|8iNlp_{~{dl~`d!d`nS0 zt5tH`3$BHpIA*DUM+B_QrQqUbs8kE7=<C_SzcU0 zOVpnZGA)&^6)C6$qYETN@4JO(F{PgPIE!XP00hy^EJ*`h{i3kCGJ+Ho=z_>N6R$$S zd*}`OG>=mT-A>A?2l{M9`e3r5FJ<)g5xyVNIGcGwm5&nNOmqf_!jc5X?q@WZu_)smSw=o8|w!aHTYe zJtvdIyKJ|6uSoYa)PdG2tF0IyD%}o%{ z6xKj6fS-z&+5>Yw_6r3bcU%2#PUAM8k8zzzY04r7?MADys?ds~Z4sI5N)Zz>Ot*{i zegWraaT-Lt6$199mH__)M-_5v!;pxv#h~xCGH{P7xv6J_!D%Ns1t7qQYtpQigujL4 z-n!3s&m@h1S-{!njL;%YT10b&PE2Ch)5PQdJeAB@BqI$15sa6jhkef1{RH(n!tF%OU?NEH*av*w0J+-FLi*F25rT zg6uut_jR`Z$IE$1>g-}MZGT3jU&1#E^r6H%*g&;XeEXQom;KG=0FRDX1O~66gP}&B z6N3MOz7S8Poa#}i9j&A0VFu*bGPAG6#c;D<%v)I6Mq}7!`>@i)V!*Bj3e~#sHrWLK zKdRm_I?&&FAFgfNwr#gtZf)Dv*0yciwzsxz+iw5;?DzM)c+R=c{Vp?;nItF4bb{dWYeM0qBPL@dD**o4UG7E-w$i2dmQK~ed>P;?iP6{ z7H4@Km%@db0W&n`WlcvFA_3`N*ESW6Vr-6>bvl7 z6b>IXI)+5lV|Zd~RL&ce{)C~qXs*BPpFdRo0=%r-Pc2+#E#7AqTs_Y4*kYx(8xcO2 zMpp|?P77okw1GiP(os@_$$c)ZJy32GSIz>I5(2#6A(auTduH4}epG;;Ud^k9!?OA8 zMZrX65c8`GDf5{kQ|{|@(ZPNK2oVbm_{4~!Om@n_b{{=ia>Za6-N|UC%E9E}tztUt zkHeWSD8R#eeEGnuiTN+8Y2!GsoHjtM!i~(o%T{kTeHj|Cdl|uyFO*6!CqY57PBU1~!4bJfYA+Do|YWWqi9!O;Dfs9mZn1Q@aa>FMK^)Dn(H$(YK+JvDPQCnjHA%!Z(HP5dw)T9YhRPP1TfFqI2Ra zo!q=XR_B>|Fe$d^+r^g3gCMRw&Q`S?<=xSInm6fC^9l?>Ho2a->qFH__Ovxb1rofE)Qn|I|qAbtC#pQSaP zKowM?Fc8(P+9cJ7&>ZQ-jX(VKJQdF+A;=-JjUYI$O3qQ$$pOLF=vqcl1B@yjq}E!# zCTx(a=nS8^s{hPoM>A6|HF*azqUSOHqIg4t`of#aj+#*?ua?LN7?k#)cZ!=@kpD2G z^33^3pLBC2rBkH*>`-7(q`_QFfnU;n2dBsrr3rhNCIuga$38{(NAL2A3^X;Km)+cj zZ2z#&-*;jE(EXr$WP8J}O!~u5L;^2iO{t&Sl70sZO2g|0q}AV-iC?~+yeghImv1@} zCn~;+qk<55qa%L-3gu&vTZ|;>lF-~}==yy0MSyt2nV$5A-Fu7lqSu6^1FE=sr^-qi zY6J0vP-uF-&U|~{9ESf;`y$<84B-@*icxV{bh|)GbbVr`LDaN*v6sj>&(D-g?r+h3 zBi7_cplWO>ViST37CKY!9jk;sP~pq65p03a@gC3&j{n%Ut7LTGN&{WAhKY!~h}(u( zx>Rm_4btggm%y(B6^a0|)b2Fy3nA0@lzK|s>nD^WGI2>CJKu0g#AEjazMvnMkT0h? zk=X4k?Y8((#`vPBZjKneJ0x;DyaX=uS%~JDUlMN%1?d>FvStC;I@7{TArHKilGwT1 zH_vAv8x?FF#|;}k4oS-FJT?j&>evoGBWRb5beUuP=(3PLD)Jeyi9HUa z;_ixUANPHJmKL_QOPI*TS(fiiD$H}qK9|=vp;pLdmO~K*Eeo0&FsZb=jm7egRFag= zM)9qMfAVYs)CINFwj0kj67dloO=LAcHvoxd$4vxyN(h@hQFGkku+I4$v*UeL99mby z1gu#bWo;^o1|~`w(2|wS6UDATHNYG!mOa*G0qDt1>)Q$U#Col0w}pL;gH5i^uB1F( zx{4WyU)#rKX^r3|k_WP;m(c0o4nWB|13cV}~LpoMwqC`A2!)wt@pq0EgxTTke(S_{8+nKKe&swv%$ypCuu%(@a zWAh?vsSzrH{V$IN5ICOvCCh~q`E_dH_Vk4#LbuDQaEp0GQa+3+y*Bcf=uvKHEy+Txg zVC76KKWPu84>&E1M=R;my#&7;1mSIM$3j=%Fv~s-rP*?b+;AVg4>%$0t7Tt0=Nm!) zWZWSEDQM%>zi8$M<|x!jD+gYYU$YLpfS$-ngNoDx5&WqyHbV<;K$MiB(%kq$C2LHH z2t2h>*PlgyC_GovwG5#nX&rRCM{rpmK#5IDUt?9F3kMY*Yv+WY%=&`GhQflE!VBV% zNILw{io%uCSQkwamV-l4skC_Pj=+D(!cx@Y*O|8WlNOikk6JrJDrXl0TgF zkX^v74b&yni`F#J)#q#p{wk!H%EMBIpxwwbR7u1hG~7#Ay4MW3>LfC4pj_|bHgu9{ z#wMi)`6#mh3+-B&*_SzKKU^;hPue3X%1?D&aQv)k&yp%U#dfIQQZ#fF0XL z^Cp?Y6#x~R^!x|I zeUld&kI*VCi)Nl2)P^n3?G}uQ1AViuEm|4v1XVr5_;=~__*dub+XHixp!+7(c2uD| zh(!6>`0tfUkR!_=L=P|eJjZj^PX1cmUfq$IE9p&|d7~@8vi;_`HUHt3>=@0zKqL6+Y)!O$ji_J&_3EF8WpkQWa zE5}oZE9R0TWfy>Ro#|lYWSypqVx4rFUrQm=PI0mBt{joCA)nua>PRnYfI`2-eT>Q= zE}w(v)xn5))?`^2^BNlZBXo)YtQx{u%EFp+0IP8MC8M^+rkv z`rt8x+3Tw1<3?t!AemXc-%KOZ$aGIf^z8y;K}`9JOYf=Zw~^e<76%m_EkU5R*E`v5 zPPa|Cc^`f;LG?L*ypM{Rzj#XSxu?EJ0*(^}hxN#NLtnlhekMbR9AmIVtek_GbW}^c zc%R-l!S%?D7|=t++xQiPxwSU(H=K?6u3m@$Xb`$i(llTLSR)v+w0CJx5W<+{Deds} zuRfn`*5PPxE-9ADujyO@;BlF1Rurrg?Hx)gG3B<*m-P+mhH3cB1H@rYVu~iJFB%i> zh=c%v1VN|PB5>av&Oz%v~`19>I_FB^rU zX&B|PL9P#C6Bnj9u-LydUxv5vxFG8qEYNS9Veg)Q{66?*ssQHJ#iz~~s!?(%oWz;q zMitH)M94@RTj}n(qyZ`8M?#eK+v`^=O`C; zNd)u`lQOR%I4;EMBSj^ny|05$p2cQC_~N3hC)t6cP%BWDMy=hYCjJ&>qnnBdv{Il9 zu9Ae$TvqUU6tL2>aAFobW+_l^wCAL(MQY;y1i?`sBw5&}z}S|w0Dr~@R21XZ4D}KV z|IL9anop)i6y$7bEiE}CEssire-3=?N`VbnK=hX_{fo=Epg{pU0&m6j5Apk1rD`!n z^wiLuuR7k03d-8=<-)UFiMJyrV3hg>k9ta>jwVrGb)F^ex;&K_pfO(+0PE<@^?uSCGvT+2{MsIe zb`QtX?odN#yhMoBT=u{pHuIe)XJ^R$la*YP8BkYhfihb!AEM1p#yH|Lx)YVfgf9;# z)9;N#z;5}IC6bxs>+-fJWtu5}Q`!pz7S>Tdk`7HM3`gJhb&xQ(baQn6;cPIFq&2%y z7VpPwg+B8zr$OnP&NoV1lZq~+)%^9r z7xSF#-xd&Ap`njwBan1wm|L#W$FhYMeDcIky+=ytGVabo+W?J_Q!`Bgl1Z zNUE2>o&w9vM9~%*mdUKc#9*JxNh{h~c=&Z?G5q3dt9IX_n01uNa;%}|FrJD}*&rw4 zuAU3@q;6BRZ5T%tIPI!ZtrCg`jR_hi+XxUB0i;o)T{BnBm=JcBsElGgBnF(RSj))! zP-6~&P@$vs8$=UYPbvMK%WWgsaDC==euacX^^U}oB1~i(VhY2> zFlMjOfj!t#snySvOPT3gS>YnOtPyB#2qeRFH5=C6RlGD{zBH}!wO;5Z;yRdMp+Y3y zwhVImw{b&cti>HwN(~v#A>lAw3}rXmQXM>>s0rTd(2tc3I~ z3Q}=li^T=Y>{^jH=syGPwfE5D=Q{C+mojyZn1nx%3^ijU9Lgy-<32M{I;2&yc7!w% z;@<^$^w&bf@3;2Bm33>mU|Gb@wgYIM4hKTkz$@=$a8 zgV;~nYeSy(fz{5K#^w8e3W^sgtjT>TN>3#%TVYmGlG>0Nw7DBmczou}s{)$ITI4cK z(+SSM49qe7*ey}T(`GP6Sc-b#UpJ-ib|tVLxk(?YbUKP)wlDNqi%;o8UL7abwW1gE z?&B(0S6{32mzy$M93dfMFM^Xyn?}KqI^zn2Gnl>P%bo;m$Kq#c@3j|2k#cAf4CZG& z^Hc4B&`8SAX}=imSPh0w=z&E~6Sp~5J5UjPotYFY@tm(VJV+YzW;Bjm@PF7f&If;X zEO?*1%vW3~O;ga#5QR+z>V->G-EYi+kiaRKPW;RjY801udS-D@KDr9(as)S65S0@`DxBOfc zJLp7LvdCXpOhH{lO1`o%%^T>M6Y7lQXuJ>-Gv$0s4XVxF2q#mo$tHtH!(@M}1THMu z-IjH!q)?gE#~-cXiPP3r*X+R3y7@Qh+dA+^&2_)khGH@NOppJ3g>G4Yt~pR`$yoyl zld;GyMED9fxv-`omZ0cA#$hjmVW>t&yf9JWP<2QqSrmF>ukbZt zjUKijMdeVuAE+{L7;mIvk&soQdMZNnAQM44O7S`+9?j*%cjqAa^v80=nf7=Ba{hcF z#TCjsMtPLkp`PnI?qqypjfSWESw6f_oO)jOHzq*3N~|)_w>zc)!|d;bUR2N-$zri= z&^Q#-q0(VWh(V`1JiqkgDB?CvRMWEj;@D?LJzC)uVsTt9eD^xMj&9bA_GCwsy3!pu zfH0nrz{8REI0A@szd}8ejARQQJ{BT@mnHQhc-cA| z>d#)srq*J~*ocsj=2af5!Bn+569}2DGxSd zGGd2gMVA)As_&S^D;3h05WYZ zHb2c|#!`ld<=CAJk<>$KgEtS$iWmyq5n>6trM=vF&Jtb+9QBdZ_KXl>Rns_15n808e);WA%jqhsbuu zHVy9@J?*=V-i90%5x*i0c70sGIYazs@|o# z`@Ek?@>6}Gdz|yvi#pSR^HnevJ_BH6_Su>WsVEwIqceDsj(XyPpW)0#sTyht>du%E zQF{!R!K5M-kBo-hT{ow3R>UgLsJ= z!%cg~cUrZ4}MbFX8dS-SEDedh27CK$gHc4)PsUz;-ijadro0 z$w=u2GEBsI^mf-PjvPk*jBN*7mYddAUtshSsb-yM=UR zLR96-qQ_2TpU1~UAUU?Gq4ygZ0vF`W66QXg!W7Pf82(>RbSlTYYhd5$Of^#SZ*c8c zTJQ)85~=OBv@Fi|>c#1qbG#Ao_0${ne+R{%LcGtZ7LAcNnYO%mm0Z%O8;X|ph>@al z*J_iNL=Z_%TD>WjPP9eFq5Kg0hhQVM;c(Y~vZ5n|M*pY5-$Kw|f}EoH5?5$k$DJbH zHb==eZ6mS^w84N-Nm}le8zaAT)=0!(%bPGp{5_W_DU#`zV(s6E{Kx$Pp+qgZ2-V1* z*x#vgA~q1zs_2Im5FEPdeP#6qm0DdIy=y<2*V~8E=Rje~!FPmnfy?{u@k zrZi6pks+Ls3&ecrvGtLbYzN9x;9<&}2jZehzuQ7Kdd zs4_-Ll_Eg4lv}^PHU0#%pP|3v+QWFi=6smK9en>^_1Vi)idKLqA5)a~K-HGd=ZmJV zDKq)4=)IoD#b)&!uG-~YlTHpJ$meuLNjh=Ma8Y)n+u21uM>qsP4UB~8kHhHiK@(&d zrZN;_8*c6mp*lK{P9ZJe6yyDYWTy#uxfU&BMp6n1hZ=xe3B3roNGkZ(A&d2|bhLZ- zZSOnxjkBYj%I<|p{gh3d+YtWC%YBK5%;sbBg{(JTCx=Qw>)^L&!_%1pWBPi$OYr5W zkt)x#|0SE?{Jt}Rqf~ed(j!mAWSYUA=*(A7lJ%Yy8#9Hsv|tQBj>7hgM@N3 zJ#i-gLRl_0M#m=oLYEowsKwW0BVOc1(ay#Y?X zypsnomD6xTWhYZ!MY#@g0&0%vAAlOsaK-y)wcEz=!CC6=(QAoSDe{ z7@|oPU$g{m>kM*~)E|5(F8BUjAX=UZs`aMwq*-~p4)01l#cLQ})Al;)9|o4k6KORx z{u_gUs46Itn`1mN9X3=4azZdKJuwqc4D`g+hkPR@4n4&n*Bj_~ay{zNj=%ki?TYR2 zpYr!kj4e{X0GZfEI5Z0e7D|E-kUB)YfOHoo6ow>I>NW@Rlc+w@j51))tpuxJ?}L2o zHc;L5;gECkEXy@OX8qejCF6LCQuKm0epX536NlY6g~uhfUJM7kE%1l>ZW~1>_st=z zRHhTZ%h6Ogc=oBblQS2;=kjg{A_W%NceqILrMCQ6a^a2#p8Rlk-e?UsP)>F2HpP(= zM)Zc=&>NPcF{@1YpLU$bW2N=j1%NUQ1c4caBd2C@Y%?mEQKgf9)*uc0SF*k_uSLr` zJK_3_m~Wi?-I?L5eYs-&R88YgT*5OA+B*TPp}C$;t&#j5s=(uiyr0f{ER;6#o{9yi z-GSVz=Y48+Niv{s)70QC@>5VN#gUQ!KaDuvWwK_OrM&s+*Z^G_3&0-j)KL{r5)X`v z_>x3fb5WyuE$+4|9NShPq25-lF6H+mW(R&kdY(i8el#~UcH?bH7DG}n7rTpB zvuwrfaAsY?yk72y2hV^p_ZDb42s|%tmRQ9B1B(q=a>yK~@^&8zpMNjmP z1K257Bn!j?--b~&h=Ey41KP*-C|Zy-Ei`6rH7yH*gaYuhuO&^23qR< zw%K8iVPS{Htn2fV4>a{uPJ^X1aE7ad491?1h0%QRczpX)!I7I|D>L|dV)q$%Ty_JZ z*2gU&gWfvUL7*>2+sw!xKD#5LW{ogI2-@4?RI+z+*Iounxs0iD?>qf^yTl?59#Ub- zEhj_}h2asDgw9A&8M`nm*#&~ZZ7?^ z@_xO3uVhhLo4f0%KZ9v(CydKU#zU1&n%GY6YBc7tim_04iOOY(Y$+(jvC6>5+29rU z6A=vFFK?BWMZmXnE%3lWc?rVW&-V>G3!||xRG8jENN7VlQ!UFU z9i354pr>ye9(PZE2n0pg#nN9v+X)zg9YZ*GUiC|iY_83dweXr&PAd`51Sb7`3>p16 z$0WFro5g`ruFEIxulB6`2vKlkyKIH4pJg9YarM%6jGePwn1Qk{hhp^=l|tnd59&wf z(FDRfg&htrWl(p|o;kE1rX4J@wh=-wLA*bZPUy46^pEeGRdtsyR<+)C#7-v?X`bJOk$|$pAsX zYZYVPCe|_0TNISO>L~f5(vZP;CT5m@q)VH2R1}zd34Q0*sdPU^_y=0p$YR$nbGd>q1Q@9QWnJ=Z8|Ap zI0w$rE@H`1-V%6%A;$$9PUse{wJizzl;BM-&kP)JvL}>Z=!mo| zB(P@0H^H?&n7r2#eEGw3S{wJX_CUZ@e{t9H3S16CX?lNCpV8co&{R+^Z_ zh-MZ|XLuk751iJAI#uP|W2o53brm}HoRFpK1e6(GmO1zGQoY0qn&5W$h|=c*#>Xl< z!oZJr+^iv2R4P_e1JxEo!9@rqisVE~!4YI#YCXYO_a05Vzu<0VfPB-mGrDQy+< zb)4`WRH!NU0ygFSVe(j%5h5UD{VqrwY(UI;M*3#c1=3-{E$3YxM6QdJY{dpY{x+mq zvo_vNf-=6Y%7hg4e+KMh38!W18XifjeX^MhrAMP=Gu<7c8u|;9`#WVpVu`E<6eP+D z>F%yWXM6zSM8fS5tEpGZ5!^X%qvF$6Jj%ck%>{*$?MP5d;-pXy&p?qQwxydFy8Bti z4x$vvVVNd8sXMslxm@LfTES{!a0+W^Neko-T#v4?Uk(#h4W#zja;rPWkKV@PFhPo^ z)VR$viTY`Qg6-HqJkG$9tXH4X*0UKFYsedJu#O?QYHa(jZ$hE+$Bb|Gsm=0!BEy|1 zLr;Np9VdFn8H#2Dp@L}!>@rtKuIDZ%c2!PCOx&v3m>j~fWM-tD-no4Hh*hUj`ATLu zZc}&_E()z#l$6X|JTCa85u7 z$$Yub$2f5Ou`NL>NZ^AGqYht`Uffg|wz~ZlMz%ok>^+)DkpM1+00|0fUSt&#LdPkR zUr6lj3!31ydL?pw$&b6{@^W8+5-Gn5>+wij!JCxzr#uS*gyjoU-R%_B%u=b~fda3F;De9RGYVO`4D#j_@avoaZK5O50Ea*6`!_TsS~c1w zZ{BBAsT9l7Y2!Wa*4;YtB{L}(2SvlFqIzReXZ^?Q)Ui+!*cB<%^omP zqXmbd6z+T33MQk2zK~iU0m-p!W#k(alQ2#JvnqW6FH?_j0Js%gOH<{t98)ja(d6p+ zl{WI=P&u8BR`7+2(#`TI^#Mr&>lIL+pldW_euf!b%}Pz zIhrn85vO)8BZ#HpIG(Ur>v|0VA)Mvbsw%z_1I($WLvNo@GXkL;q$l}-X8^rn&lcWM zphCx2jG?I-pr3)}VPtzrRk^$=V)$)gvwd0IMy?{j%#H6c?oq zzngIY_`^J@reYl_hV|Y{zBdVtCd!!@u5T{;*fkqT%qR`*vqJi{ee}x9?DeS zq<9`{?~z8L)9>KrrqCyz*R9rfyNr#NX(G;7Im%HG9+V*4&rE3lxo%BT_X2pHKQ9{Y zNaH%a11OE~r_SEIb)vvF30nfY@Zoe!Tg=i>X~dGt%-m^p0BhP zk`qcO7&`G(2}I^mR69`{xRD=_Oy?ryEF-~gOptG3`Nn&&(|d9$4B4RqP~_VO&a&_u zTv~2#FKoZl(Qox)KajZm?$Q1ofCnI=zLrh=QaZ1Oa%y-f(4Ys4(Ky#E)I~7&#PS*0 z3}ucDVbZC6N15s}h&%fahwE5qC@BtvfX0LVJ7iC2Z0J9h${_@xx7JZ)tD^h2a;e5NZL{=jEy-`ns`6Kh2$CpuPVlw^$nP^lwzz z-GYHARKfZ2<~K{zQlln=u}xWECbwzuWADwVeQ|uqS0VUO(6eTlRw>U=S{@*1OwE`S z4q<3^;9V`tAS{L>E;R)Y=~VlMJ%mG>qr&P*1*k{nxzu~X_?N200?;QfK4?~`_lmS9 zk1mx5KRRrWB`yxDQ3dh92`kb6@huZ{-r%YACIZwqm$udTW2w9B&={Sp@nJ9@;bN!n~4@YA|zs1at9>k<{(Ib3RWp*93|6A$I~s& z8PpozS7z_cA-e@^Co3BQEz(o;GlW(K?YS{CBEqD=4;Gg!Mo<>LA0a|l-?Nag_vfHC z=T-$dD3gtm%FSm*N-ADO3!|AGIk+nb*CK(aGzn^>AVqrccQBuDWTliq5RJ~IwI%at z^f1Q9Z>{z_vh3ei(m>K8H~1(&je%=iK#nz}(oE$^NX%t|iBX<0tCYh;f<2XnR-O&Y zoa$7#>n$bm;?CwFgo;rbF^iN78Vfd+qF6N}&UnK%MX6o-L$+owJ>%!VaGmFyXC-%V z>cq@O0fC@MSbr-T<~2F7&x1qtO)QEACmPQeh%Y+o>JJivP7*GPjks^|x2ojNO^kJSp#o?q%8wUQ04 zhu7(u$t7Cg2DDyiqK*xTa^Qy9K=BKOZI*#MJCx(~4H_kClXAI?zYb9Vb1X26Gv5fP z(xc28z2JM3mPljA zf%(F<%zw#mINuqFgM=i-?ggwxq?m#p8Osr)#wiUeD45$z!U;MjF!H3VZ8h)#G2&oj z6eG=eWP5=qjSUJs{0Ae1aDkupD49%pS00rpm3V}Hh=HfP=bEZ^M5_fznFjIT`T~j=jeNu%TBBfx|V^_=~xR@ z5wnE!GBgPL?w^>zI=Gt8Yt>P7M((moKVnK%{RTGFBELAktXm()uY)vkt)ANH32Y5Wy8B{}5 zY5;zfJ8BqG0bh_RhIig+#ToV6H#l%$ee$+ku_tY4PEt$6m@5^5>dY@J*9jy62q&mx z_8%Vup#k7oB|xFC;zZ^mQpjht#inP}YYHZ1KHLhzNyiVxAJUaI4!CjcRyBrbq6tF~ zAMC26*k`8E8()!id^`ohw*=U6bqz*9s{H`E#i7E)G=~8Bqa*UDHJg4=(4V@#zpG>Gft~mYAVq0ogfHoUzOmNgIZA9J ze-i+bo$5_H%O}JGt43R+8tYjJf z$OEgh%YS0QDJP5Ffm2RAJT$YIfARS*yLuIDdS|`=_DCi0u(v|-0t5ko*?n;eMQG0# zv!(tbkA=twW;EDVtO9QIFCawRpjA^CVgxF&v97%SP-#549q8F-p&^ofgfIVc+Ymz% zy6U`p#t)i%sD{f$_qQ6&dfdUO`-a4YVNruJ)j`N~CZ#^!ruV!GeIz#Vz8*?wCyvAr^J6 zzi+THWN`5^bu&jg5!5n-n8bQB(Evx`VY=!^gKD67ZnkD@HW!~Ur#^g z{H~jzOIVRJldtW<$q|;piuWvt)$R3%|E5|?AeJyPfmR0-NuRqDfQJ?K%5!fkFd#oI zNS4+!!#A>0@cD|3qJ0i4;UI<2wTO4ln>MIUw)jeJSN7-b*QfWQf^3J#EwYE!`Cmy?;<5g zAc@dQ8c{GHtWNHyD9*``dRsii?yvz}@}kIZE8U~3@#FgO&PYzN=NC*|CZ19iUZaK{ zY#C_h81bEDF8z;vJwLm^)i5@z{*p<~?QSBk8uX{ItZTeJ7~UI&sfR=4)B-$kuX})Q zui?XvnjV)m)LWPR0W{i_(;K4^0#%Au=4X#-ETcjyJK4B>jZ0*>_r-XGH@@ec&?7gGJOHXk0JKw0@eaoP-h zWozR~nXA^O@qq{M#J%n@x_!nE*SUWVU8GeCBOIV4X)+avo64x~tn+E(aOx zM*HSH7jl`)Re(__s2W3q_OA4y#>GWBd&w|+BK<%|yIxN)RxA6Z^f`UZwrzhr!CPp% z_l%Gri>B9KrIr+Hp$;}4JagzDod3Q<-!r<27xaL_QdZ>G$dLveyag)ISrsO)+Un-D zadg4OKT6nOf}sC}gJ!;2P0;%hYMVXy{7)$Rr;%A*hDOTc8Gteo5@2=it8DWIp2%;( zm9Hyfzm5;sdrmhvTd$*2#+FK1$Uj({Oi%Bqb7!X?W!_4M3>lR(2Jd&A4F3gZdiT9W ztGg?p<2aY@ODZNd0O$oDBU?oS z+dM%tHe0bB*S_zaH;vMx@kJ^jGu^o4j=*S~~~M_~5P!TV~56}EXoueTju zpWv?WMDhq!Lw#VS!H$}#obbZu1+Gke5bVFJz-Mi@V&4sPH1OBZFIy(~T`|}z)s-L2{2`UTC{suYi`txypH;aPT%%?z7ls%YmK&Lu|7NU{rZX|jcJH-SGhed zHO=t*_(?hA+&cd5^o%;Z8-C@zhxy+BF7~mB6Zm;blK=Dk`zyqhK=N9T{JYfn4Zo4@ zv&VMnfM{ZjSSHYA57!+=?hx~QoQS+x1|)ijDUNo{HdJE;hhW8yoaYfbJmqo+0S zaj5EfZu(WUDgixv+|c_mmEONBeS3L&V{T*mE~1;GiauMeDRD(8;%SJ{DBBDss$~5= z^3@P>zRGQuz2;DQd0ApUzeqkt>8-8lexk@yV`$<1W3j{~qzV1Ov8N4yW&C~$Of;PD zGta%|KH>LVM_RtUH%pLh#z#*}|F;Z7qZ7RFukVNJu>=SfjjQRQLCs$V zz&z|Y30oc-rvt!Lnl<e*ze5QlM=M7Uz$38r-gi&;1 zIu4dQJVJDmALw(`1wfbF$9DnCENbxEZ~Q=Q=ymyCJFWdHO~h9MCV*gRNhx0-!Nn5_ zrF_+gb9C_zlR$2Zyi5RMML57s-BW>Gc5A8eQ+KZ34jW=N#5fS2#H`BDRfh`wTHDHZ zDB*`9gwloRVckVb4|>j%j>ZIF##jMi^DPYFjJ|64$*$?g>hY`&+$5t5%=o# zAyGDmD(l@SJTRpr(iCI=By32~4sm`D!mN2at%e9J9w@wJz`l4CM(3;TzdRf#&uL-I zJYj&>2dcP9ZERO+n#noC4sfTPjP2|WvUkKaGNrG{fIf7@Rw}NsH{19eDTnl-_J14w z*V0;`Qi-*zL$deCywvQl{z&9;^i5#ku^!5RUJEYgDl*nD5n86>nXGnsaq>M5^8fq^ zwBlv{7N}&E3Po2!82P!#Fh?2!?Zj#V)PW+} zwJUvP0KIVo!XT+umH!6kds1cgXYH{)+_A=R%x2e-+X-rvxF-WjJ83_TKMiVmJVlPr zb{(L<$s|y}oOGeQ+f-_B%&}SDD_0)-_}qD&W7Y5sh zSY$*@7#>+vLM9f!*$%{VcJyd z^1YA9lrj}QMdF56QD6vxxr~er0(RtJ=a1N&KXL_)#RM+%ow;;$`4#JQ#%+BTn^d_G zd);MJ{|ot~t&~eFdjP}|(u<%nw{E~D_ie!M*0w45vD;^{mhZihCp?4a5~3$=+=|KC zXYF3^nv5ocXQa`{;CbOk_kfD4BXq=R%B!Z5;`A9e{S6Jg_2X{%0$r=Y|MdvJK=(n^NsnC-p^6H&o0R9h$Vg|{}j6b!$Of2 z;Dd5c>O6Q~`kx1%Ac)?jlnv_mkvsS?>w4G+90A|OO;YExi#ytQD~bj8iRbx+w00K4 zVR9X4QI2!H>U2m*7riN5e3%S;Y=e)1o?<5DWoLBmRY`4$C+_(S#WRN{dI3)E{Eu0r z5Nh=P5UNXhSnYlA>G{|On(jTu$RHd`r@?!p0H-K10!>BTD0xqVC!Y1L!L=PQESSFM zjeM55eG()8!LRl)@`qZ$g9v5?HuM)Xm1Mk<=+FulckC*kPvNUvRuJVIyp$6?zlOb$ zuKgM<#sF8#RY?K#KsR6<*L?;|GC8s-gLz|5(4*x?Zsy0V^f3xBHF%7v1ZdZtVLA63 zgklBb>I!}ib?h=pSEtQjOhpe`iou6k%YjFNro0aHh=_yBc&4nvO*Sf6FmSkWyQ?QV{nsH zI>TyyltzBcav!5$Q=-S1&!NmF_~<&%3*r5nhKp=?`FYExMAUZ>2iPiR_>Js;DuF&kGQW1|J&2^gPtZY0 z%aKR_UiCnDD6%ki%ttW;BVYtu%Mg(Pa< zSOBYS(dI8=<}1ZAO(nWS4%eZ|PKST1>b%}`!>VW1I!_&=DD;v7N|y5q(o9v{aqAAY zdH>idg~Oy^XUt#BtflYd)BWA70%X?WRQ4#T3(=Xfy6M&>^*x@kHVUqI2zwkTE6GJQ zU&yc=+-N=@>mq}oL$I9ek%oZ33Vf8i$^Sd^+S{OHk-6ME8B`+9bb zIfza&C0!#00NP`2*)@k5xjHe`1ihFPsRqEI`yM^ww6LPUEoYT5P?hvlAWgC|Ig_4< zb_j@+?7QU%o;i+I&Bca(o$Lj4pZgaq3JOeqU(^p;PcuvD&opF;lf^ zuep+UXoMbYjg>8g2xj6J@_rw-_7oCi>qZ3G(m#jvjbBgw{?6_Q7vZEg`-b2C+K09J zF$LW$U;ph~??2g%tNeZNU)epgyH)n@W=aJ6_^e{+ACH32vQnnD8G$S2$M&A$z}x3n zM=cZ_d=2yqGtft75^sgw(PIaQMB$EAk6Ql8`~IK2^$+1l*%jGawSs(UU8+Hxcp*PF zAgoEuB`mN79Wy&B-EH5>JVC|>KWQh+4KTfobTs{&jm|FL){*n}W_$-;N5X#Jjd67C z`-etdyx~9QFW1|4uXh>jnlukdM%=~xo)%Ja1=)W&OnWuUn{yMeqc|_$gbWQO-(kx< zHNW0OuKu&pXrvv>(P6STyE*Dl==0+#5_(5F}E+d;5e!iNajyT_L*ID zie*=$L73t4=e~xn1ul{jIE+0REyQ!Viu@vcsUkpd`j3x$YKNhL{|;z#AJd(OcazWC z>HG;^(=%U28C#+xh(o86hRj(!ts9HzJM^J({5solr}<^j@u(y$hYMo{F!?bs&D$O5 z!6RrsWHI2p3i@b`*jU#w*#Q4eJ|O>{e0~OzCP2RPF+0_c;h|HUri!Sq(iFstnZC?& zkG)!@fxhj?5N`ToT!|;og3gXn_BPI3s~4a_R-!jWP$-`9G82uieJ38@mHkSJ+)mlE zR(D6xx*NWOiKNo^~0; zF~BN)D0laV{2kI#{%Kf0EdJhdjIVvnK({BzcF*zMChZ2FKZz(H+o4IN*8l~tv|8vs ziVFuv$RTXLNP+E_^=0T2;?C-smsn0%KUq%h$nHNN zY(GXW$Lys2GxD5R;tW|eOcKqYL|n%Spo#6Nk|~mb!aRL_+hF=^`4;nY<_g1@ukK~l ze<%+rXv)N~EkYB;V~F`nehSURXR?>Ms3ynv=>D_x8n3tI-^^(_0&j~P4D+BZu@+veiF$rjpw{-3V##XZ6GC-kJ|?Zj{v^&%E! zN-&ESHFZgLzpHjkj!KRg__K|MuLlL`DTor^iG;q$7s=SWv38>n}j;qgt-Nu8%f|Ej5Mb_AZ3gxwXY#dxmL4i9!q-%bXGyukY`NNbb6V_2 z!UgtH9+R*m3q+NwJy>XBK*(^~!~Ap>+97-!8H)RCdWp&-(;r0-f`_70zYz6=Z8xSq zvGa$Pis5!E)yuv5F?3-%U7ruJAdSLUERDLQGDXK)?qulfvM9vCK+E-Y-R9MzmB^>F>1>AlG#9(myJ6t z&~2^mS7XOrb!-100LDN$zab=6?aB0f1cQt<=-rA`=aiZ{p?^cIvs>y4b}ROr*JV8( zWlaZL`>`7H=-5si7(wLby11?#cG0d~*V1PrE?<83tpwwYymD23Q`$2KVO0_q{$%DE z-G(Qm52LavLuBheBre)@JkI^$tajfG(VgMwSi8C|9(Hxy(Oi8or&)-U7q++=96}10m7_$IUi)>#!ZD+7uU7JF50yl zWZfqtE?<83HcEv2s;G%_I0rleA*C(4ae$^XutyS2J|FUUGvwpA3O}c{StLJvEY|>5 zhc0h4IwD(Ox#8*nx@s41VA-DyxqSWcR~;m}jt)Sr(sL zv5t1Q2HQ`GUe3GjLX~@2N|qY+T*Kr#^ILCeo6vdw5d0IY+=Onsi}r`Rd3KU02O19CaxzrampjG#B4~Pn;2c}YB`zRgw4pMjDqIZ1O zqj&#{KE8VS?BlM#2iT6f>!baiIq6H`RBh4!p4S^&g#8UwS|%mkA7wFq2de)1ZK!|0 z>`nMAdjn9d2zQX=7q(((YgMF@=|&dm;m&}wdqkcnmE&cXUpaqM=`b0ph7Ng@GsbFC zwP~wAF&Xfj!%v8|GS@$F%^9+$*EJga#!@&4_yLHaA4}dJ4o)?Mev=QBQLY0a9Gz_< zvJXaAgl)fY8YjXWZQ6uqaADTanwoU7&H#MtGpSvv8P~FCxFweLx?b^A)0_LCRLytj0-QP&E3*lQ~3{syoxb<*`W9tT~-y^`NE~ii(FdS)2i} zW>Ys{jK6qB=Rh44;6(si8n$?PSFda})8Z_%_W}a800Tpj9gwzZIJRALeJ{8rkgYCO-;H(&8Dou*ax$C&U-7sNZ0o zXTYU8P=YW`;vfdWvHCs^f$4~-sOh;ZG-`2VmD}s+2!3m6o{y~=S+@(VqPUkZIqAS5`v3Q{e|6b zfA?Gu9ZX$0tz;R&K7b0V$s_vYu_5$4SsNDX3@3Xoq7?gYFyAu|(0Rr*C}j6B+TaEc zDftTwV0UmW)J_w(S{cz3{ypXM_wG&pyQh4f&Con#fUYT@&&I@WGC()#R|7)e;_WGe zA5vk<&FZFLRn9mdQ?_u?mq2N`sm1Y!@;%R|XCBf&HyhQnDWZqZzfr$o!BpjNE!{Jt zaF4p**JM$QgLo&6hPQ z)~n5$hkG~DJLMakD@GAP;b|_VWMArMj@yr8`9K4s4 z=Le5MIl1QcQ< z4F35s?9N}1gSk)fT+Q-q7U=QgZ*w}+E~}jqtO0HE@KU-pyD>^)zwXg!nZ5_SoUc>4 zd`#&)pM|;0@LaPNPv(FgKKp8wJcHR8mcK=-E6`2X^@-UqaBaZQHyxPM9IP21v{FUq zlYc6i^A{vv?sGdg;lPvWpU02C-CruxAv&a%A5ME9-Tf=rucfn+{P>R3?a5%cQ~N2< z&J!7!`;^XyV$sj!bgp)=oXngLp2D)M4MG~}Ca)upx7`e&kD)%5#Q84&@=nM4@fSUl z&$&(FkdfI4KF`_UWfKa$YTacN&Po0i3Ct5K4mCBJ@`( z0sY3(I9)n0^C*kcJWB|ub)_$Y5n!p0_kww>Y9m8s10|H#(ZKx%Q#sJi)4v<5vxzBv z(Y$K2)N{&dFgg2JI`vu?w4lFm*8H~8Idp%BaTteh7&tI!k_;)O4j>06ahtW4rUP9B z!8m^ov-4X?=RhteK$8+#^baSKzmCyO1q1O69jfAVgq1{R-`*?G{BpS*xPaJGlcWf( z<0@;D9o{8D|4cM)^D!1xvB(joTY3Jn$sDy)8FW^GD$3$XW+{qeBa|p6{9-b8(-X~R zmHu-uo!>$-2dzd-6PXYO!+|g=iw~+;w*b3}(_Ihqj2d7#LB7fh;V8ecd=8=y)wWra z&N(2)OwCZ+mS>NU-k5Sk61NDAN~yVO!VB>zzrnN))dl1q;P5oyA9SGXzCch6(*=om z6>{50K#>@YLq7kqshxQqcL3{WC*QFkkt0)Z8KTZVNE1tYCOSU(kULZ~l>o&3!U-Ot zCAdzZAF>Svl!lgC7WB`oQO>L#d5p4h$m~?8$G#5B{`XJwc&n9Sgm}}8#RlwfCU4gY z8HuiTGXz_FP@(!QqZD^+X~9yF76> zSE7j1y18&N72Cq2fo}I^VTz>xVjKXNxH*6EYnywz@8TiAqLCgtnyBH@@Z}qfC3bz_Q44` zS8+B#4xxJ1HxGf@g8FK*eCP6IX6wU;(Yiege-01iyK`e`(!9u_-u!g9CitoS<~i8V z`;mtYJ#NQ7K8I)DcX{G&uFoMUi>S6vb=1URFR0XR?q{|Yk_>2oS?TIKSF3wc-UJGo zGkAi&lVUQ0a2ROlx~*>_yhd;$bi<9e*GZqI2O?hRfCDtF2IX_Jh{%Iq+-|lgAA3La zu(8M8;Kv8@^cyeF+|VuQ9K^dbHa4b!X;_j46tjEthPggO(w?2DqpFTFs3KVQfM_X$ zgLRxM9Wf-yJrd%vpGk%8Wc_@yw1=pY2LXV-YyqL z-VZ!%^xJk%H2%_0Ic&bOz{C>vxZX zvB&*j8++Uhe*Zw8eBp8eoas)#i&@aN4Fgbhv)aUMSHG|}MkI*o}O9uJj~&^kWHorIb4+&~%Q z-J!zR<9@J>J?;j-KUAK4wf+R=y!eW;4nynU;qG+30vHa~AL<8=gNPvHjObb$`; z=xYbkYs%Kt#QT*DE6AN0&=)nqOC8K{>bUk^}>@ZCMmPG`vOi7HQ9RS zdNK648*4+4yRq+Gujk%(dE#!aF#ADTWnN}u_4Tfw5bftMSX2l~r z;yQH(F-Vm1R|$-9+%#kr#S zl=__@1!IrkB&p1GkbnjN=)+Ta_HCE%Z{@bRVSpFm*(_#BT<2gk4faS#M@hb=_U^sH z(ul#=^ZT@Q2G_(4&!HQw@vvuEMC$MQ$@*$AMnLqrz$KmnQ^H zbAPWx`klh*_wTuUeFJwz${JnKR7M9^q$CUuLi3e?rl}N32yiLmZ-y1HMP^r^R8zWM&!vR9KQd#&76^-|%!o-z9? zRjpH|S?7Q2>>amn(Xm`tE4w&8Ial(gGo-sOpXK^Dn_L~^ceRmc)kb3cYt=^n#xG7+ zrIKEAs^y#>DlJkYv@u<{a!RM9jM_$<2Mo*fCEwfD_s)k}X3!N{oX$5?|I_!F4>V5K zkU#qjp63xbP6DLIHAye&+_LBD?c~5A;SBtYaUw8}wzSMO-`&#h`YJCetG4^HYW(%| zRqDeLIt*lDNKnL^X?!uElf$mAi-%o3?DB?Fel_Uw)fa3OE>hK5*rg~+kwkxRF^)kK zGIIfTWcwu31wJEKvw1E3hv5DXVEuu*%O$Q(%LlB!T|Mmb4b=4WL6@(-VACyPDnr#; z9fmU2G))Ek7CbAV+-3sbtSp$IKti?mA7kiz2iHf^+u79Lq4lNzt&3Ms+^0h>Uw!yB zYXU4cN|yYTEV<5giW}s5Eh91`g+TOJfdg4MSLf-P6jq=4r^p)~@%oUgRx~NC6nqcY zw~L2ey;|q;3UEn*G`wxoWI(jGgo(j=XR*$ zuo`g?&-_!IosZc48R{vOs8H(>xvz_dUA@}p^D&n%KmQuDP~IKN&YyM`G`!_%IKc%I zH2Ct$JQI&J0{*iv;N4@i@lbC9QqGN7(V761y1k(~<`uti*p#_;)@GGgBm=O zW=^%TGpM5vWTuky(V-4G#KBVYuk13>5h{%rlkz1)S%(C->;#4666L74rxvCOl+Zv~ z{L0>v&>-=0O)b)VJ?9M#x0Ysy6*ZFLs=-NRqbVxK53=LGB}Zvk{2A2#U|blD4p}m# ztGGF;=1y#j9E1FwGP{ql`R{Jh-?6=*S{_VO>$^Ny|G2#%gkP$^puWQ;W`H#D7BUEO zo0P#@P4}?GEC|f)SQ~oWj{N|Y_|*F@Pu$H-qc)+M9Gv77@V!_|SF*C|AOUIA=dQn1 zD5F+ybt)aHyOYqfy(jl25>s<)bJgDiZ+$%WEUe*xPx(? zL6|c`OJ0r3*yDb%jXmxLzke!EzVY(R4Q&W-lSM&>p4QSxUk2TGH6iw}%C8|=AAK8r zQP9(;7Qt<=xSI0r+;Y{704YR0rf5T}`kPn};b4g**iL0SuH{X=XYf!=R~B5z8e zATlDnLif!Ek>loe3TxzXH}r#EgJ<4$`R+!p(ZKwX^LQqOv0{6H579A8o7=uvf3b6S zlL|PQ@NE@oNp%bcYQd|zVY(??c8d@%*|t3hpc{bI=Whu&^0xt1tJmc1e8Gw za0Nny#CVPCsi@f|%za3nsdglIHoHrjg7-@F1Q%aoL1M6>*F_@p15P^>u=tfJja#&! zy1`~No^N41j6Cj#9ya#48~hH)^XwZh-`~z{=uB3m9+EQo34tTVjKGn{0IwbYLwQ(?{Q&mf5O8L(io zc@2W<6de0>4$5hIl2bJ-*juIlLm0O9JFw(wU`hTv;XAIlk{NNf*y{AXuyM<0nmg=V za5?El1ks2^Er^dR<#&9?OYj|E#I^RU=R5wZ|M6e{$H79)0uq$!+o6I ziuY^XKKj39WB7O9CAes*8J{G#l*D;ea_epZP#T@c7I{L3G;Z2zV+{nH6{ zz3^Li@qO0|@3y^94))}q{HH%0|MDOI?azPs)7QJ)hnrlz#9BW&7RUz_GtqUQ`-^Tg z-QVbc_h0|R|M2hsd!F5Y{L>%)lTVZ9Zuor>>^Tad>-yI=^5=iO{o|kaAJ3-U?rCxM zhaaha`|4kTW4|J+8U~R4@e`3%#pu z*G0{HMV~=n0D5Cybgm<_-!`9wc5>sByp_^?j2SLD zwfMB%HeH2^Y2HMe_hLj?X18rNQi!OM1XmARCOfvx(h%h^KyPDeaFZQZn>Fb1)d6kX zkY=%Cn~WAuRfSvKZ2o`@8y`zq;3j!m$n!I0&hzw|>9k8gbaPHDX$)E0Vgz&&U3S`= zkps<9q*rLwA;PI(?C(7oRRBPyoGxhu*T>aO(mOSNV&O>)sRF~sEwi`a%*MKQgg z;?b>1pT3^CU1V@kZSm8jK`qagEU>;vo2;kjAxVsCG4EDl>PXrM*lkk?gnt`NHK&^; z-YMfJNK;(F+YPtu#)c*M1w`=OK>`?V+l~JDCfyAO$eZD=b_04_g+MhKGB?_`nLveb zs=Xy^a&m)hdjUz0^yE7teVOan_JWrHu$qJyvs3i2ez(2Q&SSv~G+>nOS+wojV$sBp zjs(?_lL_-1v_%hqfHxIe)fKI_eU!N)XV9m;#bu<vglnmf z!NR?;yNuv+>jf=_dA>%8OsP0BpGBcLdKf@venS?tb%eYIMI!qmRdz%sg`bAk4D1@` zf_{9N(-f@mfJIA8kDZj|oL^mgm()_a9(;+}kH#Tj&D{MVBbQC*E-%O%2w9`IJEO_S z9)`dX`*439?RE(F_=`@1ToW6%o*{EQtC87&2sF^~*ePRasX(xqJ3>GOZ@=ZDQPo5UGfCVngbpb$3nQRj;pbtif}OJ+)zj5blv8$T}%y}sib)|a0Lcqt)&SEI1P4ji&q`5@`N|)@!+409w4YdbQo9GCR zVj%&jZAWLIkI8QhbvWrA3sKq*5FS_?1q3+S0-y&AULnV8O1poc(+WL6Lw8#>4W=+2 z**t=ScOFi+J8piy`O|pl6%5vr#t@PUEU`A>c_WCA1R<()x-vhan)C9RZhUw6V(~GI z^-8X8ZA#jk^$syF&$EM#%bEYM-Zq{X_oWtJ!oqTt%hhx`XeuNd$((94+tq3ir%Yc+ zlh0gDnQU9E8BFYu8oQpB8SK~=Yr&q^a4iJ0*Rc&YOpb(&%Q$V#T*uX3eAd8eqk}IR z#UXy2c88Rf5}4yh*=5eY=LJDTI3cHO-YClIwa;yVzT)|(f*~i(=d^QzjJab%&wHeK zNSZLvyxw$x26GJC{52VVxKv^H(>CI6fs@B*#Y^6TUBCmZDws?4W4ddDg9SJ_SBDX5 zA&aH~+~>5}K$b|rni+8DJ9=D0dgb(+o?&(AVR^8c0~JTVkJq{F;U2TsAT?5x!D+4^ zElq?}b1voXl+vt4AUfJY*@xg-&UrcEA;{HbKHFXeK4=KRi zqy(S$Fq}g^NZ*y55Qtc`wG&t}U``=x`j0nS(#hwxSC5OrZ{M^Lu=O@VP~ElJxuWii#&ATS63BcKhfq7 zag(cR6TEh76PZra^e{kt!iaNvGY>rfhfbgSOwPrQ zi0L`EUuEbdWmk;JFX8X#$nQb0#H`I3%D8N9&U`rabxZz%pz;hTi5v?Iu3cZD7)bwU zwDHqJ#8ZOUNw<#2C&x^Y+Nln8CW&#QALjS4YYaO#`)TeNi)IDc%{;2n5n+osJJC?}F+Ci@EbQEtWbO+htgiOOCFvJf_AdJ8iqZ!5t zrPd*?xutozA`Y!L%G;~!H3=cE&d%UrK3XUIufbUnVN;9-V7P4ww_1T)ZD!#)3&?JD zxmX12d_u9KAFdzP*O0v1wL_jXl}Y3pV%+Vv%yyXFw%HE1+cq2f0LlZTbL`w%cDtI5 zg_4IlZbtAdBX-+n3kp@$X0PMjO?I`I)YkIF1pG|w5rZAuVmPvT+}Zmkm&J~&$?&YB zx%uWcn8l85GJZ?YfvNLfadC;KfNQ$Wb@a(MdVb5eJ-T9=%y)25lyWp zA5COTlesNf%Az&3SS3WnMa++1y968gIknuVd{1{SlQOeAWnu5RK4&QG0vB#0rhcP- zjJE?ytXnkcW?NP}+-%EghnsC%O*stm?$AUe_heQeFMA=%(Ts~ycWKr-mbt7g(*g#6NN%v> z#$sNFJEKzQhe}w*vuMS#kNo=G+g?wP_6Iwe<>x9~@MQT2B@6~w2Y^91&7*gdcFO~2 z0;@&AjMt)XbuN;C6P0oJnX!3w(4Fdcj4HobunB4NJSi$bKYBul6>WRK(KS1T4QuBNWWBNYx; zMS&(h1T=U`%a;}1SoRo~{<4S@Zc2xw|HU3*0K05T(=d473MGo7dwR{$%aw;)Z5!=y zt8JqlX0>fJ?GR_UK!j#X$<21P+Tmt1tHmXe-3T<@YSFZMnO-uH+iaVRx;|uBq!G18 zE|YDG!6i$mPR*dY3>g`oZLuQ3dTj5-P&3%EEvBa`*)yb`?8h#%9ap<8MlY(oPIi@& zlQt+cwwQk?ykcTZ?`Ea#aW;9(XlI%)s3}?&<;Mx13O6a%doS6OeTIpTysAeET995s z^W7mvu@`3$4=co&Avl$uf|{45hG&2#4svC?Y`-u>L7P8N4gg*my40&YH-mq)yV4~S z^;v#2BnyDof)5is(kTz(^FEKAt{ZH7we zk5jg`41(w*Sbe86J3(GGK)&42X8AV>QL>KsWJlpb{cPz`%I~hpRzXg|{ zaocUv9m{sxbjPyYHXR_C4*ll*1?CF5@wV+^P&$g{bAQ2XcQqY}DliM@&K;QLj%_-` zK6n7C5b80T-HvTIGI}ZjEh;E8-Em_(Z37@?k`?LWN{`LC53FTWRZ>vUql`u>Jg;!N z%Vh%2QYHSP6nPdu-eIty2w^#?Dv&QDdR>udmva=nl+!ZJuR;211`g-)&<0VSBs|gz z>E~Vm(SH~0B)ad;1~CjjkV4*>3Pz>r1Uc75&s9hxx!+d z8Y*KXfxB#*rM|&d9H@BM5oGYM)K-2j2uno<{d5WX^G#Cqm13GQio-*SsQi^j*h#T0 zO;#%mrN+iCFl>hxKn^E7+xeOBnCTef9vqxU6`kTb%WEm8b?Kz7a~O%!xtmc!&?G?W zE|Rr35Cb{!rpu;FklE%1h$9rd1`LpPRYmh*-Hn;=YCXIN$yKB!dhOQR#^Yw_lf_4q z2W__7rc=pM%wXmuyWy^OLwM&@OSR$o+-TcokzAM_VD#L^GTL#q+Pux~X`vz8yUmVm zG? zb3~hh)cSVV556#Y&RBY1maxEX{vtTj?qHurNq9cuu{zP)JPb{!bAB-a7JM4;h#3_@ zrKr>J%u?})C81X_w}7T}qlZ@pJI!tR1aKF0@La@d$qeVo^2EOHqxv8%HXl-Os==U4 zk$z4m&(eE--KxKb^09?`W!+9;vUsZ0@x$!sK1l!ts;^L!Sj=G5h?Eiy-!;fHF>TMf z$yA1mcQkj9>5CMAc4-zh$>9lh+t>4dt2|3|bUafy{7mf>!1uCGg4sAd-bg~p1>9cW zb511m5(I;5W=YHel?B61g4vtLO{!k>=-T~2>1Ov%upZHwoR8cDI|dAP!~Qp?bTB5J zq%x!Z1he4PfF_<1l*;flg&A<$PxhK4ph9koVWwZU_3%FDvgRBxG=Q7#YPkp$Qfg?! z5*y~gEu$4>EQOHboqDWpwc~0wwvBGF!TMY58rx{|*Ha6kNbearC{vW#X?clGW&;DE z#nK$S0TBvWg;8$Q`YJRWO>yI?8kp+DEHI#itR-iX=#Jhy%RZ+iRVkMf(LdiiL-CRM zW+1WB+^Xi9KbM{sr#HH0HEgh7a-L2^nJo3e`K~(~!vo7AGQEJgob8dPuap5;^3w#) za+gjv+&m13dhHkod4j-{JAbB}mnr616i2#E@PBBP8P%?!Aa@~cQUR7xFbA3qi@nBUs_&aFwIkJ>EiXyx;!p^m41eGge+j|h{ z2>_Y3og0xE3~@L&qp%Q%iFa~LHxT=EooFn^F!x?u0l8NLaMXpwrqy(N)G>c4GvJcX z2GqA^2)=NLo%L=AL~MA^An=OukQt~`l@zPFkL(jqZqrDwgA&9Ch#>h_w%qwx4F?g% zDi*Yr3uGS^YQK0*ifA&qBcS~^oA(AP#?%ni5Fyjmx;S*p#ZLJJ#&0S%-6Y>i@Kecs z3;GF?A8M9m@oXEa{xI8J zO{a8#uD6BDZ-Nh);fkrHmlaYivt6ymcT4x)8(Z9DA$i@4-Kq;7j1r;4scN@Y58F@( z?!XX%l{;5zbZ}^aK=Z_a?7s(8$=Gsx^*@diqaZp<9r`O({kp%3t-EX`(T z?dzh07#|ybq!5_if+j6VU{)*1;^C4wc0VAtva7qNB%ClHmTr@%vE(7~vhZeZV>}v4 zD7NsLa<}r^hQl=x-*ntr@*qr`w**#lxwh-6uLMkp2heD5ib^>>gr1>#dhs%KuovVaWxyo9|^Mt!yMSp0~;{R zV@&5QjHp}9jy%4{(??d}(l(BzUQUkFfd#F+rw=JL{PkYhnWN9F}Ob!E;>ezcB&F5S{k4-<_+QF;=OPMK4 z`G#UY*z$e)H`xqSI|C9XmR?E2+VrS4Xj`MdjWtTEM)eqA(632iYvFp6LJPog9*{YF z6mxjHuIuS2EQq#*bhMZhMcoC$t`psNjimYuEwA40nJFG{qFY&p3`NLl{5dtNk|B3W za8YOC63q;D0Y%A4^<8FB>-P=4m-7bQjN!K3l*dehGmNyFn#k#Iv*}Lfh=P@(-zj$6 zW)q-_>SkC);v~1(aWz^#<;_W=!4e@_Uc{TQywS%gsPk!EsALV@l*+2^P z2KaH@)Kkj@JNug#71_&#C3Kv?sg$sknFWLP)M1fZ-N;NhYGbJWnP>^N*T~-EelpcC`x5# zy{ZtBrv!Sk*%jplfv)0__7&SlJYDM__P#K%6oJo0dCfD7)KbVwS8734{6jHAFarR2 z)wglepbsl6Ac=`A8cd%D^0>ve=^p0{6v%h?xFigsVjv3h)wgu=f^xmB>n^Lzmsd-A z)WZm3M{nacFEDozQ8>m`X08H~y@eIvTQgs#V=(gtpy_}>_1tZH%nC3B-iw8J*3r!w1hH>i5z1xT z387fhr_hQ17VbfzQP1l`XRwNJZ`Y`>2pTrss=C6QYT>{Igpen2D9;d1os?nqn=|si z8Jsc65k+-W5LoeW6`U3kSd3W=IdJlHC{WRdV5nUR8@Y>?qFX+gW>Dd2$r%M}7=!m+ z%)ezpl~Pcb_6x&>d$8d=!V*b|<^d;%T{HYxHaM|2ms8NzgdV5u%H(!!d)*x;z^}Ck z7@JjG@N<9e(dKHdLOiiH-U8&&)qA_FVx?WjYV!dV0yYdvWNmXrtBKI%2?nUnrXqQC zoOn}*wX~O=EnJ+rgsII$YciPK(~oFM&eIi`A$`&*pk=A`?CFD4Eakvl9=CM_K7df+ zTy+pEw+%-Y1my&33pSPAa#zE#oUlR)3wUdW+jc90SEueRlgnz`Xq4g;J*xBl+OynZ zGFY`AC#>jd^L29_S9{?GoL1yXI=swU$2J#rLe^U%Rkt*1u-LIpW_`rL&I2!;0-uc} z9hqUbYS7ojqV}TI zYCv9ru+A{NWPB3N8?Uup}$Lv=UJ z3axC2-P?^w%FLZRcw(xu6vUO`iGd-2EcviBmVPO5EfKy~Hiy!9G_!hcXMT(1+d?f1 zPM?7J*@>R2-~z-9TBS6tjAmiLExxb|40VP4nB}(N*!^gp;@Guc?huZg#K6#J zxY@SVh&PAg9_z?oCfgP(=GKayDOfU4rQvNbieqy1w4FK6OL3wPGZ>r8P_EXt6dCK- z)*^Yq@eJrTEd~gcaoW`d^1kF87IlNT2%>yhhLjpyP0!))(>%%`pevT4PARxvokkd}Bkl zgfm+Kxf>D?Zz_zCYP7AhpQI}YH$NxBUCj))?FPV50s=b3m!qH>z_#0A)=#U;+l;ntR*W)+@3wrE8*JN4RA)i) zoC==i8+u4iePKQq{IwOF=&0Z-Z8o4Fn&Q<0^`agzq9 zcGS)|ue-B*WV|~yp^v33a+G?KMMI=AU|@GSv{Ny%4KOiXei4Y5TijjXzjf-0~!+7FC40Q^Ap zP!r6vh$5sfqsWUkBNYzYX@x^H$F;i_=RpBeoQzqBUV|=xUeIm5Y!kQ#3yLL5@~76S z1{_0)S@ml;WTl9&jbq4a(V!sB(aYx7pDOt-C(Wv$^DrR`+RR}Evq?rHx}YH~zB*6( zxu`@-(hhTC?7e1fDwbTII;+A;46NYbWm%2{oWhL) zi;=-KI+dpASZe{MjZA3T$HFFhsBHg*^h=%LC=D%VpkE*ra?HRRB(OSXl)91M-|+aSS|s{Wy{vWYRKlR z^dVV<5{UEMOnuwpH|EeLPGzQ~mU=`P=P6GuP;?`DNKH`=xt z+YONf`6s6_GmCA5RbvtYj9>&2bW>Jq-O%PTniDxR2XI@RfOw28+u3{O%2An(u3B5# zO$bbKGvlt%=MMXF;m8Q^b!~2UUe)0k)zR%^3cN@pk;~lOot~kK-N`qfvH2 zo(>&@%EeuNI6*Scu$^|?)*MEpX0qvZwY492N;&vl;Hi9~fzM~yeEwta+xRGK2#Fx3 zJ1G`z0U>XMU@XaBYQtZGej_Zl&(db}X#aUy2s=ObG+#v&T_wM+H}FwnF-OC4X~!&! z2<%L9=el=oMT0mVVnK?AJ7N6;dddz9jXDhSN}>X4l#=3n$yKhE<>4_$7bX*hYe)QXTRWeW@Qn&F%)9*cKTo#Ezq?+ylTIXQCd zfM2(%;g{^_Lg#er3X|uxL^OvON@2|OL?{gv;H@_!@Z9yP$dlMGy34H3vvdUa8ipc@ za3a@eQ&#ylXAI4>PLsGxBm&m=V#44_A;G2!Re_bFQyQ_9?$H4&Cg9_lZvhzbQp6W9 zq+K1&dA0(BdX=oJg#tW_qCrtQUPtbk?$Lc5L{;Qq_5<(`i^(Xa)1hHQIk)EAEa28o zK}D|ubGaLHAGuOHI7KCb57xBC+#%2M>!~vJeQIZeh^4r5KAhR@Tn)8O&&HYRO>bST zt93ELk<$rB(SV+(f(jDyIj2Cq1TD_?zwvPE@{c#gWGhXXdG`V4GA8RR1SO~trGG*d0}EV8H|GMmMX=QL{FcTT{vRS&uNH16tZ*6Hso6*@k7pU{D;AA=@c zdGytDu}tk@eSprI4Ne1Wg=4>%nNpN)>!b_FOj!K#^aYq>h;s77|Car$7u zr5d3HFp@~7#(w}?KuKCs`SzUd;%Y6<$Dp$+&HYc+DDNCR1)qTA$vXJC)A^pdsZ^qZ zZsMht2L;YshW91ObedoDM_5Ug6E{nER+|ai%nTR6@+nUS(#O~gtydoiNL2%_foyuU z+?7~ClW$Mr))(JYHuRP8a{zBko-=G(lT|b=Ugv1azZyIEdZ_A82NbaS?hMo*?$UNG zyicET)zc-#>{VF#47u%=S)#IaX7?rSbyBjZ%g??zK}SZ%5#d?cHLi}63 z;FGVN^+92kxkgb*sa|Le4?I|jF#Pod^@WxHIEyoKqn#P4cKiqWNa`R@Z%E$Ag&gQAF zd{NogTNm-fsH7d+3`ND2MxPEPq zVZo5vn^C()cb4gbXZcZ|c3R4ywl|W}-Md*L%)l4@+ZRqrbx;cSH+lWJd6u5EIX5fC(t+ASAPPOAX4t|=+HT>oTs_8V{vUC}?U(*^$>dW<2 z2xtwk%AOaDZxo*aojhX0x1Q_Fbdr)&*;Zo#5cP;oS^>hfJek2SU7q)VHTrG!$bf$s zECn?U!G__Q*(_JZ@H7^>0KT&>6x-tvUIu##&e_5`$pf%L&y9FihO^19bt2pwb?dD*tZ3XFxHNik8d+OAM+^M} z%|ZFlNktAdP5joiPe{01PC5ECRemmopIbi{F2A@iGs||{bhzxaoTp9KF3WAhiA$%b z&CNhUX11%}W1A~@jx!3N<-i11 z+cuX9UOY@SV6+9;6>zbpMNuen`e+fZ_vCa#{wb|L5A3~6=dNPe+di)8Cz`;ugA2*! zVU8pePW!BGz4=9yP!2sii>n(sRNy=lRQ>eyd0-3Ab@t^tG)+g`Y8cd(r{7=+D|Rm` zRM6r%`8u{YkZe--bg=w()7CZS9jo8@l)!+k_h1l~aqcaU%!uipqiUfaqX@%@aEm%2 zVB=`zr7|_?0gk2;CG)^q1(J@r0|Ibg!SdPZZE&hi!vm?JIh>7$%n`4cP|;}`_9DYi zyIW1INbpQ7-Z~NH0>p9lI2x=BYg|`fyI9kO8ed5>2|mq5p3X&y$18n4>a=S6B+C@a zoTMX6IjPcGFb^2_kLj+9;KIABIZ%qGNZc~SQ&CKcW$yT*X9mKdtoez~VoV-k|Zx&iM=erf5(%f&HbOUUSoGpp2ghl0}7*!${*(r9)YGwA~6o+(E zZ=;7jBuFk`^diruLLd(aH8RQ4Hde zyljouNB)U37-xBQ7NY1ZhRsONLAF}gfcN^%MR@A@or|mCv<9;>R)9nD=SZ86IJhM>M>6`^DL`4+}MUyGoUdT1}A4dfRvu+ocdk z2HDSMY`0A(4EFqaH9N50Eq65>M3!XP0IV)RTQW@yXHFJX8kH_XIGeq;xqu6)Yxpf$ zUc!uZY-=?RS{z;P9(Q9M+gf-Is`BEHcptyYq!Yx0 zd6Dl_2^K=-;w?r-C1u#6ApNJKQtq;CueWALZ?R4x0H#FSlph@y(rj~S*P>7bsjJ2w z^^5p~sJgch;nZ^6KDiUM2mrZ>H@Pb9r@aY1ABefC3=eLO>XS>)^dwe$acfFvf|$BF zaO7ghaVh9Ux!$z}D=y6=M}V1^E$|1p*lGQCbT-;HV*pPI2&R8$v}5Vbb~>eib!Z#j z2tQlNKF=|Nc`2qkqfm67bm|L||Sx-2dVLVL2-+PDLO z!d|t4dAHOu)Zvy|hC19*%TS7hFRN+wFgtBC;RMZ~6#u~j9JABaOtO;JxvfGo(zcPr zt<=Qlvv1kxSVkh3ZIF>*j5BXlK!3APve<~H>AtU-=(yU5Y-ZP!3cJ>AhB~g6a_tx$ zO8OmRSbIRH)$3f9f=m{(iSON^8nlCVOD6|A5elc=4uh*;ZVk`rbn_D#JI;W;2kDJo zH`@qxUf0wtbRE)C%g*gJNbT3%7N;^00YLUp@}r#Mh&W|6aVe^S!%jCAx$($0@!2#9 z5;Zw9je=>lX8sQMSGHe?1klUY?}M%@G9)~M=2$(b-s$^C&C~I%Ph_nT*7Qi=4`gXZLr=Tv8z|mYN@vjjyTe}`*Px|+iW8VvzRn}sN}QEsv^)A{t!*sk8ms~)C$$Xa zc52N%D9cB=nT~BI$#mJ48BN8&%yjfEIhVxWBAqA8H<+c4tEotx2o{9@zL@{ej8vg- zvFEMAPhJc9s6ava@J3qFHZOIERNofW1uF`Xu`qqjIt=ZQ2KgvR2XZ;~7NM}s^i?G8 z!phP2X+EAvFtS&f)D$pJ=HddZIV#W9oDdo!&ZtIMTinUy9{FV^savHvdl?d{5LqlF zBGcY{rN z!UDv7tzuyvmXaOQb0@zmr8)8)r=)tOt;N)T5hy$vmT8~F}WY@7CW}d=zum#UceXCn(s~vcHoaQT0GV2>2cSH z>OOT}45l+wDo)Hcs7!3eb_p-b=Y&UTqw!1ynGwE91)ID1XzF`k!Z3QsdmO$NbX3nfR#-fChU?2gWT4)){dFQj6A_#IvrNruHreaWA4h9jWmiCr3tm0Af7n^H+vFiu*2 zR~MGC3g;Cr)97ZL$a2ZtVbgQlFd?=RB`dO*F+_!?l9^hiIbd`mrgJfy!)*s0>B<6Eu}_XILXGLR<;)LimPvQV z)@*k*9ocs!!YoJQX4_U1y&stM0Fjy+X3S>WWHcC5VK2N*!!34flX2U_^|KwXV*={i zWJy|$uBKtqJIN5s#xs4n;bR{@noV$$6FRNhN|DBk4Ss zymO_{CaghkE}#ifs|j2Wc0Wh~hrqbhTu7>WSgZq3P5nB%L zR=23snv!b7qy{CHd zFBLCIdlm~zD}PqET%UALjmW8njSSHN>QVtiok$l!{;R{mXn0Zc)1r5axVBK#dy0L2 zCZZpkJMg6WRpmQh*<{j@ur<~!ein#km40uE%W^OfV%{w3*ln9lts!xUJ;t%XX1Q%R zsW{;7sqnMzMtPZKxFmeGw2@c8XHmU6u4)NHX&2?Imdh?S zXixA(xq8pJ+w0f{tA-tDU@V=j`4nf*w%Ab@kth%#&(|X%MV27MSjbu^7}qFB>JSCqzvzah|)mo+|_z?U z(<|CdnvzFcC_oq;#296T2~w!4X0ZdjY}r48zN&<(<{_S~dHS?4n~bdXEl?8OX}Y7g zSIYy$t?RDikgX@HD9ghEqo^CkKWhSh6Q^7(o3u+j7ko)^v`F>b`dEIop|7$ryqQ}? zCQMnrL@eea7SrPHz;@eo(z^^)QlU|B%>|5iwcQZ~{2=a- zvuUQ=mP<%`T+|%eoJ$d_ZKElPsgjz^>IU2PQt_(`ZYXgD%}aF>Xm7CYc_W%OA=c&! zPfq8Z7u!Bu7J1m(U+US^9IZnq+=S&}H5m35w-AcTnuK^~SRp_;ooo}nrCq5kRzNGz z$=M1w!5Ge^>fHr`nW#x?ToI#qdbRdzgPd}ipo_v42R=>N$GKa}XOGft184V3v;Z#Mex>TZt<~f)I1>0SCUBWFtqQ_3dBA_JT zvKyADrw^bzk7qRY{VsPh7IXf1>fJF<64qT(iBW#@#TgTuqjv=y+%(+)S#mMJrsKdG zG`SuyF1$kVcdZZ%zJ3}(hf^rf7J;fr%Bz);!~;#v&T)En?bQuj#o{`ktu=^>c$H&E zGmw^XMj<1{&P`<`tbPojkdpAOcSk&wCE45Yj%B=UJJ$L1f)gOPmG8lJ+jJ6QN3a_~ z6)!enyQ}HogeT{>*m~V?+ip052s`t4b9o%BwvCpfT!F=I?4>gBn*~_#0&%>G;KpOO6USSu zyZ%B@Kpz|^IqdKdKd8aMgxB6OU-Wk{>C_aPH|x64No6Smb5<3TdUXy{T(1K7PeOkS zHrzNLa=`+ULwmXay0fFqTi8ie#KIEu6GwU4XJV z;-YAs(Zw2<>N@b!O;i{~geFSy;4%Rstl9-+nA20EOYbc4PGudzf#|KIha2rGZH7XP zn)X+&-L1BbCeM6YZN#PS?N+-QO=oMd1!*H>wQV#gk0|>UDU>kV%xc?cLom@rddk=iGF@#vE)q@gdSVwfY_%(q zD*A#Zm3Dg5qSVyl=31>LvFHok8SmhJ7ES9lLo?TNux=jtThV)FyLrLU6jxW{m2zz* zobJkS(8Hx07K{!uvncW8ljZ@}*f>F|I9igul#^WD-qvVi2fGf6s6;4kydPAZ42g&n zklcu#E^XdbGH=s+WYBuGoSikDcabN&Zt1s&r4J92eD-!F%E!fP%22wt2hIDIo?t6A zV8ag=~9kyEpN>0*2-;(4Pr@ywejZK!9mEP0En&QuXz73;ex zMrClMCFw32B~t*y?e@+}Qc7vbGSPVi;9(`KsjQPhWbrx|v*8>ibD6!T8u%2sIBR=0 zlHwtvrCX_G=miH^Ij1;v(=E#hH3~J!Qd)J>ZObWBN#2OYrOn=etGFyDYARHryA!q_ zX1Z;;ATn{q04*=&LnH2Vt3g3bMtVVW-DKNh%&t=?H_KftgB{Ca5>Hgce7M6-A;IJ* zlIQ6F03{vzB%pg-VyhBZDAqN)B^5=46&ALo2!KJ+-$|fMb0@8YIsVOb5dYN_#bE~_e)Gc9x{ zW9cU$om$X44_(xI-LZ5Xt}LX~mon-+^OMmZ3m-V=(<-ag^Mwn$Kk}bvL3~$Vv=hjZ z1zGCH0v-xM-xrLTC#|00;!3B%D2c|(wHl5YQ+PKy4xyT1HWSFo^M-XyBd(_=g|JFZ z=5ZPPxh%4?U}S90!yixQDwGv9Y)zgg*d@&W+VGoqREjYJDv{EU?dOch;zIoGKZHT_2SE z*-^{+QfPX4WIOT%ck?cIyp0+JPc$M2C}oDRpjd@lbtdb~G{s&gN22Orwbm@Mb~@w1 z9xb3(5U0YD`JtIu`TV@XRWaOyiU?clxEby)yK4w~#VRz59w$2qa$QF~J=I%~Ho@35mS5FpYMc;*fWvB8PgBVUiaN2S9c5&uwB6Iw#AsA;V4&-{Nd&N}tQ`{qUU8l{bTzJ+UZO|+z{H?=!o0{e@#Ppbs4 z4o{|(S6ENe8&svt^Ka35=VqKm38%QrPJdQggrv>NTaLLtXn8Nrfrz)k;}~20mdt|_ z9s|2O6}x2WM|O0{2Xd#KG$DvPDVR9*%7BQ$I%WH5R7nYrpKN;p+lZ3?U9dQL<^w0f zBwy5SV!TZyzxHG=57?MuiL0ZzHx3nRGHF0>;Z%R~#ZE*kEgAE0r^jjudL|{ptqe^G zyP6u-lJ+*R99dQemY&t{?yE-b3feHFIpDnspQaL>3xMj#W{I!ldN6iVg*?Ok$i`9l zwi@)aHEBoB5eUE&i<(G%mlt1=wq;L_0P27WtGWMbh4G6>f71QI4owh>9Ojvu-Im!T zs*=bEdKJj+w#`P0O{$sw&5m(d?P@g6&MxVqYz~%HdEH_(_mLb-3xRItTGooDTFPuP zB^@)>wv?I_qMoW@Vck&2vXr`2tUTtWFfdTjQmw;-DWg4u{K?Y#z?hm)cK$2&ik6&R z-Sn;5*zmSO5ZsZ6BOzLne1g*Hjyi#))QNk`hS7HEs!Bk9m_g}) zxjzW#Qhal-UBGw%&+{o70v0V2HbNoamMj5@v7zcqc1U)jNmg<~AvqdOOl1Ux872fh zgmNWL>gqngvu7t=#KQ_1&l@IV(u%L6ATAGhnB-}zx@uq|T%|q4V0_G2f-ui@X6K*X zKhZiQs4+F4^A296GyB>vGF)YPcs^F32_@WZKMh`ur?$|>hO-Ja>4Fg?PU!#eg0L;F zIbt)J%}ohjqq=fnIV&!f`uIY(l8(>by#=iVO`2(;UdSu5CxfL}UhEM2aEk% zbNMvyai*_eexpuDTn0AU;Cj)j5{GPfGsghDY(d`xUsM55xI8z^;kg|FBZl`D9~?18 zA?_Y6ZByOcZ`+LxwAywg6igP0I)ZmuD1C>xLbp12QJx;mg>8o2@;$XIa50&hXu8KP z-3z%bMT#{dN{@vQ<}EpexLo1O={#L>N3_4L^EKCDeCbU zhpiD6#l7m;kD9c-mXKV_);yWmBud$>q)_*qb;UkS1gk82<#8-Nl41jUFMN$wbAjC> zF^jm3woW4(TSYU8 zzWm7OSm@sI-BYRV>ZBJs@%P0vk}86jQVVO&dTAQ;-c3a^$Yf5uV9O0v=az0>J~QSe z8kWLR=<5oyvmSM}0kX4AE-^^M4t0iwKW)LZM7+09EZinQkep4YTQdtC193%oV#kKp zC@(1e+<*68P)+l3kUjUyL65bq3U@GWDYz0WHmJ%lM^eMa9xG~f%FpT6iDxe$8epb7 zv|d$|Wj5DPmmeKgF%7$Iv#Hw_DZsdL_HMUrwj*g#QzG+_!wh$|8@}N@QpF+JJOv*l zK43N@c_6WZH9)fT|?%DA(VJj8N~iiW>M7JL5OCBHcMwq^U5-O9z!qs`>3rL`cjD;6csZ^=@)y z?3Ky6BIrAfDhWGjFd09B9%_ZBbMv9A4z>_F^tdbZ^v(q1?X-;jDIyR~2L#3Q5<5Yu zexB=W6JGbsg7nY5;Pj+WicYGNMZ=@y2oJ1Tvd{CnU7hE1lWI#DZO~6NO;^ZRYWoDf zmjw+^ZF$_ddh&&YFnHbmaG$=9r`KSrGZtoNULy^)0I_-`#hdxr!0{w-xoiW$b*&~h z)0__>5T6SyW{eG}JE_{94KEkfka{{z33Es#U+uT6ABLnIIWsF&t0l;q-?C$+&;*x? zd0w)(?_7nTU;(di;WotWDz%Te_)jDd-BuquCj;I>rYAHzF;Y#E4bKnG0t^#=Jh|Pr z*=T^FC`EW}JCPf1+f9|mATIIL7u61i+jcvwJpd;(7ng0qbXUtogm(+UOgF|DnQdE* zLckEBFPfL(CfgPx>5+>RUA%RAKErHGO-6JCa5<+1eDw;yz!YMET7)rOpogkd!|GmY zPV(nM?!G^qr}FUAuUr&ouyY$Mjy=O+6GdD2|J&ZR?Z%N@$zKup+)d>DGH-i_fd#x+ z@7rK7pe@SMjzkKQ#ye}k|GpJ*BC9WCQEX08O=IVU5}Raq=E(m!H0ZS7|l19JTT!IB#^yvKT4?p5N0Pm+%_m( zyL@myAgMPCj%Pb)hT%-2xiJqfc|BTgHXOAVCZ7p+ev>~$%gu({Qo3%#aMpltz8#?)Je$!3d@9hz7l%e}IdKbfY5>84i@^U9&%eFvpJ@)|(E zM9Pod$d}QMG@9p;SzsKHm|fl>R21#eG1N3Aih28{V1Ri5k7^<3( zY&Jg%;5;iaRJ4a8`;)zCC9ifi9Ayo0##3lw@E>}UB=$qu1=YA}40Oqwjgz!4fb@;l z@{_!g4jSwcWg@iLBD-$fsw5dXn^Vpt?i)lrHW~ zM#gTSYwtN4@MBcc!;nCQfaSE^sM|Zh>y3!I=?Uj#qeJ=oG|tzj&0#la1V&0YfL$o3)!U@$N-5TWVMp#K=3u|lRHRDtrJ=~Q+l zIjx@;w+Gs&4q&qw{)Pfn#jlwXWf&Z$QP{Q<;sWT~;C9CsPWa5GC;KzfiD47@@6 z;Eoncx-enZ*65vE0_gU^%Za6h>@Di;_IKUHu^~02;?8tzM;#dMchX7k>Mjo`U_E+9~3vhkHStQ^HE3}3&*GeM_6W5Z6|X)PTFYa zLK?!5=E+9=k{0rnaW)8yYpdm<@(uqMWWXm;@YS$EYFCD4} zLr9>ZVRfa(*w`7iME~@e!9}SS| zj(Bv+AmXpoZ~`&4C8$|%q|w!Jg+O)@7FKGvNo{ zU}Ig7L*N^xn=MC{kxtBx^x$N=VL4W<7ax{6K0I5;qan-PBaW2iTKf&(HZt=n9$Q z2b5<*nz6L#!bXBZ^-DCvO_l(9ylZn{fg;JkTg zGUqTo%%+CoNbLzY1|k*fqP5(vPjNs@nsAn^eGHf$xJIC+O-VR=uN37R8T}R%rP&ul zYUYPfe2GVZ|N6nu?!a-GYa9w25h;5^Yw{|j2zxeuS{pW^@n8fDQV;C(dAFpIGO(h> z7qFG2K|o^(^>o2zO~nI>vTB1BsRL5Dg0)qnT|$yWv?_qjvL!`lm;^q8vDAzGl0tzS zHzd|tA^w71Ti;;@DCLkx(y*~fX!wS>>bdIRju+;>;XN!Jv41c)mOZ^DMa#{G+ZsnI z4hAn~4_R(D91Mi~IlK+EO_=3o!x0T1No?t|l}5?lGYm)iF`NrZVVlurn}LhH5Z9B_ z0OiAAv%N6uhDgs1*gl+p5;}|Uo6P~J55b9Uw%VChGn{I6d&9+{F9+I>Q8spnikX5! zTl;)6V6RhF1+9f$p=5)TVkd(L#|V&OoA7Ym$ST_rB;c-$gRqv&_YqFK1nfKM&NggV z91lD-3DKRaN{bx}9hN3_$v77h0SfHl)22hS5mkvFAiP@Dz`9) zA}Uy@g?Ye->;y#yGNNB0F~5;TjMu51hO4pYTxg^Ork=Z)+9BD8=J>!T#mF)(39?N9 zxre)eeLU^;s52N`B}SYjGO$Z(pAPkFLQAY4&^{OXzS$PvxD=4SG0kZRZyR8bA~b0* zz?ifanyxK(2euWhMjuVJR61j~Th;xT+4=7VDh6G%#ne%qFgkcv$on$0#S?^rKD|^1 zd>2wcSW)#^Lg<$jJSlxd8jp!YVbwG7h6oFsH8{fA^prxaN9yLLe|9-P24NVz%3vE|5e5tYCKE$!@dRAV(7k z9W2IFDx1wFtLpEJ%B3JTpN!63)Qv>Ydn^1I)ox^^*m?tXWP(hFttMq4+Yw>qV2#Fk zU;Z>&DypWPAT(eUUdaS)2zHl=rvyn#PhxmH+Y&W4G*5&tJ!ByO@gXPI4y^6yhm8lk zvI#kp;7qMdsOWAwb02Nw9l%9E0Ivv}Dn*}>kak|I;oI04BB4JB3U!u3OGp}Ko+n6y zPxi6i%RDIS;f-vXg%Pd@k>p8I(~SQXd69bf;7*V3#m$F{?=Jr1>dV_#{$g|S_VvYg zZ?4{dzUD(cUFR2HK20xw#5I34UGAHUpC(hgY2V{-uZ~}Kc=hw)t8mrH_Kcr>I{29z z9>o006u00Ve!BB(pRew`#F78kr>mRKZ*D(*xcJ)-dg_KulUqZ`#rkeb5$TxBZ)=*ot~PCYo>mytlZV7>znD1(H}Ay-%rEh`W&w)Gu7k>=(dVi5B~yw z-hHu);Kqh&Mt^%TKK;r@GA@fJMV;=LsIjm}No{lGWql_PwXj4unwzQHn&4w>mO6tR ztl-Yb15l$6(j(>+0UT{DOe(T4=wj4}e6-Fa#Dl;=s^7*$H=*Uz#LK{A3vCFvIsB*@ zA*jG%XK>4uDEvX;uzSV`2=y$4fN#fa|7b%A^wZcCCUMqaJkq#< z)g0heUj|o+;MLRrvZ1$gnT^G=Z|;L(*4Ss0;G27T_P~OnWMYRk+BYJdzBn4DwSYCd&}MoWgF121rO8Ir_L^ zy~sqyamb)Y&A=|CV=>rw6nBe>$x7Clwu5PmkRZuvH-&p_n89vNV0W^-R+7b?vuqhq zv3XzY9g8KXC%D%Lf^BmWss?cGM>mA7kmDNiLUAMXVI>^Y&((1DE(DZRo9XXaYqQC| zQ-L$aG+YYsh_;~brjJ1FN-{IV9S)Lx%h($IO?fL|h#Xlflp3b2#YeUQ)tqX!qv z4Y*=9MJn_OSW6Tnf+KK)U2sh#gr{e;jp|)usD=K3Y+DLJ3`0R1%0BOhBUQh6xis~8 z=9YD@MuD&V8d{_>^+EG+Su2A|v<}*%fKMmA%n7>ipjG|cKCxls|c{oZXlNiRw7#WuW<`?LT_02k0Qm2n*nB= ziStr-LGTVo@p?3OE*^`s5gUs}BURmeww$(gbag9kpk{5DENXsstGzT)<2j?T!hRIn z6QB$%#m37aNlxHR%A+gJGeqYVQB(%A#&~F}NKgR9K)b7XR0AM`m7tTX-gq+4` zekm$80Ek^io~JkJk7IB0Jy1U??7}m1;{0a45uYW>8SPn}nVDj73Ft$&MUjI!?mG0qk&vx}DuTKUNY9OiB)|)&2OC_B_011LCtt!QjDn-)&Z*CCSfZlA^bT^03xzw$24N8j{C)_22WVhgZz#n;$EnJ$ zk3ebSU_|^ttQ88D@#Fy~g6jmujLK0nP>HBrpf#AxOtd8+;}S`?fQMa#R5HLRQiu8y zsWSu1;XAjV{;kSl#w5=qt$GSUgAlRakp2;;c6SmTqZ*~WTwJF>CWS$!hSR)5acca{ z#>DL5-4PPT%MPcJ<6!|$l_95fhj?kFyN%MRmcX{~h}p~aIx^gmN+%v#xLImo2YiTG z+osw#)OIq7WObh*eV3%oDy2+kEk2ac8&y-sqP!Qw-WEzxq-Y9~NyX{rfY*=KJ_CHu z^gU9a60kwm9-MtqSQ2Q%;Au!v8Uk=5Koe;Cd+)M>OuGOiczgq7S>cg5 z^$(GUs9DLlR$Ty|XAi1w%}BIa8$vvr`vBk|_ldJ3t4SUm_IM-m7X(Es>~a7WbwB1s zQXjnjY;zX*NJbrnp6b9p7dA)@MQSQqdo($DLGq9@!Aoe$9IvrZIK75T!OQO_?+9Je zNT8w#c{H)f@cqGv2FZigBvDw%)&kv?WI zgiDsd9V*(5uA$mvNfK)q1?H!5G8@qp#+3%eZMPbQtAp&?kaKO8JBDrqf5}5gdWajR zJ?0En8qw;D@F}Yp7uk$DHYvJ0C}9{)MQ*I#*pz{qb=Dnh^6U6qK-ZC^D+f;q>3va4 z(Y3?f53zUMIwS%|#w*S|L5Uok>c+6}7a>iwbFMOUiPnQ>eA_tb;V&nV0z@lU8nckp zgAsev^g!;hZWags=JclwQrW7Nb?%ceBKy&HizInu!x`}iQb01{B~KBlor9FKk;;QH ze^CEW8B5Am>=;w=gbkfu0eAs5R-1{jjUfVvQYkR0c5mUAPg!?;eMIn zLdZ#W1+EcJ1&J?U^$-?N_xHYnnmg>PVb);-_S3FDOY#^&rcnN5AfyYNP<|*lHfg52 zJ}TWLECoH9&T=+QBzp|3AV&Te)Vf4LikLN%(@KK&Y^L;Nq#VjFjjgHpY;h{1npC3@ zBxq@$J_9uzqY^+bM&<=!eOkB&64gHueD2bkXp^pnH7~Oi71=GQG&Pv7(A`%CF3cO# z2r6Kf33i$1HIg)9e1>8K+vzM3fYfg1$zVJZ$Val<0~}h$CW`%K!K_3dJJU#jM+yM| zCz6HbnI9VfZa`4TtgF004|eE~Ez2s4PNxN_?sw!>*sbb(!NJJVR>>m^XSFUrT6#d# zJs7IM<}va@aXRj+fGLH-sa0%Wtr_b~Rn3UK_0tlWua1e5`qUC&-a5(bXh+bJB#dM7 z6&5xl$aVd<3e(?Dg~_SHgi_Ok6{cb(oTztw^ULeoFP~rS*Ox*)DlpyNvF72*_=;=# zXxTjzSCw`0`&PO~qc%j34~VPWK_v>4a*r*V)%&Kj`h;*e7l_|Z2h_b=7oFXl5jqQg z)r6W&XskS@^Wz`i|NQC4zxcgrO|$xR{pNSm?_d1s_QS^?-NnO&L7<^PJLvMgWkHnA zxDJOk!D)|%DT=#zJN@epCz5R%+q^W7{`WBt|F!k-?uAbzYa&{a#RZxC)R#RGuO$gu z62H7A;iXSSixRXbetA{m3!h5Rszj|ySYDO%(x;+TiCUGgyej#HPbF$ql2#=yuS$98 zQ_-p2eB1B)`{igV{@YEZ+Ei-QRO;eX!V8~DNj8<1Y%2JEVJh*3Pi1-=PNjRB3cg>M zN_y#2QR8J-RE+Nzrjpm0%I#85x3?NBid8{LN#_ zQdOT|?;hv3-?nhV`#*N{<#~tScEk7XtM9+RMsAbYHU8w}RycBdvD4q*-hMpvufnl| z6^>7eJC7xrxys##5@$ai${K8-+o%Xo*{irX(0<;5>hRFjwRmzwciv&jhx4-Mq6-)O zdB^F;VJw6CWs8P0k5ncNGO1s-X*}~5l}*Fgq{}u@Zy>-Fm&%V8qrz&Pfe-B%6+FZk4hI_k1y!V@T zzib~$_Z+pU04-DQOJGqu@Nyx46{jDdCH#e8zYnp0%s=q!=o~zF#f030QDJ+sy;Mol zcCrD3x4b z2S%l*K%HV?a=>JmNrM)`ibLy97#h0Ai69gqD#?s00mtE(fa6z;&7b}V0B;GvE3^?@ zm6R~Fpf@0f1_$nHgNr8*j`CGx?$3QFO_Ml{Fx&MYGr^xcv>uHW8nm)uoE(rdfUZMW z&uZcHB}LOV_=)RK*M_Dpa5JEst?MC9!|A67JDs7Y5h-wCs2ImbgXpi-hE`7BYn`p~ zSkNj#^+3QJUn%P$P{QeF8+z-(`3r`Rpmuf#o}cbWpuL)ouRD2Y733ai1BIAs1Wu0N z?@cJ+TU~ES)9DWanHK|9cnzlk96MlNIDP$k4?;TqL72{1pw7Xj7C1EEs__C4^DBY@ z)9ITHioTi9xZeHH4uo)CpfbfX3Bf;VWTfPSBB&!`XgbzfqRGOF%(dzC3m%@ZZv-wH zG6a;p0gdT#yE~YP53-OH^GT61nS2dsIHV6 z@8=Ud{ZWHRC`6uH7U~)w2--fN?oUUi+z;aDhaiq#Lr#5q!od!S2Wdui#K(d-Vmlqg z@i2PEJsv#coWTyh4Rq!Yh#2pO&djis@Mz*Qe>W2L|IZ@f)35OW@5jXFoKXBAnczcH z@^i6NJt{x}Y8Z|g={htvh?PRpVnvZO7oQN<0mBL*u_{>Mbk6$8YE;AR=S&^|Dcee? zEKnFS9f%JBJ6&}}Pd|{s{SZ7|Mq}>;9SH7qDndUK(ED*lyL4f?#^a#c2Yhq7aX`Tz z+c`4`p#My8FdD?OjjAn?=+i`xSBue4KRKxI43Z1TGaBzO$lgs`v#iK)=hIXCGEn7% z;KZ4f`n19TDLXPbuQ#+O1OUzmMj+W_lsUwtL(MnW6&Lgg!DhXro>&+xP=GlnsGQ^# z^BTVW>VZK!0;q2ndBm+Yvi|Ew2D*@5L~z*7nWq9;9sa&c!m)!%if$Na37WDzbio)hUI`?8N*Io*Uwyr~BcY zX{t`n+KsXM4G97$5PNDCuV}c_A5oB8VAr=Xll~4~N72@aMNzudfejiynl=`FuA!4E>wNt^`yx?z7|8nRpPQ=-v*Edf&q~E%f|F zdt*A7_8#1M=WO=A?(d@U`XTxba;0%I`sxmM=w|Qh{%+Ol$DiGBtmw=5bpgHhac#wI zio5RAU?(*W&JA_NzSCZ{`Y5)|ukJdu7-6tM4br?9%-(oh~&<=P!>QY&`2={iDa3&OFXjHb6f2SWnpi<*b7Zj~-_|^Egl00PWmkJ!J#* zvko>s{t9qs9_T4M!25F#_LME)pZm)C;o+W-ufOm>SBQPioOhs7FG;^G<6z&;$p?Hr z`iHXq9n|M0i}1IA?&k(ez705L4S8UO$Q literal 0 HcmV?d00001 diff --git a/Telegram-iOS/en.lproj/Localizable.strings b/Telegram-iOS/en.lproj/Localizable.strings index c2aade54e4..67b8058d9d 100644 --- a/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram-iOS/en.lproj/Localizable.strings @@ -5284,3 +5284,22 @@ Any member of this group will be able to see messages in the channel."; "Map.PlacesInThisArea" = "Places In This Area"; "Conversation.LiveLocationYouAndOther" = "**You** and %@"; + +"PeopleNearby.MakeVisible" = "Make Myself Visible"; +"PeopleNearby.MakeInvisible" = "Stop Showing Me"; + +"PeopleNearby.ShowMorePeople_0" = "Show %@ More People"; +"PeopleNearby.ShowMorePeople_1" = "Show %@ More People"; +"PeopleNearby.ShowMorePeople_2" = "Show %@ More People"; +"PeopleNearby.ShowMorePeople_3_10" = "Show %@ More People"; +"PeopleNearby.ShowMorePeople_many" = "Show %@ More People"; +"PeopleNearby.ShowMorePeople_any" = "Show %@ More People"; + +"PeopleNearby.VisibleUntil" = "visible until %@"; + +"PeopleNearby.MakeVisibleTitle" = "Make Myself Visible"; +"PeopleNearby.MakeVisibleDescription" = "Allow people nearby to view your profile for 24 hours?\n\nYour phone number will remain hidden."; + +"PeopleNearby.DiscoverDescription" = "Exchange contact info with people nearby\nand find new friends."; + +"Time.TomorrowAt" = "tomorrow at %@"; diff --git a/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift b/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift index f21f09f4a8..173646c596 100644 --- a/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift +++ b/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift @@ -42,9 +42,15 @@ public enum AnimatedStickerMode { case direct } +public enum AnimatedStickerPlaybackPosition { + case start + case end +} + public enum AnimatedStickerPlaybackMode { case once case loop + case still(AnimatedStickerPlaybackPosition) } private final class AnimatedStickerFrame { @@ -72,6 +78,7 @@ private protocol AnimatedStickerFrameSource: class { var frameCount: Int { get } func takeFrame() -> AnimatedStickerFrame? + func skipToEnd() } private final class AnimatedStickerFrameSourceWrapper { @@ -244,6 +251,9 @@ private final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource self.data = data self.dataComplete = complete } + + func skipToEnd() { + } } private final class AnimatedStickerDirectFrameSource: AnimatedStickerFrameSource { @@ -289,6 +299,10 @@ private final class AnimatedStickerDirectFrameSource: AnimatedStickerFrameSource } return AnimatedStickerFrame(data: frameData, type: .argb, width: self.width, height: self.height, bytesPerRow: self.bytesPerRow, index: frameIndex, isLastFrame: frameIndex == self.frameCount - 1) } + + func skipToEnd() { + self.currentFrame = self.frameCount - 1 + } } private final class AnimatedStickerFrameQueue { @@ -383,7 +397,7 @@ public final class AnimatedStickerNode: ASDisplayNode { private var renderer: (AnimationRenderer & ASDisplayNode)? - private var isPlaying: Bool = false + public var isPlaying: Bool = false private var canDisplayFirstFrame: Bool = false private var playbackMode: AnimatedStickerPlaybackMode = .loop @@ -456,7 +470,9 @@ public final class AnimatedStickerNode: ASDisplayNode { if let directData = try? Data(contentsOf: URL(fileURLWithPath: path), options: [.mappedRead]) { strongSelf.directData = (directData, path, width, height) } - if strongSelf.isPlaying { + if case let .still(position) = playbackMode { + strongSelf.seekTo(position) + } else if strongSelf.isPlaying { strongSelf.play() } else if strongSelf.canDisplayFirstFrame { strongSelf.play(firstFrame: true) @@ -597,11 +613,11 @@ public final class AnimatedStickerNode: ASDisplayNode { self.reportedStarted = false self.timer.swap(nil)?.invalidate() if self.playToCompletionOnStop { - self.seekToStart() + self.seekTo(.start) } } - public func seekToStart() { + public func seekTo(_ position: AnimatedStickerPlaybackPosition) { self.isPlaying = false let directData = self.directData @@ -612,6 +628,9 @@ public final class AnimatedStickerNode: ASDisplayNode { var maybeFrameSource: AnimatedStickerFrameSource? if let directData = directData { maybeFrameSource = AnimatedStickerDirectFrameSource(queue: queue, data: directData.0, width: directData.2, height: directData.3) + if position == .end { + maybeFrameSource?.skipToEnd() + } } else if let (cachedData, cachedDataComplete) = cachedData { if #available(iOS 9.0, *) { maybeFrameSource = AnimatedStickerCachedFrameSource(queue: queue, data: cachedData, complete: cachedDataComplete, notifyUpdated: {}) diff --git a/submodules/CallListUI/Sources/CallListController.swift b/submodules/CallListUI/Sources/CallListController.swift index 8de824eba8..974cd94fc7 100644 --- a/submodules/CallListUI/Sources/CallListController.swift +++ b/submodules/CallListUI/Sources/CallListController.swift @@ -59,7 +59,12 @@ public final class CallListController: ViewController { if case .tab = self.mode { self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationCallIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.callPressed)) - let icon = UIImage(bundleImageName: "Chat List/Tabs/IconCalls") + let icon: UIImage? + if useSpecialTabBarIcons() { + icon = UIImage(bundleImageName: "Chat List/Tabs/Holiday/IconCalls") + } else { + icon = UIImage(bundleImageName: "Chat List/Tabs/IconCalls") + } self.tabBarItem.title = self.presentationData.strings.Calls_TabTitle self.tabBarItem.image = icon self.tabBarItem.selectedImage = icon diff --git a/submodules/Charts/BUCK b/submodules/Charts/BUCK new file mode 100644 index 0000000000..79bf8180b8 --- /dev/null +++ b/submodules/Charts/BUCK @@ -0,0 +1,31 @@ +load("//Config:buck_rule_macros.bzl", "static_library") + +static_library( + name = "Charts", + srcs = glob([ + "Sources/**/*.swift", + ]), + deps = [ + "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared", + "//submodules/AsyncDisplayKit:AsyncDisplayKit#shared", + "//submodules/Display:Display#shared", + "//submodules/Postbox:Postbox#shared", + "//submodules/TelegramCore:TelegramCore#shared", + "//submodules/SyncCore:SyncCore#shared", + "//submodules/TelegramPresentationData:TelegramPresentationData", + "//submodules/TelegramUIPreferences:TelegramUIPreferences", + "//submodules/AccountContext:AccountContext", + "//submodules/ItemListUI:ItemListUI", + "//submodules/AvatarNode:AvatarNode", + "//submodules/TelegramStringFormatting:TelegramStringFormatting", + "//submodules/AlertUI:AlertUI", + "//submodules/PresentationDataUtils:PresentationDataUtils", + "//submodules/TelegramNotices:TelegramNotices", + "//submodules/MergeLists:MergeLists", + "//submodules/AppBundle:AppBundle", + ], + frameworks = [ + "$SDKROOT/System/Library/Frameworks/Foundation.framework", + "$SDKROOT/System/Library/Frameworks/UIKit.framework", + ], +) diff --git a/submodules/Charts/Info.plist b/submodules/Charts/Info.plist new file mode 100644 index 0000000000..e1fe4cfb7b --- /dev/null +++ b/submodules/Charts/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + + diff --git a/submodules/Charts/Sources/Chart Screen/ChartDetailsView.swift b/submodules/Charts/Sources/Chart Screen/ChartDetailsView.swift new file mode 100644 index 0000000000..7232c594c3 --- /dev/null +++ b/submodules/Charts/Sources/Chart Screen/ChartDetailsView.swift @@ -0,0 +1,258 @@ +// +// ChartDetailsView.swift +// GraphTest +// +// Created by Andrew Solovey on 14/03/2019. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +private let cornerRadius: CGFloat = 5 +private let verticalMargins: CGFloat = 8 +private var labelHeight: CGFloat = 18 +private var margin: CGFloat = 10 +private var prefixLabelWidth: CGFloat = 27 +private var textLabelWidth: CGFloat = 60 +private var valueLabelWidth: CGFloat = 65 + +struct ChartDetailsViewModel { + struct Value { + let prefix: String? + let title: String + let value: String + let color: UIColor + let visible: Bool + } + + var title: String + var showArrow: Bool + var showPrefixes: Bool + var values: [Value] + var totalValue: Value? + var tapAction: (() -> Void)? + + static let blank = ChartDetailsViewModel(title: "", showArrow: false, showPrefixes: false, values: [], totalValue: nil, tapAction: nil) +} + +class ChartDetailsView: UIControl { + let titleLabel = UILabel() + let arrowView = UIImageView() + + var prefixViews: [UILabel] = [] + var labelsViews: [UILabel] = [] + var valuesViews: [UILabel] = [] + + private var viewModel: ChartDetailsViewModel? + private var colorMode: ColorMode = .day + + static func fromNib() -> ChartDetailsView { + return Bundle.main.loadNibNamed("ChartDetailsView", owner: nil, options: nil)?.first as! ChartDetailsView + } + + override init(frame: CGRect) { + super.init(frame: frame) + + layer.cornerRadius = cornerRadius + clipsToBounds = true + + addTarget(self, action: #selector(didTap), for: .touchUpInside) + titleLabel.font = UIFont.systemFont(ofSize: 12, weight: .bold) + arrowView.image = UIImage.arrowRight + arrowView.contentMode = .scaleAspectFill + + addSubview(titleLabel) + addSubview(arrowView) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func setup(viewModel: ChartDetailsViewModel, animated: Bool) { + self.viewModel = viewModel + + titleLabel.setText(viewModel.title, animated: animated) + titleLabel.setVisible(!viewModel.title.isEmpty, animated: animated) + arrowView.setVisible(viewModel.showArrow, animated: animated) + + let width: CGFloat = margin * 2 + (viewModel.showPrefixes ? (prefixLabelWidth + margin) : 0) + textLabelWidth + valueLabelWidth + var y: CGFloat = verticalMargins + + if (!viewModel.title.isEmpty || viewModel.showArrow) { + titleLabel.frame = CGRect(x: margin, y: y, width: width, height: labelHeight) + arrowView.frame = CGRect(x: width - 6 - margin, y: margin, width: 6, height: 10) + y += labelHeight + } + let labelsCount: Int = viewModel.values.count + ((viewModel.totalValue == nil) ? 0 : 1) + + setLabelsCount(array: &prefixViews, + count: viewModel.showPrefixes ? labelsCount : 0, + font: UIFont.systemFont(ofSize: 12, weight: .bold)) + setLabelsCount(array: &labelsViews, + count: labelsCount, + font: UIFont.systemFont(ofSize: 12, weight: .regular), + textAlignment: .left) + setLabelsCount(array: &valuesViews, + count: labelsCount, + font: UIFont.systemFont(ofSize: 12, weight: .bold)) + + UIView.perform(animated: animated, animations: { + for (index, value) in viewModel.values.enumerated() { + var x: CGFloat = margin + if viewModel.showPrefixes { + let prefixLabel = self.prefixViews[index] + prefixLabel.textColor = self.colorMode.chartDetailsTextColor + prefixLabel.setText(value.prefix, animated: false) + prefixLabel.frame = CGRect(x: x, y: y, width: prefixLabelWidth, height: labelHeight) + x += prefixLabelWidth + margin + prefixLabel.alpha = value.visible ? 1 : 0 + } + let titleLabel = self.labelsViews[index] + titleLabel.setTextColor(self.colorMode.chartDetailsTextColor, animated: false) + titleLabel.setText(value.title, animated: false) + titleLabel.frame = CGRect(x: x, y: y, width: textLabelWidth, height: labelHeight) + titleLabel.alpha = value.visible ? 1 : 0 + x += textLabelWidth + + let valueLabel = self.valuesViews[index] + valueLabel.setTextColor(value.color, animated: false) + valueLabel.setText(value.value, animated: false) + valueLabel.frame = CGRect(x: x, y: y, width: valueLabelWidth, height: labelHeight) + valueLabel.alpha = value.visible ? 1 : 0 + + if value.visible { + y += labelHeight + } + } + if let value = viewModel.totalValue { + var x: CGFloat = margin + if viewModel.showPrefixes { + let prefixLabel = self.prefixViews[viewModel.values.count] + prefixLabel.textColor = self.colorMode.chartDetailsTextColor + prefixLabel.setText(value.prefix, animated: false) + prefixLabel.frame = CGRect(x: x, y: y, width: prefixLabelWidth, height: labelHeight) + prefixLabel.alpha = value.visible ? 1 : 0 + x += prefixLabelWidth + margin + } + let titleLabel = self.labelsViews[viewModel.values.count] + titleLabel.setTextColor(self.colorMode.chartDetailsTextColor, animated: false) + titleLabel.setText(value.title, animated: false) + titleLabel.frame = CGRect(x: x, y: y, width: textLabelWidth, height: labelHeight) + titleLabel.alpha = value.visible ? 1 : 0 + x += textLabelWidth + + let valueLabel = self.valuesViews[viewModel.values.count] + valueLabel.setTextColor(self.colorMode.chartDetailsTextColor, animated: false) + valueLabel.setText(value.value, animated: false) + valueLabel.frame = CGRect(x: x, y: y, width: valueLabelWidth, height: labelHeight) + valueLabel.alpha = value.visible ? 1 : 0 + } + }) + } + + override var intrinsicContentSize: CGSize { + if let viewModel = viewModel { + let height = ((!viewModel.title.isEmpty || viewModel.showArrow) ? labelHeight : 0) + + (CGFloat(viewModel.values.filter({ $0.visible }).count) * labelHeight) + + (viewModel.totalValue?.visible == true ? labelHeight : 0) + + verticalMargins * 2 + let width: CGFloat = margin * 2 + + (viewModel.showPrefixes ? (prefixLabelWidth + margin) : 0) + + textLabelWidth + + valueLabelWidth + + return CGSize(width: width, + height: height) + } else { + return CGSize(width: 140, + height: labelHeight + verticalMargins) + } + } + + @objc private func didTap() { + viewModel?.tapAction?() + } + + func setLabelsCount(array: inout [UILabel], + count: Int, + font: UIFont, + textAlignment: NSTextAlignment = .right) { + while array.count > count { + let subview = array.removeLast() + subview.removeFromSuperview() + } + while array.count < count { + let label = UILabel() + label.font = font + label.adjustsFontSizeToFitWidth = true + label.minimumScaleFactor = 0.5 + label.textAlignment = textAlignment + addSubview(label) + array.append(label) + } + } +} + +extension ChartDetailsView: ColorModeContainer { + func apply(colorMode: ColorMode, animated: Bool) { + self.colorMode = colorMode + self.titleLabel.setTextColor(colorMode.chartDetailsTextColor, animated: animated) + if let viewModel = self.viewModel { + self.setup(viewModel: viewModel, animated: animated) + } + UIView.perform(animated: animated) { + self.arrowView.tintColor = colorMode.chartDetailsArrowColor + self.backgroundColor = colorMode.chartDetailsViewColor + } + } +} + +// MARK: UIStackView+removeAllArrangedSubviews +public extension UIStackView { + func setLabelsCount(_ count: Int, + font: UIFont, + huggingPriority: UILayoutPriority, + textAlignment: NSTextAlignment = .right) { + while arrangedSubviews.count > count { + let subview = arrangedSubviews.last! + removeArrangedSubview(subview) + subview.removeFromSuperview() + } + while arrangedSubviews.count < count { + let label = UILabel() + label.font = font + label.textAlignment = textAlignment + label.setContentHuggingPriority(huggingPriority, for: .horizontal) + label.setContentHuggingPriority(huggingPriority, for: .vertical) + label.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 999), for: .horizontal) + label.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 999), for: .vertical) + addArrangedSubview(label) + } + } + + func label(at index: Int) -> UILabel { + return arrangedSubviews[index] as! UILabel + } + + func removeAllArrangedSubviews() { + for subview in arrangedSubviews { + removeArrangedSubview(subview) + subview.removeFromSuperview() + } + } +} + +// MARK: UIStackView+addArrangedSubviews +public extension UIStackView { + func addArrangedSubviews(_ views: [UIView]) { + views.forEach({ addArrangedSubview($0) }) + } +} + +// MARK: UIStackView+insertArrangedSubviews +public extension UIStackView { + func insertArrangedSubviews(_ views: [UIView], at index: Int) { + views.reversed().forEach({ insertArrangedSubview($0, at: index) }) + } +} diff --git a/submodules/Charts/Sources/Chart Screen/ChartStackSection.swift b/submodules/Charts/Sources/Chart Screen/ChartStackSection.swift new file mode 100644 index 0000000000..bef1a574f4 --- /dev/null +++ b/submodules/Charts/Sources/Chart Screen/ChartStackSection.swift @@ -0,0 +1,199 @@ +// +// ChartStackSection.swift +// GraphTest +// +// Created by Andrei Salavei on 4/13/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +private enum Constants { + static let chartViewHeightFraction: CGFloat = 0.55 +} + +class ChartStackSection: UIView, ColorModeContainer { + var chartView: ChartView + var rangeView: RangeChartView + var visibilityView: ChartVisibilityView + var sectionContainerView: UIView + var separators: [UIView] = [] + + var headerLabel: UILabel! + var titleLabel: UILabel! + var backButton: UIButton! + + var controller: BaseChartController! + + init() { + sectionContainerView = UIView() + chartView = ChartView() + rangeView = RangeChartView() + visibilityView = ChartVisibilityView() + headerLabel = UILabel() + titleLabel = UILabel() + backButton = UIButton() + + super.init(frame: CGRect()) + + self.addSubview(sectionContainerView) + sectionContainerView.addSubview(chartView) + sectionContainerView.addSubview(rangeView) + sectionContainerView.addSubview(visibilityView) + + headerLabel.font = UIFont.systemFont(ofSize: 14, weight: .regular) + titleLabel.font = UIFont.systemFont(ofSize: 14, weight: .bold) + visibilityView.clipsToBounds = true + backButton.isExclusiveTouch = true + + backButton.setVisible(false, animated: false) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func awakeFromNib() { + super.awakeFromNib() + + headerLabel.font = UIFont.systemFont(ofSize: 14, weight: .regular) + titleLabel.font = UIFont.systemFont(ofSize: 14, weight: .bold) + visibilityView.clipsToBounds = true + backButton.isExclusiveTouch = true + + backButton.setVisible(false, animated: false) + } + + func apply(colorMode: ColorMode, animated: Bool) { + UIView.perform(animated: animated && self.isVisibleInWindow) { + self.backgroundColor = colorMode.tableBackgroundColor + + self.sectionContainerView.backgroundColor = colorMode.chartBackgroundColor + self.rangeView.backgroundColor = colorMode.chartBackgroundColor + self.visibilityView.backgroundColor = colorMode.chartBackgroundColor + + self.backButton.tintColor = colorMode.actionButtonColor + self.backButton.setTitleColor(colorMode.actionButtonColor, for: .normal) + + for separator in self.separators { + separator.backgroundColor = colorMode.tableSeparatorColor + } + } + + if rangeView.isVisibleInWindow || chartView.isVisibleInWindow { + chartView.loadDetailsViewIfNeeded() + chartView.apply(colorMode: colorMode, animated: animated && chartView.isVisibleInWindow) + controller.apply(colorMode: colorMode, animated: animated) + rangeView.apply(colorMode: colorMode, animated: animated && rangeView.isVisibleInWindow) + } else { + DispatchQueue.main.asyncAfter(deadline: .now() + TimeInterval.random(in: 0...0.1)) { + self.chartView.loadDetailsViewIfNeeded() + self.controller.apply(colorMode: colorMode, animated: false) + self.chartView.apply(colorMode: colorMode, animated: false) + self.rangeView.apply(colorMode: colorMode, animated: false) + } + } + + self.titleLabel.setTextColor(colorMode.chartTitleColor, animated: animated && titleLabel.isVisibleInWindow) + self.headerLabel.setTextColor(colorMode.sectionTitleColor, animated: animated && headerLabel.isVisibleInWindow) + } + + @IBAction func didTapBackButton() { + controller.didTapZoomOut() + } + + func setBackButtonVisible(_ visible: Bool, animated: Bool) { + backButton.setVisible(visible, animated: animated) + layoutIfNeeded(animated: animated) + } + + func updateToolViews(animated: Bool) { + rangeView.setRange(controller.currentChartHorizontalRangeFraction, animated: animated) + rangeView.setRangePaging(enabled: controller.isChartRangePagingEnabled, + minimumSize: controller.minimumSelectedChartRange) + visibilityView.setVisible(controller.drawChartVisibity, animated: animated) + if controller.drawChartVisibity { + visibilityView.isExpanded = true + visibilityView.items = controller.actualChartsCollection.chartValues.map { value in + return ChartVisibilityItem(title: value.name, color: value.color) + } + visibilityView.setItemsSelection(controller.actualChartVisibility) + visibilityView.setNeedsLayout() + visibilityView.layoutIfNeeded() + } else { + visibilityView.isExpanded = false + } + superview?.superview?.layoutIfNeeded(animated: animated) + } + + override func layoutSubviews() { + super.layoutSubviews() + + let bounds = self.bounds + self.sectionContainerView.frame = CGRect(origin: CGPoint(), size: CGSize(width: bounds.width, height: 350.0)) + self.chartView.frame = CGRect(origin: CGPoint(), size: CGSize(width: bounds.width, height: 250.0)) + self.rangeView.frame = CGRect(origin: CGPoint(x: 0.0, y: 250.0), size: CGSize(width: bounds.width, height: 48.0)) + self.visibilityView.frame = CGRect(origin: CGPoint(x: 0.0, y: 308.0), size: CGSize(width: bounds.width, height: 122.0)) + } + + func setup(controller: BaseChartController, title: String) { + self.controller = controller + self.headerLabel.text = title + + // Chart + chartView.renderers = controller.mainChartRenderers + chartView.userDidSelectCoordinateClosure = { [unowned self] point in + self.controller.chartInteractionDidBegin(point: point) + } + chartView.userDidDeselectCoordinateClosure = { [unowned self] in + self.controller.chartInteractionDidEnd() + } + controller.cartViewBounds = { [unowned self] in + return self.chartView.bounds + } + controller.chartFrame = { [unowned self] in + return self.chartView.chartFrame + } + controller.setDetailsViewModel = { [unowned self] viewModel, animated in + self.chartView.setDetailsViewModel(viewModel: viewModel, animated: animated) + } + controller.setDetailsChartVisibleClosure = { [unowned self] visible, animated in + self.chartView.setDetailsChartVisible(visible, animated: animated) + } + controller.setDetailsViewPositionClosure = { [unowned self] position in + self.chartView.detailsViewPosition = position + } + controller.setChartTitleClosure = { [unowned self] title, animated in + self.titleLabel.setText(title, animated: animated) + } + controller.setBackButtonVisibilityClosure = { [unowned self] visible, animated in + self.setBackButtonVisible(visible, animated: animated) + } + controller.refreshChartToolsClosure = { [unowned self] animated in + self.updateToolViews(animated: animated) + } + + // Range view + rangeView.chartView.renderers = controller.navigationRenderers + rangeView.rangeDidChangeClosure = { range in + controller.updateChartRange(range) + } + rangeView.touchedOutsideClosure = { + controller.cancelChartInteraction() + } + controller.chartRangeUpdatedClosure = { [unowned self] (range, animated) in + self.rangeView.setRange(range, animated: animated) + } + controller.chartRangePagingClosure = { [unowned self] (isEnabled, pageSize) in + self.rangeView.setRangePaging(enabled: isEnabled, minimumSize: pageSize) + } + + // Visibility view + visibilityView.selectionCallbackClosure = { [unowned self] visibility in + self.controller.updateChartsVisibility(visibility: visibility, animated: true) + } + + controller.initializeChart() + updateToolViews(animated: false) + } +} diff --git a/submodules/Charts/Sources/Chart Screen/ChartStackSection.xib b/submodules/Charts/Sources/Chart Screen/ChartStackSection.xib new file mode 100644 index 0000000000..fc883dd96c --- /dev/null +++ b/submodules/Charts/Sources/Chart Screen/ChartStackSection.xib @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/submodules/Charts/Sources/Chart Screen/ChartView.swift b/submodules/Charts/Sources/Chart Screen/ChartView.swift new file mode 100644 index 0000000000..39b93d9fa0 --- /dev/null +++ b/submodules/Charts/Sources/Chart Screen/ChartView.swift @@ -0,0 +1,158 @@ +// +// ChartView.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +public protocol ChartViewRenderer: class { + var containerViews: [UIView] { get set } + func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) +} + +class ChartView: UIView { + override init(frame: CGRect) { + super.init(frame: frame) + + setupView() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + + setupView() + } + + var chartInsets: UIEdgeInsets = UIEdgeInsets(top: 40, left: 16, bottom: 35, right: 16) { + didSet { + setNeedsDisplay() + } + } + + var renderers: [ChartViewRenderer] = [] { + willSet { + renderers.forEach { $0.containerViews.removeAll(where: { $0 == self }) } + } + didSet { + renderers.forEach { $0.containerViews.append(self) } + setNeedsDisplay() + } + } + + var chartFrame: CGRect { + let chartBound = self.bounds + return CGRect(x: chartInsets.left, + y: chartInsets.top, + width: max(1, chartBound.width - chartInsets.left - chartInsets.right), + height: max(1, chartBound.height - chartInsets.top - chartInsets.bottom)) + } + + override func draw(_ rect: CGRect) { + guard let context = UIGraphicsGetCurrentContext() else { return } + let chartBounds = self.bounds + let chartFrame = self.chartFrame + + for renderer in renderers { + renderer.render(context: context, bounds: chartBounds, chartFrame: chartFrame) + } + } + + var userDidSelectCoordinateClosure: ((CGPoint) -> Void)? + var userDidDeselectCoordinateClosure: (() -> Void)? + + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + if let point = touches.first?.location(in: self) { + let fractionPoint = CGPoint(x: (point.x - chartFrame.origin.x) / chartFrame.width, + y: (point.y - chartFrame.origin.y) / chartFrame.height) + userDidSelectCoordinateClosure?(fractionPoint) + } + } + + override func touchesMoved(_ touches: Set, with event: UIEvent?) { + if let point = touches.first?.location(in: self) { + let fractionPoint = CGPoint(x: (point.x - chartFrame.origin.x) / chartFrame.width, + y: (point.y - chartFrame.origin.y) / chartFrame.height) + userDidSelectCoordinateClosure?(fractionPoint) + } + } + + override func touchesEnded(_ touches: Set, with event: UIEvent?) { + userDidDeselectCoordinateClosure?() + } + + override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + userDidDeselectCoordinateClosure?() + } + + // MARK: Details View + + private var detailsView: ChartDetailsView! + private var maxDetailsViewWidth: CGFloat = 0 + func loadDetailsViewIfNeeded() { + if detailsView == nil { + let detailsView = ChartDetailsView(frame: bounds) + addSubview(detailsView) + detailsView.alpha = 0 + self.detailsView = detailsView + } + } + + private var detailsTableTopOffset: CGFloat = 5 + private var detailsTableLeftOffset: CGFloat = 8 + private var isDetailsViewVisible: Bool = false + + var detailsViewPosition: CGFloat = 0 { + didSet { + loadDetailsViewIfNeeded() + let detailsViewSize = detailsView.intrinsicContentSize + maxDetailsViewWidth = max(maxDetailsViewWidth, detailsViewSize.width) + if maxDetailsViewWidth + detailsTableLeftOffset > detailsViewPosition { + detailsView.frame = CGRect(x: min(detailsViewPosition + detailsTableLeftOffset, bounds.width - maxDetailsViewWidth), + y: chartInsets.top + detailsTableTopOffset, + width: maxDetailsViewWidth, + height: detailsViewSize.height) + } else { + detailsView.frame = CGRect(x: detailsViewPosition - maxDetailsViewWidth - detailsTableLeftOffset, + y: chartInsets.top + detailsTableTopOffset, + width: maxDetailsViewWidth, + height: detailsViewSize.height) + } + } + } + + func setDetailsChartVisible(_ visible: Bool, animated: Bool) { + guard isDetailsViewVisible != visible else { + return + } + isDetailsViewVisible = visible + loadDetailsViewIfNeeded() + detailsView.setVisible(visible, animated: animated) + if !visible { + maxDetailsViewWidth = 0 + } + } + + func setDetailsViewModel(viewModel: ChartDetailsViewModel, animated: Bool) { + loadDetailsViewIfNeeded() + detailsView.setup(viewModel: viewModel, animated: animated) + UIView.perform(animated: animated, animations: { + let position = self.detailsViewPosition + self.detailsViewPosition = position + }) + } + + func setupView() { + backgroundColor = .clear + layer.drawsAsynchronously = true + } +} + + +extension ChartView: ColorModeContainer { + func apply(colorMode: ColorMode, animated: Bool) { + detailsView?.apply(colorMode: colorMode, animated: animated && (detailsView?.isVisibleInWindow ?? false)) + } +} diff --git a/submodules/Charts/Sources/Chart Screen/ChartVisibilityItemView.swift b/submodules/Charts/Sources/Chart Screen/ChartVisibilityItemView.swift new file mode 100644 index 0000000000..2476526f1a --- /dev/null +++ b/submodules/Charts/Sources/Chart Screen/ChartVisibilityItemView.swift @@ -0,0 +1,95 @@ +// +// ChartVisibilityItemCell.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class ChartVisibilityItemView: UIView { + static let textFont = UIFont.systemFont(ofSize: 14, weight: .medium) + + let checkButton: UIButton = UIButton(type: .system) + + override init(frame: CGRect) { + super.init(frame: frame) + + setupView() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + override func awakeFromNib() { + super.awakeFromNib() + setupView() + } + + func setupView() { + checkButton.frame = bounds + checkButton.titleLabel?.font = ChartVisibilityItemView.textFont + checkButton.layer.cornerRadius = 6 + checkButton.layer.masksToBounds = true + checkButton.addTarget(self, action: #selector(didTapButton), for: .touchUpInside) + let pressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(didRecognizedLongPress(recognizer:))) + pressRecognizer.cancelsTouchesInView = true + checkButton.addGestureRecognizer(pressRecognizer) + addSubview(checkButton) + } + + var tapClosure: (() -> Void)? + var longTapClosure: (() -> Void)? + + private func updateStyle(animated: Bool) { + guard let item = item else { + return + } + UIView.perform(animated: animated, animations: { + if self.isChecked { + self.checkButton.setTitleColor(.white, for: .normal) + self.checkButton.backgroundColor = item.color + self.checkButton.layer.borderColor = nil + self.checkButton.layer.borderWidth = 0 + self.checkButton.setTitle("âś“ " + item.title, for: .normal) + } else { + self.checkButton.backgroundColor = .clear + self.checkButton.layer.borderColor = item.color.cgColor + self.checkButton.layer.borderWidth = 1 + self.checkButton.setTitleColor(item.color, for: .normal) + self.checkButton.setTitle(item.title, for: .normal) + } + + }) + } + + override func layoutSubviews() { + super.layoutSubviews() + + checkButton.frame = bounds + } + + @objc private func didTapButton() { + tapClosure?() + } + + @objc private func didRecognizedLongPress(recognizer: UIGestureRecognizer) { + if recognizer.state == .began { + longTapClosure?() + } + } + + var item: ChartVisibilityItem? = nil { + didSet { + updateStyle(animated: false) + } + } + + private(set) var isChecked: Bool = true + func setChecked(isChecked: Bool, animated: Bool) { + self.isChecked = isChecked + updateStyle(animated: true) + } +} diff --git a/submodules/Charts/Sources/Chart Screen/ChartVisibilityView.swift b/submodules/Charts/Sources/Chart Screen/ChartVisibilityView.swift new file mode 100644 index 0000000000..fda3c3901f --- /dev/null +++ b/submodules/Charts/Sources/Chart Screen/ChartVisibilityView.swift @@ -0,0 +1,147 @@ +// +// ChartVisibilityView.swift +// GraphTest +// +// Created by Andrei Salavei on 4/13/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +private enum Constants { + static let itemHeight: CGFloat = 30 + static let itemSpacing: CGFloat = 8 + static let labelTextApproxInsets: CGFloat = 40 + static let insets = UIEdgeInsets(top: 0, left: 16, bottom: 16, right: 16) +} + +struct ChartVisibilityItem { + var title: String + var color: UIColor +} + +class ChartVisibilityView: UIView { + var items: [ChartVisibilityItem] = [] { + didSet { + selectedItems = items.map { _ in true } + while selectionViews.count > selectedItems.count { + selectionViews.last?.removeFromSuperview() + selectionViews.removeLast() + } + while selectionViews.count < selectedItems.count { + let view = ChartVisibilityItemView(frame: bounds) + addSubview(view) + selectionViews.append(view) + } + + for (index, item) in items.enumerated() { + let view = selectionViews[index] + view.item = item + view.tapClosure = { [weak self] in + guard let self = self else { return } + self.setItemSelected(!self.selectedItems[index], at: index, animated: true) + self.notifyItemSelection() + } + + view.longTapClosure = { [weak self] in + guard let self = self else { return } + let hasSelectedItem = self.selectedItems.enumerated().contains(where: { $0.element && $0.offset != index }) + if hasSelectedItem { + for (itemIndex, _) in self.items.enumerated() { + self.setItemSelected(itemIndex == index, at: itemIndex, animated: true) + } + } else { + for (itemIndex, _) in self.items.enumerated() { + self.setItemSelected(true, at: itemIndex, animated: true) + } + } + self.notifyItemSelection() + } + } + } + } + + private (set) var selectedItems: [Bool] = [] + var isExpanded: Bool = true { + didSet { + invalidateIntrinsicContentSize() + setNeedsUpdateConstraints() + } + } + + private var selectionViews: [ChartVisibilityItemView] = [] + + private func generateItemsFrames(frame: CGRect) -> [CGRect] { + var previousPoint = CGPoint(x: Constants.insets.left, y: Constants.insets.top) + var frames: [CGRect] = [] + + for item in items { + let labelSize = (item.title as NSString).size(withAttributes: [.font: ChartVisibilityItemView.textFont]) + let width = (labelSize.width + Constants.labelTextApproxInsets).rounded(.up) + if previousPoint.x + width < (frame.width - Constants.insets.left - Constants.insets.right) { + frames.append(CGRect(origin: previousPoint, size: CGSize(width: width, height: Constants.itemHeight))) + } else if previousPoint.x <= Constants.insets.left { + frames.append(CGRect(origin: previousPoint, size: CGSize(width: width, height: Constants.itemHeight))) + } else { + previousPoint.y += Constants.itemHeight + Constants.itemSpacing + previousPoint.x = Constants.insets.left + frames.append(CGRect(origin: previousPoint, size: CGSize(width: width, height: Constants.itemHeight))) + } + previousPoint.x += width + Constants.itemSpacing + } + + return frames + } + + var selectionCallbackClosure: (([Bool]) -> Void)? + + func setItemSelected(_ selected: Bool, at index: Int, animated: Bool) { + self.selectedItems[index] = selected + self.selectionViews[index].setChecked(isChecked: selected, animated: animated) + } + + func setItemsSelection(_ selection: [Bool]) { + assert(selection.count == items.count) + self.selectedItems = selection + for (index, selected) in self.selectedItems.enumerated() { + selectionViews[index].setChecked(isChecked: selected, animated: false) + } + } + + private func notifyItemSelection() { + selectionCallbackClosure?(selectedItems) + } + + override func layoutSubviews() { + super.layoutSubviews() + + updateFrames() + } + + private func updateFrames() { + for (index, frame) in generateItemsFrames(frame: bounds).enumerated() { + selectionViews[index].frame = frame + } + } + + override var intrinsicContentSize: CGSize { + guard isExpanded else { + var size = self.bounds.size + size.height = 0 + return size + } + let frames = generateItemsFrames(frame: UIScreen.main.bounds) + guard let lastFrame = frames.last else { return .zero } + let size = CGSize(width: frame.width, height: lastFrame.maxY + Constants.insets.bottom) + return size + } +} + +extension ChartVisibilityView: ColorModeContainer { + func apply(colorMode: ColorMode, animated: Bool) { + UIView.perform(animated: animated) { + self.backgroundColor = colorMode.chartBackgroundColor + self.tintColor = colorMode.descriptionActionColor + } + } +} diff --git a/submodules/Charts/Sources/Chart Screen/ChartsDataLoader.swift b/submodules/Charts/Sources/Chart Screen/ChartsDataLoader.swift new file mode 100644 index 0000000000..085e4689bd --- /dev/null +++ b/submodules/Charts/Sources/Chart Screen/ChartsDataLoader.swift @@ -0,0 +1,51 @@ +// +// ChartsDataLoader.swift +// GraphTest +// +// Created by Andrei Salavei on 4/8/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import Foundation + +enum ChartsDataType: String { + case generalLines = "1" + case twoAxisLines = "2" + case stackedBars = "3" + case dailyBars = "4" + case percentPie = "5" +} + +private enum Constants { + static let overviewFilename = "overview.json" + static let dataDir = "data" +} + +class ChartsDataLoader { + static var documentDirectoryURL: URL { + let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) + let documentsDirectory = paths[0] + return documentsDirectory + } + + static func overviewData(type: ChartsDataType, extraCopiesCount: Int = 0, sync: Bool = false, success: @escaping (ChartsCollection) -> Void) { + let path = Bundle.main.bundleURL + .appendingPathComponent(Constants.dataDir) + .appendingPathComponent(type.rawValue) + .appendingPathComponent(Constants.overviewFilename) + ChartsDataManager().readChart(file: path, extraCopiesCount: extraCopiesCount, sync: sync, success: success, failure: { _ in }) + } + + static func detaildData(type: ChartsDataType, extraCopiesCount: Int = 0, date: Date, success: @escaping (ChartsCollection) -> Void, failure: @escaping (Error) -> Void) { + let dateComponents = Calendar.utc.dateComponents([.day, .month, .year], from: date) + let yearMonth = String(format: "%04d-%02d", dateComponents.year ?? 0, dateComponents.month ?? 0) + let day = String(format: "%02d.json", dateComponents.day ?? 0) + + let path = Bundle.main.bundleURL + .appendingPathComponent(Constants.dataDir) + .appendingPathComponent(type.rawValue) + .appendingPathComponent(yearMonth) + .appendingPathComponent(day) + ChartsDataManager().readChart(file: path, extraCopiesCount: extraCopiesCount, sync: false, success: success, failure: failure) + } +} diff --git a/submodules/Charts/Sources/Chart Screen/ChartsStackViewController.swift b/submodules/Charts/Sources/Chart Screen/ChartsStackViewController.swift new file mode 100644 index 0000000000..e8c22e6453 --- /dev/null +++ b/submodules/Charts/Sources/Chart Screen/ChartsStackViewController.swift @@ -0,0 +1,222 @@ +// +// ChartsStackViewController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/13/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class ChartsStackViewController: UIViewController { + @IBOutlet private var stackView: UIStackView! + @IBOutlet private var scrollView: UIScrollView! + @IBOutlet private var psLabel: UILabel! + @IBOutlet private var ppsLabel: UILabel! + @IBOutlet private var animationButton: ChartVisibilityItemView! + + private var sections: [ChartStackSection] = [] + + private var colorMode: ColorMode = .night + private var colorModeButton: UIBarButtonItem! + private var performFastAnimation: Bool = false + + override func viewDidLoad() { + super.viewDidLoad() + + title = "Statistics" + colorModeButton = UIBarButtonItem(title: colorMode.switchTitle, style: .plain, target: self, action: #selector(didTapSwitchColorMode)) + navigationItem.rightBarButtonItem = colorModeButton + + apply(colorMode: colorMode, animated: false) + + self.navigationController?.navigationBar.barStyle = .black + self.navigationController?.navigationBar.isTranslucent = false + + self.view.isUserInteractionEnabled = false + animationButton.backgroundColor = .clear + animationButton.tapClosure = { [weak self] in + guard let self = self else { return } + self.setSlowAnimationEnabled(!self.animationButton.isChecked) + } + self.setSlowAnimationEnabled(false) + + loadChart1() + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + DispatchQueue.main.async { + self.view.setNeedsUpdateConstraints() + self.view.setNeedsLayout() + } + } + + func loadChart1() { + ChartsDataLoader.overviewData(type: .generalLines, sync: true, success: { collection in + let generalLinesChartController = GeneralLinesChartController(chartsCollection: collection) + self.addSection(controller: generalLinesChartController, title: "FOLLOWERS") + generalLinesChartController.getDetailsData = { date, completion in + ChartsDataLoader.detaildData(type: .generalLines, date: date, success: { collection in + completion(collection) + }, failure: { error in + completion(nil) + }) + } + DispatchQueue.main.async { + self.loadChart2() + } + }) + } + + func loadChart2() { + ChartsDataLoader.overviewData(type: .twoAxisLines, success: { collection in + let twoAxisLinesChartController = TwoAxisLinesChartController(chartsCollection: collection) + self.addSection(controller: twoAxisLinesChartController, title: "INTERACTIONS") + twoAxisLinesChartController.getDetailsData = { date, completion in + ChartsDataLoader.detaildData(type: .twoAxisLines, date: date, success: { collection in + completion(collection) + }, failure: { error in + completion(nil) + }) + } + DispatchQueue.main.async { + self.loadChart3() + } + }) + } + + func loadChart3() { + ChartsDataLoader.overviewData(type: .stackedBars, success: { collection in + let stackedBarsChartController = StackedBarsChartController(chartsCollection: collection) + self.addSection(controller: stackedBarsChartController, title: "FRUITS") + stackedBarsChartController.getDetailsData = { date, completion in + ChartsDataLoader.detaildData(type: .stackedBars, date: date, success: { collection in + completion(collection) + }, failure: { error in + completion(nil) + }) + } + DispatchQueue.main.async { + self.loadChart4() + } + }) + } + + func loadChart4() { + ChartsDataLoader.overviewData(type: .dailyBars, success: { collection in + let dailyBarsChartController = DailyBarsChartController(chartsCollection: collection) + self.addSection(controller: dailyBarsChartController, title: "VIEWS") + dailyBarsChartController.getDetailsData = { date, completion in + ChartsDataLoader.detaildData(type: .dailyBars, date: date, success: { collection in + completion(collection) + }, failure: { error in + completion(nil) + }) + } + DispatchQueue.main.async { + self.loadChart5() + } + }) + } + + func loadChart5() { + ChartsDataLoader.overviewData(type: .percentPie, success: { collection in + let percentPieChartController = PercentPieChartController(chartsCollection: collection) + self.addSection(controller: percentPieChartController, title: "MORE FRUITS") + self.finalizeChartsLoading() + }) + } + + func setSlowAnimationEnabled(_ isEnabled: Bool) { + animationButton.setChecked(isChecked: isEnabled, animated: true) + if isEnabled { + TimeInterval.animationDurationMultipler = 5 + } else { + TimeInterval.animationDurationMultipler = 1 + } + } + + func finalizeChartsLoading() { + self.view.isUserInteractionEnabled = true + } + + func addSection(controller: BaseChartController, title: String) { + let section = Bundle.main.loadNibNamed("ChartStackSection", owner: nil, options: nil)?.first as! ChartStackSection + section.frame = UIScreen.main.bounds + section.layoutIfNeeded() + section.setup(controller: controller, title: title) + section.apply(colorMode: colorMode, animated: false) + stackView.addArrangedSubview(section) + sections.append(section) + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return (colorMode == .day) ? .default : .lightContent + } + + override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation { + return .fade + } + + @objc private func didTapSwitchColorMode() { + self.colorMode = self.colorMode == .day ? .night : .day + apply(colorMode: self.colorMode, animated: !performFastAnimation) + colorModeButton.title = colorMode.switchTitle + } +} + +extension ChartsStackViewController: UIScrollViewDelegate { + func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { + performFastAnimation = decelerate + } + + func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { + performFastAnimation = false + } +} + +extension ChartsStackViewController: ColorModeContainer { + func apply(colorMode: ColorMode, animated: Bool) { + + UIView.perform(animated: animated) { + self.psLabel.setTextColor(colorMode.sectionTitleColor, animated: animated && self.psLabel.isVisibleInWindow) + self.ppsLabel.setTextColor(colorMode.sectionTitleColor, animated: animated && self.ppsLabel.isVisibleInWindow) + self.animationButton.item = ChartVisibilityItem(title: "Enable slow animations", + color: colorMode.sectionTitleColor) + + self.view.backgroundColor = colorMode.tableBackgroundColor + + if (animated) { + let animation = CATransition() + animation.timingFunction = CAMediaTimingFunction.init(name: .linear) + animation.type = .fade + animation.duration = .defaultDuration + self.navigationController?.navigationBar.layer.add(animation, forKey: "kCATransitionColorFade") + } + + self.navigationController?.navigationBar.tintColor = colorMode.actionButtonColor + self.navigationController?.navigationBar.barTintColor = colorMode.chartBackgroundColor + self.navigationController?.navigationBar.titleTextAttributes = [.font: UIFont.systemFont(ofSize: 17, weight: .medium), + .foregroundColor: colorMode.viewTintColor] + self.view.layoutIfNeeded() + } + self.setNeedsStatusBarAppearanceUpdate() + + for section in sections { + section.apply(colorMode: colorMode, animated: animated && section.isVisibleInWindow) + } + } +} + +extension ColorMode { + var switchTitle: String { + switch self { + case .day: + return "Night Mode" + case .night: + return "Day Mode" + } + } +} diff --git a/submodules/Charts/Sources/Chart Screen/RangeChartView.swift b/submodules/Charts/Sources/Chart Screen/RangeChartView.swift new file mode 100644 index 0000000000..91089c1de8 --- /dev/null +++ b/submodules/Charts/Sources/Chart Screen/RangeChartView.swift @@ -0,0 +1,291 @@ +// +// RangeChartView.swift +// GraphTest +// +// Created by Andrei Salavei on 3/11/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// +import UIKit + +private enum Constants { + static let cropIndocatorLineWidth: CGFloat = 1 + static let markerSelectionRange: CGFloat = 25 + static let defaultMinimumRangeDistance: CGFloat = 0.05 + static let titntAreaWidth: CGFloat = 10 + static let horizontalContentMargin: CGFloat = 16 + static let cornerRadius: CGFloat = 5 +} + +class RangeChartView: UIControl { + private enum Marker { + case lower + case upper + case center + } + public var lowerBound: CGFloat = 0 { + didSet { + setNeedsLayout() + } + } + public var upperBound: CGFloat = 1 { + didSet { + setNeedsLayout() + } + } + public var selectionColor: UIColor = .blue + public var defaultColor: UIColor = .lightGray + + public var minimumRangeDistance: CGFloat = Constants.defaultMinimumRangeDistance + + private let lowerBoundTintView = UIView() + private let upperBoundTintView = UIView() + private let cropFrameView = UIImageView() + + private var selectedMarker: Marker? + private var selectedMarkerHorizontalOffet: CGFloat = 0 + private var isBoundCropHighlighted: Bool = false + private var isRangePagingEnabled: Bool = false + + public let chartView = ChartView() + + override init(frame: CGRect) { + super.init(frame: frame) + + layoutMargins = UIEdgeInsets(top: Constants.cropIndocatorLineWidth, + left: Constants.horizontalContentMargin, + bottom: Constants.cropIndocatorLineWidth, + right: Constants.horizontalContentMargin) + + self.setup() + } + + func setup() { + isMultipleTouchEnabled = false + + chartView.chartInsets = .zero + chartView.backgroundColor = .clear + + addSubview(chartView) + addSubview(lowerBoundTintView) + addSubview(upperBoundTintView) + addSubview(cropFrameView) + cropFrameView.isUserInteractionEnabled = false + chartView.isUserInteractionEnabled = false + lowerBoundTintView.isUserInteractionEnabled = false + upperBoundTintView.isUserInteractionEnabled = false + + chartView.layer.cornerRadius = 5 + upperBoundTintView.layer.cornerRadius = 5 + lowerBoundTintView.layer.cornerRadius = 5 + + chartView.layer.masksToBounds = true + upperBoundTintView.layer.masksToBounds = true + lowerBoundTintView.layer.masksToBounds = true + + layoutViews() + } + + override func awakeFromNib() { + super.awakeFromNib() + + self.setup() + } + + public var rangeDidChangeClosure: ((ClosedRange) -> Void)? + public var touchedOutsideClosure: (() -> Void)? + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + func setRangePaging(enabled: Bool, minimumSize: CGFloat) { + isRangePagingEnabled = enabled + minimumRangeDistance = minimumSize + } + + func setRange(_ range: ClosedRange, animated: Bool) { + UIView.perform(animated: animated) { + self.lowerBound = range.lowerBound + self.upperBound = range.upperBound + self.layoutIfNeeded() + } + } + + override func layoutSubviews() { + super.layoutSubviews() + + layoutViews() + } + + override var isEnabled: Bool { + get { + return super.isEnabled + } + set { + if newValue == false { + selectedMarker = nil + } + super.isEnabled = newValue + } + } + + // MARK: - Touches + + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + guard isEnabled else { return } + guard let point = touches.first?.location(in: self) else { return } + + if abs(locationInView(for: upperBound) - point.x + Constants.markerSelectionRange / 2) < Constants.markerSelectionRange { + selectedMarker = .upper + selectedMarkerHorizontalOffet = point.x - locationInView(for: upperBound) + isBoundCropHighlighted = true + } else if abs(locationInView(for: lowerBound) - point.x - Constants.markerSelectionRange / 2) < Constants.markerSelectionRange { + selectedMarker = .lower + selectedMarkerHorizontalOffet = point.x - locationInView(for: lowerBound) + isBoundCropHighlighted = true + } else if point.x > locationInView(for: lowerBound) && point.x < locationInView(for: upperBound) { + selectedMarker = .center + selectedMarkerHorizontalOffet = point.x - locationInView(for: lowerBound) + isBoundCropHighlighted = true + } else { + selectedMarker = nil + return + } + + sendActions(for: .touchDown) + } + + override func touchesMoved(_ touches: Set, with event: UIEvent?) { + guard isEnabled else { return } + guard let selectedMarker = selectedMarker else { return } + guard let point = touches.first?.location(in: self) else { return } + + let horizontalPosition = point.x - selectedMarkerHorizontalOffet + let fraction = fractionFor(offsetX: horizontalPosition) + updateMarkerOffset(selectedMarker, fraction: fraction) + + sendActions(for: .valueChanged) + } + + override func touchesEnded(_ touches: Set, with event: UIEvent?) { + guard isEnabled else { return } + guard let selectedMarker = selectedMarker else { + touchedOutsideClosure?() + return + } + guard let point = touches.first?.location(in: self) else { return } + + let horizontalPosition = point.x - selectedMarkerHorizontalOffet + let fraction = fractionFor(offsetX: horizontalPosition) + updateMarkerOffset(selectedMarker, fraction: fraction) + + self.selectedMarker = nil + self.isBoundCropHighlighted = false + if bounds.contains(point) { + sendActions(for: .touchUpInside) + } else { + sendActions(for: .touchUpOutside) + } + rangeDidChangeClosure?(lowerBound...upperBound) + } + + override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + self.selectedMarker = nil + self.isBoundCropHighlighted = false + sendActions(for: .touchCancel) + } +} + +private extension RangeChartView { + var contentFrame: CGRect { + return CGRect(x: layoutMargins.right, + y: layoutMargins.top, + width: (bounds.width - layoutMargins.right - layoutMargins.left), + height: bounds.height - layoutMargins.top - layoutMargins.bottom) + } + + func locationInView(for fraction: CGFloat) -> CGFloat { + return contentFrame.minX + contentFrame.width * fraction + } + + func locationInView(for fraction: Double) -> CGFloat { + return locationInView(for: CGFloat(fraction)) + } + + func fractionFor(offsetX: CGFloat) -> CGFloat { + guard contentFrame.width > 0 else { + return 0 + } + + return crop(0, CGFloat((offsetX - contentFrame.minX ) / contentFrame.width), 1) + } + + private func updateMarkerOffset(_ marker: Marker, fraction: CGFloat, notifyDelegate: Bool = true) { + let fractionToCount: CGFloat + if isRangePagingEnabled { + guard let minValue = stride(from: CGFloat(0.0), through: CGFloat(1.0), by: minimumRangeDistance).min(by: { abs($0 - fraction) < abs($1 - fraction) }) else { return } + fractionToCount = minValue + } else { + fractionToCount = fraction + } + + switch marker { + case .lower: + lowerBound = min(fractionToCount, upperBound - minimumRangeDistance) + case .upper: + upperBound = max(fractionToCount, lowerBound + minimumRangeDistance) + case .center: + let distance = upperBound - lowerBound + lowerBound = max(0, min(fractionToCount, 1 - distance)) + upperBound = lowerBound + distance + } + if notifyDelegate { + rangeDidChangeClosure?(lowerBound...upperBound) + } + UIView.animate(withDuration: isRangePagingEnabled ? 0.1 : 0) { + self.layoutIfNeeded() + } + } + + // MARK: - Layout + + func layoutViews() { + cropFrameView.frame = CGRect(x: locationInView(for: lowerBound), + y: contentFrame.minY - Constants.cropIndocatorLineWidth, + width: locationInView(for: upperBound) - locationInView(for: lowerBound), + height: contentFrame.height + Constants.cropIndocatorLineWidth * 2) + + if chartView.frame != contentFrame { + chartView.frame = contentFrame + } + + lowerBoundTintView.frame = CGRect(x: contentFrame.minX, + y: contentFrame.minY, + width: max(0, locationInView(for: lowerBound) - contentFrame.minX + Constants.titntAreaWidth), + height: contentFrame.height) + + upperBoundTintView.frame = CGRect(x: locationInView(for: upperBound) - Constants.titntAreaWidth, + y: contentFrame.minY, + width: max(0, contentFrame.maxX - locationInView(for: upperBound) + Constants.titntAreaWidth), + height: contentFrame.height) + } +} + +extension RangeChartView: ColorModeContainer { + func apply(colorMode: ColorMode, animated: Bool) { + let colusre = { + self.lowerBoundTintView.backgroundColor = colorMode.rangeViewTintColor + self.upperBoundTintView.backgroundColor = colorMode.rangeViewTintColor + } + + self.cropFrameView.setImage(colorMode.rangeCropImage, animated: animated) + + // self.chartView.apply(colorMode: colorMode, animated: animated) + + if animated { + UIView.animate(withDuration: .defaultDuration, animations: colusre) + } else { + colusre() + } + } +} diff --git a/submodules/Charts/Sources/ChartNode.swift b/submodules/Charts/Sources/ChartNode.swift new file mode 100644 index 0000000000..b6c6da436c --- /dev/null +++ b/submodules/Charts/Sources/ChartNode.swift @@ -0,0 +1,48 @@ +import Foundation +import UIKit +import Display +import AsyncDisplayKit +import AppBundle + +public final class ChartNode: ASDisplayNode { + private var chartView: ChartStackSection { + return self.view as! ChartStackSection + } + + public override init() { + super.init() + + self.setViewBlock({ + return ChartStackSection() + }) + } + + public override func didLoad() { + super.didLoad() + + self.view.disablesInteractiveTransitionGestureRecognizer = true + } + + public func setup(_ data: String, bar: Bool = false) { + if let data = data.data(using: .utf8) { + ChartsDataManager().readChart(data: data, extraCopiesCount: 0, sync: true, success: { [weak self] collection in + let controller: BaseChartController + if bar { + controller = DailyBarsChartController(chartsCollection: collection) + } else { + controller = GeneralLinesChartController(chartsCollection: collection) + } + if let strongSelf = self { + strongSelf.chartView.setup(controller: controller, title: "") + strongSelf.chartView.apply(colorMode: .day, animated: false) + } + }) { error in + + } + } + } + + required public init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/submodules/Charts/Sources/Charts Reader/ChartsCollection.swift b/submodules/Charts/Sources/Charts Reader/ChartsCollection.swift new file mode 100644 index 0000000000..f3ecd8215d --- /dev/null +++ b/submodules/Charts/Sources/Charts Reader/ChartsCollection.swift @@ -0,0 +1,91 @@ +// +// ChardData.swift +// GraphTest +// +// Created by Andrei Salavei on 3/11/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import Foundation +import UIKit + +struct ChartsCollection { + struct Chart { + var color: UIColor + var name: String + var values: [Double] + } + + var axisValues: [Date] + var chartValues: [Chart] + + static let blank = ChartsCollection(axisValues: [], chartValues: []) + var isBlank: Bool { + return axisValues.isEmpty || chartValues.isEmpty + } +} + +extension ChartsCollection { + public init(from decodedData: [String: Any]) throws { + guard let columns = decodedData["columns"] as? [[Any]] else { + throw ChartsError.generalConversion("Unable to get columns from: \(decodedData)") + } + guard let types = decodedData["types"] as? [String: String] else { + throw ChartsError.generalConversion("Unable to get types from: \(decodedData)") + } + guard let names = decodedData["names"] as? [String: String] else { + throw ChartsError.generalConversion("Unable to get names from: \(decodedData)") + } + guard let colors = decodedData["colors"] as? [String: String] else { + throw ChartsError.generalConversion("Unable to get colors from: \(decodedData)") + } + +// chart.colors – Color for each variable in 6-hex-digit format (e.g. "#AAAAAA"). +// chart.names – Name for each variable. +// chart.percentage – true for percentage based values. +// chart.stacked – true for values stacking on top of each other. +// chart.y_scaled – true for charts with 2 Y axes. + + var axixValuesToSetup: [Date] = [] + var chartToSetup: [Chart] = [] + for column in columns { + guard let columnId = column.first as? String else { + throw ChartsError.generalConversion("Unable to get column name from: \(column)") + } + guard let typeString = types[columnId], let type = ColumnType(rawValue: typeString) else { + throw ChartsError.generalConversion("Unable to get column type from: \(types) - \(columnId)") + } + switch type { + case .axix: + axixValuesToSetup = try column.dropFirst().map { Date(timeIntervalSince1970: try Convert.doubleFrom($0) / 1000) } + case .chart, .bar, .area: + guard let colorString = colors[columnId], + let color = UIColor(hexString: colorString) else { + throw ChartsError.generalConversion("Unable to get color name from: \(colors) - \(columnId)") + } + guard let name = names[columnId] else { + throw ChartsError.generalConversion("Unable to get column name from: \(names) - \(columnId)") + } + let values = try column.dropFirst().map { try Convert.doubleFrom($0) } + chartToSetup.append(Chart(color: color, + name: name, + values: values)) + } + } + + guard axixValuesToSetup.isEmpty == false, + chartToSetup.isEmpty == false, + chartToSetup.firstIndex(where: { $0.values.count != axixValuesToSetup.count }) == nil else { + throw ChartsError.generalConversion("Saniazing: Invalid number of items: \(axixValuesToSetup), \(chartToSetup)") + } + self.axisValues = axixValuesToSetup + self.chartValues = chartToSetup + } +} + +private enum ColumnType: String { + case axix = "x" + case chart = "line" + case area = "area" + case bar = "bar" +} diff --git a/submodules/Charts/Sources/Charts Reader/ChartsDataManager.swift b/submodules/Charts/Sources/Charts Reader/ChartsDataManager.swift new file mode 100644 index 0000000000..1a32f9bcee --- /dev/null +++ b/submodules/Charts/Sources/Charts Reader/ChartsDataManager.swift @@ -0,0 +1,191 @@ +// +// ChartsDataManager.swift +// GraphTest +// +// Created by Andrei Salavei on 3/11/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import Foundation + +class ChartsDataManager { + func readChart(item: [String: Any], extraCopiesCount: Int = 0, sync: Bool, success: @escaping (ChartsCollection) -> Void, failure: @escaping (Error) -> Void) { + let workItem: (() -> Void) = { + do { + var collection = try ChartsCollection(from: item) + for _ in 0.. Void, failure: @escaping (Error) -> Void) { + let workItem: (() -> Void) = { + do { + let decoded = try JSONSerialization.jsonObject(with: data, options: []) + guard let item = decoded as? [String: Any] else { + throw ChartsError.invalidJson + } + var collection = try ChartsCollection(from: item) + for _ in 0.. Void, failure: @escaping (Error) -> Void) { + let workItem: (() -> Void) = { + do { + let data = try Data(contentsOf: file) + let decoded = try JSONSerialization.jsonObject(with: data, options: []) + guard let item = decoded as? [String: Any] else { + throw ChartsError.invalidJson + } + var collection = try ChartsCollection(from: item) + for _ in 0.. Void, failure: @escaping (Error) -> Void) { + let workItem: (() -> Void) = { + do { + let data = try Data(contentsOf: file) + let decoded = try JSONSerialization.jsonObject(with: data, options: []) + guard let items = decoded as? [[String: Any]] else { + throw ChartsError.invalidJson + } + var collections = try items.map { try ChartsCollection(from: $0) } + for _ in 0.. Double { + guard let double = try doubleFrom(value, lenientCast: false) else { + throw ChartsError.generalConversion("Unable to cast \(String(describing: value)) to \(Double.self)") + } + return double + } + + public static func doubleFrom(_ value: Any?, lenientCast: Bool = false) throws -> Double? { + guard let value = value else { + return nil + } + if let intValue = value as? Int { + return Double(intValue) + } else if let floatValue = value as? Float { + return Double(floatValue) + } else if let int64Value = value as? Int64 { + return Double(int64Value) + } else if let intValue = value as? Int { + return Double(intValue) + } else if let stringValue = value as? String { + if let doubleValue = Double(stringValue) { + return doubleValue + } + } + if lenientCast { + return nil + } else { + throw ChartsError.generalConversion("Unable to cast \(String(describing: value)) to \(Double.self)") + } + } +} diff --git a/submodules/Charts/Sources/Charts.h b/submodules/Charts/Sources/Charts.h new file mode 100644 index 0000000000..89573b3f16 --- /dev/null +++ b/submodules/Charts/Sources/Charts.h @@ -0,0 +1,19 @@ +// +// StatisticsUI.h +// StatisticsUI +// +// Created by Peter on 8/13/19. +// Copyright © 2019 Telegram Messenger LLP. All rights reserved. +// + +#import + +//! Project version number for StatisticsUI. +FOUNDATION_EXPORT double StatisticsUIVersionNumber; + +//! Project version string for StatisticsUI. +FOUNDATION_EXPORT const unsigned char StatisticsUIVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/submodules/Charts/Sources/Charts/Controllers/BaseChartController.swift b/submodules/Charts/Sources/Charts/Controllers/BaseChartController.swift new file mode 100644 index 0000000000..7f91e50ea5 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/BaseChartController.swift @@ -0,0 +1,166 @@ +// +// BaseChartController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +enum BaseConstants { + static let defaultRange: ClosedRange = 0...1 + static let minimumAxisYLabelsDistance: CGFloat = 90 + static let monthDayDateFormatter = DateFormatter.utc(format: "MMM d") + static let timeDateFormatter = DateFormatter.utc(format: "HH:mm") + static let headerFullRangeFormatter: DateFormatter = { + let formatter = DateFormatter.utc() + formatter.calendar = Calendar.utc + formatter.dateStyle = .long + return formatter + }() + static let headerMediumRangeFormatter: DateFormatter = { + let formatter = DateFormatter.utc() + formatter.dateStyle = .medium + return formatter + }() + static let headerFullZoomedFormatter: DateFormatter = { + let formatter = DateFormatter.utc() + formatter.dateStyle = .full + return formatter + }() + + static let verticalBaseAnchors: [CGFloat] = [8, 5, 2.5, 2, 1] + static let defaultVerticalBaseAnchor: CGFloat = 1 + + static let mainChartLineWidth: CGFloat = 2 + static let previewChartLineWidth: CGFloat = 1 + + static let previewLinesChartOptimizationLevel: CGFloat = 1.5 + static let linesChartOptimizationLevel: CGFloat = 1.0 + static let barsChartOptimizationLevel: CGFloat = 0.75 + + static let defaultRangePresetLength = TimeInterval.day * 60 + + static let chartNumberFormatter: ScalesNumberFormatter = { + let numberFormatter = ScalesNumberFormatter() + numberFormatter.allowsFloats = true + numberFormatter.numberStyle = .decimal + numberFormatter.usesGroupingSeparator = true + numberFormatter.groupingSeparator = " " + numberFormatter.minimumIntegerDigits = 1 + numberFormatter.minimumFractionDigits = 0 + numberFormatter.maximumFractionDigits = 2 + return numberFormatter + }() + + static let detailsNumberFormatter: NumberFormatter = { + let detailsNumberFormatter = NumberFormatter() + detailsNumberFormatter.allowsFloats = false + detailsNumberFormatter.numberStyle = .decimal + detailsNumberFormatter.usesGroupingSeparator = true + detailsNumberFormatter.groupingSeparator = " " + return detailsNumberFormatter + }() +} + +class BaseChartController: ColorModeContainer { + //let performanceRenderer = PerformanceRenderer() + var initialChartsCollection: ChartsCollection + var isZoomed: Bool = false + + var chartTitle: String = "" + + init(chartsCollection: ChartsCollection) { + self.initialChartsCollection = chartsCollection + } + + var mainChartRenderers: [ChartViewRenderer] { + fatalError("Abstract") + } + + var navigationRenderers: [ChartViewRenderer] { + fatalError("Abstract") + } + + var cartViewBounds: (() -> CGRect) = { fatalError() } + var chartFrame: (() -> CGRect) = { fatalError() } + + func initializeChart() { + fatalError("Abstract") + } + + func chartInteractionDidBegin(point: CGPoint) { + fatalError("Abstract") + } + + func chartInteractionDidEnd() { + fatalError("Abstract") + } + + func cancelChartInteraction() { + fatalError("Abstract") + } + + func didTapZoomOut() { + fatalError("Abstract") + } + + func updateChartsVisibility(visibility: [Bool], animated: Bool) { + fatalError("Abstract") + } + + var currentHorizontalRange: ClosedRange { + fatalError("Abstract") + } + + var isChartRangePagingEnabled: Bool = false + var minimumSelectedChartRange: CGFloat = 0.05 + var chartRangePagingClosure: ((Bool, CGFloat) -> Void)? // isEnabled, PageSize + func setChartRangePagingEnabled(isEnabled: Bool, minimumSelectionSize: CGFloat) { + isChartRangePagingEnabled = isEnabled + minimumSelectedChartRange = minimumSelectionSize + chartRangePagingClosure?(isChartRangePagingEnabled, minimumSelectedChartRange) + } + + var chartRangeUpdatedClosure: ((ClosedRange, Bool) -> Void)? + var currentChartHorizontalRangeFraction: ClosedRange { + fatalError("Abstract") + } + + func updateChartRange(_ rangeFraction: ClosedRange) { + fatalError("Abstract") + } + + var actualChartVisibility: [Bool] { + fatalError("Abstract") + } + + var actualChartsCollection: ChartsCollection { + fatalError("Abstract") + } + + var drawChartVisibity: Bool { + return true + } + + var drawChartNavigation: Bool { + return true + } + + var setDetailsViewPositionClosure: ((CGFloat) -> Void)? + var setDetailsChartVisibleClosure: ((Bool, Bool) -> Void)? + var setDetailsViewModel: ((ChartDetailsViewModel, Bool) -> Void)? + var getDetailsData: ((Date, @escaping (ChartsCollection?) -> Void) -> Void)? + var setChartTitleClosure: ((String, Bool) -> Void)? + var setBackButtonVisibilityClosure: ((Bool, Bool) -> Void)? + var refreshChartToolsClosure: ((Bool) -> Void)? + + func didTapZoomIn(date: Date) { + fatalError("Abstract") + } + + func apply(colorMode: ColorMode, animated: Bool) { + + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/GeneralChartComponentController.swift b/submodules/Charts/Sources/Charts/Controllers/GeneralChartComponentController.swift new file mode 100644 index 0000000000..284be92d3b --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/GeneralChartComponentController.swift @@ -0,0 +1,328 @@ +// +// GeneralChartComponentController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/11/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +enum GeneralChartComponentConstants { + static let defaultInitialRangeLength = CGFloat(TimeInterval.day * 60) + static let defaultZoomedRangeLength = CGFloat(TimeInterval.day) +} + +class GeneralChartComponentController: ColorModeContainer { + var chartsCollection: ChartsCollection = ChartsCollection.blank + var chartVisibility: [Bool] = [] + var lastChartInteractionPoint: CGPoint = .zero + var isChartInteractionBegun: Bool = false + var isChartInteracting: Bool = false + let isZoomed: Bool + + var colorMode: ColorMode = .day + var totalHorizontalRange: ClosedRange = BaseConstants.defaultRange + var totalVerticalRange: ClosedRange = BaseConstants.defaultRange + var initialHorizontalRange: ClosedRange = BaseConstants.defaultRange + var initialVerticalRange: ClosedRange = BaseConstants.defaultRange + + var cartViewBounds: (() -> CGRect) = { fatalError() } + var chartFrame: (() -> CGRect) = { fatalError() } + + init(isZoomed: Bool) { + self.isZoomed = isZoomed + } + + func initialize(chartsCollection: ChartsCollection, + initialDate: Date, + totalHorizontalRange: ClosedRange, + totalVerticalRange: ClosedRange) { + self.chartsCollection = chartsCollection + self.chartVisibility = Array(repeating: true, count: chartsCollection.chartValues.count) + self.totalHorizontalRange = totalHorizontalRange + self.totalVerticalRange = totalVerticalRange + self.initialHorizontalRange = totalHorizontalRange + self.initialVerticalRange = totalVerticalRange + + didLoad() + setupInitialChartRange(initialDate: initialDate) + } + + func didLoad() { + hideDetailsView(animated: false) + } + func willAppear(animated: Bool) { + updateChartRangeTitle(animated: animated) + setupChartRangePaging() + } + func willDisappear(animated: Bool) { + } + + func setupInitialChartRange(initialDate: Date) { + guard let first = chartsCollection.axisValues.first?.timeIntervalSince1970, + let last = chartsCollection.axisValues.last?.timeIntervalSince1970 else { return } + + let rangeStart = CGFloat(first) + let rangeEnd = CGFloat(last) + + if isZoomed { + let initalDate = CGFloat(initialDate.timeIntervalSince1970) + + initialHorizontalRange = max(initalDate, rangeStart)...min(initalDate + GeneralChartComponentConstants.defaultZoomedRangeLength, rangeEnd) + initialVerticalRange = totalVerticalRange + } else { + initialHorizontalRange = max(rangeStart, rangeEnd - GeneralChartComponentConstants.defaultInitialRangeLength)...rangeEnd + initialVerticalRange = totalVerticalRange + } + } + func setupChartRangePaging() { + chartRangePagingClosure?(false, 0.05) + } + + var visibleHorizontalMainChartRange: ClosedRange { + return currentMainRangeRenderer.verticalRange.current + } + var visibleVerticalMainChartRange: ClosedRange { + return currentMainRangeRenderer.verticalRange.current + } + var currentHorizontalMainChartRange: ClosedRange { + return currentMainRangeRenderer.horizontalRange.end + } + var currentVerticalMainChartRange: ClosedRange { + return currentMainRangeRenderer.verticalRange.end + } + var currentMainRangeRenderer: BaseChartRenderer { + fatalError("Abstract") + } + + var visiblePreviewHorizontalRange: ClosedRange { + return currentPreviewRangeRenderer.verticalRange.current + } + var visiblePreviewVerticalRange: ClosedRange { + return currentPreviewRangeRenderer.verticalRange.current + } + var currentPreviewHorizontalRange: ClosedRange { + return currentPreviewRangeRenderer.horizontalRange.end + } + var currentPreviewVerticalRange: ClosedRange { + return currentPreviewRangeRenderer.verticalRange.end + } + var currentPreviewRangeRenderer: BaseChartRenderer { + fatalError("Abstract") + } + + var mainChartRenderers: [ChartViewRenderer] { + fatalError("Abstract") + } + var previewRenderers: [ChartViewRenderer] { + fatalError("Abstract") + } + + func updateChartsVisibility(visibility: [Bool], animated: Bool) { + self.chartVisibility = visibility + if isChartInteractionBegun { + chartInteractionDidBegin(point: lastChartInteractionPoint) + } + } + + var currentChartHorizontalRangeFraction: ClosedRange { + let lowerPercent = (currentHorizontalMainChartRange.lowerBound - totalHorizontalRange.lowerBound) / totalHorizontalRange.distance + let upperPercent = (currentHorizontalMainChartRange.upperBound - totalHorizontalRange.lowerBound) / totalHorizontalRange.distance + return lowerPercent...upperPercent + } + + func chartRangeFractionDidUpdated(_ rangeFraction: ClosedRange) { + let horizontalRange = ClosedRange(uncheckedBounds: + (lower: totalHorizontalRange.lowerBound + rangeFraction.lowerBound * totalHorizontalRange.distance, + upper: totalHorizontalRange.lowerBound + rangeFraction.upperBound * totalHorizontalRange.distance)) + chartRangeDidUpdated(horizontalRange) + updateChartRangeTitle(animated: true) + } + + func chartRangeDidUpdated(_ updatedRange: ClosedRange) { + hideDetailsView(animated: true) + + if isChartInteractionBegun { + chartInteractionDidBegin(point: lastChartInteractionPoint) + } + } + + // MARK: - Details & Interaction + func findClosestDateTo(dateToFind: Date) -> (Date, Int)? { + guard chartsCollection.axisValues.count > 0 else { return nil } + var closestDate = chartsCollection.axisValues[0] + var minIndex = 0 + for (index, date) in chartsCollection.axisValues.enumerated() { + if abs(dateToFind.timeIntervalSince(date)) < abs(dateToFind.timeIntervalSince(closestDate)) { + closestDate = date + minIndex = index + } + } + return (closestDate, minIndex) + } + + func chartInteractionDidBegin(point: CGPoint) { + let chartFrame = self.chartFrame() + guard chartFrame.width > 0 else { return } + let horizontalRange = currentHorizontalMainChartRange + let dateToFind = Date(timeIntervalSince1970: TimeInterval(horizontalRange.distance * point.x + horizontalRange.lowerBound)) + guard let (closestDate, minIndex) = findClosestDateTo(dateToFind: dateToFind) else { return } + + let chartWasInteracting = isChartInteractionBegun + lastChartInteractionPoint = point + isChartInteractionBegun = true + isChartInteracting = true + + let chartValue: CGFloat = CGFloat(closestDate.timeIntervalSince1970) + let detailsViewPosition = (chartValue - horizontalRange.lowerBound) / horizontalRange.distance * chartFrame.width + chartFrame.minX + showDetailsView(at: chartValue, detailsViewPosition: detailsViewPosition, dataIndex: minIndex, date: closestDate, animted: chartWasInteracting) + } + + func showDetailsView(at chartPosition: CGFloat, detailsViewPosition: CGFloat, dataIndex: Int, date: Date, animted: Bool) { + setDetailsViewModel?(chartDetailsViewModel(closestDate: date, pointIndex: dataIndex), animted) + setDetailsChartVisibleClosure?(true, true) + setDetailsViewPositionClosure?(detailsViewPosition) + } + + func chartInteractionDidEnd() { + isChartInteracting = false + } + + func hideDetailsView(animated: Bool) { + isChartInteractionBegun = false + setDetailsChartVisibleClosure?(false, animated) + } + + var visibleDetailsChartValues: [ChartsCollection.Chart] { + let visibleCharts: [ChartsCollection.Chart] = chartVisibility.enumerated().compactMap { args in + args.element ? chartsCollection.chartValues[args.offset] : nil + } + return visibleCharts + } + + var updatePreviewRangeClosure: ((ClosedRange, Bool) -> Void)? + var zoomInOnDateClosure: ((Date) -> Void)? + var setChartTitleClosure: ((String, Bool) -> Void)? + var setDetailsViewPositionClosure: ((CGFloat) -> Void)? + var setDetailsChartVisibleClosure: ((Bool, Bool) -> Void)? + var setDetailsViewModel: ((ChartDetailsViewModel, Bool) -> Void)? + var chartRangePagingClosure: ((Bool, CGFloat) -> Void)? // isEnabled, PageSize + + func apply(colorMode: ColorMode, animated: Bool) { + self.colorMode = colorMode + } + +// MARK: - Helpers + var prevoiusHorizontalStrideInterval: Int = -1 + func updateHorizontalLimitLabels(horizontalScalesRenderer: HorizontalScalesRenderer, + horizontalRange: ClosedRange, + scaleType: ChartScaleType, + forceUpdate: Bool, + animated: Bool) { + let scaleTimeInterval: TimeInterval + if chartsCollection.axisValues.count >= 1 { + scaleTimeInterval = chartsCollection.axisValues[1].timeIntervalSince1970 - chartsCollection.axisValues[0].timeIntervalSince1970 + } else { + scaleTimeInterval = scaleType.timeInterval + } + + let numberOfItems = horizontalRange.distance / CGFloat(scaleTimeInterval) + let maximumNumberOfItems = chartFrame().width / scaleType.minimumAxisXDistance + let tempStride = max(1, Int((numberOfItems / maximumNumberOfItems).rounded(.up))) + var strideInterval = 1 + while strideInterval < tempStride { + strideInterval *= 2 + } + + if forceUpdate || (strideInterval != prevoiusHorizontalStrideInterval && strideInterval > 0) { + var labels: [LinesChartLabel] = [] + for index in stride(from: chartsCollection.axisValues.count - 1, to: -1, by: -strideInterval).reversed() { + let date = chartsCollection.axisValues[index] + labels.append(LinesChartLabel(value: CGFloat(date.timeIntervalSince1970), + text: scaleType.dateFormatter.string(from: date))) + } + prevoiusHorizontalStrideInterval = strideInterval + horizontalScalesRenderer.setup(labels: labels, animated: animated) + } + } + + func verticalLimitsLabels(verticalRange: ClosedRange) -> (ClosedRange, [LinesChartLabel]) { + let ditance = verticalRange.distance + let chartHeight = chartFrame().height + + guard ditance > 0, chartHeight > 0 else { return (BaseConstants.defaultRange, []) } + + let approximateNumberOfChartValues = (chartHeight / BaseConstants.minimumAxisYLabelsDistance) + + var numberOfOffsetsPerItem = ditance / approximateNumberOfChartValues + var multiplier: CGFloat = 1.0 + while numberOfOffsetsPerItem > 10 { + numberOfOffsetsPerItem /= 10 + multiplier *= 10 + } + var dividor: CGFloat = 1.0 + var maximumNumberOfDecimals = 2 + while numberOfOffsetsPerItem < 1 { + numberOfOffsetsPerItem *= 10 + dividor *= 10 + maximumNumberOfDecimals += 1 + } + + var base: CGFloat = BaseConstants.verticalBaseAnchors.first { numberOfOffsetsPerItem > $0 } ?? BaseConstants.defaultVerticalBaseAnchor + base = base * multiplier / dividor + + var verticalLabels: [LinesChartLabel] = [] + var verticalValue = (verticalRange.lowerBound / base).rounded(.down) * base + let lowerBound = verticalValue + + let numberFormatter = BaseConstants.chartNumberFormatter + numberFormatter.maximumFractionDigits = maximumNumberOfDecimals + while verticalValue < verticalRange.upperBound { + let text: String = numberFormatter.string(from: NSNumber(value: Double(verticalValue))) ?? "" + + verticalLabels.append(LinesChartLabel(value: verticalValue, text: text)) + verticalValue += base + } + let updatedRange = lowerBound...verticalValue + + return (updatedRange, verticalLabels) + } + + func chartDetailsViewModel(closestDate: Date, pointIndex: Int) -> ChartDetailsViewModel { + let values: [ChartDetailsViewModel.Value] = chartsCollection.chartValues.enumerated().map { arg in + let (index, component) = arg + return ChartDetailsViewModel.Value(prefix: nil, + title: component.name, + value: BaseConstants.detailsNumberFormatter.string(from: NSNumber(value: component.values[pointIndex])) ?? "", + color: component.color, + visible: chartVisibility[index]) + } + let dateString: String + if isZoomed { + dateString = BaseConstants.timeDateFormatter.string(from: closestDate) + } else { + dateString = BaseConstants.headerMediumRangeFormatter.string(from: closestDate) + } + let viewModel = ChartDetailsViewModel(title: dateString, + showArrow: !self.isZoomed, + showPrefixes: false, + values: values, + totalValue: nil, + tapAction: { [weak self] in + self?.zoomInOnDateClosure?(closestDate) }) + return viewModel + } + + func updateChartRangeTitle(animated: Bool) { + let fromDate = Date(timeIntervalSince1970: TimeInterval(currentHorizontalMainChartRange.lowerBound) + 1) + let toDate = Date(timeIntervalSince1970: TimeInterval(currentHorizontalMainChartRange.upperBound)) + if Calendar.utc.startOfDay(for: fromDate) == Calendar.utc.startOfDay(for: toDate) { + let stirng = BaseConstants.headerFullZoomedFormatter.string(from: fromDate) + self.setChartTitleClosure?(stirng, animated) + } else { + let stirng = "\(BaseConstants.headerMediumRangeFormatter.string(from: fromDate)) - \(BaseConstants.headerMediumRangeFormatter.string(from: toDate))" + self.setChartTitleClosure?(stirng, animated) + } + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/Lines/BaseLinesChartController.swift b/submodules/Charts/Sources/Charts/Controllers/Lines/BaseLinesChartController.swift new file mode 100644 index 0000000000..60d5069d10 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Lines/BaseLinesChartController.swift @@ -0,0 +1,236 @@ +// +// BaseLinesChartController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/14/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class BaseLinesChartController: BaseChartController { + var chartVisibility: [Bool] + var zoomChartVisibility: [Bool] + var lastChartInteractionPoint: CGPoint = .zero + var isChartInteractionBegun: Bool = false + + var initialChartRange: ClosedRange = BaseConstants.defaultRange + var zoomedChartRange: ClosedRange = BaseConstants.defaultRange + + override init(chartsCollection: ChartsCollection) { + self.chartVisibility = Array(repeating: true, count: chartsCollection.chartValues.count) + self.zoomChartVisibility = [] + super.init(chartsCollection: chartsCollection) + } + + func setupChartCollection(chartsCollection: ChartsCollection, animated: Bool, isZoomed: Bool) { + if animated { + TimeInterval.setDefaultSuration(.expandAnimationDuration) + DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) { + TimeInterval.setDefaultSuration(.osXDuration) + } + } + + self.initialChartsCollection = chartsCollection + self.isZoomed = isZoomed + + self.setBackButtonVisibilityClosure?(isZoomed, animated) + + updateChartRangeTitle(animated: animated) + } + + func updateChartRangeTitle(animated: Bool) { + let fromDate = Date(timeIntervalSince1970: TimeInterval(zoomedChartRange.lowerBound) + .hour) + let toDate = Date(timeIntervalSince1970: TimeInterval(zoomedChartRange.upperBound)) + if Calendar.utc.startOfDay(for: fromDate) == Calendar.utc.startOfDay(for: toDate) { + let stirng = BaseConstants.headerFullZoomedFormatter.string(from: fromDate) + self.setChartTitleClosure?(stirng, animated) + } else { + let stirng = "\(BaseConstants.headerMediumRangeFormatter.string(from: fromDate)) - \(BaseConstants.headerMediumRangeFormatter.string(from: toDate))" + self.setChartTitleClosure?(stirng, animated) + } + } + + override func chartInteractionDidBegin(point: CGPoint) { + lastChartInteractionPoint = point + isChartInteractionBegun = true + } + + override func chartInteractionDidEnd() { + + } + + override func cancelChartInteraction() { + isChartInteractionBegun = false + } + + override func updateChartRange(_ rangeFraction: ClosedRange) { + + } + + override var actualChartVisibility: [Bool] { + return isZoomed ? zoomChartVisibility : chartVisibility + } + + override var actualChartsCollection: ChartsCollection { + return initialChartsCollection + } + + var visibleChartValues: [ChartsCollection.Chart] { + let visibleCharts: [ChartsCollection.Chart] = actualChartVisibility.enumerated().compactMap { args in + args.element ? initialChartsCollection.chartValues[args.offset] : nil + } + return visibleCharts + } + + + func chartDetailsViewModel(closestDate: Date, pointIndex: Int) -> ChartDetailsViewModel { + let values: [ChartDetailsViewModel.Value] = actualChartsCollection.chartValues.enumerated().map { arg in + let (index, component) = arg + return ChartDetailsViewModel.Value(prefix: nil, + title: component.name, + value: BaseConstants.detailsNumberFormatter.string(from: component.values[pointIndex]), + color: component.color, + visible: actualChartVisibility[index]) + } + let dateString: String + if isZoomed { + dateString = BaseConstants.timeDateFormatter.string(from: closestDate) + } else { + dateString = BaseConstants.headerMediumRangeFormatter.string(from: closestDate) + } + let viewModel = ChartDetailsViewModel(title: dateString, + showArrow: !self.isZoomed, + showPrefixes: false, + values: values, + totalValue: nil, + tapAction: { [weak self] in self?.didTapZoomIn(date: closestDate) }) + return viewModel + } + + override func didTapZoomIn(date: Date) { + guard isZoomed == false else { return } + cancelChartInteraction() + self.getDetailsData?(date, { updatedCollection in + if let updatedCollection = updatedCollection { + self.initialChartRange = self.currentHorizontalRange + if let startDate = updatedCollection.axisValues.first, + let endDate = updatedCollection.axisValues.last { + self.zoomedChartRange = CGFloat(max(date.timeIntervalSince1970, startDate.timeIntervalSince1970))...CGFloat(min(date.timeIntervalSince1970 + .day - .hour, endDate.timeIntervalSince1970)) + } else { + self.zoomedChartRange = CGFloat(date.timeIntervalSince1970)...CGFloat(date.timeIntervalSince1970 + .day - 1) + } + self.setupChartCollection(chartsCollection: updatedCollection, animated: true, isZoomed: true) + } + }) + } + + func horizontalLimitsLabels(horizontalRange: ClosedRange, + scaleType: ChartScaleType, + prevoiusHorizontalStrideInterval: Int) -> (Int, [LinesChartLabel])? { + let numberOfItems = horizontalRange.distance / CGFloat(scaleType.timeInterval) + let maximumNumberOfItems = chartFrame().width / scaleType.minimumAxisXDistance + let tempStride = max(1, Int((numberOfItems / maximumNumberOfItems).rounded(.up))) + var strideInterval = 1 + while strideInterval < tempStride { + strideInterval *= 2 + } + + if strideInterval != prevoiusHorizontalStrideInterval && strideInterval > 0 { + var labels: [LinesChartLabel] = [] + for index in stride(from: initialChartsCollection.axisValues.count - 1, to: -1, by: -strideInterval).reversed() { + let date = initialChartsCollection.axisValues[index] + labels.append(LinesChartLabel(value: CGFloat(date.timeIntervalSince1970), + text: scaleType.dateFormatter.string(from: date))) + } + return (strideInterval, labels) + } + return nil + } + + func findClosestDateTo(dateToFind: Date) -> (Date, Int)? { + guard initialChartsCollection.axisValues.count > 0 else { return nil } + var closestDate = initialChartsCollection.axisValues[0] + var minIndex = 0 + for (index, date) in initialChartsCollection.axisValues.enumerated() { + if abs(dateToFind.timeIntervalSince(date)) < abs(dateToFind.timeIntervalSince(closestDate)) { + closestDate = date + minIndex = index + } + } + return (closestDate, minIndex) + } + + func verticalLimitsLabels(verticalRange: ClosedRange) -> (ClosedRange, [LinesChartLabel]) { + let ditance = verticalRange.distance + let chartHeight = chartFrame().height + + guard ditance > 0, chartHeight > 0 else { return (BaseConstants.defaultRange, []) } + + let approximateNumberOfChartValues = (chartHeight / BaseConstants.minimumAxisYLabelsDistance) + + var numberOfOffsetsPerItem = ditance / approximateNumberOfChartValues + var multiplier: CGFloat = 1.0 + while numberOfOffsetsPerItem > 10 { + numberOfOffsetsPerItem /= 10 + multiplier *= 10 + } + var dividor: CGFloat = 1.0 + var maximumNumberOfDecimals = 2 + while numberOfOffsetsPerItem < 1 { + numberOfOffsetsPerItem *= 10 + dividor *= 10 + maximumNumberOfDecimals += 1 + } + + var base: CGFloat = BaseConstants.verticalBaseAnchors.first { numberOfOffsetsPerItem > $0 } ?? BaseConstants.defaultVerticalBaseAnchor + base = base * multiplier / dividor + + var verticalLabels: [LinesChartLabel] = [] + var verticalValue = (verticalRange.lowerBound / base).rounded(.down) * base + let lowerBound = verticalValue + + let numberFormatter = BaseConstants.chartNumberFormatter + numberFormatter.maximumFractionDigits = maximumNumberOfDecimals + while verticalValue < verticalRange.upperBound { + let text: String = numberFormatter.string(from: NSNumber(value: Double(verticalValue))) ?? "" + + verticalLabels.append(LinesChartLabel(value: verticalValue, text: text)) + verticalValue += base + } + let updatedRange = lowerBound...verticalValue + + return (updatedRange, verticalLabels) + } +} + +enum ChartScaleType { + case day + case hour + case minutes5 +} + +extension ChartScaleType { + var timeInterval: TimeInterval { + switch self { + case .day: return .day + case .hour: return .hour + case .minutes5: return .minute * 5 + } + } + + var minimumAxisXDistance: CGFloat { + switch self { + case .day: return 50 + case .hour: return 40 + case .minutes5: return 40 + } + } + var dateFormatter: DateFormatter { + switch self { + case .day: return BaseConstants.monthDayDateFormatter + case .hour: return BaseConstants.timeDateFormatter + case .minutes5: return BaseConstants.timeDateFormatter + } + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/Lines/GeneralLinesChartController.swift b/submodules/Charts/Sources/Charts/Controllers/Lines/GeneralLinesChartController.swift new file mode 100644 index 0000000000..3d52888d72 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Lines/GeneralLinesChartController.swift @@ -0,0 +1,247 @@ +// +// LinesChartController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +private enum Constants { + static let defaultRange: ClosedRange = 0...1 +} + +class GeneralLinesChartController: BaseLinesChartController { + private let initialChartCollection: ChartsCollection + + private let mainLinesRenderer = LinesChartRenderer() + private let horizontalScalesRenderer = HorizontalScalesRenderer() + private let verticalScalesRenderer = VerticalScalesRenderer() + private let verticalLineRenderer = VerticalLinesRenderer() + private let lineBulletsRenerer = LineBulletsRenerer() + + private let previewLinesRenderer = LinesChartRenderer() + + private var totalVerticalRange: ClosedRange = Constants.defaultRange + private var totalHorizontalRange: ClosedRange = Constants.defaultRange + + private var prevoiusHorizontalStrideInterval: Int = 1 + + private (set) var chartLines: [LinesChartRenderer.LineData] = [] + + override init(chartsCollection: ChartsCollection) { + self.initialChartCollection = chartsCollection + self.mainLinesRenderer.lineWidth = 2 + self.mainLinesRenderer.optimizationLevel = BaseConstants.linesChartOptimizationLevel + self.previewLinesRenderer.optimizationLevel = BaseConstants.previewLinesChartOptimizationLevel + + self.lineBulletsRenerer.isEnabled = false + + super.init(chartsCollection: chartsCollection) + self.zoomChartVisibility = chartVisibility + } + + override func setupChartCollection(chartsCollection: ChartsCollection, animated: Bool, isZoomed: Bool) { + super.setupChartCollection(chartsCollection: chartsCollection, animated: animated, isZoomed: isZoomed) + + self.chartLines = chartsCollection.chartValues.map { chart in + let points = chart.values.enumerated().map({ (arg) -> CGPoint in + return CGPoint(x: chartsCollection.axisValues[arg.offset].timeIntervalSince1970, + y: arg.element) + }) + return LinesChartRenderer.LineData(color: chart.color, points: points) + } + + self.prevoiusHorizontalStrideInterval = -1 + self.totalVerticalRange = LinesChartRenderer.LineData.verticalRange(lines: chartLines) ?? Constants.defaultRange + self.totalHorizontalRange = LinesChartRenderer.LineData.horizontalRange(lines: chartLines) ?? Constants.defaultRange + self.lineBulletsRenerer.bullets = self.chartLines.map { LineBulletsRenerer.Bullet(coordinate: $0.points.first ?? .zero, + color: $0.color)} + + let chartRange: ClosedRange + if isZoomed { + chartRange = zoomedChartRange + } else { + chartRange = initialChartRange + } + + self.previewLinesRenderer.setup(horizontalRange: totalHorizontalRange, animated: animated) + self.previewLinesRenderer.setup(verticalRange: totalVerticalRange, animated: animated) + + self.mainLinesRenderer.setLines(lines: chartLines, animated: animated) + self.previewLinesRenderer.setLines(lines: chartLines, animated: animated) + + updateHorizontalLimists(horizontalRange: chartRange, animated: animated) + updateMainChartHorizontalRange(range: chartRange, animated: animated) + updateVerticalLimitsAndRange(horizontalRange: chartRange, animated: animated) + + self.chartRangeUpdatedClosure?(currentChartHorizontalRangeFraction, animated) + } + + override func initializeChart() { + if let first = initialChartCollection.axisValues.first?.timeIntervalSince1970, + let last = initialChartCollection.axisValues.last?.timeIntervalSince1970 { + initialChartRange = CGFloat(max(first, last - BaseConstants.defaultRangePresetLength))...CGFloat(last) + } + setupChartCollection(chartsCollection: initialChartCollection, animated: false, isZoomed: false) + } + + override var mainChartRenderers: [ChartViewRenderer] { + return [//performanceRenderer, + mainLinesRenderer, + horizontalScalesRenderer, + verticalScalesRenderer, + verticalLineRenderer, + lineBulletsRenerer + ] + } + + override var navigationRenderers: [ChartViewRenderer] { + return [previewLinesRenderer] + } + + override func updateChartsVisibility(visibility: [Bool], animated: Bool) { + chartVisibility = visibility + zoomChartVisibility = visibility + for (index, isVisible) in visibility.enumerated() { + mainLinesRenderer.setLineVisible(isVisible, at: index, animated: animated) + previewLinesRenderer.setLineVisible(isVisible, at: index, animated: animated) + lineBulletsRenerer.setLineVisible(isVisible, at: index, animated: animated) + } + + updateVerticalLimitsAndRange(horizontalRange: currentHorizontalRange, animated: true) + + if isChartInteractionBegun { + chartInteractionDidBegin(point: lastChartInteractionPoint) + } + } + + override func chartInteractionDidBegin(point: CGPoint) { + let horizontalRange = mainLinesRenderer.horizontalRange.current + let chartFrame = self.chartFrame() + guard chartFrame.width > 0 else { return } + let chartInteractionWasBegin = isChartInteractionBegun + + let dateToFind = Date(timeIntervalSince1970: TimeInterval(horizontalRange.distance * point.x + horizontalRange.lowerBound)) + guard let (closestDate, minIndex) = findClosestDateTo(dateToFind: dateToFind) else { return } + + super.chartInteractionDidBegin(point: point) + + self.lineBulletsRenerer.bullets = chartLines.compactMap { chart in + return LineBulletsRenerer.Bullet(coordinate: chart.points[minIndex], color: chart.color) + } + self.lineBulletsRenerer.isEnabled = true + + let chartValue: CGFloat = CGFloat(closestDate.timeIntervalSince1970) + let detailsViewPosition = (chartValue - horizontalRange.lowerBound) / horizontalRange.distance * chartFrame.width + chartFrame.minX + self.setDetailsViewModel?(chartDetailsViewModel(closestDate: closestDate, pointIndex: minIndex), chartInteractionWasBegin) + self.setDetailsChartVisibleClosure?(true, true) + self.setDetailsViewPositionClosure?(detailsViewPosition) + self.verticalLineRenderer.values = [chartValue] + } + + + override var currentChartHorizontalRangeFraction: ClosedRange { + let lowerPercent = (currentHorizontalRange.lowerBound - totalHorizontalRange.lowerBound) / totalHorizontalRange.distance + let upperPercent = (currentHorizontalRange.upperBound - totalHorizontalRange.lowerBound) / totalHorizontalRange.distance + return lowerPercent...upperPercent + } + + override var currentHorizontalRange: ClosedRange { + return mainLinesRenderer.horizontalRange.end + } + + override func cancelChartInteraction() { + super.cancelChartInteraction() + self.lineBulletsRenerer.isEnabled = false + + self.setDetailsChartVisibleClosure?(false, true) + self.verticalLineRenderer.values = [] + } + + override func didTapZoomOut() { + cancelChartInteraction() + self.setupChartCollection(chartsCollection: initialChartCollection, animated: true, isZoomed: false) + } + + var visibleCharts: [LinesChartRenderer.LineData] { + let visibleCharts: [LinesChartRenderer.LineData] = chartVisibility.enumerated().compactMap { args in + args.element ? chartLines[args.offset] : nil + } + return visibleCharts + } + + override func updateChartRange(_ rangeFraction: ClosedRange) { + cancelChartInteraction() + + let horizontalRange = ClosedRange(uncheckedBounds: + (lower: totalHorizontalRange.lowerBound + rangeFraction.lowerBound * totalHorizontalRange.distance, + upper: totalHorizontalRange.lowerBound + rangeFraction.upperBound * totalHorizontalRange.distance)) + + zoomedChartRange = horizontalRange + updateChartRangeTitle(animated: true) + + updateMainChartHorizontalRange(range: horizontalRange, animated: false) + updateHorizontalLimists(horizontalRange: horizontalRange, animated: true) + updateVerticalLimitsAndRange(horizontalRange: horizontalRange, animated: true) + } + + func updateMainChartHorizontalRange(range: ClosedRange, animated: Bool) { + mainLinesRenderer.setup(horizontalRange: range, animated: animated) + horizontalScalesRenderer.setup(horizontalRange: range, animated: animated) + verticalScalesRenderer.setup(horizontalRange: range, animated: animated) + verticalLineRenderer.setup(horizontalRange: range, animated: animated) + lineBulletsRenerer.setup(horizontalRange: range, animated: animated) + } + + func updateMainChartVerticalRange(range: ClosedRange, animated: Bool) { + mainLinesRenderer.setup(verticalRange: range, animated: animated) + horizontalScalesRenderer.setup(verticalRange: range, animated: animated) + verticalScalesRenderer.setup(verticalRange: range, animated: animated) + verticalLineRenderer.setup(verticalRange: range, animated: animated) + lineBulletsRenerer.setup(verticalRange: range, animated: animated) + } + + func updateHorizontalLimists(horizontalRange: ClosedRange, animated: Bool) { + if let (stride, labels) = horizontalLimitsLabels(horizontalRange: horizontalRange, + scaleType: isZoomed ? .hour : .day, + prevoiusHorizontalStrideInterval: prevoiusHorizontalStrideInterval) { + self.horizontalScalesRenderer.setup(labels: labels, animated: animated) + self.prevoiusHorizontalStrideInterval = stride + } + } + + func updateVerticalLimitsAndRange(horizontalRange: ClosedRange, animated: Bool) { + if let verticalRange = LinesChartRenderer.LineData.verticalRange(lines: visibleCharts, + calculatingRange: horizontalRange, + addBounds: true) { + + + let (range, labels) = verticalLimitsLabels(verticalRange: verticalRange) + + if verticalScalesRenderer.verticalRange.end != range { + verticalScalesRenderer.setup(verticalLimitsLabels: labels, animated: animated) + updateMainChartVerticalRange(range: range, animated: animated) + } + verticalScalesRenderer.setVisible(true, animated: animated) + } else { + verticalScalesRenderer.setVisible(false, animated: animated) + } + + guard let previewVerticalRange = LinesChartRenderer.LineData.verticalRange(lines: visibleCharts) else { return } + + if previewLinesRenderer.verticalRange.end != previewVerticalRange { + previewLinesRenderer.setup(verticalRange: previewVerticalRange, animated: animated) + } + } + + override func apply(colorMode: ColorMode, animated: Bool) { + horizontalScalesRenderer.labelsColor = colorMode.chartLabelsColor + verticalScalesRenderer.labelsColor = colorMode.chartLabelsColor + verticalScalesRenderer.axisXColor = colorMode.chartStrongLinesColor + verticalScalesRenderer.horizontalLinesColor = colorMode.chartHelperLinesColor + lineBulletsRenerer.setInnerColor(colorMode.chartBackgroundColor, animated: animated) + verticalLineRenderer.linesColor = colorMode.chartStrongLinesColor + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/Lines/TwoAxisLinesChartController.swift b/submodules/Charts/Sources/Charts/Controllers/Lines/TwoAxisLinesChartController.swift new file mode 100644 index 0000000000..251e76271e --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Lines/TwoAxisLinesChartController.swift @@ -0,0 +1,306 @@ +// +// TwoAxisLinesChartController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +private enum Constants { + static let verticalBaseAnchors: [CGFloat] = [8, 5, 4, 2.5, 2, 1] + static let defaultRange: ClosedRange = 0...1 +} + +class TwoAxisLinesChartController: BaseLinesChartController { + class GraphController { + let mainLinesRenderer = LinesChartRenderer() + let verticalScalesRenderer = VerticalScalesRenderer() + let lineBulletsRenerer = LineBulletsRenerer() + let previewLinesRenderer = LinesChartRenderer() + + var chartLines: [LinesChartRenderer.LineData] = [] + + var totalVerticalRange: ClosedRange = Constants.defaultRange + + init() { + self.mainLinesRenderer.lineWidth = 2 + self.previewLinesRenderer.lineWidth = 1 + self.lineBulletsRenerer.isEnabled = false + + self.mainLinesRenderer.optimizationLevel = BaseConstants.linesChartOptimizationLevel + self.previewLinesRenderer.optimizationLevel = BaseConstants.previewLinesChartOptimizationLevel + } + + func updateMainChartVerticalRange(range: ClosedRange, animated: Bool) { + mainLinesRenderer.setup(verticalRange: range, animated: animated) + verticalScalesRenderer.setup(verticalRange: range, animated: animated) + lineBulletsRenerer.setup(verticalRange: range, animated: animated) + } + } + + private var graphControllers: [GraphController] = [] + private let verticalLineRenderer = VerticalLinesRenderer() + private let horizontalScalesRenderer = HorizontalScalesRenderer() + + var totalHorizontalRange: ClosedRange = Constants.defaultRange + + private let initialChartCollection: ChartsCollection + + private var prevoiusHorizontalStrideInterval: Int = 1 + + override init(chartsCollection: ChartsCollection) { + self.initialChartCollection = chartsCollection + graphControllers = chartsCollection.chartValues.map { _ in GraphController() } + + super.init(chartsCollection: chartsCollection) + self.zoomChartVisibility = chartVisibility + } + + override func setupChartCollection(chartsCollection: ChartsCollection, animated: Bool, isZoomed: Bool) { + super.setupChartCollection(chartsCollection: chartsCollection, animated: animated, isZoomed: isZoomed) + + for (index, controller) in self.graphControllers.enumerated() { + let chart = chartsCollection.chartValues[index] + let points = chart.values.enumerated().map({ (arg) -> CGPoint in + return CGPoint(x: chartsCollection.axisValues[arg.offset].timeIntervalSince1970, + y: arg.element) + }) + let chartLines = [LinesChartRenderer.LineData(color: chart.color, points: points)] + controller.chartLines = [LinesChartRenderer.LineData(color: chart.color, points: points)] + controller.verticalScalesRenderer.labelsColor = chart.color + controller.totalVerticalRange = LinesChartRenderer.LineData.verticalRange(lines: chartLines) ?? Constants.defaultRange + self.totalHorizontalRange = LinesChartRenderer.LineData.horizontalRange(lines: chartLines) ?? Constants.defaultRange + controller.lineBulletsRenerer.bullets = chartLines.map { LineBulletsRenerer.Bullet(coordinate: $0.points.first ?? .zero, + color: $0.color) } + controller.previewLinesRenderer.setup(horizontalRange: self.totalHorizontalRange, animated: animated) + controller.previewLinesRenderer.setup(verticalRange: controller.totalVerticalRange, animated: animated) + controller.mainLinesRenderer.setLines(lines: chartLines, animated: animated) + controller.previewLinesRenderer.setLines(lines: chartLines, animated: animated) + + controller.verticalScalesRenderer.setHorizontalLinesVisible((index == 0), animated: animated) + controller.verticalScalesRenderer.isRightAligned = (index != 0) + } + + self.prevoiusHorizontalStrideInterval = -1 + + let chartRange: ClosedRange + if isZoomed { + chartRange = zoomedChartRange + } else { + chartRange = initialChartRange + } + + updateHorizontalLimists(horizontalRange: chartRange, animated: animated) + updateMainChartHorizontalRange(range: chartRange, animated: animated) + updateVerticalLimitsAndRange(horizontalRange: chartRange, animated: animated) + + self.chartRangeUpdatedClosure?(currentChartHorizontalRangeFraction, animated) + } + + override func initializeChart() { + if let first = initialChartCollection.axisValues.first?.timeIntervalSince1970, + let last = initialChartCollection.axisValues.last?.timeIntervalSince1970 { + initialChartRange = CGFloat(max(first, last - BaseConstants.defaultRangePresetLength))...CGFloat(last) + } + setupChartCollection(chartsCollection: initialChartCollection, animated: false, isZoomed: false) + } + + override var mainChartRenderers: [ChartViewRenderer] { + return graphControllers.map { $0.mainLinesRenderer } + + graphControllers.flatMap { [$0.verticalScalesRenderer, $0.lineBulletsRenerer] } + + [horizontalScalesRenderer, verticalLineRenderer, +// performanceRenderer + ] + } + + override var navigationRenderers: [ChartViewRenderer] { + return graphControllers.map { $0.previewLinesRenderer } + } + + override func updateChartsVisibility(visibility: [Bool], animated: Bool) { + chartVisibility = visibility + zoomChartVisibility = visibility + let firstIndex = visibility.firstIndex(where: { $0 }) + for (index, isVisible) in visibility.enumerated() { + let graph = graphControllers[index] + for graphIndex in graph.chartLines.indices { + graph.mainLinesRenderer.setLineVisible(isVisible, at: graphIndex, animated: animated) + graph.previewLinesRenderer.setLineVisible(isVisible, at: graphIndex, animated: animated) + graph.lineBulletsRenerer.setLineVisible(isVisible, at: graphIndex, animated: animated) + } + graph.verticalScalesRenderer.setVisible(isVisible, animated: animated) + if let firstIndex = firstIndex { + graph.verticalScalesRenderer.setHorizontalLinesVisible(index == firstIndex, animated: animated) + } + } + + updateVerticalLimitsAndRange(horizontalRange: currentHorizontalRange, animated: true) + + if isChartInteractionBegun { + chartInteractionDidBegin(point: lastChartInteractionPoint) + } + } + + override func chartInteractionDidBegin(point: CGPoint) { + let horizontalRange = currentHorizontalRange + let chartFrame = self.chartFrame() + guard chartFrame.width > 0 else { return } + + let dateToFind = Date(timeIntervalSince1970: TimeInterval(horizontalRange.distance * point.x + horizontalRange.lowerBound)) + guard let (closestDate, minIndex) = findClosestDateTo(dateToFind: dateToFind) else { return } + + let chartInteractionWasBegin = isChartInteractionBegun + super.chartInteractionDidBegin(point: point) + + for graphController in graphControllers { + graphController.lineBulletsRenerer.bullets = graphController.chartLines.map { chart in + LineBulletsRenerer.Bullet(coordinate: chart.points[minIndex], color: chart.color) + } + graphController.lineBulletsRenerer.isEnabled = true + } + + let chartValue: CGFloat = CGFloat(closestDate.timeIntervalSince1970) + let detailsViewPosition = (chartValue - horizontalRange.lowerBound) / horizontalRange.distance * chartFrame.width + chartFrame.minX + self.setDetailsViewModel?(chartDetailsViewModel(closestDate: closestDate, pointIndex: minIndex), chartInteractionWasBegin) + self.setDetailsChartVisibleClosure?(true, true) + self.setDetailsViewPositionClosure?(detailsViewPosition) + self.verticalLineRenderer.values = [chartValue] + } + + override var currentChartHorizontalRangeFraction: ClosedRange { + let lowerPercent = (currentHorizontalRange.lowerBound - totalHorizontalRange.lowerBound) / totalHorizontalRange.distance + let upperPercent = (currentHorizontalRange.upperBound - totalHorizontalRange.lowerBound) / totalHorizontalRange.distance + return lowerPercent...upperPercent + } + + override var currentHorizontalRange: ClosedRange { + return graphControllers.first?.mainLinesRenderer.horizontalRange.end ?? Constants.defaultRange + } + + override func cancelChartInteraction() { + super.cancelChartInteraction() + for graphController in graphControllers { + graphController.lineBulletsRenerer.isEnabled = false + } + + self.setDetailsChartVisibleClosure?(false, true) + self.verticalLineRenderer.values = [] + } + + override func didTapZoomOut() { + cancelChartInteraction() + self.setupChartCollection(chartsCollection: initialChartCollection, animated: true, isZoomed: false) + } + + override func updateChartRange(_ rangeFraction: ClosedRange) { + cancelChartInteraction() + + let horizontalRange = ClosedRange(uncheckedBounds: + (lower: totalHorizontalRange.lowerBound + rangeFraction.lowerBound * totalHorizontalRange.distance, + upper: totalHorizontalRange.lowerBound + rangeFraction.upperBound * totalHorizontalRange.distance)) + + zoomedChartRange = horizontalRange + updateChartRangeTitle(animated: true) + + updateMainChartHorizontalRange(range: horizontalRange, animated: false) + updateHorizontalLimists(horizontalRange: horizontalRange, animated: true) + updateVerticalLimitsAndRange(horizontalRange: horizontalRange, animated: true) + } + + func updateMainChartHorizontalRange(range: ClosedRange, animated: Bool) { + for controller in graphControllers { + controller.mainLinesRenderer.setup(horizontalRange: range, animated: animated) + controller.verticalScalesRenderer.setup(horizontalRange: range, animated: animated) + controller.lineBulletsRenerer.setup(horizontalRange: range, animated: animated) + } + horizontalScalesRenderer.setup(horizontalRange: range, animated: animated) + verticalLineRenderer.setup(horizontalRange: range, animated: animated) + } + + func updateHorizontalLimists(horizontalRange: ClosedRange, animated: Bool) { + if let (stride, labels) = horizontalLimitsLabels(horizontalRange: horizontalRange, + scaleType: isZoomed ? .hour : .day, + prevoiusHorizontalStrideInterval: prevoiusHorizontalStrideInterval) { + self.horizontalScalesRenderer.setup(labels: labels, animated: animated) + self.prevoiusHorizontalStrideInterval = stride + } + } + + func updateVerticalLimitsAndRange(horizontalRange: ClosedRange, animated: Bool) { + let chartHeight = chartFrame().height + let approximateNumberOfChartValues = (chartHeight / BaseConstants.minimumAxisYLabelsDistance) + + var dividorsAndMultiplers: [(startValue: CGFloat, base: CGFloat, count: Int, maximumNumberOfDecimals: Int)] = graphControllers.enumerated().map { arg in + let (index, controller) = arg + let verticalRange = LinesChartRenderer.LineData.verticalRange(lines: controller.chartLines, + calculatingRange: horizontalRange, + addBounds: true) ?? controller.totalVerticalRange + + var numberOfOffsetsPerItem = verticalRange.distance / approximateNumberOfChartValues + + var multiplier: CGFloat = 1.0 + while numberOfOffsetsPerItem > 10 { + numberOfOffsetsPerItem /= 10 + multiplier *= 10 + } + var dividor: CGFloat = 1.0 + var maximumNumberOfDecimals = 2 + while numberOfOffsetsPerItem < 1 { + numberOfOffsetsPerItem *= 10 + dividor *= 10 + maximumNumberOfDecimals += 1 + } + + let generalBase = Constants.verticalBaseAnchors.first { numberOfOffsetsPerItem > $0 } ?? BaseConstants.defaultVerticalBaseAnchor + let base = generalBase * multiplier / dividor + + var verticalValue = (verticalRange.lowerBound / base).rounded(.down) * base + let startValue = verticalValue + var count = 0 + if chartVisibility[index] { + while verticalValue < verticalRange.upperBound { + count += 1 + verticalValue += base + } + } + return (startValue: startValue, base: base, count: count, maximumNumberOfDecimals: maximumNumberOfDecimals) + } + + let totalCount = dividorsAndMultiplers.map { $0.count }.max() ?? 0 + guard totalCount > 0 else { return } + + let numberFormatter = BaseConstants.chartNumberFormatter + for (index, controller) in graphControllers.enumerated() { + + let (startValue, base, _, maximumNumberOfDecimals) = dividorsAndMultiplers[index] + + let updatedRange = startValue...(startValue + base * CGFloat(totalCount)) + if controller.verticalScalesRenderer.verticalRange.end != updatedRange { + numberFormatter.maximumFractionDigits = maximumNumberOfDecimals + + var verticalLabels: [LinesChartLabel] = [] + for multipler in 0...(totalCount - 1) { + let verticalValue = startValue + base * CGFloat(multipler) + let text: String = numberFormatter.string(from: NSNumber(value: Double(verticalValue))) ?? "" + verticalLabels.append(LinesChartLabel(value: verticalValue, text: text)) + } + + controller.verticalScalesRenderer.setup(verticalLimitsLabels: verticalLabels, animated: animated) + controller.updateMainChartVerticalRange(range: updatedRange, animated: animated) + } + } + } + + override func apply(colorMode: ColorMode, animated: Bool) { + horizontalScalesRenderer.labelsColor = colorMode.chartLabelsColor + verticalLineRenderer.linesColor = colorMode.chartStrongLinesColor + + for controller in graphControllers { + controller.verticalScalesRenderer.horizontalLinesColor = colorMode.chartHelperLinesColor + controller.lineBulletsRenerer.setInnerColor(colorMode.chartBackgroundColor, animated: animated) + controller.verticalScalesRenderer.axisXColor = colorMode.chartStrongLinesColor + } + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PercentChartComponentController.swift b/submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PercentChartComponentController.swift new file mode 100644 index 0000000000..d75ba09d91 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PercentChartComponentController.swift @@ -0,0 +1,195 @@ +// +// PercentChartComponentController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/14/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class PercentChartComponentController: GeneralChartComponentController { + let mainPecentChartRenderer: PecentChartRenderer + let horizontalScalesRenderer: HorizontalScalesRenderer + let verticalScalesRenderer: VerticalScalesRenderer + let verticalLineRenderer: VerticalLinesRenderer + let previewPercentChartRenderer: PecentChartRenderer + var percentageData: PecentChartRenderer.PercentageData = .blank + + init(isZoomed: Bool, + mainPecentChartRenderer: PecentChartRenderer, + horizontalScalesRenderer: HorizontalScalesRenderer, + verticalScalesRenderer: VerticalScalesRenderer, + verticalLineRenderer: VerticalLinesRenderer, + previewPercentChartRenderer: PecentChartRenderer) { + self.mainPecentChartRenderer = mainPecentChartRenderer + self.horizontalScalesRenderer = horizontalScalesRenderer + self.verticalScalesRenderer = verticalScalesRenderer + self.verticalLineRenderer = verticalLineRenderer + self.previewPercentChartRenderer = previewPercentChartRenderer + + super.init(isZoomed: isZoomed) + } + + override func initialize(chartsCollection: ChartsCollection, initialDate: Date, totalHorizontalRange _: ClosedRange, totalVerticalRange _: ClosedRange) { + let components = chartsCollection.chartValues.map { PecentChartRenderer.PercentageData.Component(color: $0.color, + values: $0.values.map { CGFloat($0) }) } + self.percentageData = PecentChartRenderer.PercentageData(locations: chartsCollection.axisValues.map { CGFloat($0.timeIntervalSince1970) }, + components: components) + let totalHorizontalRange = PecentChartRenderer.PercentageData.horizontalRange(data: self.percentageData) ?? BaseConstants.defaultRange + let totalVerticalRange = BaseConstants.defaultRange + + super.initialize(chartsCollection: chartsCollection, + initialDate: initialDate, + totalHorizontalRange: totalHorizontalRange, + totalVerticalRange: totalVerticalRange) + + mainPecentChartRenderer.percentageData = self.percentageData + previewPercentChartRenderer.percentageData = self.percentageData + + let axisValues: [CGFloat] = [0, 25, 50, 75, 100] + let labels: [LinesChartLabel] = axisValues.map { value in + return LinesChartLabel(value: value / 100, text: BaseConstants.detailsNumberFormatter.string(from: NSNumber(value: Double(value))) ?? "") + } + verticalScalesRenderer.setup(verticalLimitsLabels: labels, animated: false) + + setupMainChart(horizontalRange: initialHorizontalRange, animated: false) + setupMainChart(verticalRange: initialVerticalRange, animated: false) + previewPercentChartRenderer.setup(verticalRange: totalVerticalRange, animated: false) + previewPercentChartRenderer.setup(horizontalRange: totalHorizontalRange, animated: false) + updateHorizontalLimitLabels(animated: false) + } + + override func willAppear(animated: Bool) { + previewPercentChartRenderer.setup(verticalRange: totalVerticalRange, animated: animated) + previewPercentChartRenderer.setup(horizontalRange: totalHorizontalRange, animated: animated) + + setConponentsVisible(visible: true, animated: true) + + setupMainChart(verticalRange: initialVerticalRange, animated: animated) + setupMainChart(horizontalRange: initialHorizontalRange, animated: animated) + + updatePreviewRangeClosure?(currentChartHorizontalRangeFraction, animated) + + super.willAppear(animated: animated) + } + + override func chartRangeDidUpdated(_ updatedRange: ClosedRange) { + super.chartRangeDidUpdated(updatedRange) + + initialHorizontalRange = updatedRange + setupMainChart(horizontalRange: updatedRange, animated: false) + updateHorizontalLimitLabels(animated: true) + } + + func updateHorizontalLimitLabels(animated: Bool) { + updateHorizontalLimitLabels(horizontalScalesRenderer: horizontalScalesRenderer, + horizontalRange: initialHorizontalRange, + scaleType: isZoomed ? .hour : .day, + forceUpdate: false, + animated: animated) + } + + func prepareAppearanceAnimation(horizontalRnage: ClosedRange) { + setupMainChart(horizontalRange: horizontalRnage, animated: false) + setConponentsVisible(visible: false, animated: false) + } + + func setConponentsVisible(visible: Bool, animated: Bool) { + mainPecentChartRenderer.setVisible(visible, animated: animated) + horizontalScalesRenderer.setVisible(visible, animated: animated) + verticalScalesRenderer.setVisible(visible, animated: animated) + verticalLineRenderer.setVisible(visible, animated: animated) + previewPercentChartRenderer.setVisible(visible, animated: animated) + } + + func setupMainChart(horizontalRange: ClosedRange, animated: Bool) { + mainPecentChartRenderer.setup(horizontalRange: horizontalRange, animated: animated) + horizontalScalesRenderer.setup(horizontalRange: horizontalRange, animated: animated) + verticalScalesRenderer.setup(horizontalRange: horizontalRange, animated: animated) + verticalLineRenderer.setup(horizontalRange: horizontalRange, animated: animated) + } + + func setupMainChart(verticalRange: ClosedRange, animated: Bool) { + mainPecentChartRenderer.setup(verticalRange: verticalRange, animated: animated) + horizontalScalesRenderer.setup(verticalRange: verticalRange, animated: animated) + verticalScalesRenderer.setup(verticalRange: verticalRange, animated: animated) + verticalLineRenderer.setup(verticalRange: verticalRange, animated: animated) + } + + override func updateChartsVisibility(visibility: [Bool], animated: Bool) { + super.updateChartsVisibility(visibility: visibility, animated: animated) + for (index, isVisible) in visibility.enumerated() { + mainPecentChartRenderer.setComponentVisible(isVisible, at: index, animated: animated) + previewPercentChartRenderer.setComponentVisible(isVisible, at: index, animated: animated) + } + verticalScalesRenderer.setVisible(visibility.contains(true), animated: animated) + } + + override func chartDetailsViewModel(closestDate: Date, pointIndex: Int) -> ChartDetailsViewModel { + let visibleValues = visibleDetailsChartValues + + let total = visibleValues.map { $0.values[pointIndex] }.reduce(0, +) + + let values: [ChartDetailsViewModel.Value] = chartsCollection.chartValues.enumerated().map { arg in + let (index, component) = arg + return ChartDetailsViewModel.Value(prefix: PercentConstants.percentValueFormatter.string(from: component.values[pointIndex] / total * 100), + title: component.name, + value: BaseConstants.detailsNumberFormatter.string(from: component.values[pointIndex]), + color: component.color, + visible: chartVisibility[index]) + } + let dateString: String + if isZoomed { + dateString = BaseConstants.timeDateFormatter.string(from: closestDate) + } else { + dateString = BaseConstants.headerMediumRangeFormatter.string(from: closestDate) + } + let viewModel = ChartDetailsViewModel(title: dateString, + showArrow: !self.isZoomed, + showPrefixes: true, + values: values, + totalValue: nil, + tapAction: { [weak self] in + self?.hideDetailsView(animated: true) + self?.zoomInOnDateClosure?(closestDate) }) + return viewModel + } + + var currentlyVisiblePercentageData: PecentChartRenderer.PercentageData { + var currentPercentageData = percentageData + currentPercentageData.components = chartVisibility.enumerated().compactMap { $0.element ? currentPercentageData.components[$0.offset] : nil } + return currentPercentageData + } + + override var currentMainRangeRenderer: BaseChartRenderer { + return mainPecentChartRenderer + } + + override var currentPreviewRangeRenderer: BaseChartRenderer { + return previewPercentChartRenderer + } + + override func showDetailsView(at chartPosition: CGFloat, detailsViewPosition: CGFloat, dataIndex: Int, date: Date, animted: Bool) { + super.showDetailsView(at: chartPosition, detailsViewPosition: detailsViewPosition, dataIndex: dataIndex, date: date, animted: animted) + verticalLineRenderer.values = [chartPosition] + verticalLineRenderer.isEnabled = true + } + + override func hideDetailsView(animated: Bool) { + super.hideDetailsView(animated: animated) + + verticalLineRenderer.values = [] + verticalLineRenderer.isEnabled = false + } + + override func apply(colorMode: ColorMode, animated: Bool) { + super.apply(colorMode: colorMode, animated: animated) + + horizontalScalesRenderer.labelsColor = colorMode.chartLabelsColor + verticalScalesRenderer.labelsColor = colorMode.chartLabelsColor + verticalScalesRenderer.axisXColor = colorMode.barChartStrongLinesColor + verticalScalesRenderer.horizontalLinesColor = colorMode.barChartStrongLinesColor + verticalLineRenderer.linesColor = colorMode.chartStrongLinesColor + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PercentPieChartController.swift b/submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PercentPieChartController.swift new file mode 100644 index 0000000000..484d8a2f11 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PercentPieChartController.swift @@ -0,0 +1,281 @@ +// +// PercentPieChartController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +enum PercentConstants { + static let percentValueFormatter: NumberFormatter = { + let formatter = NumberFormatter() + formatter.positiveSuffix = "%" + return formatter + }() +} + +private enum Constants { + static let zoomedRange = 7 +} + +class PercentPieChartController: BaseChartController { + let percentController: PercentChartComponentController + let pieController: PieChartComponentController + let transitionRenderer: PercentPieAnimationRenderer + + override init(chartsCollection: ChartsCollection) { + transitionRenderer = PercentPieAnimationRenderer() + percentController = PercentChartComponentController(isZoomed: false, + mainPecentChartRenderer: PecentChartRenderer(), + horizontalScalesRenderer: HorizontalScalesRenderer(), + verticalScalesRenderer: VerticalScalesRenderer(), + verticalLineRenderer: VerticalLinesRenderer(), + previewPercentChartRenderer: PecentChartRenderer()) + pieController = PieChartComponentController(isZoomed: true, + pieChartRenderer: PieChartRenderer(), + previewBarChartRenderer: BarChartRenderer()) + + super.init(chartsCollection: chartsCollection) + + [percentController, pieController].forEach { controller in + controller.chartFrame = { [unowned self] in self.chartFrame() } + controller.cartViewBounds = { [unowned self] in self.cartViewBounds() } + controller.zoomInOnDateClosure = { [unowned self] date in + self.didTapZoomIn(date: date) + } + controller.setChartTitleClosure = { [unowned self] (title, animated) in + self.setChartTitleClosure?(title, animated) + } + controller.setDetailsViewPositionClosure = { [unowned self] (position) in + self.setDetailsViewPositionClosure?(position) + } + controller.setDetailsChartVisibleClosure = { [unowned self] (visible, animated) in + self.setDetailsChartVisibleClosure?(visible, animated) + } + controller.setDetailsViewModel = { [unowned self] (viewModel, animated) in + self.setDetailsViewModel?(viewModel, animated) + } + controller.updatePreviewRangeClosure = { [unowned self] (fraction, animated) in + self.chartRangeUpdatedClosure?(fraction, animated) + } + controller.chartRangePagingClosure = { [unowned self] (isEnabled, pageSize) in + self.setChartRangePagingEnabled(isEnabled: isEnabled, minimumSelectionSize: pageSize) + } + } + transitionRenderer.isEnabled = false + } + + override var mainChartRenderers: [ChartViewRenderer] { + return [percentController.mainPecentChartRenderer, + transitionRenderer, + percentController.horizontalScalesRenderer, + percentController.verticalScalesRenderer, + percentController.verticalLineRenderer, + pieController.pieChartRenderer, +// performanceRenderer + ] + } + + override var navigationRenderers: [ChartViewRenderer] { + return [percentController.previewPercentChartRenderer, + pieController.previewBarChartRenderer] + } + + override func initializeChart() { + percentController.initialize(chartsCollection: initialChartsCollection, + initialDate: Date(), + totalHorizontalRange: BaseConstants.defaultRange, + totalVerticalRange: BaseConstants.defaultRange) + switchToChart(chartsCollection: percentController.chartsCollection, isZoomed: false, animated: false) + } + + func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) { + if animated { + TimeInterval.setDefaultSuration(.expandAnimationDuration) + DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) { + TimeInterval.setDefaultSuration(.osXDuration) + } + } + + super.isZoomed = isZoomed + if isZoomed { + let toHorizontalRange = pieController.initialHorizontalRange + + pieController.updateChartsVisibility(visibility: percentController.chartVisibility, animated: false) + pieController.pieChartRenderer.setup(horizontalRange: percentController.currentHorizontalMainChartRange, animated: false) + pieController.previewBarChartRenderer.setup(horizontalRange: percentController.currentPreviewHorizontalRange, animated: false) + pieController.pieChartRenderer.setVisible(false, animated: false) + pieController.previewBarChartRenderer.setVisible(true, animated: false) + + pieController.willAppear(animated: animated) + percentController.willDisappear(animated: animated) + + pieController.pieChartRenderer.drawPie = false + percentController.mainPecentChartRenderer.isEnabled = false + + setupTransitionRenderer() + + percentController.setupMainChart(horizontalRange: toHorizontalRange, animated: animated) + percentController.previewPercentChartRenderer.setup(horizontalRange: toHorizontalRange, animated: animated) + percentController.setConponentsVisible(visible: false, animated: animated) + + transitionRenderer.animate(fromDataToPie: true, animated: animated) { [weak self] in + self?.pieController.pieChartRenderer.drawPie = true + self?.percentController.mainPecentChartRenderer.isEnabled = true + } + } else { + if !pieController.chartsCollection.isBlank { + let fromHorizontalRange = pieController.currentHorizontalMainChartRange + let toHorizontalRange = percentController.initialHorizontalRange + + pieController.pieChartRenderer.setup(horizontalRange: toHorizontalRange, animated: animated) + pieController.previewBarChartRenderer.setup(horizontalRange: toHorizontalRange, animated: animated) + pieController.pieChartRenderer.setVisible(false, animated: animated) + pieController.previewBarChartRenderer.setVisible(false, animated: animated) + + percentController.updateChartsVisibility(visibility: pieController.chartVisibility, animated: false) + percentController.setupMainChart(horizontalRange: fromHorizontalRange, animated: false) + percentController.previewPercentChartRenderer.setup(horizontalRange: fromHorizontalRange, animated: false) + percentController.setConponentsVisible(visible: false, animated: false) + } + + percentController.willAppear(animated: animated) + pieController.willDisappear(animated: animated) + + if animated { + pieController.pieChartRenderer.drawPie = false + percentController.mainPecentChartRenderer.isEnabled = false + + setupTransitionRenderer() + + transitionRenderer.animate(fromDataToPie: false, animated: true) { + self.pieController.pieChartRenderer.drawPie = true + self.percentController.mainPecentChartRenderer.isEnabled = true + } + } + } + + self.setBackButtonVisibilityClosure?(isZoomed, animated) + } + + func setupTransitionRenderer() { + transitionRenderer.setup(verticalRange: percentController.currentVerticalMainChartRange, animated: false) + transitionRenderer.setup(horizontalRange: percentController.currentHorizontalMainChartRange, animated: false) + transitionRenderer.visiblePieComponents = pieController.visiblePieDataWithCurrentPreviewRange + transitionRenderer.visiblePercentageData = percentController.currentlyVisiblePercentageData + } + + override func updateChartsVisibility(visibility: [Bool], animated: Bool) { + if isZoomed { + pieController.updateChartsVisibility(visibility: visibility, animated: animated) + } else { + percentController.updateChartsVisibility(visibility: visibility, animated: animated) + } + } + + var visibleChartValues: [ChartsCollection.Chart] { + let visibility = isZoomed ? pieController.chartVisibility : percentController.chartVisibility + let collection = isZoomed ? pieController.chartsCollection : percentController.chartsCollection + let visibleCharts: [ChartsCollection.Chart] = visibility.enumerated().compactMap { args in + args.element ? collection.chartValues[args.offset] : nil + } + return visibleCharts + } + + override var actualChartVisibility: [Bool] { + return isZoomed ? pieController.chartVisibility : percentController.chartVisibility + } + + override var actualChartsCollection: ChartsCollection { + return isZoomed ? pieController.chartsCollection : percentController.chartsCollection + } + + override func chartInteractionDidBegin(point: CGPoint) { + if isZoomed { + pieController.chartInteractionDidBegin(point: point) + } else { + percentController.chartInteractionDidBegin(point: point) + } + } + + override func chartInteractionDidEnd() { + if isZoomed { + pieController.chartInteractionDidEnd() + } else { + percentController.chartInteractionDidEnd() + } + } + + override var drawChartVisibity: Bool { + return true + } + + override var currentChartHorizontalRangeFraction: ClosedRange { + if isZoomed { + return pieController.currentChartHorizontalRangeFraction + } else { + return percentController.currentChartHorizontalRangeFraction + } + } + + override func cancelChartInteraction() { + if isZoomed { + return pieController.hideDetailsView(animated: true) + } else { + return percentController.hideDetailsView(animated: true) + } + } + + override func didTapZoomIn(date: Date) { + guard isZoomed == false else { return } + cancelChartInteraction() + let currentCollection = percentController.chartsCollection + let range: Int = Constants.zoomedRange + guard let (foundDate, index) = percentController.findClosestDateTo(dateToFind: date) else { return } + var lowIndex = max(0, index - range / 2) + var highIndex = min(currentCollection.axisValues.count - 1, index + range / 2) + if lowIndex == 0 { + highIndex = lowIndex + (range - 1) + } else if highIndex == currentCollection.axisValues.count - 1 { + lowIndex = highIndex - (range - 1) + } + + let newValues = currentCollection.chartValues.map { chart in + return ChartsCollection.Chart(color: chart.color, + name: chart.name, + values: Array(chart.values[(lowIndex...highIndex)])) + } + let newCollection = ChartsCollection(axisValues: Array(currentCollection.axisValues[(lowIndex...highIndex)]), + chartValues: newValues) + let selectedRange = CGFloat(foundDate.timeIntervalSince1970 - .day)...CGFloat(foundDate.timeIntervalSince1970) + pieController.initialize(chartsCollection: newCollection, initialDate: date, totalHorizontalRange: 0...1, totalVerticalRange: 0...1) + pieController.initialHorizontalRange = selectedRange + + switchToChart(chartsCollection: newCollection, isZoomed: true, animated: true) + } + + override func didTapZoomOut() { + self.pieController.deselectSegment(completion: { [weak self] in + guard let self = self else { return } + self.switchToChart(chartsCollection: self.percentController.chartsCollection, isZoomed: false, animated: true) + }) + } + + override func updateChartRange(_ rangeFraction: ClosedRange) { + if isZoomed { + return pieController.chartRangeFractionDidUpdated(rangeFraction) + } else { + return percentController.chartRangeFractionDidUpdated(rangeFraction) + } + } + + override func apply(colorMode: ColorMode, animated: Bool) { + super.apply(colorMode: colorMode, animated: animated) + + pieController.apply(colorMode: colorMode, animated: animated) + percentController.apply(colorMode: colorMode, animated: animated) + transitionRenderer.backgroundColor = colorMode.chartBackgroundColor + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PieChartComponentController.swift b/submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PieChartComponentController.swift new file mode 100644 index 0000000000..68c3541912 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PieChartComponentController.swift @@ -0,0 +1,198 @@ +// +// PieChartComponentController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/14/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class PieChartComponentController: GeneralChartComponentController { + let pieChartRenderer: PieChartRenderer + let previewBarChartRenderer: BarChartRenderer + var barWidth: CGFloat = 1 + + var chartBars: BarChartRenderer.BarsData = .blank + + init(isZoomed: Bool, + pieChartRenderer: PieChartRenderer, + previewBarChartRenderer: BarChartRenderer) { + self.pieChartRenderer = pieChartRenderer + self.previewBarChartRenderer = previewBarChartRenderer + super.init(isZoomed: isZoomed) + } + + override func initialize(chartsCollection: ChartsCollection, initialDate: Date, totalHorizontalRange _: ClosedRange, totalVerticalRange _: ClosedRange) { + let (width, chartBars, totalHorizontalRange, _) = BarChartRenderer.BarsData.initialComponents(chartsCollection: chartsCollection) + self.barWidth = width + self.chartBars = chartBars + super.initialize(chartsCollection: chartsCollection, + initialDate: initialDate, + totalHorizontalRange: totalHorizontalRange, + totalVerticalRange: BaseConstants.defaultRange) + + self.previewBarChartRenderer.bars = chartBars + self.previewBarChartRenderer.fillToTop = true + + pieChartRenderer.valuesFormatter = PercentConstants.percentValueFormatter + pieChartRenderer.setup(horizontalRange: initialHorizontalRange, animated: false) + previewBarChartRenderer.setup(verticalRange: initialVerticalRange, animated: false) + previewBarChartRenderer.setup(horizontalRange: initialHorizontalRange, animated: false) + + pieChartRenderer.updatePercentageData(pieDataWithCurrentPreviewRange, animated: false) + pieChartRenderer.selectSegmentAt(at: nil, animated: false) + } + + private var pieDataWithCurrentPreviewRange: [PieChartRenderer.PieComponent] { + let range = currentHorizontalMainChartRange + var pieComponents = chartsCollection.chartValues.map { PieChartRenderer.PieComponent(color: $0.color, + value: 0) } + guard var valueIndex = chartsCollection.axisValues.firstIndex(where: { CGFloat($0.timeIntervalSince1970) > (range.lowerBound + 1)}) else { + return pieComponents + } + var count = 0 + while valueIndex < chartsCollection.axisValues.count, CGFloat(chartsCollection.axisValues[valueIndex].timeIntervalSince1970) <= range.upperBound { + count += 1 + for pieIndex in pieComponents.indices { + pieComponents[pieIndex].value += CGFloat(chartsCollection.chartValues[pieIndex].values[valueIndex]) + } + valueIndex += 1 + } + return pieComponents + } + + var visiblePieDataWithCurrentPreviewRange: [PieChartRenderer.PieComponent] { + let currentData = pieDataWithCurrentPreviewRange + return chartVisibility.enumerated().compactMap { $0.element ? currentData[$0.offset] : nil } + } + + override func willAppear(animated: Bool) { + pieChartRenderer.setup(horizontalRange: initialHorizontalRange, animated: animated) + pieChartRenderer.setVisible(true, animated: animated) + + previewBarChartRenderer.setup(verticalRange: totalVerticalRange, animated: animated) + previewBarChartRenderer.setup(horizontalRange: totalHorizontalRange, animated: animated) + previewBarChartRenderer.setVisible(true, animated: animated) + + updatePreviewRangeClosure?(currentChartHorizontalRangeFraction, animated) + pieChartRenderer.updatePercentageData(pieDataWithCurrentPreviewRange, animated: false) + + super.willAppear(animated: animated) + } + + override func setupChartRangePaging() { + let valuesCount = chartsCollection.axisValues.count + guard valuesCount > 0 else { return } + chartRangePagingClosure?(true, 1.0 / CGFloat(valuesCount)) + } + + override func chartRangeDidUpdated(_ updatedRange: ClosedRange) { + if isChartInteractionBegun { + chartInteractionDidBegin(point: lastChartInteractionPoint) + } + initialHorizontalRange = updatedRange + + setupMainChart(horizontalRange: updatedRange, animated: true) + updateSelectedDataLabelIfNeeded() + } + + func setupMainChart(horizontalRange: ClosedRange, animated: Bool) { + pieChartRenderer.setup(horizontalRange: horizontalRange, animated: animated) + pieChartRenderer.updatePercentageData(pieDataWithCurrentPreviewRange, animated: animated) + } + + override func updateChartsVisibility(visibility: [Bool], animated: Bool) { + super.updateChartsVisibility(visibility: visibility, animated: animated) + for (index, isVisible) in visibility.enumerated() { + pieChartRenderer.setComponentVisible(isVisible, at: index, animated: animated) + previewBarChartRenderer.setComponentVisible(isVisible, at: index, animated: animated) + } + if let segment = pieChartRenderer.selectedSegment { + if !visibility[segment] { + pieChartRenderer.selectSegmentAt(at: nil, animated: true) + } + } + updateSelectedDataLabelIfNeeded() + } + + func deselectSegment(completion: @escaping () -> Void) { + if pieChartRenderer.hasSelectedSegments { + hideDetailsView(animated: true) + pieChartRenderer.selectSegmentAt(at: nil, animated: true) + DispatchQueue.main.asyncAfter(deadline: .now() + .defaultDuration / 2) { + completion() + } + } else { + completion() + } + } + + func updateSelectedDataLabelIfNeeded() { + if let segment = pieChartRenderer.selectedSegment { + self.setDetailsChartVisibleClosure?(true, true) + self.setDetailsViewModel?(chartDetailsViewModel(segmentInde: segment), false) + self.setDetailsViewPositionClosure?(chartFrame().width / 4) + } else { + self.setDetailsChartVisibleClosure?(false, true) + } + } + + func chartDetailsViewModel(segmentInde: Int) -> ChartDetailsViewModel { + let pieItem = pieDataWithCurrentPreviewRange[segmentInde] + let title = chartsCollection.chartValues[segmentInde].name + let valueString = BaseConstants.detailsNumberFormatter.string(from: pieItem.value) + let viewModel = ChartDetailsViewModel(title: "", + showArrow: false, + showPrefixes: false, + values: [ChartDetailsViewModel.Value(prefix: nil, + title: title, + value: valueString, + color: pieItem.color, + visible: true)], + totalValue: nil, + tapAction: nil) + return viewModel + } + + override var currentMainRangeRenderer: BaseChartRenderer { + return pieChartRenderer + } + + override var currentPreviewRangeRenderer: BaseChartRenderer { + return previewBarChartRenderer + } + + var lastInteractionPoint: CGPoint = .zero + override func chartInteractionDidBegin(point: CGPoint) { + lastInteractionPoint = point + } + + override func chartInteractionDidEnd() { + if let segment = pieChartRenderer.selectedItemIndex(at: lastInteractionPoint) { + if pieChartRenderer.selectedSegment == segment { + pieChartRenderer.selectSegmentAt(at: nil, animated: true) + } else { + pieChartRenderer.selectSegmentAt(at: segment, animated: true) + } + updateSelectedDataLabelIfNeeded() + } + } + + override func hideDetailsView(animated: Bool) { + pieChartRenderer.selectSegmentAt(at: nil, animated: animated) + updateSelectedDataLabelIfNeeded() + } + + override func updateChartRangeTitle(animated: Bool) { + let fromDate = Date(timeIntervalSince1970: TimeInterval(currentHorizontalMainChartRange.lowerBound) + .day + 1) + let toDate = Date(timeIntervalSince1970: TimeInterval(currentHorizontalMainChartRange.upperBound)) + if Calendar.utc.startOfDay(for: fromDate) == Calendar.utc.startOfDay(for: toDate) { + let stirng = BaseConstants.headerFullZoomedFormatter.string(from: fromDate) + self.setChartTitleClosure?(stirng, animated) + } else { + let stirng = "\(BaseConstants.headerMediumRangeFormatter.string(from: fromDate)) - \(BaseConstants.headerMediumRangeFormatter.string(from: toDate))" + self.setChartTitleClosure?(stirng, animated) + } + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/BarsComponentController.swift b/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/BarsComponentController.swift new file mode 100644 index 0000000000..2e1894465b --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/BarsComponentController.swift @@ -0,0 +1,226 @@ +// +// BarsComponentController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/14/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class BarsComponentController: GeneralChartComponentController { + let mainBarsRenderer: BarChartRenderer + let horizontalScalesRenderer: HorizontalScalesRenderer + let verticalScalesRenderer: VerticalScalesRenderer + + let previewBarsChartRenderer: BarChartRenderer + private(set) var barsWidth: CGFloat = 1 + + private (set) var chartBars: BarChartRenderer.BarsData = .blank + + init(isZoomed: Bool, + mainBarsRenderer: BarChartRenderer, + horizontalScalesRenderer: HorizontalScalesRenderer, + verticalScalesRenderer: VerticalScalesRenderer, + previewBarsChartRenderer: BarChartRenderer) { + self.mainBarsRenderer = mainBarsRenderer + self.horizontalScalesRenderer = horizontalScalesRenderer + self.verticalScalesRenderer = verticalScalesRenderer + self.previewBarsChartRenderer = previewBarsChartRenderer + + self.mainBarsRenderer.optimizationLevel = BaseConstants.barsChartOptimizationLevel + self.previewBarsChartRenderer.optimizationLevel = BaseConstants.barsChartOptimizationLevel + + super.init(isZoomed: isZoomed) + } + + override func initialize(chartsCollection: ChartsCollection, initialDate: Date, totalHorizontalRange _: ClosedRange, totalVerticalRange _: ClosedRange) { + let (width, chartBars, totalHorizontalRange, totalVerticalRange) = BarChartRenderer.BarsData.initialComponents(chartsCollection: chartsCollection) + self.chartBars = chartBars + self.barsWidth = width + + super.initialize(chartsCollection: chartsCollection, + initialDate: initialDate, + totalHorizontalRange: totalHorizontalRange, + totalVerticalRange: totalVerticalRange) + } + + override func setupInitialChartRange(initialDate: Date) { + guard let first = chartsCollection.axisValues.first?.timeIntervalSince1970, + let last = chartsCollection.axisValues.last?.timeIntervalSince1970 else { return } + + let rangeStart = CGFloat(first) + let rangeEnd = CGFloat(last) + + if isZoomed { + let initalDate = CGFloat(initialDate.timeIntervalSince1970) + + initialHorizontalRange = max(initalDate - barsWidth, rangeStart)...min(initalDate + GeneralChartComponentConstants.defaultZoomedRangeLength - barsWidth, rangeEnd) + initialVerticalRange = totalVerticalRange + } else { + super.setupInitialChartRange(initialDate: initialDate) + } + } + + + override func willAppear(animated: Bool) { + mainBarsRenderer.bars = self.chartBars + previewBarsChartRenderer.bars = self.chartBars + + previewBarsChartRenderer.setup(verticalRange: totalVerticalRange, animated: animated) + previewBarsChartRenderer.setup(horizontalRange: totalHorizontalRange, animated: animated) + + setupMainChart(verticalRange: initialVerticalRange, animated: animated) + setupMainChart(horizontalRange: initialHorizontalRange, animated: animated) + + updateChartVerticalRanges(horizontalRange: initialHorizontalRange, animated: animated) + + super.willAppear(animated: animated) + + updatePreviewRangeClosure?(currentChartHorizontalRangeFraction, animated) + setConponentsVisible(visible: true, animated: animated) + updateHorizontalLimitLabels(animated: animated, forceUpdate: true) + } + + override func chartRangeDidUpdated(_ updatedRange: ClosedRange) { + super.chartRangeDidUpdated(updatedRange) + if !isZoomed { + initialHorizontalRange = updatedRange + } + setupMainChart(horizontalRange: updatedRange, animated: false) + updateHorizontalLimitLabels(animated: true, forceUpdate: false) + updateChartVerticalRanges(horizontalRange: updatedRange, animated: true) + } + + func updateHorizontalLimitLabels(animated: Bool, forceUpdate: Bool) { + updateHorizontalLimitLabels(horizontalScalesRenderer: horizontalScalesRenderer, + horizontalRange: currentHorizontalMainChartRange, + scaleType: isZoomed ? .hour : .day, + forceUpdate: forceUpdate, + animated: animated) + } + + func prepareAppearanceAnimation(horizontalRnage: ClosedRange) { + setupMainChart(horizontalRange: horizontalRnage, animated: false) + setConponentsVisible(visible: false, animated: false) + } + + func setConponentsVisible(visible: Bool, animated: Bool) { + mainBarsRenderer.setVisible(visible, animated: animated) + horizontalScalesRenderer.setVisible(visible, animated: animated) + verticalScalesRenderer.setVisible(visible, animated: animated) + previewBarsChartRenderer.setVisible(visible, animated: animated) + } + + func setupMainChart(horizontalRange: ClosedRange, animated: Bool) { + mainBarsRenderer.setup(horizontalRange: horizontalRange, animated: animated) + horizontalScalesRenderer.setup(horizontalRange: horizontalRange, animated: animated) + verticalScalesRenderer.setup(horizontalRange: horizontalRange, animated: animated) + } + + var visibleBars: BarChartRenderer.BarsData { + let visibleComponents: [BarChartRenderer.BarsData.Component] = chartVisibility.enumerated().compactMap { args in + args.element ? chartBars.components[args.offset] : nil + } + return BarChartRenderer.BarsData(barWidth: chartBars.barWidth, + locations: chartBars.locations, + components: visibleComponents) + } + + func updateChartVerticalRanges(horizontalRange: ClosedRange, animated: Bool) { + if let range = BarChartRenderer.BarsData.verticalRange(bars: visibleBars, + calculatingRange: horizontalRange, + addBounds: true) { + let (range, labels) = verticalLimitsLabels(verticalRange: range) + if verticalScalesRenderer.verticalRange.end != range { + verticalScalesRenderer.setup(verticalLimitsLabels: labels, animated: animated) + } + verticalScalesRenderer.setVisible(true, animated: animated) + + setupMainChart(verticalRange: range, animated: animated) + } else { + verticalScalesRenderer.setVisible(false, animated: animated) + } + + if let range = BarChartRenderer.BarsData.verticalRange(bars: visibleBars) { + previewBarsChartRenderer.setup(verticalRange: range, animated: animated) + } + } + + func setupMainChart(verticalRange: ClosedRange, animated: Bool) { + mainBarsRenderer.setup(verticalRange: verticalRange, animated: animated) + horizontalScalesRenderer.setup(verticalRange: verticalRange, animated: animated) + verticalScalesRenderer.setup(verticalRange: verticalRange, animated: animated) + } + + override func updateChartsVisibility(visibility: [Bool], animated: Bool) { + super.updateChartsVisibility(visibility: visibility, animated: animated) + for (index, isVisible) in visibility.enumerated() { + mainBarsRenderer.setComponentVisible(isVisible, at: index, animated: animated) + previewBarsChartRenderer.setComponentVisible(isVisible, at: index, animated: animated) + } + updateChartVerticalRanges(horizontalRange: currentHorizontalMainChartRange, animated: true) + } + + var visibleChartValues: [ChartsCollection.Chart] { + let visibleCharts: [ChartsCollection.Chart] = chartVisibility.enumerated().compactMap { args in + args.element ? chartsCollection.chartValues[args.offset] : nil + } + return visibleCharts + } + + override func chartDetailsViewModel(closestDate: Date, pointIndex: Int) -> ChartDetailsViewModel { + var viewModel = super.chartDetailsViewModel(closestDate: closestDate, pointIndex: pointIndex) + let visibleChartValues = self.visibleChartValues + let totalSumm: CGFloat = visibleChartValues.map { CGFloat($0.values[pointIndex]) }.reduce(0, +) + + viewModel.totalValue = ChartDetailsViewModel.Value(prefix: nil, + title: "Total", + value: BaseConstants.detailsNumberFormatter.string(from: totalSumm), + color: .white, + visible: visibleChartValues.count > 1) + return viewModel + } + + override var currentMainRangeRenderer: BaseChartRenderer { + return mainBarsRenderer + } + + override var currentPreviewRangeRenderer: BaseChartRenderer { + return previewBarsChartRenderer + } + + override func showDetailsView(at chartPosition: CGFloat, detailsViewPosition: CGFloat, dataIndex: Int, date: Date, animted: Bool) { + let rangeWithOffset = detailsViewPosition - barsWidth / currentHorizontalMainChartRange.distance * chartFrame().width / 2 + super.showDetailsView(at: chartPosition, detailsViewPosition: rangeWithOffset, dataIndex: dataIndex, date: date, animted: animted) + mainBarsRenderer.setSelectedIndex(dataIndex, animated: true) + } + + override func hideDetailsView(animated: Bool) { + super.hideDetailsView(animated: animated) + + mainBarsRenderer.setSelectedIndex(nil, animated: animated) + } + override func apply(colorMode: ColorMode, animated: Bool) { + super.apply(colorMode: colorMode, animated: animated) + + horizontalScalesRenderer.labelsColor = colorMode.chartLabelsColor + verticalScalesRenderer.labelsColor = colorMode.chartLabelsColor + verticalScalesRenderer.axisXColor = colorMode.barChartStrongLinesColor + verticalScalesRenderer.horizontalLinesColor = colorMode.barChartStrongLinesColor + mainBarsRenderer.update(backgroundColor: colorMode.chartBackgroundColor, animated: false) + previewBarsChartRenderer.update(backgroundColor: colorMode.chartBackgroundColor, animated: false) + } + + override func updateChartRangeTitle(animated: Bool) { + let fromDate = Date(timeIntervalSince1970: TimeInterval(currentHorizontalMainChartRange.lowerBound + barsWidth)) + let toDate = Date(timeIntervalSince1970: TimeInterval(currentHorizontalMainChartRange.upperBound)) + if Calendar.utc.startOfDay(for: fromDate) == Calendar.utc.startOfDay(for: toDate) { + let stirng = BaseConstants.headerFullZoomedFormatter.string(from: fromDate) + self.setChartTitleClosure?(stirng, animated) + } else { + let stirng = "\(BaseConstants.headerMediumRangeFormatter.string(from: fromDate)) - \(BaseConstants.headerMediumRangeFormatter.string(from: toDate))" + self.setChartTitleClosure?(stirng, animated) + } + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/DailyBarsChartController.swift b/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/DailyBarsChartController.swift new file mode 100644 index 0000000000..ae83803bb1 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/DailyBarsChartController.swift @@ -0,0 +1,249 @@ +// +// DailyBarsChartController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class DailyBarsChartController: BaseChartController { + let barsController: BarsComponentController + let linesController: LinesComponentController + + override init(chartsCollection: ChartsCollection) { + let horizontalScalesRenderer = HorizontalScalesRenderer() + let verticalScalesRenderer = VerticalScalesRenderer() + barsController = BarsComponentController(isZoomed: false, + mainBarsRenderer: BarChartRenderer(), + horizontalScalesRenderer: horizontalScalesRenderer, + verticalScalesRenderer: verticalScalesRenderer, + previewBarsChartRenderer: BarChartRenderer()) + linesController = LinesComponentController(isZoomed: true, + userLinesTransitionAnimation: false, + mainLinesRenderer: LinesChartRenderer(), + horizontalScalesRenderer: horizontalScalesRenderer, + verticalScalesRenderer: verticalScalesRenderer, + verticalLineRenderer: VerticalLinesRenderer(), + lineBulletsRenerer: LineBulletsRenerer(), + previewLinesChartRenderer: LinesChartRenderer()) + + super.init(chartsCollection: chartsCollection) + + [barsController, linesController].forEach { controller in + controller.chartFrame = { [unowned self] in self.chartFrame() } + controller.cartViewBounds = { [unowned self] in self.cartViewBounds() } + controller.zoomInOnDateClosure = { [unowned self] date in + self.didTapZoomIn(date: date) + } + controller.setChartTitleClosure = { [unowned self] (title, animated) in + self.setChartTitleClosure?(title, animated) + } + controller.setDetailsViewPositionClosure = { [unowned self] (position) in + self.setDetailsViewPositionClosure?(position) + } + controller.setDetailsChartVisibleClosure = { [unowned self] (visible, animated) in + self.setDetailsChartVisibleClosure?(visible, animated) + } + controller.setDetailsViewModel = { [unowned self] (viewModel, animated) in + self.setDetailsViewModel?(viewModel, animated) + } + controller.updatePreviewRangeClosure = { [unowned self] (fraction, animated) in + self.chartRangeUpdatedClosure?(fraction, animated) + } + controller.chartRangePagingClosure = { [unowned self] (isEnabled, pageSize) in + self.setChartRangePagingEnabled(isEnabled: isEnabled, minimumSelectionSize: pageSize) + } + } + } + + override var mainChartRenderers: [ChartViewRenderer] { + return [barsController.mainBarsRenderer, + linesController.mainLinesRenderer, + barsController.horizontalScalesRenderer, + barsController.verticalScalesRenderer, + linesController.verticalLineRenderer, + linesController.lineBulletsRenerer, +// performanceRenderer + ] + } + + override var navigationRenderers: [ChartViewRenderer] { + return [barsController.previewBarsChartRenderer, + linesController.previewLinesChartRenderer] + } + + override func initializeChart() { + barsController.initialize(chartsCollection: initialChartsCollection, + initialDate: Date(), + totalHorizontalRange: BaseConstants.defaultRange, + totalVerticalRange: BaseConstants.defaultRange) + switchToChart(chartsCollection: barsController.chartsCollection, isZoomed: false, animated: false) + } + + func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) { + if animated { + TimeInterval.setDefaultSuration(.expandAnimationDuration) + DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) { + TimeInterval.setDefaultSuration(.osXDuration) + } + } + + super.isZoomed = isZoomed + if isZoomed { + let toHorizontalRange = linesController.initialHorizontalRange + let destinationHorizontalRange = (toHorizontalRange.lowerBound - barsController.barsWidth)...(toHorizontalRange.upperBound - barsController.barsWidth) + let initialChartVerticalRange = lineProportionAnimationRange() + + linesController.mainLinesRenderer.setup(horizontalRange: barsController.currentHorizontalMainChartRange, animated: false) + linesController.previewLinesChartRenderer.setup(horizontalRange: barsController.currentPreviewHorizontalRange, animated: false) + linesController.mainLinesRenderer.setup(verticalRange: initialChartVerticalRange, animated: false) + linesController.previewLinesChartRenderer.setup(verticalRange: initialChartVerticalRange, animated: false) + linesController.mainLinesRenderer.setVisible(false, animated: false) + linesController.previewLinesChartRenderer.setVisible(false, animated: false) + + barsController.setupMainChart(horizontalRange: destinationHorizontalRange, animated: animated) + barsController.previewBarsChartRenderer.setup(horizontalRange: linesController.totalHorizontalRange, animated: animated) + barsController.mainBarsRenderer.setVisible(false, animated: animated) + barsController.previewBarsChartRenderer.setVisible(false, animated: animated) + + linesController.willAppear(animated: animated) + barsController.willDisappear(animated: animated) + + linesController.updateChartsVisibility(visibility: linesController.chartLines.map { _ in true }, animated: false) + } else { + if !linesController.chartsCollection.isBlank { + barsController.hideDetailsView(animated: false) + let visibleVerticalRange = BarChartRenderer.BarsData.verticalRange(bars: barsController.visibleBars, + calculatingRange: barsController.initialHorizontalRange) ?? BaseConstants.defaultRange + barsController.mainBarsRenderer.setup(verticalRange: visibleVerticalRange, animated: false) + + let toHorizontalRange = barsController.initialHorizontalRange + let destinationChartVerticalRange = lineProportionAnimationRange() + + linesController.setupMainChart(horizontalRange: toHorizontalRange, animated: animated) + linesController.mainLinesRenderer.setup(verticalRange: destinationChartVerticalRange, animated: animated) + linesController.previewLinesChartRenderer.setup(verticalRange: destinationChartVerticalRange, animated: animated) + linesController.previewLinesChartRenderer.setup(horizontalRange: barsController.totalHorizontalRange, animated: animated) + linesController.mainLinesRenderer.setVisible(false, animated: animated) + linesController.previewLinesChartRenderer.setVisible(false, animated: animated) + } + + barsController.willAppear(animated: animated) + linesController.willDisappear(animated: animated) + } + + self.setBackButtonVisibilityClosure?(isZoomed, animated) + self.refreshChartToolsClosure?(animated) + } + + override func updateChartsVisibility(visibility: [Bool], animated: Bool) { + if isZoomed { + linesController.updateChartsVisibility(visibility: visibility, animated: animated) + } else { + barsController.updateChartsVisibility(visibility: visibility, animated: animated) + } + } + + var visibleChartValues: [ChartsCollection.Chart] { + let visibility = isZoomed ? linesController.chartVisibility : barsController.chartVisibility + let collection = isZoomed ? linesController.chartsCollection : barsController.chartsCollection + let visibleCharts: [ChartsCollection.Chart] = visibility.enumerated().compactMap { args in + args.element ? collection.chartValues[args.offset] : nil + } + return visibleCharts + } + + override var actualChartVisibility: [Bool] { + return isZoomed ? linesController.chartVisibility : barsController.chartVisibility + } + + override var actualChartsCollection: ChartsCollection { + return isZoomed ? linesController.chartsCollection : barsController.chartsCollection + } + + override func chartInteractionDidBegin(point: CGPoint) { + if isZoomed { + linesController.chartInteractionDidBegin(point: point) + } else { + barsController.chartInteractionDidBegin(point: point) + } + } + + override func chartInteractionDidEnd() { + if isZoomed { + linesController.chartInteractionDidEnd() + } else { + barsController.chartInteractionDidEnd() + } + } + + override var currentChartHorizontalRangeFraction: ClosedRange { + if isZoomed { + return linesController.currentChartHorizontalRangeFraction + } else { + return barsController.currentChartHorizontalRangeFraction + } + } + + override func cancelChartInteraction() { + if isZoomed { + return linesController.hideDetailsView(animated: true) + } else { + return barsController.hideDetailsView(animated: true) + } + } + + override func didTapZoomIn(date: Date) { + guard isZoomed == false else { return } + if isZoomed { + return linesController.hideDetailsView(animated: true) + } + self.getDetailsData?(date, { updatedCollection in + if let updatedCollection = updatedCollection { + self.linesController.initialize(chartsCollection: updatedCollection, + initialDate: date, + totalHorizontalRange: 0...1, + totalVerticalRange: 0...1) + self.switchToChart(chartsCollection: updatedCollection, isZoomed: true, animated: true) + } + }) + } + + func lineProportionAnimationRange() -> ClosedRange { + let visibleLines = self.barsController.chartVisibility.enumerated().compactMap { $0.element ? self.linesController.chartLines[$0.offset] : nil } + let linesRange = LinesChartRenderer.LineData.verticalRange(lines: visibleLines) ?? BaseConstants.defaultRange + let barsRange = BarChartRenderer.BarsData.verticalRange(bars: self.barsController.visibleBars, + calculatingRange: self.linesController.totalHorizontalRange) ?? BaseConstants.defaultRange + let range = 0...(linesRange.upperBound / barsRange.distance * self.barsController.currentVerticalMainChartRange.distance) + return range + } + + override func didTapZoomOut() { + cancelChartInteraction() + switchToChart(chartsCollection: barsController.chartsCollection, isZoomed: false, animated: true) + } + + override func updateChartRange(_ rangeFraction: ClosedRange) { + if isZoomed { + return linesController.chartRangeFractionDidUpdated(rangeFraction) + } else { + return barsController.chartRangeFractionDidUpdated(rangeFraction) + } + } + + override func apply(colorMode: ColorMode, animated: Bool) { + super.apply(colorMode: colorMode, animated: animated) + + linesController.apply(colorMode: colorMode, animated: animated) + barsController.apply(colorMode: colorMode, animated: animated) + } + + override var drawChartVisibity: Bool { + return isZoomed + } +} + +//TODO: Убрать Performance полоŃки ŃĐ˛ĐµŃ€Đ·Ń Ń‡Đ°Ń€Ń‚ĐľĐ˛ (Не забыть) +//TODO: Добавить ховеры на кнопки diff --git a/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/LinesComponentController.swift b/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/LinesComponentController.swift new file mode 100644 index 0000000000..fc39a5f4c6 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/LinesComponentController.swift @@ -0,0 +1,210 @@ +// +// LinesComponentController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/14/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class LinesComponentController: GeneralChartComponentController { + let mainLinesRenderer: LinesChartRenderer + let horizontalScalesRenderer: HorizontalScalesRenderer + let verticalScalesRenderer: VerticalScalesRenderer + let verticalLineRenderer: VerticalLinesRenderer + let lineBulletsRenerer: LineBulletsRenerer + + let previewLinesChartRenderer: LinesChartRenderer + + private let zoomedLinesRenderer = LinesChartRenderer() + private let zoomedPreviewLinesRenderer = LinesChartRenderer() + + private let userLinesTransitionAnimation: Bool + + private(set) var chartLines: [LinesChartRenderer.LineData] = [] + + init(isZoomed: Bool, + userLinesTransitionAnimation: Bool, + mainLinesRenderer: LinesChartRenderer, + horizontalScalesRenderer: HorizontalScalesRenderer, + verticalScalesRenderer: VerticalScalesRenderer, + verticalLineRenderer: VerticalLinesRenderer, + lineBulletsRenerer: LineBulletsRenerer, + previewLinesChartRenderer: LinesChartRenderer) { + self.mainLinesRenderer = mainLinesRenderer + self.horizontalScalesRenderer = horizontalScalesRenderer + self.verticalScalesRenderer = verticalScalesRenderer + self.verticalLineRenderer = verticalLineRenderer + self.lineBulletsRenerer = lineBulletsRenerer + self.previewLinesChartRenderer = previewLinesChartRenderer + self.userLinesTransitionAnimation = userLinesTransitionAnimation + + super.init(isZoomed: isZoomed) + + self.mainLinesRenderer.lineWidth = BaseConstants.mainChartLineWidth + self.mainLinesRenderer.optimizationLevel = BaseConstants.linesChartOptimizationLevel + self.previewLinesChartRenderer.lineWidth = BaseConstants.previewChartLineWidth + self.previewLinesChartRenderer.optimizationLevel = BaseConstants.previewLinesChartOptimizationLevel + + self.lineBulletsRenerer.isEnabled = false + } + + override func initialize(chartsCollection: ChartsCollection, + initialDate: Date, + totalHorizontalRange _: ClosedRange, + totalVerticalRange _: ClosedRange) { + let (chartLines, totalHorizontalRange, totalVerticalRange) = LinesChartRenderer.LineData.initialComponents(chartsCollection: chartsCollection) + self.chartLines = chartLines + + self.lineBulletsRenerer.bullets = self.chartLines.map { LineBulletsRenerer.Bullet(coordinate: $0.points.first ?? .zero, + color: $0.color)} + + super.initialize(chartsCollection: chartsCollection, + initialDate: initialDate, + totalHorizontalRange: totalHorizontalRange, + totalVerticalRange: totalVerticalRange) + + self.mainLinesRenderer.setup(verticalRange: totalVerticalRange, animated: true) + } + + override func willAppear(animated: Bool) { + mainLinesRenderer.setLines(lines: self.chartLines, animated: animated && userLinesTransitionAnimation) + previewLinesChartRenderer.setLines(lines: self.chartLines, animated: animated && userLinesTransitionAnimation) + + previewLinesChartRenderer.setup(verticalRange: totalVerticalRange, animated: animated) + previewLinesChartRenderer.setup(horizontalRange: totalHorizontalRange, animated: animated) + + setupMainChart(verticalRange: initialVerticalRange, animated: animated) + setupMainChart(horizontalRange: initialHorizontalRange, animated: animated) + + updateChartVerticalRanges(horizontalRange: initialHorizontalRange, animated: animated) + + super.willAppear(animated: animated) + + updatePreviewRangeClosure?(currentChartHorizontalRangeFraction, animated) + setConponentsVisible(visible: true, animated: animated) + updateHorizontalLimitLabels(animated: animated, forceUpdate: true) + } + + override func chartRangeDidUpdated(_ updatedRange: ClosedRange) { + super.chartRangeDidUpdated(updatedRange) + if !isZoomed { + initialHorizontalRange = updatedRange + } + setupMainChart(horizontalRange: updatedRange, animated: false) + updateHorizontalLimitLabels(animated: true, forceUpdate: false) + updateChartVerticalRanges(horizontalRange: updatedRange, animated: true) + } + + func updateHorizontalLimitLabels(animated: Bool, forceUpdate: Bool) { + updateHorizontalLimitLabels(horizontalScalesRenderer: horizontalScalesRenderer, + horizontalRange: currentHorizontalMainChartRange, + scaleType: isZoomed ? .hour : .day, + forceUpdate: forceUpdate, + animated: animated) + } + + func prepareAppearanceAnimation(horizontalRnage: ClosedRange) { + setupMainChart(horizontalRange: horizontalRnage, animated: false) + setConponentsVisible(visible: false, animated: false) + } + + func setConponentsVisible(visible: Bool, animated: Bool) { + mainLinesRenderer.setVisible(visible, animated: animated) + horizontalScalesRenderer.setVisible(visible, animated: animated) + verticalScalesRenderer.setVisible(visible, animated: animated) + verticalLineRenderer.setVisible(visible, animated: animated) + previewLinesChartRenderer.setVisible(visible, animated: animated) + lineBulletsRenerer.setVisible(visible, animated: animated) + } + + func setupMainChart(horizontalRange: ClosedRange, animated: Bool) { + mainLinesRenderer.setup(horizontalRange: horizontalRange, animated: animated) + horizontalScalesRenderer.setup(horizontalRange: horizontalRange, animated: animated) + verticalScalesRenderer.setup(horizontalRange: horizontalRange, animated: animated) + verticalLineRenderer.setup(horizontalRange: horizontalRange, animated: animated) + lineBulletsRenerer.setup(horizontalRange: horizontalRange, animated: animated) + } + + var visibleLines: [LinesChartRenderer.LineData] { + return chartVisibility.enumerated().compactMap { $0.element ? chartLines[$0.offset] : nil } + } + + func updateChartVerticalRanges(horizontalRange: ClosedRange, animated: Bool) { + if let range = LinesChartRenderer.LineData.verticalRange(lines: visibleLines, + calculatingRange: horizontalRange, + addBounds: true) { + let (range, labels) = verticalLimitsLabels(verticalRange: range) + if verticalScalesRenderer.verticalRange.end != range { + verticalScalesRenderer.setup(verticalLimitsLabels: labels, animated: animated) + } + + setupMainChart(verticalRange: range, animated: animated) + verticalScalesRenderer.setVisible(true, animated: animated) + } else { + verticalScalesRenderer.setVisible(false, animated: animated) + } + + if let range = LinesChartRenderer.LineData.verticalRange(lines: visibleLines) { + previewLinesChartRenderer.setup(verticalRange: range, animated: animated) + } + } + + func setupMainChart(verticalRange: ClosedRange, animated: Bool) { + mainLinesRenderer.setup(verticalRange: verticalRange, animated: animated) + horizontalScalesRenderer.setup(verticalRange: verticalRange, animated: animated) + verticalScalesRenderer.setup(verticalRange: verticalRange, animated: animated) + verticalLineRenderer.setup(verticalRange: verticalRange, animated: animated) + lineBulletsRenerer.setup(verticalRange: verticalRange, animated: animated) + } + + override func updateChartsVisibility(visibility: [Bool], animated: Bool) { + super.updateChartsVisibility(visibility: visibility, animated: animated) + for (index, isVisible) in visibility.enumerated() { + mainLinesRenderer.setLineVisible(isVisible, at: index, animated: animated) + previewLinesChartRenderer.setLineVisible(isVisible, at: index, animated: animated) + lineBulletsRenerer.setLineVisible(isVisible, at: index, animated: animated) + } + updateChartVerticalRanges(horizontalRange: currentHorizontalMainChartRange, animated: true) + } + + override var currentMainRangeRenderer: BaseChartRenderer { + return mainLinesRenderer + } + + override var currentPreviewRangeRenderer: BaseChartRenderer { + return previewLinesChartRenderer + } + + override func showDetailsView(at chartPosition: CGFloat, detailsViewPosition: CGFloat, dataIndex: Int, date: Date, animted: Bool) { + super.showDetailsView(at: chartPosition, detailsViewPosition: detailsViewPosition, dataIndex: dataIndex, date: date, animted: animted) + verticalLineRenderer.values = [chartPosition] + verticalLineRenderer.isEnabled = true + + lineBulletsRenerer.isEnabled = true + lineBulletsRenerer.setVisible(true, animated: animted) + lineBulletsRenerer.bullets = chartLines.compactMap { chart in + return LineBulletsRenerer.Bullet(coordinate: chart.points[dataIndex], color: chart.color) + } + } + + override func hideDetailsView(animated: Bool) { + super.hideDetailsView(animated: animated) + + verticalLineRenderer.values = [] + verticalLineRenderer.isEnabled = false + lineBulletsRenerer.isEnabled = false + } + + override func apply(colorMode: ColorMode, animated: Bool) { + super.apply(colorMode: colorMode, animated: animated) + + horizontalScalesRenderer.labelsColor = colorMode.chartLabelsColor + verticalScalesRenderer.labelsColor = colorMode.chartLabelsColor + verticalScalesRenderer.axisXColor = colorMode.chartStrongLinesColor + verticalScalesRenderer.horizontalLinesColor = colorMode.chartHelperLinesColor + lineBulletsRenerer.setInnerColor(colorMode.chartBackgroundColor, animated: animated) + verticalLineRenderer.linesColor = colorMode.chartStrongLinesColor + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/StackedBarsChartController.swift b/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/StackedBarsChartController.swift new file mode 100644 index 0000000000..ab836d00d2 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/StackedBarsChartController.swift @@ -0,0 +1,243 @@ +// +// StackedBarsChartController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class StackedBarsChartController: BaseChartController { + let barsController: BarsComponentController + let zoomedBarsController: BarsComponentController + + override init(chartsCollection: ChartsCollection) { + let horizontalScalesRenderer = HorizontalScalesRenderer() + let verticalScalesRenderer = VerticalScalesRenderer() + barsController = BarsComponentController(isZoomed: false, + mainBarsRenderer: BarChartRenderer(), + horizontalScalesRenderer: horizontalScalesRenderer, + verticalScalesRenderer: verticalScalesRenderer, + previewBarsChartRenderer: BarChartRenderer()) + zoomedBarsController = BarsComponentController(isZoomed: true, + mainBarsRenderer: BarChartRenderer(), + horizontalScalesRenderer: horizontalScalesRenderer, + verticalScalesRenderer: verticalScalesRenderer, + previewBarsChartRenderer: BarChartRenderer()) + + super.init(chartsCollection: chartsCollection) + + [barsController, zoomedBarsController].forEach { controller in + controller.chartFrame = { [unowned self] in self.chartFrame() } + controller.cartViewBounds = { [unowned self] in self.cartViewBounds() } + controller.zoomInOnDateClosure = { [unowned self] date in + self.didTapZoomIn(date: date) + } + controller.setChartTitleClosure = { [unowned self] (title, animated) in + self.setChartTitleClosure?(title, animated) + } + controller.setDetailsViewPositionClosure = { [unowned self] (position) in + self.setDetailsViewPositionClosure?(position) + } + controller.setDetailsChartVisibleClosure = { [unowned self] (visible, animated) in + self.setDetailsChartVisibleClosure?(visible, animated) + } + controller.setDetailsViewModel = { [unowned self] (viewModel, animated) in + self.setDetailsViewModel?(viewModel, animated) + } + controller.updatePreviewRangeClosure = { [unowned self] (fraction, animated) in + self.chartRangeUpdatedClosure?(fraction, animated) + } + controller.chartRangePagingClosure = { [unowned self] (isEnabled, pageSize) in + self.setChartRangePagingEnabled(isEnabled: isEnabled, minimumSelectionSize: pageSize) + } + } + } + + override var mainChartRenderers: [ChartViewRenderer] { + return [barsController.mainBarsRenderer, + zoomedBarsController.mainBarsRenderer, + barsController.horizontalScalesRenderer, + barsController.verticalScalesRenderer, +// performanceRenderer + ] + } + + override var navigationRenderers: [ChartViewRenderer] { + return [barsController.previewBarsChartRenderer, + zoomedBarsController.previewBarsChartRenderer] + } + + override func initializeChart() { + barsController.initialize(chartsCollection: initialChartsCollection, + initialDate: Date(), + totalHorizontalRange: BaseConstants.defaultRange, + totalVerticalRange: BaseConstants.defaultRange) + switchToChart(chartsCollection: barsController.chartsCollection, isZoomed: false, animated: false) + } + + func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) { + if animated { + TimeInterval.setDefaultSuration(.expandAnimationDuration) + DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) { + TimeInterval.setDefaultSuration(.osXDuration) + } + } + + super.isZoomed = isZoomed + if isZoomed { + let toHorizontalRange = zoomedBarsController.initialHorizontalRange + let destinationHorizontalRange = (toHorizontalRange.lowerBound - barsController.barsWidth)...(toHorizontalRange.upperBound - barsController.barsWidth) + let verticalVisibleRange = barsController.currentVerticalMainChartRange + let initialVerticalRange = verticalVisibleRange.lowerBound...(verticalVisibleRange.upperBound + verticalVisibleRange.distance * 10) + + zoomedBarsController.mainBarsRenderer.setup(horizontalRange: barsController.currentHorizontalMainChartRange, animated: false) + zoomedBarsController.previewBarsChartRenderer.setup(horizontalRange: barsController.currentPreviewHorizontalRange, animated: false) + zoomedBarsController.mainBarsRenderer.setup(verticalRange: initialVerticalRange, animated: false) + zoomedBarsController.previewBarsChartRenderer.setup(verticalRange: initialVerticalRange, animated: false) + zoomedBarsController.mainBarsRenderer.setVisible(true, animated: false) + zoomedBarsController.previewBarsChartRenderer.setVisible(true, animated: false) + + barsController.setupMainChart(horizontalRange: destinationHorizontalRange, animated: animated) + barsController.previewBarsChartRenderer.setup(horizontalRange: zoomedBarsController.totalHorizontalRange, animated: animated) + barsController.mainBarsRenderer.setVisible(false, animated: animated) + barsController.previewBarsChartRenderer.setVisible(false, animated: animated) + + zoomedBarsController.willAppear(animated: animated) + barsController.willDisappear(animated: animated) + + zoomedBarsController.updateChartsVisibility(visibility: barsController.chartVisibility, animated: false) + zoomedBarsController.mainBarsRenderer.setup(verticalRange: zoomedBarsController.currentVerticalMainChartRange, animated: animated, timeFunction: .easeOut) + zoomedBarsController.previewBarsChartRenderer.setup(verticalRange: zoomedBarsController.currentPreviewVerticalRange, animated: animated, timeFunction: .easeOut) + } else { + if !zoomedBarsController.chartsCollection.isBlank { + barsController.hideDetailsView(animated: false) + barsController.chartVisibility = zoomedBarsController.chartVisibility + let visibleVerticalRange = BarChartRenderer.BarsData.verticalRange(bars: barsController.visibleBars, + calculatingRange: barsController.initialHorizontalRange) ?? BaseConstants.defaultRange + barsController.mainBarsRenderer.setup(verticalRange: visibleVerticalRange, animated: false) + + let toHorizontalRange = barsController.initialHorizontalRange + + let verticalVisibleRange = barsController.initialVerticalRange + let targetVerticalRange = verticalVisibleRange.lowerBound...(verticalVisibleRange.upperBound + verticalVisibleRange.distance * 10) + + zoomedBarsController.setupMainChart(horizontalRange: toHorizontalRange, animated: animated) + zoomedBarsController.mainBarsRenderer.setup(verticalRange: targetVerticalRange, animated: animated, timeFunction: .easeIn) + zoomedBarsController.previewBarsChartRenderer.setup(verticalRange: targetVerticalRange, animated: animated, timeFunction: .easeIn) + zoomedBarsController.previewBarsChartRenderer.setup(horizontalRange: barsController.totalHorizontalRange, animated: animated) + DispatchQueue.main.asyncAfter(deadline: .now() + .defaultDuration) { [weak self] in + self?.zoomedBarsController.mainBarsRenderer.setVisible(false, animated: false) + self?.zoomedBarsController.previewBarsChartRenderer.setVisible(false, animated: false) + } + } + + barsController.willAppear(animated: animated) + zoomedBarsController.willDisappear(animated: animated) + + if !zoomedBarsController.chartsCollection.isBlank { + barsController.updateChartsVisibility(visibility: zoomedBarsController.chartVisibility, animated: false) + } + } + + self.setBackButtonVisibilityClosure?(isZoomed, animated) + } + + override func updateChartsVisibility(visibility: [Bool], animated: Bool) { + if isZoomed { + zoomedBarsController.updateChartsVisibility(visibility: visibility, animated: animated) + } else { + barsController.updateChartsVisibility(visibility: visibility, animated: animated) + } + } + + var visibleChartValues: [ChartsCollection.Chart] { + let visibility = isZoomed ? zoomedBarsController.chartVisibility : barsController.chartVisibility + let collection = isZoomed ? zoomedBarsController.chartsCollection : barsController.chartsCollection + let visibleCharts: [ChartsCollection.Chart] = visibility.enumerated().compactMap { args in + args.element ? collection.chartValues[args.offset] : nil + } + return visibleCharts + } + + override var actualChartVisibility: [Bool] { + return isZoomed ? zoomedBarsController.chartVisibility : barsController.chartVisibility + } + + override var actualChartsCollection: ChartsCollection { + return isZoomed ? zoomedBarsController.chartsCollection : barsController.chartsCollection + } + + override func chartInteractionDidBegin(point: CGPoint) { + if isZoomed { + zoomedBarsController.chartInteractionDidBegin(point: point) + } else { + barsController.chartInteractionDidBegin(point: point) + } + } + + override func chartInteractionDidEnd() { + if isZoomed { + zoomedBarsController.chartInteractionDidEnd() + } else { + barsController.chartInteractionDidEnd() + } + } + + override var drawChartVisibity: Bool { + return true + } + + override var currentChartHorizontalRangeFraction: ClosedRange { + if isZoomed { + return zoomedBarsController.currentChartHorizontalRangeFraction + } else { + return barsController.currentChartHorizontalRangeFraction + } + } + + override func cancelChartInteraction() { + if isZoomed { + return zoomedBarsController.hideDetailsView(animated: true) + } else { + return barsController.hideDetailsView(animated: true) + } + } + + override func didTapZoomIn(date: Date) { + guard isZoomed == false else { return } + if isZoomed { + return zoomedBarsController.hideDetailsView(animated: true) + } + self.getDetailsData?(date, { updatedCollection in + if let updatedCollection = updatedCollection { + self.zoomedBarsController.initialize(chartsCollection: updatedCollection, + initialDate: date, + totalHorizontalRange: 0...1, + totalVerticalRange: 0...1) + self.switchToChart(chartsCollection: updatedCollection, isZoomed: true, animated: true) + } + }) + } + + override func didTapZoomOut() { + cancelChartInteraction() + switchToChart(chartsCollection: barsController.chartsCollection, isZoomed: false, animated: true) + } + + override func updateChartRange(_ rangeFraction: ClosedRange) { + if isZoomed { + return zoomedBarsController.chartRangeFractionDidUpdated(rangeFraction) + } else { + return barsController.chartRangeFractionDidUpdated(rangeFraction) + } + } + + override func apply(colorMode: ColorMode, animated: Bool) { + super.apply(colorMode: colorMode, animated: animated) + + zoomedBarsController.apply(colorMode: colorMode, animated: animated) + barsController.apply(colorMode: colorMode, animated: animated) + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/BarChartRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/BarChartRenderer.swift new file mode 100644 index 0000000000..73a6b52f42 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/BarChartRenderer.swift @@ -0,0 +1,293 @@ +// +// BarChartRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class BarChartRenderer: BaseChartRenderer { + struct BarsData { + static let blank = BarsData(barWidth: 1, locations: [], components: []) + var barWidth: CGFloat + var locations: [CGFloat] + var components: [Component] + + struct Component { + var color: UIColor + var values: [CGFloat] + } + } + + var fillToTop: Bool = false + private(set) lazy var selectedIndexAnimator: AnimationController = { + return AnimationController(current: 0, refreshClosure: self.refreshClosure) + }() + func setSelectedIndex(_ index: Int?, animated: Bool) { + let destinationValue: CGFloat = (index == nil) ? 0 : 1 + if animated { + if index != nil { + selectedBarIndex = index + } + self.selectedIndexAnimator.completionClosure = { + self.selectedBarIndex = index + } + guard self.selectedIndexAnimator.end != destinationValue else { return } + self.selectedIndexAnimator.animate(to: destinationValue, duration: .defaultDuration) + } else { + self.selectedIndexAnimator.set(current: destinationValue) + self.selectedBarIndex = index + } + } + + private var selectedBarIndex: Int? { + didSet { + setNeedsDisplay() + } + } + var generalUnselectedAlpha: CGFloat = 0.5 + + private var componentsAnimators: [AnimationController] = [] + var bars: BarsData = BarsData(barWidth: 1, locations: [], components: []) { + willSet { + if bars.components.count != newValue.components.count { + componentsAnimators = newValue.components.map { _ in AnimationController(current: 1, refreshClosure: self.refreshClosure) } + } + } + didSet { + setNeedsDisplay() + } + } + + func setComponentVisible(_ isVisible: Bool, at index: Int, animated: Bool) { + componentsAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + } + + private lazy var backgroundColorAnimator = AnimationController(current: UIColorContainer(color: .white), refreshClosure: refreshClosure) + func update(backgroundColor: UIColor, animated: Bool) { + if animated { + backgroundColorAnimator.animate(to: UIColorContainer(color: backgroundColor), duration: .defaultDuration) + } else { + backgroundColorAnimator.set(current: UIColorContainer(color: backgroundColor)) + } + } + + override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + guard isEnabled && verticalRange.current.distance > 0 && verticalRange.current.distance > 0 else { return } + let chartsAlpha = chartAlphaAnimator.current + if chartsAlpha == 0 { return } + + let range = renderRange(bounds: bounds, chartFrame: chartFrame) + + var selectedPaths: [[CGRect]] = bars.components.map { _ in [] } + var unselectedPaths: [[CGRect]] = bars.components.map { _ in [] } + + if var barIndex = bars.locations.firstIndex(where: { $0 >= range.lowerBound }) { + if fillToTop { + barIndex = max(0, barIndex - 1) + + while barIndex < bars.locations.count { + let currentLocation = bars.locations[barIndex] + let right = transform(toChartCoordinateHorizontal: currentLocation, chartFrame: chartFrame).roundedUpToPixelGrid() + let left = transform(toChartCoordinateHorizontal: currentLocation - bars.barWidth, chartFrame: chartFrame).roundedUpToPixelGrid() + + var summ: CGFloat = 0 + for (index, component) in bars.components.enumerated() { + summ += componentsAnimators[index].current * component.values[barIndex] + } + guard summ > 0 else { + barIndex += 1 + continue + } + + var stackedValue: CGFloat = 0 + for (index, component) in bars.components.enumerated() { + let visibilityPercent = componentsAnimators[index].current + if visibilityPercent == 0 { continue } + + let bottomFraction = stackedValue + let topFraction = stackedValue + ((component.values[barIndex] * visibilityPercent) / summ) + + let rect = CGRect(x: left, + y: chartFrame.maxY - chartFrame.height * topFraction, + width: right - left, + height: chartFrame.height * (topFraction - bottomFraction)) + if selectedBarIndex == barIndex { + selectedPaths[index].append(rect) + } else { + unselectedPaths[index].append(rect) + } + stackedValue = topFraction + } + if currentLocation > range.upperBound { + break + } + barIndex += 1 + } + + for (index, component) in bars.components.enumerated() { + context.saveGState() + context.setFillColor(component.color.withAlphaComponent(chartsAlpha * component.color.alphaValue).cgColor) + context.fill(selectedPaths[index]) + let resultAlpha: CGFloat = 1.0 - (1.0 - generalUnselectedAlpha) * selectedIndexAnimator.current + context.setFillColor(component.color.withAlphaComponent(chartsAlpha * component.color.alphaValue * resultAlpha).cgColor) + context.fill(unselectedPaths[index]) + context.restoreGState() + } + } else { + var selectedPaths: [[CGRect]] = bars.components.map { _ in [] } + barIndex = max(0, barIndex - 1) + + var currentLocation = bars.locations[barIndex] + var leftX = transform(toChartCoordinateHorizontal: currentLocation - bars.barWidth, chartFrame: chartFrame) + var rightX: CGFloat = 0 + + let startPoint = CGPoint(x: leftX, + y: transform(toChartCoordinateVertical: verticalRange.current.lowerBound, chartFrame: chartFrame)) + + var backgourndPaths: [[CGPoint]] = bars.components.map { _ in Array() } + let itemsCount = ((bars.locations.count - barIndex) * 2) + 4 + for path in backgourndPaths.indices { + backgourndPaths[path].reserveCapacity(itemsCount) + backgourndPaths[path].append(startPoint) + } + var maxValues: [CGFloat] = bars.components.map { _ in 0 } + while barIndex < bars.locations.count { + currentLocation = bars.locations[barIndex] + rightX = transform(toChartCoordinateHorizontal: currentLocation, chartFrame: chartFrame) + + var stackedValue: CGFloat = 0 + var bottomY: CGFloat = transform(toChartCoordinateVertical: stackedValue, chartFrame: chartFrame) + for (index, component) in bars.components.enumerated() { + let visibilityPercent = componentsAnimators[index].current + if visibilityPercent == 0 { continue } + + let height = component.values[barIndex] * visibilityPercent + stackedValue += height + let topY = transform(toChartCoordinateVertical: stackedValue, chartFrame: chartFrame) + let componentHeight = (bottomY - topY) + maxValues[index] = max(maxValues[index], componentHeight) + if selectedBarIndex == barIndex { + let rect = CGRect(x: leftX, + y: topY, + width: rightX - leftX, + height: componentHeight) + selectedPaths[index].append(rect) + } + backgourndPaths[index].append(CGPoint(x: leftX, y: topY)) + backgourndPaths[index].append(CGPoint(x: rightX, y: topY)) + bottomY = topY + } + if currentLocation > range.upperBound { + break + } + leftX = rightX + barIndex += 1 + } + + let endPoint = CGPoint(x: transform(toChartCoordinateHorizontal: currentLocation, chartFrame: chartFrame).roundedUpToPixelGrid(), + y: transform(toChartCoordinateVertical: verticalRange.current.lowerBound, chartFrame: chartFrame)) + let colorOffset = Double((1.0 - (1.0 - generalUnselectedAlpha) * selectedIndexAnimator.current) * chartsAlpha) + + for (index, component) in bars.components.enumerated().reversed() { + if maxValues[index] < optimizationLevel { + continue + } + context.saveGState() + backgourndPaths[index].append(endPoint) + + context.setFillColor(UIColor.valueBetween(start: backgroundColorAnimator.current.color, + end: component.color, + offset: colorOffset).cgColor) + context.beginPath() + context.addLines(between: backgourndPaths[index]) + context.closePath() + context.fillPath() + context.restoreGState() + } + + for (index, component) in bars.components.enumerated().reversed() { + context.setFillColor(component.color.withAlphaComponent(chartsAlpha * component.color.alphaValue).cgColor) + context.fill(selectedPaths[index]) + } + } + } + } +} + +extension BarChartRenderer.BarsData { + static func initialComponents(chartsCollection: ChartsCollection) -> + (width: CGFloat, + chartBars: BarChartRenderer.BarsData, + totalHorizontalRange: ClosedRange, + totalVerticalRange: ClosedRange) { + let width: CGFloat + if chartsCollection.axisValues.count > 1 { + width = CGFloat(abs(chartsCollection.axisValues[1].timeIntervalSince1970 - chartsCollection.axisValues[0].timeIntervalSince1970)) + } else { + width = 1 + } + let components = chartsCollection.chartValues.map { BarChartRenderer.BarsData.Component(color: $0.color, + values: $0.values.map { CGFloat($0) }) } + let chartBars = BarChartRenderer.BarsData(barWidth: width, + locations: chartsCollection.axisValues.map { CGFloat($0.timeIntervalSince1970) }, + components: components) + + + + let totalVerticalRange = BarChartRenderer.BarsData.verticalRange(bars: chartBars) ?? 0...1 + let totalHorizontalRange = BarChartRenderer.BarsData.visibleHorizontalRange(bars: chartBars, width: width) ?? 0...1 + return (width: width, chartBars: chartBars, totalHorizontalRange: totalHorizontalRange, totalVerticalRange: totalVerticalRange) + } + + static func visibleHorizontalRange(bars: BarChartRenderer.BarsData, width: CGFloat) -> ClosedRange? { + guard let firstPoint = bars.locations.first, + let lastPoint = bars.locations.last, + firstPoint <= lastPoint else { + return nil + } + + return (firstPoint - width)...lastPoint + } + + static func verticalRange(bars: BarChartRenderer.BarsData, calculatingRange: ClosedRange? = nil, addBounds: Bool = false) -> ClosedRange? { + guard bars.components.count > 0 else { + return nil + } + if let calculatingRange = calculatingRange { + guard var index = bars.locations.firstIndex(where: { $0 >= calculatingRange.lowerBound && $0 <= calculatingRange.upperBound }) else { + return nil + } + + var vMax: CGFloat = bars.components[0].values[index] + while index < bars.locations.count { + var summ: CGFloat = 0 + for component in bars.components { + summ += component.values[index] + } + vMax = max(vMax, summ) + + if bars.locations[index] > calculatingRange.upperBound { + break + } + index += 1 + } + return 0...vMax + } else { + var index = 0 + + var vMax: CGFloat = bars.components[0].values[index] + while index < bars.locations.count { + var summ: CGFloat = 0 + for component in bars.components { + summ += component.values[index] + } + vMax = max(vMax, summ) + index += 1 + } + return 0...vMax + } + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/BaseChartRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/BaseChartRenderer.swift new file mode 100644 index 0000000000..63627566e7 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/BaseChartRenderer.swift @@ -0,0 +1,116 @@ +// +// BaseChartRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +private let exponentialAnimationTrashold: CGFloat = 100 + +class BaseChartRenderer: ChartViewRenderer { + var containerViews: [UIView] = [] + + var optimizationLevel: CGFloat = 1 { + didSet { + setNeedsDisplay() + } + } + var isEnabled: Bool = true { + didSet { + setNeedsDisplay() + } + } + + private(set) lazy var chartAlphaAnimator: AnimationController = { + return AnimationController(current: 1, refreshClosure: self.refreshClosure) + }() + func setVisible(_ visible: Bool, animated: Bool) { + let destinationValue: CGFloat = visible ? 1 : 0 + guard self.chartAlphaAnimator.end != destinationValue else { return } + if animated { + self.chartAlphaAnimator.animate(to: destinationValue, duration: .defaultDuration) + } else { + self.chartAlphaAnimator.set(current: destinationValue) + } + } + + lazy var horizontalRange = AnimationController>(current: 0...1, refreshClosure: refreshClosure) + lazy var verticalRange = AnimationController>(current: 0...1, refreshClosure: refreshClosure) + + func setup(verticalRange: ClosedRange, animated: Bool, timeFunction: TimeFunction? = nil) { + guard self.verticalRange.end != verticalRange else { + self.verticalRange.timeFunction = timeFunction ?? .linear + return + } + if animated { + let function: TimeFunction + if let timeFunction = timeFunction { + function = timeFunction + } else if self.verticalRange.current.distance > 0 && verticalRange.distance > 0 { + if self.verticalRange.current.distance / verticalRange.distance > exponentialAnimationTrashold { + function = .easeIn + } else if verticalRange.distance / self.verticalRange.current.distance > exponentialAnimationTrashold { + function = .easeOut + } else { + function = .linear + } + } else { + function = .linear + } + + self.verticalRange.animate(to: verticalRange, duration: .defaultDuration, timeFunction: function) + } else { + self.verticalRange.set(current: verticalRange) + } + } + + func setup(horizontalRange: ClosedRange, animated: Bool) { + guard self.horizontalRange.end != horizontalRange else { return } + if animated { + let animationCurve: TimeFunction = self.horizontalRange.current.distance > horizontalRange.distance ? .easeOut : .easeIn + self.horizontalRange.animate(to: horizontalRange, duration: .defaultDuration, timeFunction: animationCurve) + } else { + self.horizontalRange.set(current: horizontalRange) + } + } + + func transform(toChartCoordinateHorizontal x: CGFloat, chartFrame: CGRect) -> CGFloat { + return chartFrame.origin.x + (x - horizontalRange.current.lowerBound) / horizontalRange.current.distance * chartFrame.width + } + + func transform(toChartCoordinateVertical y: CGFloat, chartFrame: CGRect) -> CGFloat { + return chartFrame.height + chartFrame.origin.y - (y - verticalRange.current.lowerBound) / verticalRange.current.distance * chartFrame.height + } + + func transform(toChartCoordinate point: CGPoint, chartFrame: CGRect) -> CGPoint { + return CGPoint(x: transform(toChartCoordinateHorizontal: point.x, chartFrame: chartFrame), + y: transform(toChartCoordinateVertical: point.y, chartFrame: chartFrame)) + } + + func renderRange(bounds: CGRect, chartFrame: CGRect) -> ClosedRange { + let lowerBound = horizontalRange.current.lowerBound - chartFrame.origin.x / chartFrame.width * horizontalRange.current.distance + let upperBound = horizontalRange.current.upperBound + (bounds.width - chartFrame.width - chartFrame.origin.x) / chartFrame.width * horizontalRange.current.distance + guard lowerBound <= upperBound else { + print("Error: Unexpecated bounds range!") + return 0...1 + } + return lowerBound...upperBound + } + + func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + fatalError("abstract") + } + + func setNeedsDisplay() { + containerViews.forEach { $0.setNeedsDisplay() } + } + + var refreshClosure: () -> Void { + return { [weak self] in + self?.setNeedsDisplay() + } + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/ChartDetailsRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/ChartDetailsRenderer.swift new file mode 100644 index 0000000000..ad61ff5dd9 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/ChartDetailsRenderer.swift @@ -0,0 +1,147 @@ +// +// ChartDetailsRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/13/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class ChartDetailsRenderer: BaseChartRenderer, ColorModeContainer { + private lazy var colorAnimator = AnimationController(current: 1, refreshClosure: refreshClosure) + private var fromColorMode: ColorMode = .day + private var currentColorMode: ColorMode = .day + func apply(colorMode: ColorMode, animated: Bool) { + if currentColorMode != colorMode { + fromColorMode = currentColorMode + currentColorMode = colorMode + if animated { + colorAnimator.set(current: 0) + colorAnimator.animate(to: 1, duration: .defaultDuration) + } else { + colorAnimator.set(current: 1) + } + } + } + + private var valuesAnimators: [AnimationController] = [] + func setValueVisible(_ isVisible: Bool, at index: Int, animated: Bool) { + valuesAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + } + var detailsViewModel: ChartDetailsViewModel = .blank { + didSet { + if detailsViewModel.values.count != valuesAnimators.count { + valuesAnimators = detailsViewModel.values.map { _ in AnimationController(current: 1, refreshClosure: refreshClosure) } + } + setNeedsDisplay() + } + } + + var detailsViewPosition: CGFloat = 0 { + didSet { + setNeedsDisplay() + } + } + var detailViewPositionOffset: CGFloat = 10 + var detailViewTopOffset: CGFloat = 10 + private var iconWidth: CGFloat = 10 + private var margins: CGFloat = 10 + private let cornerRadius: CGFloat = 5 + private var rowHeight: CGFloat = 20 + private let titleFont = UIFont.systemFont(ofSize: 14, weight: .bold) + private let prefixFont = UIFont.systemFont(ofSize: 14, weight: .bold) + private let labelsFont = UIFont.systemFont(ofSize: 14, weight: .medium) + private let valuesFont = UIFont.systemFont(ofSize: 14, weight: .bold) + private let labelsColor: UIColor = .black + + private(set) var previousRenderBannerFrame: CGRect = .zero + override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + previousRenderBannerFrame = .zero + guard isEnabled && verticalRange.current.distance > 0 && verticalRange.current.distance > 0 else { return } + let generalAlpha = chartAlphaAnimator.current + if generalAlpha == 0 { return } + + let widths: [(prefix: CGFloat, label: CGFloat, value: CGFloat)] = detailsViewModel.values.map { value in + var prefixWidth: CGFloat = 0 + if let prefixText = value.prefix { + prefixWidth = (prefixText as NSString).boundingRect(with: bounds.size, + options: .usesLineFragmentOrigin, + attributes: [.font: prefixFont], + context: nil).width.rounded(.up) + margins + } + + let labelWidth = (value.title as NSString).boundingRect(with: bounds.size, + options: .usesLineFragmentOrigin, + attributes: [.font: labelsFont], + context: nil).width.rounded(.up) + margins + + let valueWidth = (value.value as NSString).boundingRect(with: bounds.size, + options: .usesLineFragmentOrigin, + attributes: [.font: valuesFont], + context: nil).width.rounded(.up) + return (prefixWidth, labelWidth, valueWidth) + } + + let titleWidth = (detailsViewModel.title as NSString).boundingRect(with: bounds.size, + options: .usesLineFragmentOrigin, + attributes: [.font: titleFont], + context: nil).width + let prefixesWidth = widths.map { $0.prefix }.max() ?? 0 + let labelsWidth = widths.map { $0.label }.max() ?? 0 + let valuesWidth = widths.map { $0.value }.max() ?? 0 + + let totalWidth: CGFloat = max(prefixesWidth + labelsWidth + valuesWidth, titleWidth + iconWidth) + margins * 2 + let totalHeight: CGFloat = CGFloat(detailsViewModel.values.count + 1) * rowHeight + margins * 2 + let backgroundColor = UIColor.valueBetween(start: fromColorMode.chartDetailsViewColor, + end: currentColorMode.chartDetailsViewColor, + offset: Double(colorAnimator.current)) + let titleAndTextColor = UIColor.valueBetween(start: fromColorMode.chartDetailsTextColor, + end: currentColorMode.chartDetailsTextColor, + offset: Double(colorAnimator.current)) + let detailsViewFrame: CGRect + if totalWidth + detailViewTopOffset > detailsViewPosition { + detailsViewFrame = CGRect(x: detailsViewPosition + detailViewTopOffset, + y: detailViewTopOffset + chartFrame.minY, + width: totalWidth, + height: totalHeight) + } else { + detailsViewFrame = CGRect(x: detailsViewPosition - totalWidth - detailViewTopOffset, + y: detailViewTopOffset + chartFrame.minY, + width: totalWidth, + height: totalHeight) + } + previousRenderBannerFrame = detailsViewFrame + context.saveGState() + context.setFillColor(backgroundColor.cgColor) + context.beginPath() + context.addPath(CGPath(roundedRect: detailsViewFrame, cornerWidth: 5, cornerHeight: 5, transform: nil)) + context.fillPath() + context.endPage() + context.restoreGState() + + var drawY = detailsViewFrame.minY + margins + (rowHeight - titleFont.pointSize) / 2 + (detailsViewModel.title as NSString).draw(at: CGPoint(x: detailsViewFrame.minX + margins, y: drawY), withAttributes: [.font: titleFont, + .foregroundColor: titleAndTextColor]) + drawY += rowHeight + + for (index, row) in widths.enumerated() { + let value = detailsViewModel.values[index] + if let prefixText = value.prefix { + (prefixText as NSString).draw(at: CGPoint(x: detailsViewFrame.minX + prefixesWidth - row.prefix, + y: drawY), + withAttributes: [.font: prefixText, .foregroundColor: titleAndTextColor]) + } + + (value.title as NSString).draw(at: CGPoint(x: detailsViewFrame.minX + prefixesWidth + margins, + y: drawY), + withAttributes: [.font: labelsFont, .foregroundColor: titleAndTextColor]) + + (value.value as NSString).draw(at: CGPoint(x: detailsViewFrame.minX + prefixesWidth + labelsWidth + valuesWidth - row.value + margins, + y: drawY), + withAttributes: [.font: labelsFont, .foregroundColor: value.color]) + + drawY += rowHeight + } + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/HorizontalScalesRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/HorizontalScalesRenderer.swift new file mode 100644 index 0000000000..3ab90ef546 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/HorizontalScalesRenderer.swift @@ -0,0 +1,99 @@ +// +// HorizontalScalesRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/8/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class HorizontalScalesRenderer: BaseChartRenderer { + private var horizontalLabels: [LinesChartLabel] = [] + private var animatedHorizontalLabels: [AnimatedLinesChartLabels] = [] + + var labelsVerticalOffset: CGFloat = 8 + var labelsFont: UIFont = .systemFont(ofSize: 11) + var labelsColor: UIColor = .gray + + func setup(labels: [LinesChartLabel], animated: Bool) { + if animated { + var labelsToKeepVisible: [LinesChartLabel] = [] + let labelsToHide: [LinesChartLabel] + var labelsToShow: [LinesChartLabel] = [] + + for label in labels { + if horizontalLabels.contains(label) { + labelsToKeepVisible.append(label) + } else { + labelsToShow.append(label) + } + } + labelsToHide = horizontalLabels.filter { !labels.contains($0) } + animatedHorizontalLabels.removeAll() + horizontalLabels = labelsToKeepVisible + + let showAnimation = AnimatedLinesChartLabels(labels: labelsToShow, alphaAnimator: AnimationController(current: 1.0, refreshClosure: refreshClosure)) + showAnimation.isAppearing = true + showAnimation.alphaAnimator.set(current: 0) + showAnimation.alphaAnimator.animate(to: 1, duration: .defaultDuration) + showAnimation.alphaAnimator.completionClosure = { [weak self, weak showAnimation] in + guard let self = self, let showAnimation = showAnimation else { return } + self.animatedHorizontalLabels.removeAll(where: { $0 === showAnimation }) + self.horizontalLabels = labels + } + + let hideAnimation = AnimatedLinesChartLabels(labels: labelsToHide, alphaAnimator: AnimationController(current: 1.0, refreshClosure: refreshClosure)) + hideAnimation.isAppearing = false + hideAnimation.alphaAnimator.set(current: 1) + hideAnimation.alphaAnimator.animate(to: 0, duration: .defaultDuration) + hideAnimation.alphaAnimator.completionClosure = { [weak self, weak hideAnimation] in + guard let self = self, let hideAnimation = hideAnimation else { return } + self.animatedHorizontalLabels.removeAll(where: { $0 === hideAnimation }) + } + + animatedHorizontalLabels.append(showAnimation) + animatedHorizontalLabels.append(hideAnimation) + } else { + horizontalLabels = labels + animatedHorizontalLabels = [] + } + } + + override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + guard isEnabled && verticalRange.current.distance > 0 && verticalRange.current.distance > 0 else { return } + let itemsAlpha = chartAlphaAnimator.current + guard itemsAlpha > 0 else { return } + + let range = renderRange(bounds: bounds, chartFrame: chartFrame) + + func drawHorizontalLabels(_ labels: [LinesChartLabel], color: UIColor) { + let attributes: [NSAttributedString.Key : Any] = [.foregroundColor: color, + .font: labelsFont] + let y = chartFrame.origin.y + chartFrame.height + labelsVerticalOffset + + if let start = labels.firstIndex(where: { $0.value > range.lowerBound }) { + for index in start.. range.upperBound { + break + } + } + } + } + let labelColorAlpha = labelsColor.alphaValue * itemsAlpha + drawHorizontalLabels(horizontalLabels, color: labelsColor.withAlphaComponent(labelColorAlpha * itemsAlpha)) + for animation in animatedHorizontalLabels { + let color = labelsColor.withAlphaComponent(animation.alphaAnimator.current * labelColorAlpha) + drawHorizontalLabels(animation.labels, color: color) + } + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/LineBulletsRenerer.swift b/submodules/Charts/Sources/Charts/Renderes/LineBulletsRenerer.swift new file mode 100644 index 0000000000..e0417719d7 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/LineBulletsRenerer.swift @@ -0,0 +1,67 @@ +// +// LineBulletsRenerer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/8/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class LineBulletsRenerer: BaseChartRenderer { + struct Bullet { + var coordinate: CGPoint + var color: UIColor + } + + var bullets: [Bullet] = [] { + willSet { + if alphaAnimators.count != newValue.count { + alphaAnimators = newValue.map { _ in AnimationController(current: 1.0, refreshClosure: refreshClosure) } + } + } + didSet { + setNeedsDisplay() + } + } + private var alphaAnimators: [AnimationController] = [] + + private lazy var innerColorAnimator = AnimationController(current: UIColorContainer(color: .white), refreshClosure: refreshClosure) + public func setInnerColor(_ color: UIColor, animated: Bool) { + if animated { + innerColorAnimator.animate(to: UIColorContainer(color: color), duration: .defaultDuration) + } else { + innerColorAnimator.set(current: UIColorContainer(color: color)) + } + } + + var linesWidth: CGFloat = 2 + var bulletRadius: CGFloat = 6 + + func setLineVisible(_ isVisible: Bool, at index: Int, animated: Bool) { + alphaAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + } + + override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + guard isEnabled && verticalRange.current.distance > 0 && verticalRange.current.distance > 0 else { return } + let generalAlpha = chartAlphaAnimator.current + if generalAlpha == 0 { return } + + for (index, bullet) in bullets.enumerated() { + let alpha = alphaAnimators[index].current + if alpha == 0 { continue } + + let centerX = transform(toChartCoordinateHorizontal: bullet.coordinate.x, chartFrame: chartFrame) + let centerY = transform(toChartCoordinateVertical: bullet.coordinate.y, chartFrame: chartFrame) + context.setFillColor(innerColorAnimator.current.color.withAlphaComponent(alpha).cgColor) + context.setStrokeColor(bullet.color.withAlphaComponent(alpha).cgColor) + context.setLineWidth(linesWidth) + let rect = CGRect(x: centerX - bulletRadius / 2, + y: centerY - bulletRadius / 2, + width: bulletRadius, + height: bulletRadius) + context.fillEllipse(in: rect) + context.strokeEllipse(in: rect) + } + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/LinesChartRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/LinesChartRenderer.swift new file mode 100644 index 0000000000..fe3cdd47ab --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/LinesChartRenderer.swift @@ -0,0 +1,538 @@ +// +// LinesChartRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class LinesChartRenderer: BaseChartRenderer { + struct LineData { + var color: UIColor + var points: [CGPoint] + } + + private var linesAlphaAnimators: [AnimationController] = [] + + var lineWidth: CGFloat = 1 { + didSet { + setNeedsDisplay() + } + } + private lazy var linesShapeAnimator = AnimationController(current: 1, refreshClosure: self.refreshClosure) + private var fromLines: [LineData] = [] + private var toLines: [LineData] = [] + + func setLines(lines: [LineData], animated: Bool) { + if toLines.count != lines.count { + linesAlphaAnimators = lines.map { _ in AnimationController(current: 1, refreshClosure: self.refreshClosure) } + } + if animated { + self.fromLines = self.toLines + self.toLines = lines + linesShapeAnimator.set(current: 1.0 - linesShapeAnimator.current) + linesShapeAnimator.completionClosure = { + self.fromLines = [] + } + linesShapeAnimator.animate(to: 1, duration: .defaultDuration) + } else { + self.fromLines = [] + self.toLines = lines + linesShapeAnimator.set(current: 1) + } + } + + func setLineVisible(_ isVisible: Bool, at index: Int, animated: Bool) { + linesAlphaAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + } + + override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + guard isEnabled && verticalRange.current.distance > 0 && verticalRange.current.distance > 0 else { return } + let chartsAlpha = chartAlphaAnimator.current + if chartsAlpha == 0 { return } + let range = renderRange(bounds: bounds, chartFrame: chartFrame) + + for (index, toLine) in toLines.enumerated() { + let alpha = linesAlphaAnimators[index].current * chartsAlpha + if alpha == 0 { continue } + context.setStrokeColor(toLine.color.withAlphaComponent(alpha).cgColor) + context.setLineWidth(lineWidth) + + if linesShapeAnimator.isAnimating { + let animationOffset = linesShapeAnimator.current + + let path = CGMutablePath() + let fromPoints = fromLines.safeElement(at: index)?.points ?? [] + let toPoints = toLines.safeElement(at: index)?.points ?? [] + + var fromIndex: Int? = fromPoints.firstIndex(where: { $0.x >= range.lowerBound }) + var toIndex: Int? = toPoints.firstIndex(where: { $0.x >= range.lowerBound }) + + let fromRange = verticalRange.start + let currentRange = verticalRange.current + let toRange = verticalRange.end + + func convertFromPoint(_ fromPoint: CGPoint) -> CGPoint { + return CGPoint(x: fromPoint.x, + y: (fromPoint.y - fromRange.lowerBound) / fromRange.distance * currentRange.distance + currentRange.lowerBound) + } + + func convertToPoint(_ toPoint: CGPoint) -> CGPoint { + return CGPoint(x: toPoint.x, + y: (toPoint.y - toRange.lowerBound) / toRange.distance * currentRange.distance + currentRange.lowerBound) + } + + var previousFromPoint: CGPoint + var previousToPoint: CGPoint + let startFromPoint: CGPoint? + let startToPoint: CGPoint? + + if let validFrom = fromIndex { + previousFromPoint = convertFromPoint(fromPoints[max(0, validFrom - 1)]) + startFromPoint = previousFromPoint + } else { + previousFromPoint = .zero + startFromPoint = nil + } + if let validTo = toIndex { + previousToPoint = convertToPoint(toPoints[max(0, validTo - 1)]) + startToPoint = previousToPoint + } else { + previousToPoint = .zero + startToPoint = nil + } + + var combinedPoints: [CGPoint] = [] + + func add(pointToDraw: CGPoint) { + if let startFromPoint = startFromPoint, + pointToDraw.x < startFromPoint.x { + let animatedPoint = CGPoint(x: pointToDraw.x, + y: CGFloat.valueBetween(start: startFromPoint.y, end: pointToDraw.y, offset: animationOffset)) + combinedPoints.append(transform(toChartCoordinate: animatedPoint, chartFrame: chartFrame)) + } else if let startToPoint = startToPoint, + pointToDraw.x < startToPoint.x { + let animatedPoint = CGPoint(x: pointToDraw.x, + y: CGFloat.valueBetween(start: startToPoint.y, end: pointToDraw.y, offset: 1 - animationOffset)) + combinedPoints.append(transform(toChartCoordinate: animatedPoint, chartFrame: chartFrame)) + } else { + combinedPoints.append(transform(toChartCoordinate: pointToDraw, chartFrame: chartFrame)) + } + } + + if previousToPoint != .zero && previousFromPoint != .zero { + add(pointToDraw: (previousToPoint.x < previousFromPoint.x ? previousToPoint : previousFromPoint)) + } else if previousToPoint != .zero { + add(pointToDraw: previousToPoint) + } else if previousFromPoint != .zero { + add(pointToDraw: previousFromPoint) + } + + while let validFromIndex = fromIndex, + let validToIndex = toIndex, + validFromIndex < fromPoints.count, + validToIndex < toPoints.count { + let currentFromPoint = convertFromPoint(fromPoints[validFromIndex]) + let currentToPoint = convertToPoint(toPoints[validToIndex]) + let pointToAdd: CGPoint + if currentFromPoint.x == currentToPoint.x { + pointToAdd = CGPoint.valueBetween(start: currentFromPoint, end: currentToPoint, offset: animationOffset) + previousFromPoint = currentFromPoint + previousToPoint = currentToPoint + fromIndex = validFromIndex + 1 + toIndex = validToIndex + 1 + } else if currentFromPoint.x < currentToPoint.x { + if previousToPoint.x < currentFromPoint.x { + let offset = Double((currentFromPoint.x - previousToPoint.x) / (currentToPoint.x - previousToPoint.x)) + let intermidiateToPoint = CGPoint.valueBetween(start: previousToPoint, end: currentToPoint, offset: offset) + pointToAdd = CGPoint.valueBetween(start: currentFromPoint, end: intermidiateToPoint, offset: animationOffset) + } else { + pointToAdd = currentFromPoint + } + previousFromPoint = currentFromPoint + fromIndex = validFromIndex + 1 + } else { + if previousFromPoint.x < currentToPoint.x { + let offset = Double((currentToPoint.x - previousFromPoint.x) / (currentFromPoint.x - previousFromPoint.x)) + let intermidiateFromPoint = CGPoint.valueBetween(start: previousFromPoint, end: currentFromPoint, offset: offset) + pointToAdd = CGPoint.valueBetween(start: intermidiateFromPoint, end: currentToPoint, offset: animationOffset) + } else { + pointToAdd = currentToPoint + } + previousToPoint = currentToPoint + toIndex = validToIndex + 1 + } + add(pointToDraw: pointToAdd) + if (pointToAdd.x > range.upperBound) { + break + } + } + + while let validToIndex = toIndex, validToIndex < toPoints.count { + var pointToAdd = convertToPoint(toPoints[validToIndex]) + pointToAdd.y = CGFloat.valueBetween(start: previousFromPoint.y, + end: pointToAdd.y, + offset: animationOffset) + + add(pointToDraw: pointToAdd) + if (pointToAdd.x > range.upperBound) { + break + } + + toIndex = validToIndex + 1 + } + + while let validFromIndex = fromIndex, validFromIndex < fromPoints.count { + var pointToAdd = convertFromPoint(fromPoints[validFromIndex]) + pointToAdd.y = CGFloat.valueBetween(start: previousToPoint.y, + end: pointToAdd.y, + offset: 1 - animationOffset) + + add(pointToDraw: pointToAdd) + if (pointToAdd.x > range.upperBound) { + break + } + + fromIndex = validFromIndex + 1 + } + + var index = 0 + var lines: [CGPoint] = [] + var currentChartPoint = combinedPoints[index] + lines.append(currentChartPoint) + + var chartPoints = [currentChartPoint] + var minIndex = 0 + var maxIndex = 0 + index += 1 + + while index < combinedPoints.count { + currentChartPoint = combinedPoints[index] + + if currentChartPoint.x - chartPoints[0].x < lineWidth * optimizationLevel { + chartPoints.append(currentChartPoint) + + if currentChartPoint.y > chartPoints[maxIndex].y { + maxIndex = chartPoints.count - 1 + } + if currentChartPoint.y < chartPoints[minIndex].y { + minIndex = chartPoints.count - 1 + } + + index += 1 + } else { + if chartPoints.count == 1 { + lines.append(currentChartPoint) + lines.append(currentChartPoint) + chartPoints[0] = currentChartPoint + index += 1 + minIndex = 0 + maxIndex = 0 + } else { + if minIndex < maxIndex { + if minIndex != 0 { + lines.append(chartPoints[minIndex]) + lines.append(chartPoints[minIndex]) + } + lines.append(chartPoints[maxIndex]) + lines.append(chartPoints[maxIndex]) + if maxIndex != chartPoints.count - 1 { + chartPoints = [chartPoints[maxIndex], chartPoints.last!] + } else { + chartPoints = [chartPoints[maxIndex]] + } + } else { + if maxIndex != 0 { + lines.append(chartPoints[maxIndex]) + lines.append(chartPoints[maxIndex]) + } + lines.append(chartPoints[minIndex]) + lines.append(chartPoints[minIndex]) + if minIndex != chartPoints.count - 1 { + chartPoints = [chartPoints[minIndex], chartPoints.last!] + } else { + chartPoints = [chartPoints[minIndex]] + } + } + if chartPoints.count == 2 { + if chartPoints[0].y < chartPoints[1].y { + minIndex = 0 + maxIndex = 1 + } else { + minIndex = 1 + maxIndex = 0 + } + } else { + minIndex = 0 + maxIndex = 0 + } + } + } + } + + if chartPoints.count == 1 { + lines.append(currentChartPoint) + lines.append(currentChartPoint) + } else { + if minIndex < maxIndex { + if minIndex != 0 { + lines.append(chartPoints[minIndex]) + lines.append(chartPoints[minIndex]) + } + lines.append(chartPoints[maxIndex]) + lines.append(chartPoints[maxIndex]) + if maxIndex != chartPoints.count - 1 { + lines.append(chartPoints.last!) + lines.append(chartPoints.last!) + } + } else { + if maxIndex != 0 { + lines.append(chartPoints[maxIndex]) + lines.append(chartPoints[maxIndex]) + } + lines.append(chartPoints[minIndex]) + lines.append(chartPoints[minIndex]) + if minIndex != chartPoints.count - 1 { + lines.append(chartPoints.last!) + lines.append(chartPoints.last!) + } + } + } + + if (lines.count % 2) == 1 { + lines.removeLast() + } + + context.setLineCap(.round) + context.strokeLineSegments(between: lines) + + } else { + let alpha = linesAlphaAnimators[index].current * chartsAlpha + if alpha == 0 { continue } + context.setStrokeColor(toLine.color.withAlphaComponent(alpha).cgColor) + context.setLineWidth(lineWidth) + + if var index = toLine.points.firstIndex(where: { $0.x >= range.lowerBound }) { + var lines: [CGPoint] = [] + index = max(0, index - 1) + var currentPoint = toLine.points[index] + var currentChartPoint = transform(toChartCoordinate: currentPoint, chartFrame: chartFrame) + lines.append(currentChartPoint) + //context.move(to: currentChartPoint) + + var chartPoints = [currentChartPoint] + var minIndex = 0 + var maxIndex = 0 + index += 1 + + while index < toLine.points.count { + currentPoint = toLine.points[index] + currentChartPoint = transform(toChartCoordinate: currentPoint, chartFrame: chartFrame) + + if currentChartPoint.x - chartPoints[0].x < lineWidth * optimizationLevel { + chartPoints.append(currentChartPoint) + + if currentChartPoint.y > chartPoints[maxIndex].y { + maxIndex = chartPoints.count - 1 + } + if currentChartPoint.y < chartPoints[minIndex].y { + minIndex = chartPoints.count - 1 + } + + index += 1 + } else { + if chartPoints.count == 1 { + lines.append(currentChartPoint) + lines.append(currentChartPoint) + chartPoints[0] = currentChartPoint + index += 1 + minIndex = 0 + maxIndex = 0 + } else { + if minIndex < maxIndex { + if minIndex != 0 { + lines.append(chartPoints[minIndex]) + lines.append(chartPoints[minIndex]) + } + lines.append(chartPoints[maxIndex]) + lines.append(chartPoints[maxIndex]) + if maxIndex != chartPoints.count - 1 { + chartPoints = [chartPoints[maxIndex], chartPoints.last!] + } else { + chartPoints = [chartPoints[maxIndex]] + } + } else { + if maxIndex != 0 { + lines.append(chartPoints[maxIndex]) + lines.append(chartPoints[maxIndex]) + } + lines.append(chartPoints[minIndex]) + lines.append(chartPoints[minIndex]) + if minIndex != chartPoints.count - 1 { + chartPoints = [chartPoints[minIndex], chartPoints.last!] + } else { + chartPoints = [chartPoints[minIndex]] + } + } + if chartPoints.count == 2 { + if chartPoints[0].y < chartPoints[1].y { + minIndex = 0 + maxIndex = 1 + } else { + minIndex = 1 + maxIndex = 0 + } + } else { + minIndex = 0 + maxIndex = 0 + } + } + } + if currentPoint.x > range.upperBound { + break + } + } + + if chartPoints.count == 1 { + lines.append(currentChartPoint) + lines.append(currentChartPoint) + } else { + if minIndex < maxIndex { + if minIndex != 0 { + lines.append(chartPoints[minIndex]) + lines.append(chartPoints[minIndex]) + } + lines.append(chartPoints[maxIndex]) + lines.append(chartPoints[maxIndex]) + if maxIndex != chartPoints.count - 1 { + lines.append(chartPoints.last!) + lines.append(chartPoints.last!) + } + } else { + if maxIndex != 0 { + lines.append(chartPoints[maxIndex]) + lines.append(chartPoints[maxIndex]) + } + lines.append(chartPoints[minIndex]) + lines.append(chartPoints[minIndex]) + if minIndex != chartPoints.count - 1 { + lines.append(chartPoints.last!) + lines.append(chartPoints.last!) + } + } + } + + if (lines.count % 2) == 1 { + lines.removeLast() + } + + context.setLineCap(.round) + context.strokeLineSegments(between: lines) + } + +// if var start = toLine.points.firstIndex(where: { $0.x > range.lowerBound }) { +// let alpha = linesAlphaAnimators[index].current * chartsAlpha +// if alpha == 0 { continue } +// context.setStrokeColor(toLine.color.withAlphaComponent(alpha).cgColor) +// context.setLineWidth(lineWidth) +// +// context.setLineCap(.round) +// start = max(0, start - 1) +// let startPoint = toLine.points[start] +// var lines: [CGPoint] = [] +// var pointToDraw = CGPoint(x: transform(toChartCoordinateHorizontal: startPoint.x, chartFrame: chartFrame), +// y: transform(toChartCoordinateVertical: startPoint.y, chartFrame: chartFrame)) +// for index in (start + 1).. range.upperBound { +// break +// } +// } +// +// context.strokeLineSegments(between: lines) +// } + } + } + } +} + +extension LinesChartRenderer.LineData { + static func initialComponents(chartsCollection: ChartsCollection) -> (linesData: [LinesChartRenderer.LineData], + totalHorizontalRange: ClosedRange, + totalVerticalRange: ClosedRange) { + let lines: [LinesChartRenderer.LineData] = chartsCollection.chartValues.map { chart in + let points = chart.values.enumerated().map({ (arg) -> CGPoint in + return CGPoint(x: chartsCollection.axisValues[arg.offset].timeIntervalSince1970, + y: arg.element) + }) + return LinesChartRenderer.LineData(color: chart.color, points: points) + } + let horizontalRange = LinesChartRenderer.LineData.horizontalRange(lines: lines) ?? BaseConstants.defaultRange + let verticalRange = LinesChartRenderer.LineData.verticalRange(lines: lines) ?? BaseConstants.defaultRange + return (linesData: lines, totalHorizontalRange: horizontalRange, totalVerticalRange: verticalRange) + } + + static func horizontalRange(lines: [LinesChartRenderer.LineData]) -> ClosedRange? { + guard let firstPoint = lines.first?.points.first else { return nil } + var hMin: CGFloat = firstPoint.x + var hMax: CGFloat = firstPoint.x + + for line in lines { + if let first = line.points.first, + let last = line.points.last { + hMin = min(hMin, first.x) + hMax = max(hMax, last.x) + } + } + + return hMin...hMax + } + + static func verticalRange(lines: [LinesChartRenderer.LineData], calculatingRange: ClosedRange? = nil, addBounds: Bool = false) -> ClosedRange? { + if let calculatingRange = calculatingRange { + guard let initalStart = lines.first?.points.first(where: { $0.x >= calculatingRange.lowerBound && + $0.x <= calculatingRange.upperBound }) else { return nil } + var vMin: CGFloat = initalStart.y + var vMax: CGFloat = initalStart.y + for line in lines { + if var index = line.points.firstIndex(where: { $0.x > calculatingRange.lowerBound }) { + if addBounds { + index = max(0, index - 1) + } + while index < line.points.count { + let point = line.points[index] + if point.x < calculatingRange.upperBound { + vMin = min(vMin, point.y) + vMax = max(vMax, point.y) + } else if addBounds { + vMin = min(vMin, point.y) + vMax = max(vMax, point.y) + break + } else { + break + } + index += 1 + } + } + } + return vMin...vMax + } else { + guard let firstPoint = lines.first?.points.first else { return nil } + var vMin: CGFloat = firstPoint.y + var vMax: CGFloat = firstPoint.y + for line in lines { + for point in line.points { + vMin = min(vMin, point.y) + vMax = max(vMax, point.y) + } + } + return vMin...vMax + } + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/PecentChartRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/PecentChartRenderer.swift new file mode 100644 index 0000000000..07ff3daaaa --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/PecentChartRenderer.swift @@ -0,0 +1,132 @@ +// +// PecentChartRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class PecentChartRenderer: BaseChartRenderer { + struct PercentageData { + static let blank = PecentChartRenderer.PercentageData(locations: [], components: []) + var locations: [CGFloat] + var components: [Component] + + struct Component { + var color: UIColor + var values: [CGFloat] + } + } + + override func setup(verticalRange: ClosedRange, animated: Bool, timeFunction: TimeFunction? = nil) { + super.setup(verticalRange: 0...1, animated: animated, timeFunction: timeFunction) + } + + private var componentsAnimators: [AnimationController] = [] + var percentageData: PercentageData = PercentageData(locations: [], components: []) { + willSet { + if percentageData.components.count != newValue.components.count { + componentsAnimators = newValue.components.map { _ in AnimationController(current: 1, refreshClosure: self.refreshClosure) } + } + } + didSet { + setNeedsDisplay() + } + } + + func setComponentVisible(_ isVisible: Bool, at index: Int, animated: Bool) { + componentsAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + } + + override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + guard isEnabled && verticalRange.current.distance > 0 && verticalRange.current.distance > 0 else { return } + let alpha = chartAlphaAnimator.current + guard alpha > 0 else { return } + + let range = renderRange(bounds: bounds, chartFrame: chartFrame) + + var paths: [CGMutablePath] = percentageData.components.map { _ in CGMutablePath() } + var vertices: [CGFloat] = Array(repeating: 0, count: percentageData.components.count) + + if var locationIndex = percentageData.locations.firstIndex(where: { $0 > range.lowerBound }) { + locationIndex = max(0, locationIndex - 1) + + var currentLocation = transform(toChartCoordinateHorizontal: percentageData.locations[locationIndex], chartFrame: chartFrame) + + let startPoint = CGPoint(x: currentLocation, + y: transform(toChartCoordinateVertical: verticalRange.current.lowerBound, chartFrame: chartFrame)) + + for path in paths { + path.move(to: startPoint) + } + paths.last?.addLine(to: CGPoint(x: currentLocation, + y: transform(toChartCoordinateVertical: verticalRange.current.upperBound, chartFrame: chartFrame))) + + while locationIndex < percentageData.locations.count { + currentLocation = transform(toChartCoordinateHorizontal: percentageData.locations[locationIndex], chartFrame: chartFrame) + var summ: CGFloat = 0 + + for (index, component) in percentageData.components.enumerated() { + let visibilityPercent = componentsAnimators[index].current + + let value = component.values[locationIndex] * visibilityPercent + if index == 0 { + vertices[index] = value + } else { + vertices[index] = value + vertices[index - 1] + } + summ += value + } + + if summ > 0 { + for (index, value) in vertices.dropLast().enumerated() { + paths[index].addLine(to: CGPoint(x: currentLocation, + y: transform(toChartCoordinateVertical: value / summ, chartFrame: chartFrame))) + } + } + + if currentLocation > range.upperBound { + break + } + + locationIndex += 1 + } + + paths.last?.addLine(to: CGPoint(x: currentLocation, + y: transform(toChartCoordinateVertical: verticalRange.current.upperBound, chartFrame: chartFrame))) + + let endPoint = CGPoint(x: currentLocation, + y: transform(toChartCoordinateVertical: verticalRange.current.lowerBound, chartFrame: chartFrame)) + + for (index, path) in paths.enumerated().reversed() { + let visibilityPercent = componentsAnimators[index].current + if visibilityPercent == 0 { continue } + + path.addLine(to: endPoint) + path.closeSubpath() + + context.saveGState() + context.beginPath() + context.addPath(path) + + context.setFillColor(percentageData.components[index].color.cgColor) + context.fillPath() + context.restoreGState() + } + } + } +} + +extension PecentChartRenderer.PercentageData { + static func horizontalRange(data: PecentChartRenderer.PercentageData) -> ClosedRange? { + guard let firstPoint = data.locations.first, + let lastPoint = data.locations.last, + firstPoint <= lastPoint else { + return nil + } + + return firstPoint...lastPoint + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/PercentPieAnimationRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/PercentPieAnimationRenderer.swift new file mode 100644 index 0000000000..e36fdaf913 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/PercentPieAnimationRenderer.swift @@ -0,0 +1,202 @@ +// +// PercentPieAnimationRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/13/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class PercentPieAnimationRenderer: BaseChartRenderer { + override func setup(verticalRange: ClosedRange, animated: Bool, timeFunction: TimeFunction? = nil) { + super.setup(verticalRange: 0...1, animated: animated, timeFunction: timeFunction) + } + + private lazy var transitionAnimator = AnimationController(current: 0, refreshClosure: refreshClosure) + private var animationComponentsPoints: [[CGPoint]] = [] + var visiblePercentageData: PecentChartRenderer.PercentageData = .blank { + didSet { + animationComponentsPoints = [] + } + } + var visiblePieComponents: [PieChartRenderer.PieComponent] = [] + + func animate(fromDataToPie: Bool, animated: Bool, completion: @escaping () -> Void) { + assert(visiblePercentageData.components.count == visiblePieComponents.count) + + isEnabled = true + transitionAnimator.completionClosure = { [weak self] in + self?.isEnabled = false + completion() + } + transitionAnimator.animate(to: fromDataToPie ? 1 : 0, duration: animated ? .defaultDuration : 0) + } + + private func generateAnimationComponentPoints(bounds: CGRect, chartFrame: CGRect) { + let range = renderRange(bounds: bounds, chartFrame: chartFrame) + + let componentsCount = visiblePercentageData.components.count + guard componentsCount > 0 else { return } + animationComponentsPoints = visiblePercentageData.components.map { _ in [] } + var vertices: [CGFloat] = Array(repeating: 0, count: visiblePercentageData.components.count) + + if var locationIndex = visiblePercentageData.locations.firstIndex(where: { $0 > range.lowerBound }) { + locationIndex = max(0, locationIndex - 1) + var currentLocation = transform(toChartCoordinateHorizontal: visiblePercentageData.locations[locationIndex], chartFrame: chartFrame) + let startPoint = CGPoint(x: currentLocation, y: transform(toChartCoordinateVertical: verticalRange.current.lowerBound, chartFrame: chartFrame)) + for index in 0.. range.upperBound { + break + } + locationIndex += 1 + } + + animationComponentsPoints[componentsCount - 1].append(CGPoint(x: currentLocation, y: transform(toChartCoordinateVertical: verticalRange.current.upperBound, chartFrame: chartFrame))) + let endPoint = CGPoint(x: currentLocation, y: transform(toChartCoordinateVertical: verticalRange.current.lowerBound, chartFrame: chartFrame)) + for index in 0.. 0 && verticalRange.current.distance > 0 else { return } + self.optimizationLevel = 1 + + if animationComponentsPoints.isEmpty { + generateAnimationComponentPoints(bounds: bounds, chartFrame: chartFrame) + } + + let numberOfComponents = animationComponentsPoints.count + guard numberOfComponents > 0 else { return } + let destinationRadius = max(chartFrame.width, chartFrame.height) + + let animationFraction = transitionAnimator.current + let animationFractionD = Double(transitionAnimator.current) + let easeInAnimationFractionD = animationFractionD * animationFractionD * animationFractionD * animationFractionD + let center = CGPoint(x: chartFrame.midX, y: chartFrame.midY) + let totalPieSumm: CGFloat = visiblePieComponents.map { $0.value } .reduce(0, +) + + let pathsToDraw: [CGMutablePath] = (0.. 4 else { + return + } + + let percent = visiblePieComponents[componentIndex].value / totalPieSumm + let segmentSize = 2 * .pi * percent + let endAngle = startAngle + segmentSize + let centerAngle = (startAngle + endAngle) / 2 + + let lineCenterPoint = CGPoint.valueBetween(start: componentPoints[componentPoints.count / 2], + end: center, + offset: animationFractionD) + + let startDestinationPoint = lineCenterPoint + CGPoint(x: destinationRadius, y: 0) + let centerDestinationPoint = lineCenterPoint + CGPoint(x: 0, y: destinationRadius) + let endDestinationPoint = lineCenterPoint + CGPoint(x: -destinationRadius, y: 0) + let initialStartDestinationAngle: CGFloat = 0 + let initialCenterDestinationAngle: CGFloat = .pi / 2 + let initialEndDestinationAngle: CGFloat = .pi + + var previousAddedPoint = (componentPoints[0] * 2 - center) + .rotate(origin: lineCenterPoint, angle: CGFloat.valueBetween(start: 0, end: centerAngle - initialCenterDestinationAngle, offset: animationFractionD)) + + pathsToDraw[componentIndex].move(to: previousAddedPoint) + + func addPointToPath(_ point: CGPoint) { + if (point - previousAddedPoint).lengthSquared() > optimizationLevel { + pathsToDraw[componentIndex].addLine(to: point) + previousAddedPoint = point + } + } + + for endPointIndex in 1..<(componentPoints.count / 2) { + addPointToPath(CGPoint.valueBetween(start: componentPoints[endPointIndex], end: endDestinationPoint, offset: easeInAnimationFractionD) + .rotate(origin: lineCenterPoint, angle: CGFloat.valueBetween(start: 0, end: endAngle - initialEndDestinationAngle, offset: animationFractionD))) + } + + addPointToPath(lineCenterPoint) + + for startPointIndex in (componentPoints.count / 2 + 1)..<(componentPoints.count - 1) { + addPointToPath(CGPoint.valueBetween(start: componentPoints[startPointIndex], end: startDestinationPoint, offset: easeInAnimationFractionD) + .rotate(origin: lineCenterPoint, angle: CGFloat.valueBetween(start: 0, end: startAngle - initialStartDestinationAngle, offset: animationFractionD))) + } + + if let lastPoint = componentPoints.last { + addPointToPath((lastPoint * 2 - center) + .rotate(origin: lineCenterPoint, angle: CGFloat.valueBetween(start: 0, end: centerAngle - initialCenterDestinationAngle, offset: animationFractionD))) + } + + startAngle = endAngle + } + + if let lastPath = animationComponentsPoints.last { + pathsToDraw.last?.addLines(between: lastPath) + } + + for (index, path) in pathsToDraw.enumerated().reversed() { + path.closeSubpath() + + context.saveGState() + context.beginPath() + context.addPath(path) + + context.setFillColor(visiblePieComponents[index].color.cgColor) + context.fillPath() + context.restoreGState() + } + + let diagramRadius = (min(chartFrame.width, chartFrame.height) / 2) * 0.925 + let targetFrame = CGRect(origin: CGPoint(x: center.x - diagramRadius, + y: center.y - diagramRadius), + size: CGSize(width: diagramRadius * 2, + height: diagramRadius * 2)) + + let minX = animationComponentsPoints.last?.first?.x ?? 0 + let maxX = animationComponentsPoints.last?.last?.x ?? 0 + let startFrame = CGRect(x: minX, + y: chartFrame.minY, + width: maxX - minX, + height: chartFrame.height) + let cornerRadius = diagramRadius * animationFraction + let fadeOutFrame = CGRect.valueBetween(start: startFrame, end: targetFrame, offset: animationFractionD) + let fadeOutPath = CGMutablePath() + fadeOutPath.addRect(bounds) + fadeOutPath.addPath(CGPath(roundedRect: fadeOutFrame, cornerWidth: cornerRadius, cornerHeight: cornerRadius, transform: nil)) + + context.saveGState() + context.beginPath() + context.addPath(fadeOutPath) + context.setFillColor(backgroundColor.cgColor) + context.fillPath(using: .evenOdd) + context.restoreGState() + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/PerformanceRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/PerformanceRenderer.swift new file mode 100644 index 0000000000..c17663ce5f --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/PerformanceRenderer.swift @@ -0,0 +1,31 @@ +// +// PerformanceRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/10/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class PerformanceRenderer: ChartViewRenderer { + var containerViews: [UIView] = [] + + private var previousTickTime: TimeInterval = CACurrentMediaTime() + + func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + let currentTime = CACurrentMediaTime() + let delta = currentTime - previousTickTime + previousTickTime = currentTime + + let normalDelta = 0.017 + let redDelta = 0.05 + + if delta > normalDelta || delta < 0.75 { + let green = CGFloat( 1.0 - crop(0, (delta - normalDelta) / (redDelta - normalDelta), 1)) + let color = UIColor(red: 1.0, green: green, blue: 0, alpha: 1) + context.setFillColor(color.cgColor) + context.fill(CGRect(x: 0, y: 0, width: bounds.width, height: 3)) + } + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/PieChartRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/PieChartRenderer.swift new file mode 100644 index 0000000000..ed4e6bdd49 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/PieChartRenderer.swift @@ -0,0 +1,191 @@ +// +// PieChartRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/11/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class PieChartRenderer: BaseChartRenderer { + struct PieComponent: Hashable { + var color: UIColor + var value: CGFloat + } + + override func setup(verticalRange: ClosedRange, animated: Bool, timeFunction: TimeFunction? = nil) { + super.setup(verticalRange: 0...1, animated: animated, timeFunction: timeFunction) + } + + var valuesFormatter: NumberFormatter = NumberFormatter() + var drawValues: Bool = true + + private var componentsAnimators: [AnimationController] = [] + private lazy var transitionAnimator: AnimationController = { AnimationController(current: 1, refreshClosure: self.refreshClosure) }() + private var oldPercentageData: [PieComponent] = [] + private var percentageData: [PieComponent] = [] + private var setlectedSegmentsAnimators: [AnimationController] = [] + + var drawPie: Bool = true + var initialAngle: CGFloat = .pi / 3 + var hasSelectedSegments: Bool { + return selectedSegment != nil + } + private(set) var selectedSegment: Int? + func selectSegmentAt(at indexToSelect: Int?, animated: Bool) { + selectedSegment = indexToSelect + for (index, animator) in setlectedSegmentsAnimators.enumerated() { + let fraction: CGFloat = (index == indexToSelect) ? 1.0 : 0.0 + if animated { + animator.animate(to: fraction, duration: .defaultDuration / 2) + } else { + animator.set(current: fraction) + } + } + } + + func updatePercentageData(_ percentageData: [PieComponent], animated: Bool) { + if self.percentageData.count != percentageData.count { + componentsAnimators = percentageData.map { _ in AnimationController(current: 1, refreshClosure: self.refreshClosure) } + setlectedSegmentsAnimators = percentageData.map { _ in AnimationController(current: 0, refreshClosure: self.refreshClosure) } + } + if animated { + self.oldPercentageData = self.currentTransitionAnimationData + self.percentageData = percentageData + transitionAnimator.completionClosure = { [weak self] in + self?.oldPercentageData = [] + } + transitionAnimator.set(current: 0) + transitionAnimator.animate(to: 1, duration: .defaultDuration) + } else { + self.oldPercentageData = [] + self.percentageData = percentageData + transitionAnimator.set(current: 0) + } + } + + func setComponentVisible(_ isVisible: Bool, at index: Int, animated: Bool) { + componentsAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + } + + var lastRenderedBounds: CGRect = .zero + var lastRenderedChartFrame: CGRect = .zero + func selectedItemIndex(at point: CGPoint) -> Int? { + let touchPosition = lastRenderedChartFrame.origin + point * lastRenderedChartFrame.size + let center = CGPoint(x: lastRenderedChartFrame.midX, y: lastRenderedChartFrame.midY) + let radius = min(lastRenderedChartFrame.width, lastRenderedChartFrame.height) / 2 + if center.distanceTo(touchPosition) > radius { return nil } + let angle = (center - touchPosition).angle + .pi + let currentData = currentlyVisibleData + let total: CGFloat = currentData.map({ $0.value }).reduce(0, +) + var startAngle: CGFloat = initialAngle + for (index, piece) in currentData.enumerated() { + let percent = piece.value / total + let segmentSize = 2 * .pi * percent + let endAngle = startAngle + segmentSize + if angle >= startAngle && angle <= endAngle || + angle + .pi * 2 >= startAngle && angle + .pi * 2 <= endAngle { + return index + } + startAngle = endAngle + } + return nil + } + + private var currentTransitionAnimationData: [PieComponent] { + if transitionAnimator.isAnimating { + let animationFraction = transitionAnimator.current + return percentageData.enumerated().map { arg in + return PieComponent(color: arg.element.color, + value: oldPercentageData[arg.offset].value * (1 - animationFraction) + arg.element.value * animationFraction) + } + } else { + return percentageData + } + } + + var currentlyVisibleData: [PieComponent] { + return currentTransitionAnimationData.enumerated().map { arg in + return PieComponent(color: arg.element.color, + value: arg.element.value * componentsAnimators[arg.offset].current) + } + } + + override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + guard isEnabled && verticalRange.current.distance > 0 && verticalRange.current.distance > 0 else { return } + lastRenderedBounds = bounds + lastRenderedChartFrame = chartFrame + let chartAlpha = chartAlphaAnimator.current + if chartAlpha == 0 { return } + + let center = CGPoint(x: chartFrame.midX, y: chartFrame.midY) + let radius = min(chartFrame.width, chartFrame.height) / 2 + + let currentData = currentlyVisibleData + + let total: CGFloat = currentData.map({ $0.value }).reduce(0, +) + guard total > 0 else { + return + } + + let animationSelectionOffset: CGFloat = radius / 15 + let maximumFontSize: CGFloat = radius / 7 + let minimumFontSize: CGFloat = 4 + let centerOffsetStartAngle = CGFloat.pi / 4 + let minimumValueToDraw: CGFloat = 0.01 + let diagramRadius = radius - animationSelectionOffset + + let numberOfVisibleItems = currentlyVisibleData.filter { $0.value > 0 }.count + var startAngle: CGFloat = initialAngle + for (index, piece) in currentData.enumerated() { + let percent = piece.value / total + guard percent > 0 else { continue } + let segmentSize = 2 * .pi * percent * chartAlpha + let endAngle = startAngle + segmentSize + let centerAngle = (startAngle + endAngle) / 2 + let labelVector = CGPoint(x: cos(centerAngle), + y: sin(centerAngle)) + + let selectionAnimationFraction = (numberOfVisibleItems > 1 ? setlectedSegmentsAnimators[index].current : 0) + + let updatedCenter = CGPoint(x: center.x + labelVector.x * selectionAnimationFraction * animationSelectionOffset, + y: center.y + labelVector.y * selectionAnimationFraction * animationSelectionOffset) + if drawPie { + context.saveGState() + context.setFillColor(piece.color.withAlphaComponent(piece.color.alphaValue * chartAlpha).cgColor) + context.move(to: updatedCenter) + context.addArc(center: updatedCenter, + radius: radius - animationSelectionOffset, + startAngle: startAngle, + endAngle: endAngle, + clockwise: false) + context.fillPath() + context.restoreGState() + } + + if drawValues && percent >= minimumValueToDraw { + context.saveGState() + + let text = valuesFormatter.string(from: percent * 100) + let fraction = crop(0, segmentSize / centerOffsetStartAngle, 1) + let fontSize = (minimumFontSize + (maximumFontSize - minimumFontSize) * fraction).rounded(.up) + let labelPotisionOffset = diagramRadius / 2 + diagramRadius / 2 * (1 - fraction) + let font = UIFont.systemFont(ofSize: fontSize, weight: .bold) + let labelsEaseInColor = crop(0, chartAlpha * chartAlpha * 2 - 1, 1) + let attributes: [NSAttributedString.Key: Any] = [.foregroundColor: UIColor.white.withAlphaComponent(labelsEaseInColor), + .font: font] + let rect = (text as NSString).boundingRect(with: bounds.size, + options: .usesLineFragmentOrigin, + attributes: attributes, + context: nil) + let labelPoint = CGPoint(x: labelVector.x * labelPotisionOffset + updatedCenter.x - rect.width / 2, + y: labelVector.y * labelPotisionOffset + updatedCenter.y - rect.height / 2) + (text as NSString).draw(at: labelPoint, withAttributes: attributes) + context.restoreGState() + } + + startAngle = endAngle + } + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/VerticalLinesRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/VerticalLinesRenderer.swift new file mode 100644 index 0000000000..39d1f26a46 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/VerticalLinesRenderer.swift @@ -0,0 +1,42 @@ +// +// VerticalLinesRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/8/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class VerticalLinesRenderer: BaseChartRenderer { + var values: [CGFloat] = [] { + didSet { + alphaAnimators = values.map { _ in AnimationController(current: 1.0, refreshClosure: refreshClosure) } + setNeedsDisplay() + } + } + private var alphaAnimators: [AnimationController] = [] + + var linesColor: UIColor = .black + var linesWidth: CGFloat = UIView.oneDevicePixel + + func setLineVisible(_ isVisible: Bool, at index: Int, animated: Bool) { + alphaAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + } + + override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + guard isEnabled && verticalRange.current.distance > 0 && verticalRange.current.distance > 0 else { return } + + context.setLineWidth(linesWidth) + + for (index, value) in values.enumerated() { + let alpha = alphaAnimators[index].current + if alpha == 0 { continue } + + context.setStrokeColor(linesColor.withAlphaComponent(linesColor.alphaValue * alpha).cgColor) + let pointX = transform(toChartCoordinateHorizontal: value, chartFrame: chartFrame) + context.strokeLineSegments(between: [CGPoint(x: pointX, y: chartFrame.minY), + CGPoint(x: pointX, y: chartFrame.maxY)]) + } + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/VerticalScalesRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/VerticalScalesRenderer.swift new file mode 100644 index 0000000000..79d9dcec22 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/VerticalScalesRenderer.swift @@ -0,0 +1,162 @@ +// +// VerticalScalesRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/8/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class VerticalScalesRenderer: BaseChartRenderer { + private var verticalLabelsAndLines: [LinesChartLabel] = [] + private var animatedVerticalLabelsAndLines: [AnimatedLinesChartLabels] = [] + private lazy var horizontalLinesAlphaAnimator: AnimationController = { + return AnimationController(current: 1, refreshClosure: self.refreshClosure) + }() + + var drawAxisX: Bool = true + var axisXColor: UIColor = .black + var axisXWidth: CGFloat = UIView.oneDevicePixel + + var isRightAligned: Bool = false + + var horizontalLinesColor: UIColor = .black { + didSet { + setNeedsDisplay() + } + } + var horizontalLinesWidth: CGFloat = UIView.oneDevicePixel + var lavelsAsisOffset: CGFloat = 6 + var labelsColor: UIColor = .black { + didSet { + setNeedsDisplay() + } + } + var labelsFont: UIFont = .systemFont(ofSize: 11) + + func setHorizontalLinesVisible(_ visible: Bool, animated: Bool) { + let destinationValue: CGFloat = visible ? 1 : 0 + guard self.horizontalLinesAlphaAnimator.end != destinationValue else { return } + if animated { + self.horizontalLinesAlphaAnimator.animate(to: destinationValue, duration: .defaultDuration) + } else { + self.horizontalLinesAlphaAnimator.set(current: destinationValue) + } + } + + func setup(verticalLimitsLabels: [LinesChartLabel], animated: Bool) { + if animated { + var labelsToKeepVisible: [LinesChartLabel] = [] + let labelsToHide: [LinesChartLabel] + var labelsToShow: [LinesChartLabel] = [] + + for label in verticalLimitsLabels { + if verticalLabelsAndLines.contains(label) { + labelsToKeepVisible.append(label) + } else { + labelsToShow.append(label) + } + } + labelsToHide = verticalLabelsAndLines.filter { !verticalLimitsLabels.contains($0) } + animatedVerticalLabelsAndLines.removeAll(where: { $0.isAppearing }) + verticalLabelsAndLines = labelsToKeepVisible + + let showAnimation = AnimatedLinesChartLabels(labels: labelsToShow, alphaAnimator: AnimationController(current: 1.0, refreshClosure: refreshClosure)) + showAnimation.isAppearing = true + showAnimation.alphaAnimator.set(current: 0) + showAnimation.alphaAnimator.animate(to: 1, duration: .defaultDuration) + showAnimation.alphaAnimator.completionClosure = { [weak self, weak showAnimation] in + guard let self = self, let showAnimation = showAnimation else { return } + self.animatedVerticalLabelsAndLines.removeAll(where: { $0 === showAnimation }) + self.verticalLabelsAndLines = verticalLimitsLabels + } + + let hideAnimation = AnimatedLinesChartLabels(labels: labelsToHide, alphaAnimator: AnimationController(current: 1.0, refreshClosure: refreshClosure)) + hideAnimation.isAppearing = false + hideAnimation.alphaAnimator.set(current: 1) + hideAnimation.alphaAnimator.animate(to: 0, duration: .defaultDuration) + hideAnimation.alphaAnimator.completionClosure = { [weak self, weak hideAnimation] in + guard let self = self, let hideAnimation = hideAnimation else { return } + self.animatedVerticalLabelsAndLines.removeAll(where: { $0 === hideAnimation }) + } + + animatedVerticalLabelsAndLines.append(showAnimation) + animatedVerticalLabelsAndLines.append(hideAnimation) + } else { + verticalLabelsAndLines = verticalLimitsLabels + animatedVerticalLabelsAndLines = [] + } + } + + override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + guard isEnabled && verticalRange.current.distance > 0 && verticalRange.current.distance > 0 else { return } + let generalAlpha = chartAlphaAnimator.current + if generalAlpha == 0 { return } + let labelColorAlpha = labelsColor.alphaValue + + func drawLines(_ labels: [LinesChartLabel], alpha: CGFloat) { + var lineSegments: [CGPoint] = [] + let x0 = chartFrame.minX + let x1 = chartFrame.maxX + + context.setStrokeColor(horizontalLinesColor.withAlphaComponent(horizontalLinesColor.alphaValue * alpha).cgColor) + + for lineInfo in labels { + let y = transform(toChartCoordinateVertical: lineInfo.value, chartFrame: chartFrame).roundedUpToPixelGrid() + lineSegments.append(CGPoint(x: x0, y: y)) + lineSegments.append(CGPoint(x: x1, y: y)) + } + context.strokeLineSegments(between: lineSegments) + } + + func drawVerticalLabels(_ labels: [LinesChartLabel], attributes: [NSAttributedString.Key: Any]) { + if isRightAligned { + for label in labels { + let y = transform(toChartCoordinateVertical: label.value, chartFrame: chartFrame) - labelsFont.pointSize - lavelsAsisOffset + + let rect = (label.text as NSString).boundingRect(with: bounds.size, + options: .usesLineFragmentOrigin, + attributes: attributes, + context: nil) + + (label.text as NSString).draw(at: CGPoint(x:chartFrame.maxX - rect.width, y: y), withAttributes: attributes) + } + } else { + for label in labels { + let y = transform(toChartCoordinateVertical: label.value, chartFrame: chartFrame) - labelsFont.pointSize - lavelsAsisOffset + + (label.text as NSString).draw(at: CGPoint(x:chartFrame.minX, y: y), withAttributes: attributes) + } + } + } + + let horizontalLinesAlpha = horizontalLinesAlphaAnimator.current + if horizontalLinesAlpha > 0 { + context.setLineWidth(horizontalLinesWidth) + + drawLines(verticalLabelsAndLines, alpha: generalAlpha) + for animatedLabesAndLines in animatedVerticalLabelsAndLines { + drawLines(animatedLabesAndLines.labels, alpha: animatedLabesAndLines.alphaAnimator.current * generalAlpha * horizontalLinesAlpha) + } + + if drawAxisX { + context.setLineWidth(axisXWidth) + context.setStrokeColor(axisXColor.withAlphaComponent(axisXColor.alphaValue * horizontalLinesAlpha * generalAlpha).cgColor) + + let lineSegments: [CGPoint] = [CGPoint(x: chartFrame.minX, y: chartFrame.maxY.roundedUpToPixelGrid()), + CGPoint(x: chartFrame.maxX, y: chartFrame.maxY.roundedUpToPixelGrid())] + + context.strokeLineSegments(between: lineSegments) + } + } + + drawVerticalLabels(verticalLabelsAndLines, attributes: [.foregroundColor: labelsColor.withAlphaComponent(labelColorAlpha * generalAlpha), + .font: labelsFont]) + for animatedLabesAndLines in animatedVerticalLabelsAndLines { + drawVerticalLabels(animatedLabesAndLines.labels, + attributes: [.foregroundColor: labelsColor.withAlphaComponent(animatedLabesAndLines.alphaAnimator.current * labelColorAlpha * generalAlpha), + .font: labelsFont]) + } + } +} diff --git a/submodules/Charts/Sources/Helpers/AnimationController.swift b/submodules/Charts/Sources/Helpers/AnimationController.swift new file mode 100644 index 0000000000..6df8d17f76 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/AnimationController.swift @@ -0,0 +1,178 @@ +// +// RangeAnimatedContainer.swift +// GraphTest +// +// Created by Andrei Salavei on 3/12/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +protocol Animatable { + static func valueBetween(start: Self, end: Self, offset: Double) -> Self +} + +enum TimeFunction { + case linear + case easeOut + case easeIn + + func profress(time: TimeInterval, duration: TimeInterval) -> TimeInterval { + switch self { + case .linear: + return time / duration + case .easeIn: + return (pow(2, 10 * (time / duration - 1)) - 0.0009765625) * 1.0009775171065499 + + case .easeOut: + return (-pow(2, -10 * time / duration)) + 1 * 1.0009775171065499 + } + } +} + +class AnimationController { + + private(set) var isAnimating: Bool = false + private(set) var animationDuration: TimeInterval = 0.0 + private(set) var currentTime: TimeInterval = 0.0 + + private(set) var start: AnimatableObject + private(set) var end: AnimatableObject + private(set) var current: AnimatableObject + + var timeFunction: TimeFunction = .linear + + var refreshClosure: (() -> Void)? +// var updateClosure: ((AnimatableObject) -> Void)? + var completionClosure: (() -> Void)? + + init(current: AnimatableObject, refreshClosure: (() -> Void)?) { + self.current = current + self.start = current + self.end = current + self.refreshClosure = refreshClosure + } + + func animate(to: AnimatableObject, duration: TimeInterval, timeFunction: TimeFunction = .linear) { + self.timeFunction = timeFunction + currentTime = 0 + animationDuration = duration + if animationDuration > 0 { + start = current + end = to + isAnimating = true + DisplayLinkService.shared.add(listner: self) + } else { + start = to + end = to + current = to + isAnimating = false + DisplayLinkService.shared.remove(listner: self) + } + refreshClosure?() + } + + func set(current: AnimatableObject) { + self.start = current + self.end = current + self.current = current + + animationDuration = 0.0 + currentTime = 0.0 +// updateClosure?(current) + refreshClosure?() + if isAnimating { + isAnimating = false + DisplayLinkService.shared.remove(listner: self) + } + } +} + +extension AnimationController: DisplayLinkListner { + func update(delta: TimeInterval) { + guard isAnimating else { + DisplayLinkService.shared.remove(listner: self) + return + } + + currentTime += delta + if currentTime > animationDuration || animationDuration <= 0 { + start = end + current = end + isAnimating = false + animationDuration = 0.0 + currentTime = 0.0 +// updateClosure?(end) + completionClosure?() + refreshClosure?() + DisplayLinkService.shared.remove(listner: self) + } else { + let offset = timeFunction.profress(time: currentTime, duration: animationDuration) + current = AnimatableObject.valueBetween(start: start, end: end, offset: offset) +// updateClosure?(current) + refreshClosure?() + } + } +} + +extension ClosedRange: Animatable where Bound: BinaryFloatingPoint { + static func valueBetween(start: ClosedRange, end: ClosedRange, offset: Double) -> ClosedRange { + let castedOffset = Bound(offset) + return ClosedRange(uncheckedBounds: (lower: start.lowerBound + (end.lowerBound - start.lowerBound) * castedOffset, + upper: start.upperBound + (end.upperBound - start.upperBound) * castedOffset)) + } +} + +extension CGFloat: Animatable { + static func valueBetween(start: CGFloat, end: CGFloat, offset: Double) -> CGFloat { + return start + (end - start) * CGFloat(offset) + } +} + +extension Double: Animatable { + static func valueBetween(start: Double, end: Double, offset: Double) -> Double { + return start + (end - start) * Double(offset) + } +} + +extension Int: Animatable { + static func valueBetween(start: Int, end: Int, offset: Double) -> Int { + return start + Int(Double(end - start) * offset) + } +} + +extension CGPoint: Animatable { + static func valueBetween(start: CGPoint, end: CGPoint, offset: Double) -> CGPoint { + return CGPoint(x: start.x + (end.x - start.x) * CGFloat(offset), + y: start.y + (end.y - start.y) * CGFloat(offset)) + } +} + +extension CGRect: Animatable { + static func valueBetween(start: CGRect, end: CGRect, offset: Double) -> CGRect { + return CGRect(x: start.origin.x + (end.origin.x - start.origin.x) * CGFloat(offset), + y: start.origin.y + (end.origin.y - start.origin.y) * CGFloat(offset), + width: start.width + (end.width - start.width) * CGFloat(offset), + height: start.height + (end.height - start.height) * CGFloat(offset)) + } +} + +struct UIColorContainer: Animatable { + var color: UIColor + + static func valueBetween(start: UIColorContainer, end: UIColorContainer, offset: Double) -> UIColorContainer { + return UIColorContainer(color: UIColor.valueBetween(start: start.color, end: end.color, offset: offset)) + } +} + +extension UIColor { + static func valueBetween(start: UIColor, end: UIColor, offset: Double) -> UIColor { + let offsetF = CGFloat(offset) + let startCIColor = CIColor(color: start) + let endCIColor = CIColor(color: end) + return UIColor(red: startCIColor.red + (endCIColor.red - startCIColor.red) * offsetF, + green: startCIColor.green + (endCIColor.green - startCIColor.green) * offsetF, + blue: startCIColor.blue + (endCIColor.blue - startCIColor.blue) * offsetF, + alpha: startCIColor.alpha + (endCIColor.alpha - startCIColor.alpha) * offsetF) + } +} diff --git a/submodules/Charts/Sources/Helpers/Array+Utils.swift b/submodules/Charts/Sources/Helpers/Array+Utils.swift new file mode 100644 index 0000000000..539a559756 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/Array+Utils.swift @@ -0,0 +1,18 @@ +// +// Array+Utils.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import Foundation + +extension Array { + func safeElement(at index: Int) -> Element? { + if index >= 0 && index < count { + return self[index] + } + return nil + } +} diff --git a/submodules/Charts/Sources/Helpers/CGFloat.swift b/submodules/Charts/Sources/Helpers/CGFloat.swift new file mode 100644 index 0000000000..7bde39b84f --- /dev/null +++ b/submodules/Charts/Sources/Helpers/CGFloat.swift @@ -0,0 +1,17 @@ +// +// CGFloat.swift +// GraphTest +// +// Created by Andrei Salavei on 4/11/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +private let screenScale: CGFloat = UIScreen.main.scale + +extension CGFloat { + func roundedUpToPixelGrid() -> CGFloat { + return (self * screenScale).rounded(.up) / screenScale + } +} diff --git a/submodules/Charts/Sources/Helpers/CGPoint+Extensions.swift b/submodules/Charts/Sources/Helpers/CGPoint+Extensions.swift new file mode 100644 index 0000000000..b5bbd06da4 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/CGPoint+Extensions.swift @@ -0,0 +1,219 @@ +// +// CGPoint+Extensions.swift +// GraphTest +// +// Created by Andrei Salavei on 4/11/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +extension CGPoint { + public init(vector: CGVector) { + self.init(x: vector.dx, y: vector.dy) + } + + + public init(angle: CGFloat) { + self.init(x: cos(angle), y: sin(angle)) + } + + + public mutating func offset(dx: CGFloat, dy: CGFloat) -> CGPoint { + x += dx + y += dy + return self + } + + public func length() -> CGFloat { + return sqrt(x*x + y*y) + } + + public func lengthSquared() -> CGFloat { + return x*x + y*y + } + + func normalized() -> CGPoint { + let len = length() + return len>0 ? self / len : CGPoint.zero + } + + public mutating func normalize() -> CGPoint { + self = normalized() + return self + } + + public func distanceTo(_ point: CGPoint) -> CGFloat { + return (self - point).length() + } + + public var angle: CGFloat { + return atan2(y, x) + } + + public var cgSize: CGSize { + return CGSize(width: x, height: y) + } + + func rotate(origin: CGPoint, angle: CGFloat) -> CGPoint { + let point = self - origin + let s = sin(angle) + let c = cos(angle) + return CGPoint(x: c * point.x - s * point.y, + y: s * point.x + c * point.y) + origin + } +} + +extension CGSize { + public var cgPoint: CGPoint { + return CGPoint(x: width, y: height) + } + + public init(point: CGPoint) { + self.init(width: point.x, height: point.y) + } +} + +public func + (left: CGPoint, right: CGPoint) -> CGPoint { + return CGPoint(x: left.x + right.x, y: left.y + right.y) +} + +public func += (left: inout CGPoint, right: CGPoint) { + left = left + right +} + +public func + (left: CGPoint, right: CGVector) -> CGPoint { + return CGPoint(x: left.x + right.dx, y: left.y + right.dy) +} + +public func += (left: inout CGPoint, right: CGVector) { + left = left + right +} + +public func - (left: CGPoint, right: CGPoint) -> CGPoint { return CGPoint(x: left.x - right.x, y: left.y - right.y) } +public func - (left: CGSize, right: CGSize) -> CGSize { return CGSize(width: left.width - right.width, height: left.height - right.height) } +public func - (left: CGSize, right: CGPoint) -> CGSize { return CGSize(width: left.width - right.x, height: left.height - right.x) } +public func - (left: CGPoint, right: CGSize) -> CGPoint { return CGPoint(x: left.x - right.width, y: left.y - right.height) } + +public func -= (left: inout CGPoint, right: CGPoint) { + left = left - right +} + +public func - (left: CGPoint, right: CGVector) -> CGPoint { + return CGPoint(x: left.x - right.dx, y: left.y - right.dy) +} + +public func -= (left: inout CGPoint, right: CGVector) { + left = left - right +} + +public func *= (left: inout CGPoint, right: CGPoint) { + left = left * right +} + +public func * (point: CGPoint, scalar: CGFloat) -> CGPoint { return CGPoint(x: point.x * scalar, y: point.y * scalar) } +public func * (point: CGSize, scalar: CGFloat) -> CGSize { return CGSize(width: point.width * scalar, height: point.height * scalar) } + +public func *= (point: inout CGPoint, scalar: CGFloat) { point = point * scalar } + +public func * (left: CGPoint, right: CGVector) -> CGPoint { + return CGPoint(x: left.x * right.dx, y: left.y * right.dy) +} + +public func *= (left: inout CGPoint, right: CGVector) { + left = left * right +} + +public func / (left: CGPoint, right: CGPoint) -> CGPoint { return CGPoint(x: left.x / right.x, y: left.y / right.y) } +public func / (left: CGSize, right: CGSize) -> CGSize { return CGSize(width: left.width / right.width, height: left.height / right.height) } +public func / (left: CGPoint, right: CGSize) -> CGPoint { return CGPoint(x: left.x / right.width, y: left.y / right.height) } +public func / (left: CGSize, right: CGPoint) -> CGSize { return CGSize(width: left.width / right.x, height: left.height / right.y) } +public func /= (left: inout CGPoint, right: CGPoint) { left = left / right } +public func /= (left: inout CGSize, right: CGSize) { left = left / right } +public func /= (left: inout CGSize, right: CGPoint) { left = left / right } +public func /= (left: inout CGPoint, right: CGSize) { left = left / right } + + +public func / (point: CGPoint, scalar: CGFloat) -> CGPoint { return CGPoint(x: point.x / scalar, y: point.y / scalar) } +public func / (point: CGSize, scalar: CGFloat) -> CGSize { return CGSize(width: point.width / scalar, height: point.height / scalar) } + +public func /= (point: inout CGPoint, scalar: CGFloat) { + point = point / scalar +} + +public func / (left: CGPoint, right: CGVector) -> CGPoint { + return CGPoint(x: left.x / right.dx, y: left.y / right.dy) +} + +public func / (left: CGSize, right: CGVector) -> CGSize { + return CGSize(width: left.width / right.dx, height: left.height / right.dy) +} + +public func /= (left: inout CGPoint, right: CGVector) { + left = left / right +} + +public func * (left: CGPoint, right: CGPoint) -> CGPoint { return CGPoint(x: left.x * right.x, y: left.y * right.y) } +public func * (left: CGPoint, right: CGSize) -> CGPoint { return CGPoint(x: left.x * right.width, y: left.y * right.height) } +public func *= (left: inout CGPoint, right: CGSize) { left = left * right } +public func * (left: CGSize, right: CGSize) -> CGSize { return CGSize(width: left.width * right.width, height: left.height * right.height) } +public func *= (left: inout CGSize, right: CGSize) { left = left * right } +public func * (left: CGSize, right: CGPoint) -> CGSize { return CGSize(width: left.width * right.x, height: left.height * right.y) } +public func *= (left: inout CGSize, right: CGPoint) { left = left * right } + + +public func lerp(start: CGPoint, end: CGPoint, t: CGFloat) -> CGPoint { + return start + (end - start) * t +} + +public func abs(_ point: CGPoint) -> CGPoint { + return CGPoint(x: abs(point.x), y: abs(point.y)) +} + +extension CGSize { + var isValid: Bool { + return width > 0 && height > 0 && width != .infinity && height != .infinity && width != .nan && height != .nan + } + + var ratio: CGFloat { + return width / height + } +} + + +extension CGRect { + static var identity: CGRect { + return CGRect(x: 0, y: 0, width: 1, height: 1) + } + + var center: CGPoint { + return origin + size.cgPoint / 2 + } + + var rounded: CGRect { + return CGRect(x: origin.x.rounded(), + y: origin.y.rounded(), + width: width.rounded(.up), + height: height.rounded(.up)) + } + + var mirroredVertically: CGRect { + return CGRect(x: origin.x, + y: 1.0 - (origin.y + height), + width: width, + height: height) + } +} + +extension CGAffineTransform { + func inverted(with size: CGSize) -> CGAffineTransform { + var transform = self + let transformedSize = CGRect(origin: .zero, size: size).applying(transform).size + transform.tx /= transformedSize.width; + transform.ty /= transformedSize.height; + transform = transform.inverted() + transform.tx *= transformedSize.width; + transform.ty *= transformedSize.height; + return transform + } +} diff --git a/submodules/Charts/Sources/Helpers/ClosedRange+Utils.swift b/submodules/Charts/Sources/Helpers/ClosedRange+Utils.swift new file mode 100644 index 0000000000..236d6c8a38 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/ClosedRange+Utils.swift @@ -0,0 +1,15 @@ +// +// ClosedRange+Utils.swift +// GraphTest +// +// Created by Andrei Salavei on 3/11/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import Foundation + +extension ClosedRange where Bound: Numeric { + var distance: Bound { + return upperBound - lowerBound + } +} diff --git a/submodules/Charts/Sources/Helpers/CustomNavigationController.swift b/submodules/Charts/Sources/Helpers/CustomNavigationController.swift new file mode 100644 index 0000000000..977244dfcc --- /dev/null +++ b/submodules/Charts/Sources/Helpers/CustomNavigationController.swift @@ -0,0 +1,19 @@ +// +// CustomNavigationController.swift +// GraphTest +// +// Created by Andrew Solovey on 15/03/2019. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class CustomNavigationController: UINavigationController { + override var preferredStatusBarStyle: UIStatusBarStyle { + return topViewController?.preferredStatusBarStyle ?? .default + } + + override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation { + return topViewController?.preferredStatusBarUpdateAnimation ?? .fade + } +} diff --git a/submodules/Charts/Sources/Helpers/DisplayLinkService.swift b/submodules/Charts/Sources/Helpers/DisplayLinkService.swift new file mode 100644 index 0000000000..2c91471c39 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/DisplayLinkService.swift @@ -0,0 +1,114 @@ +// +// DisplayLinkService.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit +import CoreGraphics + +public protocol DisplayLinkListner: class { + func update(delta: TimeInterval) +} + +// DispatchSource mares refreshes more accurate +class DisplayLinkService { + let listners = NSHashTable.weakObjects() + static let shared = DisplayLinkService() + + public func add(listner: DisplayLinkListner) { + listners.add(listner) + startDisplayLink() + } + + public func remove(listner: DisplayLinkListner) { + listners.remove(listner) + + if listners.count == 0 { + stopDisplayLink() + } + } + +// private init() { +// displayLink.add(to: .main, forMode: .common) +// displayLink.preferredFramesPerSecond = 60 +// displayLink.isPaused = true +// } +// +// // MARK: - Display Link +// private lazy var displayLink: CADisplayLink! = { CADisplayLink(target: self, selector: #selector(displayLinkDidFire)) } () +// private var previousTickTime = 0.0 +// +// private func startDisplayLink() { +// guard displayLink.isPaused else { +// return +// } +// previousTickTime = CACurrentMediaTime() +// displayLink.isPaused = false +// } +// +// @objc private func displayLinkDidFire(_ displayLink: CADisplayLink) { +// let currentTime = CACurrentMediaTime() +// let delta = currentTime - previousTickTime +// previousTickTime = currentTime +// let allListners = listners.allObjects +// var hasListners = false +// for listner in allListners { +// (listner as! DisplayLinkListner).update(delta: delta) +// hasListners = true +// } +// +// if !hasListners { +// stopDisplayLink() +// } +// } +// +// private func stopDisplayLink() { +// displayLink.isPaused = true +// } + + private init() { + dispatchSourceTimer.schedule(deadline: .now() + 1.0 / 60, repeating: 1.0 / 60) + dispatchSourceTimer.setEventHandler { + DispatchQueue.main.sync { + self.fire() + } + } + } + + private var dispatchSourceTimer = DispatchSource.makeTimerSource(flags: [], queue: .global(qos: .userInteractive)) + private var dispatchSourceTimerStarted: Bool = false + private var previousTickTime = 0.0 + + private func startDisplayLink() { + guard !dispatchSourceTimerStarted else { return } + dispatchSourceTimerStarted = true + previousTickTime = CACurrentMediaTime() + dispatchSourceTimer.resume() + } + + private func stopDisplayLink() { + guard dispatchSourceTimerStarted else { return } + dispatchSourceTimerStarted = false + dispatchSourceTimer.suspend() + } + + public func fire() { + let currentTime = CACurrentMediaTime() + + let delta = currentTime - previousTickTime + previousTickTime = currentTime + let allListners = listners.allObjects + var hasListners = false + for listner in allListners { + (listner as! DisplayLinkListner).update(delta: delta) + hasListners = true + } + + if !hasListners { + stopDisplayLink() + } + } +} diff --git a/submodules/Charts/Sources/Helpers/GlobalHelpers.swift b/submodules/Charts/Sources/Helpers/GlobalHelpers.swift new file mode 100644 index 0000000000..3f5c488ff9 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/GlobalHelpers.swift @@ -0,0 +1,12 @@ +// +// GlobalHelpers.swift +// TrackingRecorder +// +// Created by Andrew Solovey on 07.09.2018. +// Copyright © 2018 Andrew Solovey. All rights reserved. +// + +public func crop(_ lower: Type, _ val: Type, _ upper: Type) -> Type where Type : Comparable { + assert(lower < upper, "Invalid lover and upper values") + return max(lower, min(upper, val)) +} diff --git a/submodules/Charts/Sources/Helpers/NumberFormatter+Utils.swift b/submodules/Charts/Sources/Helpers/NumberFormatter+Utils.swift new file mode 100644 index 0000000000..1254d44249 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/NumberFormatter+Utils.swift @@ -0,0 +1,19 @@ +// +// NumberFormatter+Utils.swift +// GraphTest +// +// Created by Andrei Salavei on 4/12/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +extension NumberFormatter { + func string(from value: CGFloat) -> String { + return string(from: Double(value)) + } + + func string(from value: Double) -> String { + return string(from: NSNumber(value: Double(value))) ?? "" + } +} diff --git a/submodules/Charts/Sources/Helpers/OnePixelConstraint.swift b/submodules/Charts/Sources/Helpers/OnePixelConstraint.swift new file mode 100644 index 0000000000..03e33e6524 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/OnePixelConstraint.swift @@ -0,0 +1,17 @@ +// +// OnePixelConstraint.swift +// GraphTest +// +// Created by Andrei Salavei on 4/13/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +public class OnePixelConstrain: NSLayoutConstraint { + public override func awakeFromNib() { + super.awakeFromNib() + + constant = UIView.oneDevicePixel + } +} diff --git a/submodules/Charts/Sources/Helpers/ScalesNumberFormatter.swift b/submodules/Charts/Sources/Helpers/ScalesNumberFormatter.swift new file mode 100644 index 0000000000..db067f8a95 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/ScalesNumberFormatter.swift @@ -0,0 +1,32 @@ +// +// ScalesNumberFormatter.swift +// GraphTest +// +// Created by Andrei Salavei on 4/13/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +private let milionsScale = "M" +private let thousandsScale = "K" + +class ScalesNumberFormatter: NumberFormatter { + override func string(from number: NSNumber) -> String? { + let value = number.doubleValue + let pow = log10(value) + if pow >= 6 { + guard let string = super.string(from: NSNumber(value: value / 1_000_000)) else { + return nil + } + return string + milionsScale + } else if pow >= 4 { + guard let string = super.string(from: NSNumber(value: value / 1_000)) else { + return nil + } + return string + thousandsScale + } else { + return super.string(from: number) + } + } +} diff --git a/submodules/Charts/Sources/Helpers/TimeInterval+Utils.swift b/submodules/Charts/Sources/Helpers/TimeInterval+Utils.swift new file mode 100644 index 0000000000..204b1e861a --- /dev/null +++ b/submodules/Charts/Sources/Helpers/TimeInterval+Utils.swift @@ -0,0 +1,27 @@ +// +// TimeInterval+Utils.swift +// GraphTest +// +// Created by Andrei Salavei on 3/13/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import Foundation + +extension TimeInterval { + static let minute: TimeInterval = 60 + static let hour: TimeInterval = 60 * 60 + static let day: TimeInterval = 60 * 60 * 24 + static let osXDuration: TimeInterval = 0.25 + static let expandAnimationDuration: TimeInterval = 0.4 + static var animationDurationMultipler: Double = 1.0 + + static var defaultDuration: TimeInterval { + return innerDefaultDuration * animationDurationMultipler + } + private static var innerDefaultDuration: TimeInterval = osXDuration + + static func setDefaultSuration(_ duration: TimeInterval) { + innerDefaultDuration = duration + } +} diff --git a/submodules/Charts/Sources/Helpers/TimeZone.swift b/submodules/Charts/Sources/Helpers/TimeZone.swift new file mode 100644 index 0000000000..40ba9ab8f5 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/TimeZone.swift @@ -0,0 +1,36 @@ +// +// TimeZone.swift +// GraphTest +// +// Created by Andrei Salavei on 4/9/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import Foundation + +extension TimeZone { + static let utc = TimeZone(secondsFromGMT: 0)! +} + +extension Locale { + static let posix = Locale(identifier: "en_US_POSIX") +} + +extension Calendar { + static let utc: Calendar = { + var calendar = Calendar.current + calendar.locale = Locale.posix + calendar.timeZone = TimeZone.utc + return calendar + }() +} + +extension DateFormatter { + static func utc(format: String = "") -> DateFormatter { + let formatter = DateFormatter() + formatter.calendar = Calendar.utc + formatter.dateFormat = format + formatter.timeZone = TimeZone.utc + return formatter + } +} diff --git a/submodules/Charts/Sources/Helpers/UIColor+Utils.swift b/submodules/Charts/Sources/Helpers/UIColor+Utils.swift new file mode 100644 index 0000000000..0a70421d5e --- /dev/null +++ b/submodules/Charts/Sources/Helpers/UIColor+Utils.swift @@ -0,0 +1,64 @@ +// +// UIColor+Utils.swift +// GraphTest +// +// Created by Andrei Salavei on 3/11/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +extension UIColor { + public convenience init?(hexString: String) { + let r, g, b, a: CGFloat + + if hexString.hasPrefix("#") { + let start = hexString.index(hexString.startIndex, offsetBy: 1) + let hexColor = String(hexString[start...]) + + if hexColor.count == 8 { + let scanner = Scanner(string: hexColor) + var hexNumber: UInt64 = 0 + + if scanner.scanHexInt64(&hexNumber) { + r = CGFloat((hexNumber & 0xff000000) >> 24) / 255 + g = CGFloat((hexNumber & 0x00ff0000) >> 16) / 255 + b = CGFloat((hexNumber & 0x0000ff00) >> 8) / 255 + a = CGFloat(hexNumber & 0x000000ff) / 255 + + self.init(red: r, green: g, blue: b, alpha: a) + return + } + } else if hexColor.count == 6 { + let scanner = Scanner(string: hexColor) + var hexNumber: UInt64 = 0 + + if scanner.scanHexInt64(&hexNumber) { + r = CGFloat((hexNumber & 0xff0000) >> 16) / 255 + g = CGFloat((hexNumber & 0x00ff00) >> 8) / 255 + b = CGFloat((hexNumber & 0x0000ff) >> 0) / 255 + + self.init(red: r, green: g, blue: b, alpha: 1.0) + return + } + } + } + return nil + } + + func image(_ size: CGSize = CGSize(width: 1, height: 1)) -> UIImage { + if #available(iOS 10.0, *) { + return UIGraphicsImageRenderer(size: size).image { rendererContext in + self.setFill() + rendererContext.fill(CGRect(origin: .zero, size: size)) + } + } else { + return UIImage() + } + } + + var redValue: CGFloat{ return CIColor(color: self).red } + var greenValue: CGFloat{ return CIColor(color: self).green } + var blueValue: CGFloat{ return CIColor(color: self).blue } + var alphaValue: CGFloat{ return CIColor(color: self).alpha } +} diff --git a/submodules/Charts/Sources/Helpers/UIImage+Utils.swift b/submodules/Charts/Sources/Helpers/UIImage+Utils.swift new file mode 100644 index 0000000000..50964025c2 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/UIImage+Utils.swift @@ -0,0 +1,28 @@ +// +// UIImage+Utils.swift +// GraphTest +// +// Created by Andrei Salavei on 4/8/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +extension UIImage { + static let arrowRight = UIImage(bundleImageName: "Chart/arrow_right") + static let arrowLeft = UIImage(bundleImageName: "Chart/arrow_left") + + public convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) { + let rect = CGRect(origin: .zero, size: size) + UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0) + color.setFill() + UIRectFill(rect) + let image = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + + guard let cgImage = image?.cgImage else { return nil } + self.init(cgImage: cgImage) + } + + +} diff --git a/submodules/Charts/Sources/Helpers/UIImageView+Utils.swift b/submodules/Charts/Sources/Helpers/UIImageView+Utils.swift new file mode 100644 index 0000000000..608f25a114 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/UIImageView+Utils.swift @@ -0,0 +1,24 @@ +// +// UIImageView+Utils.swift +// GraphTest +// +// Created by Andrei Salavei on 4/9/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +extension UIImageView { + func setImage(_ image: UIImage?, animated: Bool) { + if self.image != image { + if animated { + let animation = CATransition() + animation.timingFunction = CAMediaTimingFunction.init(name: .linear) + animation.type = .fade + animation.duration = .defaultDuration + self.layer.add(animation, forKey: "kCATransitionImageFade") + } + self.image = image + } + } +} diff --git a/submodules/Charts/Sources/Helpers/UILabel+Utils.swift b/submodules/Charts/Sources/Helpers/UILabel+Utils.swift new file mode 100644 index 0000000000..6c41c73fd9 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/UILabel+Utils.swift @@ -0,0 +1,37 @@ +// +// UILabel+Utils.swift +// GraphTest +// +// Created by Andrei Salavei on 4/9/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +extension UILabel { + func setTextColor(_ color: UIColor, animated: Bool) { + if self.textColor != color { + if animated { + let animation = CATransition() + animation.timingFunction = CAMediaTimingFunction.init(name: .linear) + animation.type = .fade + animation.duration = .defaultDuration + self.layer.add(animation, forKey: "kCATransitionColorFade") + } + self.textColor = color + } + } + + func setText(_ title: String?, animated: Bool) { + if self.text != title { + if animated { + let animation = CATransition() + animation.timingFunction = CAMediaTimingFunction.init(name: .linear) + animation.type = .fade + animation.duration = .defaultDuration + self.layer.add(animation, forKey: "kCATransitionTextFade") + } + self.text = title + } + } +} diff --git a/submodules/Charts/Sources/Helpers/UIView+Extensions.swift b/submodules/Charts/Sources/Helpers/UIView+Extensions.swift new file mode 100644 index 0000000000..bba2d1f886 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/UIView+Extensions.swift @@ -0,0 +1,57 @@ +// +// UIView+Extensions.swift +// GraphTest +// +// Created by Andrei Salavei on 4/10/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +extension UIView { + static let oneDevicePixel: CGFloat = (1.0 / max(2, min(1, UIScreen.main.scale))) +} + +// MARK: UIView+Animation +public extension UIView { + func bringToFront() { + superview?.bringSubviewToFront(self) + } + + func layoutIfNeeded(animated: Bool) { + UIView.perform(animated: animated) { + self.layoutIfNeeded() + } + } + + func setVisible(_ visible: Bool, animated: Bool) { + let updatedAlpha: CGFloat = visible ? 1 : 0 + if self.alpha != updatedAlpha { + UIView.perform(animated: animated) { + self.alpha = updatedAlpha + } + } + } + + static func perform(animated: Bool, animations: @escaping () -> Void) { + perform(animated: animated, animations: animations, completion: { _ in }) + } + + static func perform(animated: Bool, animations: @escaping () -> Void, completion: @escaping (Bool) -> Void) { + if animated { + + UIView.animate(withDuration: .defaultDuration, delay: 0, animations: animations, completion: completion) + } else { + animations() + completion(true) + } + } + + var isVisibleInWindow: Bool { + guard let windowBounds = window?.bounds else { + return false + } + let frame = convert(bounds, to: nil) + return frame.intersects(windowBounds) + } +} diff --git a/submodules/Charts/Sources/Models/ChartLineData.swift b/submodules/Charts/Sources/Models/ChartLineData.swift new file mode 100644 index 0000000000..79813a2a35 --- /dev/null +++ b/submodules/Charts/Sources/Models/ChartLineData.swift @@ -0,0 +1,76 @@ +// +// ChartLineData.swift +// GraphTest +// +// Created by Andrei Salavei on 3/13/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +struct ChartLineData { + var title: String + var color: UIColor + var width: CGFloat? + var points: [CGPoint] +} + +extension ChartLineData { + static func horizontalRange(lines: [ChartLineData]) -> ClosedRange? { + guard let firstPoint = lines.first?.points.first else { return nil } + var hMin: CGFloat = firstPoint.x + var hMax: CGFloat = firstPoint.x + + for line in lines { + if let first = line.points.first, + let last = line.points.last { + hMin = min(hMin, first.x) + hMax = max(hMax, last.x) + } + } + + return hMin...hMax + } + + static func verticalRange(lines: [ChartLineData], calculatingRange: ClosedRange? = nil, addBounds: Bool = false) -> ClosedRange? { + if let calculatingRange = calculatingRange { + guard let initalStart = lines.first?.points.first(where: { $0.x > calculatingRange.lowerBound && + $0.x < calculatingRange.upperBound }) else { return nil } + var vMin: CGFloat = initalStart.y + var vMax: CGFloat = initalStart.y + for line in lines { + if var index = line.points.firstIndex(where: { $0.x > calculatingRange.lowerBound }) { + if addBounds { + index = max(0, index - 1) + } + while index < line.points.count { + let point = line.points[index] + if point.x < calculatingRange.upperBound { + vMin = min(vMin, point.y) + vMax = max(vMax, point.y) + } else if addBounds { + vMin = min(vMin, point.y) + vMax = max(vMax, point.y) + break + } else { + break + } + index += 1 + } + } + } + return vMin...vMax + } else { + guard let firstPoint = lines.first?.points.first else { return nil } + var vMin: CGFloat = firstPoint.y + var vMax: CGFloat = firstPoint.y + for line in lines { + for point in line.points { + vMin = min(vMin, point.y) + vMax = max(vMax, point.y) + } + } + return vMin...vMax + } + } +} diff --git a/submodules/Charts/Sources/Models/ColorMode.swift b/submodules/Charts/Sources/Models/ColorMode.swift new file mode 100644 index 0000000000..f0de7b52ae --- /dev/null +++ b/submodules/Charts/Sources/Models/ColorMode.swift @@ -0,0 +1,175 @@ +// +// ColorMode.swift +// GraphTest +// +// Created by Andrew Solovey on 15/03/2019. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit +import AppBundle + +protocol ColorModeContainer { + func apply(colorMode: ColorMode, animated: Bool) +} + +enum ColorMode { + case day + case night +} + +extension ColorMode { + var chartTitleColor: UIColor { // ТекŃŃ‚ Ń Đ´Đ°Ń‚ĐľĐą на чарте + switch self { + case .day: return .black + case .night: return .white + } + } + + var actionButtonColor: UIColor { // Кнопка Zoom Out/ Смена режима день/ночь + switch self { + case .day: return UIColor(red: 53/255.0, green: 120/255.0, blue: 246/255.0, alpha: 1.0) + case .night: return UIColor(red: 84/255.0, green: 164/255.0, blue: 247/255.0, alpha: 1.0) + } + } + + var tableBackgroundColor: UIColor { + switch self { + case .day: return UIColor(red: 239/255.0, green: 239/255.0, blue: 244/255.0, alpha: 1.0) + case .night: return UIColor(red: 24/255.0, green: 34/255.0, blue: 45/255.0, alpha: 1.0) + } + } + + var chartBackgroundColor: UIColor { + switch self { + case .day: return UIColor(red: 254/255.0, green: 254/255.0, blue: 254/255.0, alpha: 1.0) + case .night: return UIColor(red: 34/255.0, green: 47/255.0, blue: 63/255.0, alpha: 1.0) + } + } + + var sectionTitleColor: UIColor { + switch self { + case .day: return UIColor(red: 109/255.0, green: 109/255.0, blue: 114/255.0, alpha: 1.0) + case .night: return UIColor(red: 133/255.0, green: 150/255.0, blue: 171/255.0, alpha: 1.0) + } + } + + var tableSeparatorColor: UIColor { + switch self { + case .day: return UIColor(red: 200/255.0, green: 199/255.0, blue: 204/255.0, alpha: 1.0) + case .night: return UIColor(red: 18/255.0, green: 26/255.0, blue: 35/255.0, alpha: 1.0) + } + } + + var chartLabelsColor: UIColor { + switch self { + case .day: return UIColor(red: 37/255.0, green: 37/255.0, blue: 41/255.0, alpha: 0.5) + case .night: return UIColor(red: 186/255.0, green: 204/255.0, blue: 225/255.0, alpha: 0.6) + } + } + + var chartHelperLinesColor: UIColor { + switch self { + case .day: return UIColor(red: 24/255.0, green: 45/255.0, blue: 59/255.0, alpha: 0.1) + case .night: return UIColor(red: 133/255.0, green: 150/255.0, blue: 171/255.0, alpha: 0.20) + } + } + + var chartStrongLinesColor: UIColor { + switch self { + case .day: return UIColor(red: 24/255.0, green: 45/255.0, blue: 59/255.0, alpha: 0.35) + case .night: return UIColor(red: 186/255.0, green: 204/255.0, blue: 225/255.0, alpha: 0.45) + } + } + + var barChartStrongLinesColor: UIColor { + switch self { + case .day: return UIColor(red: 37/255.0, green: 37/255.0, blue: 41/255.0, alpha: 0.2) + case .night: return UIColor(red: 186/255.0, green: 204/255.0, blue: 225/255.0, alpha: 0.45) + } + } + + var chartDetailsTextColor: UIColor { + switch self { + case .day: return UIColor(red: 109/255.0, green: 109/255.0, blue: 114/255.0, alpha: 1.0) + case .night: return UIColor(red: 254/255.0, green: 254/255.0, blue: 254/255.0, alpha: 1.0) + } + } + + var chartDetailsArrowColor: UIColor { + switch self { + case .day: return UIColor(red: 197/255.0, green: 199/255.0, blue: 205/255.0, alpha: 1.0) + case .night: return UIColor(red: 76/255.0, green: 84/255.0, blue: 96/255.0, alpha: 1.0) + } + } + + var chartDetailsViewColor: UIColor { + switch self { + case .day: return UIColor(red: 245/255.0, green: 245/255.0, blue: 251/255.0, alpha: 1.0) + case .night: return UIColor(red: 25/255.0, green: 35/255.0, blue: 47/255.0, alpha: 1.0) + } + } + + var descriptionChatNameColor: UIColor { + switch self { + case .day: return .black + case .night: return UIColor(red: 254/255.0, green: 254/255.0, blue: 254/255.0, alpha: 1.0) + } + } + + var descriptionActionColor: UIColor { + switch self { + case .day: return UIColor(red: 1/255.0, green: 125/255.0, blue: 229/255.0, alpha: 1.0) + case .night: return UIColor(red: 24/255.0, green: 145/255.0, blue: 255/255.0, alpha: 1.0) + } + } + + var rangeViewBackgroundColor: UIColor { + switch self { + case .day: return UIColor(red: 254/255.0, green: 254/255.0, blue: 254/255.0, alpha: 1.0) + case .night: return UIColor(red: 34/255.0, green: 47/255.0, blue: 63/255.0, alpha: 1.0) + } + } + + var rangeViewFrameColor: UIColor { + switch self { + case .day: return UIColor(red: 202/255.0, green: 212/255.0, blue: 222/255.0, alpha: 1.0) + case .night: return UIColor(red: 53/255.0, green: 70/255.0, blue: 89/255.0, alpha: 1.0) + } + } + + var rangeViewTintColor: UIColor { + switch self { + case .day: return UIColor(red: 239/255.0, green: 239/255.0, blue: 244/255.0, alpha: 0.5) + case .night: return UIColor(red: 24/255.0, green: 34/255.0, blue: 45/255.0, alpha: 0.5) + } + } + + var rangeViewMarkerColor: UIColor { + switch self { + case .day: return UIColor.white + case .night: return UIColor.white + } + } + + var statusBarStyle: UIStatusBarStyle { + switch self { + case .day: return .default + case .night: return .lightContent + } + } + + var viewTintColor: UIColor { + switch self { + case .day: return .black + case .night: return UIColor(red: 254/255.0, green: 254/255.0, blue: 254/255.0, alpha: 1.0) + } + } + + var rangeCropImage: UIImage? { + switch self { + case .day: return UIImage(bundleImageName: "Chart/selection_frame_light") + case .night: return UIImage(bundleImageName: "Chart/selection_frame_dark") + } + } +} diff --git a/submodules/Charts/Sources/Models/LinesChartLabel.swift b/submodules/Charts/Sources/Models/LinesChartLabel.swift new file mode 100644 index 0000000000..6ace8c2c65 --- /dev/null +++ b/submodules/Charts/Sources/Models/LinesChartLabel.swift @@ -0,0 +1,25 @@ +// +// LinesChartLabel.swift +// GraphTest +// +// Created by Andrei Salavei on 3/18/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +struct LinesChartLabel: Hashable { + let value: CGFloat + let text: String +} + +class AnimatedLinesChartLabels { + var labels: [LinesChartLabel] + var isAppearing: Bool = false + let alphaAnimator: AnimationController + + init(labels: [LinesChartLabel], alphaAnimator: AnimationController) { + self.labels = labels + self.alphaAnimator = alphaAnimator + } +} diff --git a/submodules/Charts/Sources/Models/LinesSelectionLabel.swift b/submodules/Charts/Sources/Models/LinesSelectionLabel.swift new file mode 100644 index 0000000000..0fd7142eda --- /dev/null +++ b/submodules/Charts/Sources/Models/LinesSelectionLabel.swift @@ -0,0 +1,15 @@ +// +// LinesSelectionLabel.swift +// GraphTest +// +// Created by Andrei Salavei on 3/18/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +struct LinesSelectionLabel { + let coordinate: CGPoint + let valueText: String + let color: UIColor +} diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index f2049711c5..4874490784 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -22,10 +22,6 @@ import AppBundle import LocalizedPeerData import TelegramIntents -public func useSpecialTabBarIcons() -> Bool { - return (Date(timeIntervalSince1970: 1545642000)...Date(timeIntervalSince1970: 1546387200)).contains(Date()) -} - private func fixListNodeScrolling(_ listNode: ListView, searchNode: NavigationBarSearchContentNode) -> Bool { if searchNode.expansionProgress > 0.0 && searchNode.expansionProgress < 1.0 { let scrollToItem: ListViewScrollToItem @@ -178,8 +174,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController, self.tabBarItem.title = self.presentationData.strings.DialogList_Title let icon: UIImage? - if (useSpecialTabBarIcons()) { - icon = UIImage(bundleImageName: "Chat List/Tabs/NY/IconChats") + if useSpecialTabBarIcons() { + icon = UIImage(bundleImageName: "Chat List/Tabs/Holiday/IconChats") } else { icon = UIImage(bundleImageName: "Chat List/Tabs/IconChats") } diff --git a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift index 22e250ef4a..af2a6d1b88 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift @@ -715,7 +715,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo return (views, local) } } - |> mapToSignal{ viewsAndPeers -> Signal<(peers: [RenderedPeer], unread: [PeerId: (Int32, Bool)]), NoError> in + |> mapToSignal { viewsAndPeers -> Signal<(peers: [RenderedPeer], unread: [PeerId: (Int32, Bool)]), NoError> in return context.account.postbox.unreadMessageCountsView(items: viewsAndPeers.0.map {.peer($0.peerId)}) |> map { values in var unread: [PeerId: (Int32, Bool)] = [:] for peerView in viewsAndPeers.0 { @@ -804,8 +804,18 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo ) } - return combineLatest(accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, presentationDataPromise.get(), searchStatePromise.get()) - |> map { accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, presentationData, searchState -> ([ChatListSearchEntry], Bool)? in + let resolvedMessage = .single(nil) + |> then(context.sharedContext.resolveUrl(account: context.account, url: query) + |> mapToSignal { resolvedUrl -> Signal in + if case let .channelMessage(peerId, messageId) = resolvedUrl { + return downloadMessage(postbox: context.account.postbox, network: context.account.network, messageId: messageId) + } else { + return .single(nil) + } + }) + + return combineLatest(accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, presentationDataPromise.get(), searchStatePromise.get(), resolvedMessage) + |> map { accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, presentationData, searchState, resolvedMessage -> ([ChatListSearchEntry], Bool)? in var entries: [ChatListSearchEntry] = [] let isSearching = foundRemotePeers.2 || foundRemoteMessages.1 var index = 0 @@ -938,6 +948,17 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo } } + if let message = resolvedMessage { + var peer = RenderedPeer(message: message) + if let group = message.peers[message.id.peerId] as? TelegramGroup, let migrationReference = group.migrationReference { + if let channelPeer = message.peers[migrationReference.peerId] { + peer = RenderedPeer(peer: channelPeer) + } + } + entries.append(.message(message, peer, nil, presentationData)) + index += 1 + } + if !foundRemotePeers.2 { index = 0 for message in foundRemoteMessages.0.0 { diff --git a/submodules/ContactListUI/Sources/ContactsController.swift b/submodules/ContactListUI/Sources/ContactsController.swift index 7dcfc4b716..b65dfabfec 100644 --- a/submodules/ContactListUI/Sources/ContactsController.swift +++ b/submodules/ContactListUI/Sources/ContactsController.swift @@ -105,7 +105,12 @@ public class ContactsController: ViewController { self.title = self.presentationData.strings.Contacts_Title self.tabBarItem.title = self.presentationData.strings.Contacts_Title - let icon = UIImage(bundleImageName: "Chat List/Tabs/IconContacts") + let icon: UIImage? + if useSpecialTabBarIcons() { + icon = UIImage(bundleImageName: "Chat List/Tabs/Holiday/IconContacts") + } else { + icon = UIImage(bundleImageName: "Chat List/Tabs/IconContacts") + } self.tabBarItem.image = icon self.tabBarItem.selectedImage = icon diff --git a/submodules/Display/Display/TabBarNode.swift b/submodules/Display/Display/TabBarNode.swift index f83a6b1289..9301512ec1 100644 --- a/submodules/Display/Display/TabBarNode.swift +++ b/submodules/Display/Display/TabBarNode.swift @@ -442,7 +442,7 @@ class TabBarNode: ASDisplayNode { if horizontal { backgroundFrame = CGRect(origin: CGPoint(x: originX + 15.0, y: 3.0), size: backgroundSize) } else { - let contentWidth = node.contentWidth ?? node.frame.width + let contentWidth: CGFloat = 25.0 //node.contentWidth ?? node.frame.width backgroundFrame = CGRect(origin: CGPoint(x: floor(originX + node.frame.width / 2.0) + contentWidth - backgroundSize.width - 5.0, y: self.centered ? 9.0 : 2.0), size: backgroundSize) } transition.updateFrame(node: container.badgeContainerNode, frame: backgroundFrame) diff --git a/submodules/GalleryUI/Sources/GalleryController.swift b/submodules/GalleryUI/Sources/GalleryController.swift index 53b10ecb22..e0acc9d09c 100644 --- a/submodules/GalleryUI/Sources/GalleryController.swift +++ b/submodules/GalleryUI/Sources/GalleryController.swift @@ -332,7 +332,7 @@ public class GalleryController: ViewController, StandalonePresentableController private let centralItemRightBarButtonItem = Promise() private let centralItemRightBarButtonItems = Promise<[UIBarButtonItem]?>(nil) private let centralItemNavigationStyle = Promise() - private let centralItemFooterContentNode = Promise() + private let centralItemFooterContentNode = Promise<(GalleryFooterContentNode?, GalleryOverlayContentNode?)>() private let centralItemAttributesDisposable = DisposableSet(); private let _hiddenMedia = Promise<(MessageId, Media)?>(nil) @@ -531,9 +531,9 @@ public class GalleryController: ViewController, StandalonePresentableController } })) - self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode in + self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode, overlayContentNode in self?.galleryNode.updatePresentationState({ - $0.withUpdatedFooterContentNode(footerContentNode) + $0.withUpdatedFooterContentNode(footerContentNode).withUpdatedOverlayContentNode(overlayContentNode) }, transition: .immediate) })) diff --git a/submodules/GalleryUI/Sources/GalleryControllerNode.swift b/submodules/GalleryUI/Sources/GalleryControllerNode.swift index 0c82bd5bec..5409b07a5b 100644 --- a/submodules/GalleryUI/Sources/GalleryControllerNode.swift +++ b/submodules/GalleryUI/Sources/GalleryControllerNode.swift @@ -250,8 +250,8 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture self.updateThumbnailContainerNodeAlpha(transition) } - self.footerNode.updateLayout(layout, footerContentNode: self.presentationState.footerContentNode, thumbnailPanelHeight: thumbnailPanelHeight, transition: transition) - + self.footerNode.updateLayout(layout, footerContentNode: self.presentationState.footerContentNode, overlayContentNode: self.presentationState.overlayContentNode, thumbnailPanelHeight: thumbnailPanelHeight, transition: transition) + let previousContentHeight = self.scrollView.contentSize.height let previousVerticalOffset = self.scrollView.contentOffset.y @@ -276,14 +276,14 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture let alpha: CGFloat = self.areControlsHidden ? 0.0 : 1.0 self.navigationBar?.alpha = alpha self.statusBar?.updateAlpha(alpha, transition: .animated(duration: 0.3, curve: .easeInOut)) - self.footerNode.alpha = alpha + self.footerNode.setVisibilityAlpha(alpha) self.updateThumbnailContainerNodeAlpha(.immediate) }) } else { let alpha: CGFloat = self.areControlsHidden ? 0.0 : 1.0 self.navigationBar?.alpha = alpha self.statusBar?.updateAlpha(alpha, transition: .immediate) - self.footerNode.alpha = alpha + self.footerNode.setVisibilityAlpha(alpha) self.updateThumbnailContainerNodeAlpha(.immediate) } } diff --git a/submodules/GalleryUI/Sources/GalleryControllerPresentationState.swift b/submodules/GalleryUI/Sources/GalleryControllerPresentationState.swift index 7fd9620cb5..4881b7744e 100644 --- a/submodules/GalleryUI/Sources/GalleryControllerPresentationState.swift +++ b/submodules/GalleryUI/Sources/GalleryControllerPresentationState.swift @@ -2,16 +2,23 @@ import Foundation public final class GalleryControllerPresentationState { public let footerContentNode: GalleryFooterContentNode? + public let overlayContentNode: GalleryOverlayContentNode? public init() { self.footerContentNode = nil + self.overlayContentNode = nil } - public init(footerContentNode: GalleryFooterContentNode?) { + public init(footerContentNode: GalleryFooterContentNode?, overlayContentNode: GalleryOverlayContentNode?) { self.footerContentNode = footerContentNode + self.overlayContentNode = overlayContentNode } public func withUpdatedFooterContentNode(_ footerContentNode: GalleryFooterContentNode?) -> GalleryControllerPresentationState { - return GalleryControllerPresentationState(footerContentNode: footerContentNode) + return GalleryControllerPresentationState(footerContentNode: footerContentNode, overlayContentNode: self.overlayContentNode) + } + + public func withUpdatedOverlayContentNode(_ overlayContentNode: GalleryOverlayContentNode?) -> GalleryControllerPresentationState { + return GalleryControllerPresentationState(footerContentNode: self.footerContentNode, overlayContentNode: overlayContentNode) } } diff --git a/submodules/GalleryUI/Sources/GalleryFooterContentNode.swift b/submodules/GalleryUI/Sources/GalleryFooterContentNode.swift index 9fe0dadf41..1d9126eec0 100644 --- a/submodules/GalleryUI/Sources/GalleryFooterContentNode.swift +++ b/submodules/GalleryUI/Sources/GalleryFooterContentNode.swift @@ -31,3 +31,20 @@ open class GalleryFooterContentNode: ASDisplayNode { completion() } } + +open class GalleryOverlayContentNode: ASDisplayNode { + var visibilityAlpha: CGFloat = 1.0 + open func setVisibilityAlpha(_ alpha: CGFloat) { + self.visibilityAlpha = alpha + } + + open func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) { + } + + open func animateIn(previousContentNode: GalleryOverlayContentNode?, transition: ContainedViewLayoutTransition) { + } + + open func animateOut(nextContentNode: GalleryOverlayContentNode?, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void) { + completion() + } +} diff --git a/submodules/GalleryUI/Sources/GalleryFooterNode.swift b/submodules/GalleryUI/Sources/GalleryFooterNode.swift index 7537360dce..155f2cc358 100644 --- a/submodules/GalleryUI/Sources/GalleryFooterNode.swift +++ b/submodules/GalleryUI/Sources/GalleryFooterNode.swift @@ -7,6 +7,7 @@ public final class GalleryFooterNode: ASDisplayNode { private let backgroundNode: ASDisplayNode private var currentFooterContentNode: GalleryFooterContentNode? + private var currentOverlayContentNode: GalleryOverlayContentNode? private var currentLayout: (ContainerViewLayout, CGFloat)? private let controllerInteraction: GalleryControllerInteraction @@ -22,38 +23,59 @@ public final class GalleryFooterNode: ASDisplayNode { self.addSubnode(self.backgroundNode) } - public func updateLayout(_ layout: ContainerViewLayout, footerContentNode: GalleryFooterContentNode?, thumbnailPanelHeight: CGFloat, transition: ContainedViewLayoutTransition) { + private var visibilityAlpha: CGFloat = 1.0 + public func setVisibilityAlpha(_ alpha: CGFloat) { + self.visibilityAlpha = alpha + self.backgroundNode.alpha = alpha + self.currentFooterContentNode?.alpha = alpha + self.currentOverlayContentNode?.setVisibilityAlpha(alpha) + } + + public func updateLayout(_ layout: ContainerViewLayout, footerContentNode: GalleryFooterContentNode?, overlayContentNode: GalleryOverlayContentNode?, thumbnailPanelHeight: CGFloat, transition: ContainedViewLayoutTransition) { self.currentLayout = (layout, thumbnailPanelHeight) let cleanInsets = layout.insets(options: []) - var removeCurrentFooterContentNode: GalleryFooterContentNode? + var dismissedCurrentFooterContentNode: GalleryFooterContentNode? if self.currentFooterContentNode !== footerContentNode { if let currentFooterContentNode = self.currentFooterContentNode { currentFooterContentNode.requestLayout = nil - removeCurrentFooterContentNode = currentFooterContentNode + dismissedCurrentFooterContentNode = currentFooterContentNode } self.currentFooterContentNode = footerContentNode if let footerContentNode = footerContentNode { + footerContentNode.alpha = self.visibilityAlpha footerContentNode.controllerInteraction = self.controllerInteraction footerContentNode.requestLayout = { [weak self] transition in if let strongSelf = self, let (currentLayout, currentThumbnailPanelHeight) = strongSelf.currentLayout { - strongSelf.updateLayout(currentLayout, footerContentNode: strongSelf.currentFooterContentNode, thumbnailPanelHeight: currentThumbnailPanelHeight, transition: transition) + strongSelf.updateLayout(currentLayout, footerContentNode: strongSelf.currentFooterContentNode, overlayContentNode: strongSelf.currentOverlayContentNode, thumbnailPanelHeight: currentThumbnailPanelHeight, transition: transition) } } self.addSubnode(footerContentNode) } } + var dismissedCurrentOverlayContentNode: GalleryOverlayContentNode? + if self.currentOverlayContentNode !== overlayContentNode { + if let currentOverlayContentNode = self.currentOverlayContentNode { + dismissedCurrentOverlayContentNode = currentOverlayContentNode + } + self.currentOverlayContentNode = overlayContentNode + if let overlayContentNode = overlayContentNode { + overlayContentNode.setVisibilityAlpha(self.visibilityAlpha) + self.addSubnode(overlayContentNode) + } + } + var backgroundHeight: CGFloat = 0.0 if let footerContentNode = self.currentFooterContentNode { backgroundHeight = footerContentNode.updateLayout(size: layout.size, metrics: layout.metrics, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: cleanInsets.bottom, contentInset: thumbnailPanelHeight, transition: transition) transition.updateFrame(node: footerContentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - backgroundHeight), size: CGSize(width: layout.size.width, height: backgroundHeight))) - if let removeCurrentFooterContentNode = removeCurrentFooterContentNode { + if let dismissedCurrentFooterContentNode = dismissedCurrentFooterContentNode { let contentTransition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring) - footerContentNode.animateIn(fromHeight: removeCurrentFooterContentNode.bounds.height, previousContentNode: removeCurrentFooterContentNode, transition: contentTransition) - removeCurrentFooterContentNode.animateOut(toHeight: backgroundHeight, nextContentNode: footerContentNode, transition: contentTransition, completion: { [weak self, weak removeCurrentFooterContentNode] in - if let strongSelf = self, let removeCurrentFooterContentNode = removeCurrentFooterContentNode, removeCurrentFooterContentNode !== strongSelf.currentFooterContentNode { - removeCurrentFooterContentNode.removeFromSupernode() + footerContentNode.animateIn(fromHeight: dismissedCurrentFooterContentNode.bounds.height, previousContentNode: dismissedCurrentFooterContentNode, transition: contentTransition) + dismissedCurrentFooterContentNode.animateOut(toHeight: backgroundHeight, nextContentNode: footerContentNode, transition: contentTransition, completion: { [weak self, weak dismissedCurrentFooterContentNode] in + if let strongSelf = self, let dismissedCurrentFooterContentNode = dismissedCurrentFooterContentNode, dismissedCurrentFooterContentNode !== strongSelf.currentFooterContentNode { + dismissedCurrentFooterContentNode.removeFromSupernode() } }) contentTransition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - backgroundHeight), size: CGSize(width: layout.size.width, height: backgroundHeight))) @@ -61,15 +83,41 @@ public final class GalleryFooterNode: ASDisplayNode { transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - backgroundHeight), size: CGSize(width: layout.size.width, height: backgroundHeight))) } } else { - if let removeCurrentFooterContentNode = removeCurrentFooterContentNode { - removeCurrentFooterContentNode.removeFromSupernode() + if let dismissedCurrentFooterContentNode = dismissedCurrentFooterContentNode { + dismissedCurrentFooterContentNode.removeFromSupernode() } transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - backgroundHeight), size: CGSize(width: layout.size.width, height: backgroundHeight))) } + + let contentTransition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring) + if let overlayContentNode = self.currentOverlayContentNode { + overlayContentNode.updateLayout(size: layout.size, metrics: layout.metrics, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: backgroundHeight, transition: transition) + transition.updateFrame(node: overlayContentNode, frame: CGRect(origin: CGPoint(), size: layout.size)) + + overlayContentNode.animateIn(previousContentNode: dismissedCurrentOverlayContentNode, transition: contentTransition) + if let dismissedCurrentOverlayContentNode = dismissedCurrentOverlayContentNode { + dismissedCurrentOverlayContentNode.animateOut(nextContentNode: overlayContentNode, transition: contentTransition, completion: { [weak self, weak dismissedCurrentOverlayContentNode] in + if let strongSelf = self, let dismissedCurrentOverlayContentNode = dismissedCurrentOverlayContentNode, dismissedCurrentOverlayContentNode !== strongSelf.currentOverlayContentNode { + dismissedCurrentOverlayContentNode.removeFromSupernode() + } + }) + } + } else { + if let dismissedCurrentOverlayContentNode = dismissedCurrentOverlayContentNode { + dismissedCurrentOverlayContentNode.animateOut(nextContentNode: overlayContentNode, transition: contentTransition, completion: { [weak self, weak dismissedCurrentOverlayContentNode] in + if let strongSelf = self, let dismissedCurrentOverlayContentNode = dismissedCurrentOverlayContentNode, dismissedCurrentOverlayContentNode !== strongSelf.currentOverlayContentNode { + dismissedCurrentOverlayContentNode.removeFromSupernode() + } + }) + } + } } override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + if let overlayResult = self.currentOverlayContentNode?.hitTest(point, with: event) { + return overlayResult + } if !self.backgroundNode.frame.contains(point) { return nil } diff --git a/submodules/GalleryUI/Sources/GalleryItemNode.swift b/submodules/GalleryUI/Sources/GalleryItemNode.swift index ce3d8b3c59..615bdde364 100644 --- a/submodules/GalleryUI/Sources/GalleryItemNode.swift +++ b/submodules/GalleryUI/Sources/GalleryItemNode.swift @@ -21,6 +21,8 @@ open class GalleryItemNode: ASDisplayNode { } public var toggleControlsVisibility: () -> Void = { } + public var goToPreviousItem: () -> Void = { } + public var goToNextItem: () -> Void = { } public var dismiss: () -> Void = { } public var beginCustomDismiss: () -> Void = { } public var completeCustomDismiss: () -> Void = { } @@ -54,8 +56,8 @@ open class GalleryItemNode: ASDisplayNode { return .single(nil) } - open func footerContent() -> Signal { - return .single(nil) + open func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((nil, nil)) } open func navigationStyle() -> Signal { diff --git a/submodules/GalleryUI/Sources/GalleryPagerNode.swift b/submodules/GalleryUI/Sources/GalleryPagerNode.swift index fea7e407af..125b432cdc 100644 --- a/submodules/GalleryUI/Sources/GalleryPagerNode.swift +++ b/submodules/GalleryUI/Sources/GalleryPagerNode.swift @@ -241,6 +241,20 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate { private func makeNodeForItem(at index: Int) -> GalleryItemNode { let node = self.items[index].node() node.toggleControlsVisibility = self.toggleControlsVisibility + node.goToPreviousItem = { [weak self] in + if let strongSelf = self { + if let index = strongSelf.centralItemIndex, index > 0 { + strongSelf.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: index - 1)) + } + } + } + node.goToNextItem = { [weak self] in + if let strongSelf = self { + if let index = strongSelf.centralItemIndex, index < strongSelf.items.count - 1 { + strongSelf.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: index + 1)) + } + } + } node.dismiss = self.dismiss node.beginCustomDismiss = self.beginCustomDismiss node.completeCustomDismiss = self.completeCustomDismiss @@ -314,7 +328,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate { } } - if centralItemIndex != items.count - 1 { + if centralItemIndex != self.items.count - 1 { if self.shouldLoadItems(force: forceLoad) && self.visibleItemNode(at: centralItemIndex + 1) == nil { let node = self.makeNodeForItem(at: centralItemIndex + 1) node.frame = centralItemNode.frame.offsetBy(dx: centralItemNode.frame.size.width + self.pageGap, dy: 0.0) diff --git a/submodules/GalleryUI/Sources/Items/ChatAnimationGalleryItem.swift b/submodules/GalleryUI/Sources/Items/ChatAnimationGalleryItem.swift index f4f24f1221..834d6758d1 100644 --- a/submodules/GalleryUI/Sources/Items/ChatAnimationGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/ChatAnimationGalleryItem.swift @@ -325,8 +325,8 @@ final class ChatAnimationGalleryItemNode: ZoomableContentGalleryItemNode { return self._rightBarButtonItems.get() } - override func footerContent() -> Signal { - return .single(self.footerContentNode) + override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((self.footerContentNode, nil)) } @objc func statusPressed() { diff --git a/submodules/GalleryUI/Sources/Items/ChatDocumentGalleryItem.swift b/submodules/GalleryUI/Sources/Items/ChatDocumentGalleryItem.swift index 1537d93a17..2be4d488cc 100644 --- a/submodules/GalleryUI/Sources/Items/ChatDocumentGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/ChatDocumentGalleryItem.swift @@ -375,8 +375,8 @@ class ChatDocumentGalleryItemNode: ZoomableContentGalleryItemNode, WKNavigationD self.statusNodeContainer.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, timingFunction: CAMediaTimingFunctionName.easeIn.rawValue, removeOnCompletion: false) } - override func footerContent() -> Signal { - return .single(self.footerContentNode) + override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((self.footerContentNode, nil)) } @objc func statusPressed() { diff --git a/submodules/GalleryUI/Sources/Items/ChatExternalFileGalleryItem.swift b/submodules/GalleryUI/Sources/Items/ChatExternalFileGalleryItem.swift index c0714f5fd1..753b5cc904 100644 --- a/submodules/GalleryUI/Sources/Items/ChatExternalFileGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/ChatExternalFileGalleryItem.swift @@ -310,8 +310,8 @@ class ChatExternalFileGalleryItemNode: GalleryItemNode { self.statusNodeContainer.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, timingFunction: CAMediaTimingFunctionName.easeIn.rawValue, removeOnCompletion: false) } - override func footerContent() -> Signal { - return .single(self.footerContentNode) + override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((self.footerContentNode, nil)) } @objc func statusPressed() { diff --git a/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift b/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift index 083195070c..e07033342e 100644 --- a/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift @@ -505,8 +505,8 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode { return self._rightBarButtonItem.get() } - override func footerContent() -> Signal { - return .single(self.footerContentNode) + override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((self.footerContentNode, nil)) } @objc func statusPressed() { diff --git a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift index 183bce8efd..dc01efd988 100644 --- a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift @@ -145,6 +145,87 @@ private final class UniversalVideoGalleryItemPictureInPictureNode: ASDisplayNode } } +private let soundOnImage = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/SoundOn"), color: .white) +private let soundOffImage = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/SoundOff"), color: .white) +private var roundButtonBackgroundImage = { + return generateImage(CGSize(width: 42.0, height: 42), rotatedContext: { size, context in + let bounds = CGRect(origin: CGPoint(), size: size) + context.clear(bounds) + context.setFillColor(UIColor(white: 0.0, alpha: 0.5).cgColor) + context.fillEllipse(in: bounds) + }) +}() + +private final class UniversalVideoGalleryItemOverlayNode: GalleryOverlayContentNode { + private let soundButtonNode: HighlightableButtonNode + private var validLayout: (CGSize, LayoutMetrics, CGFloat, CGFloat, CGFloat)? + + override init() { + self.soundButtonNode = HighlightableButtonNode() + self.soundButtonNode.alpha = 0.0 + self.soundButtonNode.setBackgroundImage(roundButtonBackgroundImage, for: .normal) + self.soundButtonNode.setImage(soundOffImage, for: .normal) + self.soundButtonNode.setImage(soundOnImage, for: .selected) + self.soundButtonNode.setImage(soundOnImage, for: [.selected, .highlighted]) + + super.init() + + self.soundButtonNode.addTarget(self, action: #selector(self.soundButtonPressed), forControlEvents: .touchUpInside) + self.addSubnode(self.soundButtonNode) + } + + func hide() { + self.soundButtonNode.isHidden = true + } + + override func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) { + self.validLayout = (size, metrics, leftInset, rightInset, bottomInset) + + let soundButtonDiameter: CGFloat = 42.0 + let inset: CGFloat = 12.0 + let effectiveBottomInset = self.visibilityAlpha < 1.0 ? 0.0 : bottomInset + let soundButtonFrame = CGRect(origin: CGPoint(x: size.width - soundButtonDiameter - inset - rightInset, y: size.height - soundButtonDiameter - inset - effectiveBottomInset), size: CGSize(width: soundButtonDiameter, height: soundButtonDiameter)) + transition.updateFrame(node: self.soundButtonNode, frame: soundButtonFrame) + } + + override func animateIn(previousContentNode: GalleryOverlayContentNode?, transition: ContainedViewLayoutTransition) { + transition.updateAlpha(node: self.soundButtonNode, alpha: 1.0) + } + + override func animateOut(nextContentNode: GalleryOverlayContentNode?, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void) { + transition.updateAlpha(node: self.soundButtonNode, alpha: 0.0) + } + + override func setVisibilityAlpha(_ alpha: CGFloat) { + super.setVisibilityAlpha(alpha) + self.updateSoundButtonVisibility() + } + + func updateSoundButtonVisibility() { + if self.soundButtonNode.isSelected { + self.soundButtonNode.alpha = self.visibilityAlpha + } else { + self.soundButtonNode.alpha = 1.0 + } + + if let validLayout = self.validLayout { + self.updateLayout(size: validLayout.0, metrics: validLayout.1, leftInset: validLayout.2, rightInset: validLayout.3, bottomInset: validLayout.4, transition: .animated(duration: 0.3, curve: .easeInOut)) + } + } + + @objc func soundButtonPressed() { + self.soundButtonNode.isSelected = !self.soundButtonNode.isSelected + self.updateSoundButtonVisibility() + } + + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + if !self.soundButtonNode.frame.contains(point) { + return nil + } + return super.hitTest(point, with: event) + } +} + private struct FetchControls { let fetch: () -> Void let cancel: () -> Void @@ -161,6 +242,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { private let scrubberView: ChatVideoGalleryItemScrubberView private let footerContentNode: ChatItemGalleryFooterContentNode + private let overlayContentNode: UniversalVideoGalleryItemOverlayNode private var videoNode: UniversalVideoNode? private var videoFramePreview: MediaPlayerFramePreview? @@ -206,6 +288,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { self.footerContentNode.performAction = performAction self.footerContentNode.openActionOptions = openActionOptions + self.overlayContentNode = UniversalVideoGalleryItemOverlayNode() + self.statusButtonNode = HighlightableButtonNode() self.statusNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.5)) self.statusNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 50.0, height: 50.0)) @@ -398,6 +482,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { videoNode.backgroundColor = videoNode.ownsContentNode ? UIColor.black : UIColor(rgb: 0x333335) if item.fromPlayingVideo { videoNode.canAttachContent = false + self.overlayContentNode.hide() } else { self.updateDisplayPlaceholder(!videoNode.ownsContentNode) } @@ -982,7 +1067,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { transformedSuperFrame = transformedSuperFrame.offsetBy(dx: videoNode.position.x - previousFrame.center.x, dy: videoNode.position.y - previousFrame.center.y) } - let initialScale: CGFloat = 1.0 //min(videoNode.layer.bounds.width / node.0.view.bounds.width, videoNode.layer.bounds.height / node.0.view.bounds.height) + let initialScale: CGFloat = 1.0 let targetScale = max(transformedFrame.size.width / videoNode.layer.bounds.size.width, transformedFrame.size.height / videoNode.layer.bounds.size.height) videoNode.backgroundColor = .clear @@ -1197,7 +1282,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { } } - override func footerContent() -> Signal { - return .single(self.footerContentNode) + override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((self.footerContentNode, self.overlayContentNode)) } } diff --git a/submodules/GalleryUI/Sources/ZoomableContentGalleryItemNode.swift b/submodules/GalleryUI/Sources/ZoomableContentGalleryItemNode.swift index 7c7851232a..a0abf7e711 100644 --- a/submodules/GalleryUI/Sources/ZoomableContentGalleryItemNode.swift +++ b/submodules/GalleryUI/Sources/ZoomableContentGalleryItemNode.swift @@ -3,8 +3,36 @@ import UIKit import Display import AsyncDisplayKit +private let leftFadeImage = generateImage(CGSize(width: 64.0, height: 1.0), opaque: false, rotatedContext: { size, context in + let bounds = CGRect(origin: CGPoint(), size: size) + context.clear(bounds) + + let gradientColors = [UIColor.black.withAlphaComponent(0.5).cgColor, UIColor.black.withAlphaComponent(0.0).cgColor] as CFArray + + var locations: [CGFloat] = [0.0, 1.0] + let colorSpace = CGColorSpaceCreateDeviceRGB() + let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)! + + context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 64.0, y: 0.0), options: CGGradientDrawingOptions()) +}) + +private let rightFadeImage = generateImage(CGSize(width: 64.0, height: 1.0), opaque: false, rotatedContext: { size, context in + let bounds = CGRect(origin: CGPoint(), size: size) + context.clear(bounds) + + let gradientColors = [UIColor.black.withAlphaComponent(0.0).cgColor, UIColor.black.withAlphaComponent(0.5).cgColor] as CFArray + + var locations: [CGFloat] = [0.0, 1.0] + let colorSpace = CGColorSpaceCreateDeviceRGB() + let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)! + + context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 64.0, y: 0.0), options: CGGradientDrawingOptions()) +}) + open class ZoomableContentGalleryItemNode: GalleryItemNode, UIScrollViewDelegate { public let scrollNode: ASScrollNode + private let leftFadeNode: ASImageNode + private let rightFadeNode: ASImageNode private var containerLayout: ContainerViewLayout? @@ -32,6 +60,16 @@ open class ZoomableContentGalleryItemNode: GalleryItemNode, UIScrollViewDelegate self.scrollNode.view.contentInsetAdjustmentBehavior = .never } + self.leftFadeNode = ASImageNode() + self.leftFadeNode.contentMode = .scaleToFill + self.leftFadeNode.image = leftFadeImage + self.leftFadeNode.isHidden = true + + self.rightFadeNode = ASImageNode() + self.rightFadeNode.contentMode = .scaleToFill + self.rightFadeNode.image = rightFadeImage + self.rightFadeNode.isHidden = true + super.init() self.scrollNode.view.delegate = self @@ -42,41 +80,69 @@ open class ZoomableContentGalleryItemNode: GalleryItemNode, UIScrollViewDelegate self.scrollNode.view.delaysContentTouches = false let tapRecognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.contentTap(_:))) - tapRecognizer.tapActionAtPoint = { _ in + tapRecognizer.tapActionAtPoint = { [weak self] location in + if let strongSelf = self { + if location.x < 44.0 || location.x > strongSelf.frame.width - 44.0 { + return .waitForSingleTap + } + } return .waitForDoubleTap } + tapRecognizer.highlight = { [weak self] location in + if let strongSelf = self { + if let location = location, location.x < 44.0 { + strongSelf.leftFadeNode.isHidden = false + } else { + strongSelf.leftFadeNode.isHidden = true + } + if let location = location, location.x > strongSelf.frame.width - 44.0 { + strongSelf.rightFadeNode.isHidden = false + } else { + strongSelf.rightFadeNode.isHidden = true + } + } + } self.scrollNode.view.addGestureRecognizer(tapRecognizer) + self.addSubnode(self.scrollNode) + self.addSubnode(self.leftFadeNode) + self.addSubnode(self.rightFadeNode) } @objc open func contentTap(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { if recognizer.state == .ended { if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation { - switch gesture { - case .tap: - self.toggleControlsVisibility() - case .doubleTap: - if let contentView = self.zoomableContent?.1.view, self.scrollNode.view.zoomScale.isLessThanOrEqualTo(self.scrollNode.view.minimumZoomScale) { - let pointInView = self.scrollNode.view.convert(location, to: contentView) - - let newZoomScale = self.scrollNode.view.maximumZoomScale - let scrollViewSize = self.scrollNode.view.bounds.size - - let w = scrollViewSize.width / newZoomScale - let h = scrollViewSize.height / newZoomScale - let x = pointInView.x - (w / 2.0) - let y = pointInView.y - (h / 2.0) - - let rectToZoomTo = CGRect(x: x, y: y, width: w, height: h) - - self.scrollNode.view.zoom(to: rectToZoomTo, animated: true) - } else { - self.scrollNode.view.setZoomScale(self.scrollNode.view.minimumZoomScale, animated: true) - } - default: - break + if location.x < 44.0 { + self.goToPreviousItem() + } else if location.x > self.frame.width - 44.0 { + self.goToNextItem() + } else { + switch gesture { + case .tap: + self.toggleControlsVisibility() + case .doubleTap: + if let contentView = self.zoomableContent?.1.view, self.scrollNode.view.zoomScale.isLessThanOrEqualTo(self.scrollNode.view.minimumZoomScale) { + let pointInView = self.scrollNode.view.convert(location, to: contentView) + + let newZoomScale = self.scrollNode.view.maximumZoomScale + let scrollViewSize = self.scrollNode.view.bounds.size + + let w = scrollViewSize.width / newZoomScale + let h = scrollViewSize.height / newZoomScale + let x = pointInView.x - (w / 2.0) + let y = pointInView.y - (h / 2.0) + + let rectToZoomTo = CGRect(x: x, y: y, width: w, height: h) + + self.scrollNode.view.zoom(to: rectToZoomTo, animated: true) + } else { + self.scrollNode.view.setZoomScale(self.scrollNode.view.minimumZoomScale, animated: true) + } + default: + break + } } } } @@ -93,6 +159,9 @@ open class ZoomableContentGalleryItemNode: GalleryItemNode, UIScrollViewDelegate } self.containerLayout = layout + self.leftFadeNode.frame = CGRect(x: 0.0, y: 0.0, width: layout.size.width * 0.2, height: layout.size.height) + self.rightFadeNode.frame = CGRect(x: layout.size.width - layout.size.width * 0.2, y: 0.0, width: layout.size.width * 0.2, height: layout.size.height) + if shouldResetContents { var previousFrame: CGRect? var previousScale: CGFloat? diff --git a/submodules/InstantPageUI/Sources/InstantImageGalleryItem.swift b/submodules/InstantPageUI/Sources/InstantImageGalleryItem.swift index 9254384396..1d0c082ae5 100644 --- a/submodules/InstantPageUI/Sources/InstantImageGalleryItem.swift +++ b/submodules/InstantPageUI/Sources/InstantImageGalleryItem.swift @@ -301,7 +301,7 @@ final class InstantImageGalleryItemNode: ZoomableContentGalleryItemNode { return self._title.get() } - override func footerContent() -> Signal { - return .single(self.footerContentNode) + override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((self.footerContentNode, nil)) } } diff --git a/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift b/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift index 0e32aadb82..d50fc2b478 100644 --- a/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift +++ b/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift @@ -170,7 +170,7 @@ public class InstantPageGalleryController: ViewController, StandalonePresentable private let centralItemTitleView = Promise() private let centralItemRightBarButtonItem = Promise() private let centralItemNavigationStyle = Promise() - private let centralItemFooterContentNode = Promise() + private let centralItemFooterContentNode = Promise<(GalleryFooterContentNode?, GalleryOverlayContentNode?)>() private let centralItemAttributesDisposable = DisposableSet(); private let _hiddenMedia = Promise(nil) @@ -243,7 +243,7 @@ public class InstantPageGalleryController: ViewController, StandalonePresentable self?.navigationItem.rightBarButtonItem = rightBarButtonItem })) - self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode in + self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode, _ in self?.galleryNode.updatePresentationState({ $0.withUpdatedFooterContentNode(footerContentNode) }, transition: .immediate) diff --git a/submodules/ItemListPeerActionItem/Sources/ItemListPeerActionItem.swift b/submodules/ItemListPeerActionItem/Sources/ItemListPeerActionItem.swift index 2b0988c6d8..b9da7f99eb 100644 --- a/submodules/ItemListPeerActionItem/Sources/ItemListPeerActionItem.swift +++ b/submodules/ItemListPeerActionItem/Sources/ItemListPeerActionItem.swift @@ -12,6 +12,11 @@ public enum ItemListPeerActionItemHeight { case peerList } +public enum ItemListPeerActionItemColor { + case accent + case destructive +} + public class ItemListPeerActionItem: ListViewItem, ItemListItem { let presentationData: ItemListPresentationData let icon: UIImage? @@ -19,16 +24,18 @@ public class ItemListPeerActionItem: ListViewItem, ItemListItem { public let alwaysPlain: Bool let editing: Bool let height: ItemListPeerActionItemHeight + let color: ItemListPeerActionItemColor public let sectionId: ItemListSectionId let action: (() -> Void)? - public init(presentationData: ItemListPresentationData, icon: UIImage?, title: String, alwaysPlain: Bool = false, sectionId: ItemListSectionId, height: ItemListPeerActionItemHeight = .peerList, editing: Bool, action: (() -> Void)?) { + public init(presentationData: ItemListPresentationData, icon: UIImage?, title: String, alwaysPlain: Bool = false, sectionId: ItemListSectionId, height: ItemListPeerActionItemHeight = .peerList, color: ItemListPeerActionItemColor = .accent, editing: Bool, action: (() -> Void)?) { self.presentationData = presentationData self.icon = icon self.title = title self.alwaysPlain = alwaysPlain self.editing = editing self.height = height + self.color = color self.sectionId = sectionId self.action = action } @@ -167,7 +174,15 @@ class ItemListPeerActionItemNode: ListViewItemNode { let editingOffset: CGFloat = (item.editing ? 38.0 : 0.0) - let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: titleFont, textColor: item.presentationData.theme.list.itemAccentColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - editingOffset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + let textColor: UIColor + switch item.color { + case .accent: + textColor = item.presentationData.theme.list.itemAccentColor + case .destructive: + textColor = item.presentationData.theme.list.itemDestructiveColor + } + + let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: titleFont, textColor: textColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - editingOffset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let separatorHeight = UIScreenPixel diff --git a/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift b/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift index 0eb1793f6c..f707e88839 100644 --- a/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift +++ b/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift @@ -31,6 +31,7 @@ public enum ItemListStickerPackItemControl: Equatable { case none case installation(installed: Bool) case selection + case check(checked: Bool) } public final class ItemListStickerPackItem: ListViewItem, ItemListItem { @@ -305,6 +306,8 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode { case .selection: rightInset += 16.0 checkImage = PresentationResourcesItemList.checkIconImage(item.presentationData.theme) + case .check: + rightInset += 16.0 } var unreadImage: UIImage? @@ -531,6 +534,10 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode { strongSelf.selectionIconNode.image = image strongSelf.selectionIconNode.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - image.size.width - floor((44.0 - image.size.width) / 2.0), y: floor((contentSize.height - image.size.height) / 2.0)), size: image.size) } + case let .check(checked): + strongSelf.installationActionNode.isHidden = true + strongSelf.installationActionImageNode.isHidden = true + strongSelf.selectionIconNode.isHidden = true } if strongSelf.backgroundNode.supernode == nil { diff --git a/submodules/PassportUI/Sources/SecureIdDocumentGalleryController.swift b/submodules/PassportUI/Sources/SecureIdDocumentGalleryController.swift index d8a06b4494..b2604b8881 100644 --- a/submodules/PassportUI/Sources/SecureIdDocumentGalleryController.swift +++ b/submodules/PassportUI/Sources/SecureIdDocumentGalleryController.swift @@ -68,7 +68,7 @@ class SecureIdDocumentGalleryController: ViewController, StandalonePresentableCo private let centralItemTitle = Promise() private let centralItemTitleView = Promise() private let centralItemNavigationStyle = Promise() - private let centralItemFooterContentNode = Promise() + private let centralItemFooterContentNode = Promise<(GalleryFooterContentNode?, GalleryOverlayContentNode?)>() private let centralItemAttributesDisposable = DisposableSet(); private let _hiddenMedia = Promise(nil) @@ -123,7 +123,7 @@ class SecureIdDocumentGalleryController: ViewController, StandalonePresentableCo self?.navigationItem.titleView = titleView })) - self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode in + self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode, _ in self?.galleryNode.updatePresentationState({ $0.withUpdatedFooterContentNode(footerContentNode) }, transition: .immediate) diff --git a/submodules/PassportUI/Sources/SecureIdDocumentImageGalleryItem.swift b/submodules/PassportUI/Sources/SecureIdDocumentImageGalleryItem.swift index b4f80aa4d5..857c233cc3 100644 --- a/submodules/PassportUI/Sources/SecureIdDocumentImageGalleryItem.swift +++ b/submodules/PassportUI/Sources/SecureIdDocumentImageGalleryItem.swift @@ -210,8 +210,8 @@ final class SecureIdDocumentGalleryItemNode: ZoomableContentGalleryItemNode { return self._title.get() } - override func footerContent() -> Signal { - return .single(self.footerContentNode) + override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((self.footerContentNode, nil)) } } diff --git a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift index 30c25a1b5b..cb2f0a9d82 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift @@ -118,7 +118,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr private let centralItemTitle = Promise() private let centralItemTitleView = Promise() private let centralItemNavigationStyle = Promise() - private let centralItemFooterContentNode = Promise() + private let centralItemFooterContentNode = Promise<(GalleryFooterContentNode?, GalleryOverlayContentNode?)>() private let centralItemAttributesDisposable = DisposableSet(); private let _hiddenMedia = Promise(nil) @@ -232,7 +232,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr self?.navigationItem.titleView = titleView })) - self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode in + self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode, _ in self?.galleryNode.updatePresentationState({ $0.withUpdatedFooterContentNode(footerContentNode) }, transition: .immediate) diff --git a/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift b/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift index 4789f0c18f..d2db820983 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift @@ -355,7 +355,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode { } } - override func footerContent() -> Signal { - return .single(self.footerContentNode) + override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((self.footerContentNode, nil)) } } diff --git a/submodules/PeerInfoUI/BUCK b/submodules/PeerInfoUI/BUCK index 47da260275..16d723277d 100644 --- a/submodules/PeerInfoUI/BUCK +++ b/submodules/PeerInfoUI/BUCK @@ -64,6 +64,7 @@ static_library( "//submodules/TelegramIntents:TelegramIntents", "//submodules/SolidRoundedButtonNode:SolidRoundedButtonNode", "//submodules/ChatListSearchItemHeader:ChatListSearchItemHeader", + "//submodules/StatisticsUI:StatisticsUI", ], frameworks = [ "$SDKROOT/System/Library/Frameworks/Foundation.framework", diff --git a/submodules/PeersNearbyUI/BUCK b/submodules/PeersNearbyUI/BUCK index 5a6ca7965b..a6c565b2b6 100644 --- a/submodules/PeersNearbyUI/BUCK +++ b/submodules/PeersNearbyUI/BUCK @@ -26,6 +26,8 @@ static_library( "//submodules/PeersNearbyIconNode:PeersNearbyIconNode", "//submodules/Geocoding:Geocoding", "//submodules/AppBundle:AppBundle", + "//submodules/AnimatedStickerNode:AnimatedStickerNode", + "//submodules/TelegramStringFormatting:TelegramStringFormatting", ], frameworks = [ "$SDKROOT/System/Library/Frameworks/Foundation.framework", diff --git a/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift b/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift index 5c6a28bdae..32b5157750 100644 --- a/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift +++ b/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift @@ -20,6 +20,9 @@ import TelegramPermissionsUI import ItemListPeerActionItem import Geocoding import AppBundle +import ContextUI +import TelegramNotices +import TelegramStringFormatting private struct PeerNearbyEntry { let peer: (Peer, CachedPeerData?) @@ -49,13 +52,19 @@ private func arePeerNearbyArraysEqual(_ lhs: [PeerNearbyEntry], _ rhs: [PeerNear private final class PeersNearbyControllerArguments { let context: AccountContext + let toggleVisibility: (Bool) -> Void + let openProfile: (Peer) -> Void let openChat: (Peer) -> Void let openCreateGroup: (Double, Double, String?) -> Void + let contextAction: (Peer, ASDisplayNode, ContextGesture?) -> Void - init(context: AccountContext, openChat: @escaping (Peer) -> Void, openCreateGroup: @escaping (Double, Double, String?) -> Void) { + init(context: AccountContext, toggleVisibility: @escaping (Bool) -> Void, openProfile: @escaping (Peer) -> Void, openChat: @escaping (Peer) -> Void, openCreateGroup: @escaping (Double, Double, String?) -> Void, contextAction: @escaping (Peer, ASDisplayNode, ContextGesture?) -> Void) { self.context = context + self.toggleVisibility = toggleVisibility + self.openProfile = openProfile self.openChat = openChat self.openCreateGroup = openCreateGroup + self.contextAction = contextAction } } @@ -71,6 +80,7 @@ private enum PeersNearbyEntry: ItemListNodeEntry { case usersHeader(PresentationTheme, String, Bool) case empty(PresentationTheme, String) + case visibility(PresentationTheme, String, Bool) case user(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, PeerNearbyEntry) case groupsHeader(PresentationTheme, String, Bool) @@ -84,7 +94,7 @@ private enum PeersNearbyEntry: ItemListNodeEntry { switch self { case .header: return PeersNearbySection.header.rawValue - case .usersHeader, .empty, .user: + case .usersHeader, .empty, .visibility, .user: return PeersNearbySection.users.rawValue case .groupsHeader, .createGroup, .group: return PeersNearbySection.groups.rawValue @@ -101,8 +111,10 @@ private enum PeersNearbyEntry: ItemListNodeEntry { return 1 case .empty: return 2 + case .visibility: + return 3 case let .user(index, _, _, _, _, _): - return 3 + index + return 4 + index case .groupsHeader: return 1000 case .createGroup: @@ -136,6 +148,13 @@ private enum PeersNearbyEntry: ItemListNodeEntry { } else { return false } + case let .visibility(lhsTheme, lhsText, lhsStop): + if case let .visibility(rhsTheme, rhsText, rhsStop) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsStop == rhsStop { + return true + } else { + return false + } + case let .user(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsDisplayOrder, lhsPeer): if case let .user(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsDisplayOrder, rhsPeer) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsDisplayOrder == rhsDisplayOrder, arePeersNearbyEqual(lhsPeer, rhsPeer) { return true @@ -199,10 +218,20 @@ private enum PeersNearbyEntry: ItemListNodeEntry { return ItemListSectionHeaderItem(presentationData: presentationData, text: text, activityIndicator: loading ? .left : .none, sectionId: self.section) case let .empty(theme, text): return ItemListPlaceholderItem(theme: theme, text: text, sectionId: self.section, style: .blocks) + case let .visibility(theme, title, stop): + return ItemListPeerActionItem(presentationData: presentationData, icon: stop ? PresentationResourcesItemList.makeInvisibleIcon(theme) : PresentationResourcesItemList.makeVisibleIcon(theme), title: title, alwaysPlain: false, sectionId: self.section, color: stop ? .destructive : .accent, editing: false, action: { + arguments.toggleVisibility(!stop) + }) case let .user(_, theme, strings, dateTimeFormat, nameDisplayOrder, peer): + var text = strings.Map_DistanceAway(stringForDistance(peer.distance)).0 + if peer.peer.0.id == arguments.context.account.peerId { + text = strings.PeopleNearby_VisibleUntil(humanReadableStringForTimestamp(strings: strings, dateTimeFormat: dateTimeFormat, timestamp: peer.expires)).0 + } return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer.peer.0, aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: .text(strings.Map_DistanceAway(stringForDistance(peer.distance)).0), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: true, sectionId: self.section, action: { - arguments.openChat(peer.peer.0) - }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, hasTopGroupInset: false, tag: nil) + arguments.openProfile(peer.peer.0) + }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: { node, gesture in + arguments.contextAction(peer.peer.0, node, gesture) + }, hasTopGroupInset: false, tag: nil) case let .groupsHeader(theme, text, loading): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, activityIndicator: loading ? .left : .none, sectionId: self.section) case let .createGroup(theme, title, latitude, longitude, address): @@ -220,7 +249,9 @@ private enum PeersNearbyEntry: ItemListNodeEntry { } return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer.peer.0, aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: text, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: true, sectionId: self.section, action: { arguments.openChat(peer.peer.0) - }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, hasTopGroupInset: false, tag: nil) + }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: { node, gesture in + arguments.contextAction(peer.peer.0, node, gesture) + }, hasTopGroupInset: false, tag: nil) case let .channelsHeader(theme, text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) case let .channel(_, theme, strings, dateTimeFormat, nameDisplayOrder, peer): @@ -232,7 +263,9 @@ private enum PeersNearbyEntry: ItemListNodeEntry { } return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer.peer.0, aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: text, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: true, sectionId: self.section, action: { arguments.openChat(peer.peer.0) - }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, hasTopGroupInset: false, tag: nil) + }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: { node, gesture in + arguments.contextAction(peer.peer.0, node, gesture) + }, hasTopGroupInset: false, tag: nil) } } } @@ -241,37 +274,41 @@ private struct PeersNearbyData: Equatable { let latitude: Double let longitude: Double let address: String? + let visible: Bool let users: [PeerNearbyEntry] let groups: [PeerNearbyEntry] let channels: [PeerNearbyEntry] - init(latitude: Double, longitude: Double, address: String?, users: [PeerNearbyEntry], groups: [PeerNearbyEntry], channels: [PeerNearbyEntry]) { + init(latitude: Double, longitude: Double, address: String?, visible: Bool, users: [PeerNearbyEntry], groups: [PeerNearbyEntry], channels: [PeerNearbyEntry]) { self.latitude = latitude self.longitude = longitude self.address = address + self.visible = visible self.users = users self.groups = groups self.channels = channels } static func ==(lhs: PeersNearbyData, rhs: PeersNearbyData) -> Bool { - return lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude && lhs.address == rhs.address && arePeerNearbyArraysEqual(lhs.users, rhs.users) && arePeerNearbyArraysEqual(lhs.groups, rhs.groups) && arePeerNearbyArraysEqual(lhs.channels, rhs.channels) + return lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude && lhs.address == rhs.address && lhs.visible == rhs.visible && arePeerNearbyArraysEqual(lhs.users, rhs.users) && arePeerNearbyArraysEqual(lhs.groups, rhs.groups) && arePeerNearbyArraysEqual(lhs.channels, rhs.channels) } } private func peersNearbyControllerEntries(data: PeersNearbyData?, presentationData: PresentationData, displayLoading: Bool) -> [PeersNearbyEntry] { var entries: [PeersNearbyEntry] = [] - entries.append(.header(presentationData.theme, presentationData.strings.PeopleNearby_Description)) + entries.append(.header(presentationData.theme, presentationData.strings.PeopleNearby_DiscoverDescription)) entries.append(.usersHeader(presentationData.theme, presentationData.strings.PeopleNearby_Users.uppercased(), displayLoading && data == nil)) + + let visible = data?.visible ?? false + entries.append(.visibility(presentationData.theme, visible ? presentationData.strings.PeopleNearby_MakeInvisible : presentationData.strings.PeopleNearby_MakeVisible, visible)) + if let data = data, !data.users.isEmpty { var i: Int32 = 0 for user in data.users { entries.append(.user(i, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, user)) i += 1 } - } else { - entries.append(.empty(presentationData.theme, presentationData.strings.PeopleNearby_UsersEmpty)) } entries.append(.groupsHeader(presentationData.theme, presentationData.strings.PeopleNearby_Groups.uppercased(), displayLoading && data == nil)) @@ -295,11 +332,94 @@ private func peersNearbyControllerEntries(data: PeersNearbyData?, presentationDa return entries } +private final class ContextControllerContentSourceImpl: ContextControllerContentSource { + let controller: ViewController + weak var sourceNode: ASDisplayNode? + + let navigationController: NavigationController? = nil + + let passthroughTouches: Bool = true + + init(controller: ViewController, sourceNode: ASDisplayNode?) { + self.controller = controller + self.sourceNode = sourceNode + } + + func transitionInfo() -> ContextControllerTakeControllerInfo? { + let sourceNode = self.sourceNode + return ContextControllerTakeControllerInfo(contentAreaInScreenSpace: CGRect(origin: CGPoint(), size: CGSize(width: 10.0, height: 10.0)), sourceNode: { [weak sourceNode] in + if let sourceNode = sourceNode { + return (sourceNode, sourceNode.bounds) + } else { + return nil + } + }) + } + + func animatedIn() { + } +} + +private func peerNearbyContextMenuItems(context: AccountContext, peerId: PeerId, present: @escaping (ViewController) -> Void) -> Signal<[ContextMenuItem], NoError> { + let presentationData = context.sharedContext.currentPresentationData.with({ $0 }) + return context.account.postbox.transaction { transaction -> [ContextMenuItem] in + var items: [ContextMenuItem] = [] +// +// let peer = transaction.getPeer(peerId) +// +// if let peer = peer as? TelegramUser { +// items.append(.action(ContextMenuActionItem(text: presentationData.strings.ChatList_Context_AddToContacts, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor) }, action: { _, f in +// f(.default) +// }))) +// } else { +// items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeopleNearby_Context_JoinGroup, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor) }, action: { _, f in +// let _ = (joinChannel(account: context.account, peerId: peerId) |> deliverOnMainQueue).start(next: { participant in +// f(.default) +// }, error: { error in +//// if let strongSelf = self { +//// if case .tooMuchJoined = error { +//// if let parentNavigationController = strongSelf.parentNavigationController { +//// let context = strongSelf.context +//// let link = strongSelf.link +//// let navigateToPeer = strongSelf.navigateToPeer +//// let resolvedState = strongSelf.resolvedState +//// parentNavigationController.pushViewController(oldChannelsController(context: strongSelf.context, intent: .join, completed: { [weak parentNavigationController] value in +//// if value { +//// (parentNavigationController?.viewControllers.last as? ViewController)?.present(JoinLinkPreviewController(context: context, link: link, navigateToPeer: navigateToPeer, parentNavigationController: parentNavigationController, resolvedState: resolvedState), in: .window(.root)) +//// } +//// })) +//// } else { +//// strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.Join_ChannelsTooMuch, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) +//// } +//// strongSelf.dismiss() +//// } +//// } +// }) +// }))) +// +// items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeopleNearby_Context_UnrelatedLocation, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Report"), color: theme.contextMenu.primaryColor) }, action: { _, f in +// let _ = (TelegramCore.reportPeer(account: context.account, peerId: peerId, reason: .irrelevantLocation) +// |> deliverOnMainQueue).start(completed: { +// let _ = ApplicationSpecificNotice.setIrrelevantPeerGeoReport(postbox: context.account.postbox, peerId: peerId).start() +// +// present(textAlertController(context: context, title: nil, text: presentationData.strings.ReportPeer_AlertSuccess, actions: [TextAlertAction(type: TextAlertActionType.defaultAction, title: presentationData.strings.Common_OK, action: {})])) +// }) +// f(.default) +// }))) +// } + + return items + } +} + + public func peersNearbyController(context: AccountContext) -> ViewController { var pushControllerImpl: ((ViewController) -> Void)? var replaceAllButRootControllerImpl: ((ViewController, Bool) -> Void)? var replaceTopControllerImpl: ((ViewController) -> Void)? var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)? + var presentInGlobalOverlayImpl: ((ViewController) -> Void)? + var navigateToProfileImpl: ((Peer) -> Void)? var navigateToChatImpl: ((Peer) -> Void)? let actionsDisposable = DisposableSet() @@ -309,7 +429,27 @@ public func peersNearbyController(context: AccountContext) -> ViewController { let dataPromise = Promise(nil) let addressPromise = Promise(nil) - let arguments = PeersNearbyControllerArguments(context: context, openChat: { peer in + let coordinatePromise = Promise(nil) + coordinatePromise.set(.single(nil) |> then(currentLocationManagerCoordinate(manager: context.sharedContext.locationManager!, timeout: 5.0))) + + let arguments = PeersNearbyControllerArguments(context: context, toggleVisibility: { visible in + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + + if visible { + presentControllerImpl?(textAlertController(context: context, title: presentationData.strings.PeopleNearby_MakeVisibleTitle, text: presentationData.strings.PeopleNearby_MakeVisibleDescription, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: { + let _ = (coordinatePromise.get() + |> deliverOnMainQueue).start(next: { coordinate in + if let coordinate = coordinate { + let _ = peersNearbyUpdateVisibility(network: context.account.network, stateManager: context.account.stateManager, update: .visible(latitude: coordinate.latitude, longitude: coordinate.longitude), background: false).start() + } + }) + })]), nil) + } else { + let _ = peersNearbyUpdateVisibility(network: context.account.network, stateManager: context.account.stateManager, update: .invisible, background: false).start() + } + }, openProfile: { peer in + navigateToProfileImpl?(peer) + }, openChat: { peer in navigateToChatImpl?(peer) }, openCreateGroup: { latitude, longitude, address in let presentationData = context.sharedContext.currentPresentationData.with { $0 } @@ -350,16 +490,24 @@ public func peersNearbyController(context: AccountContext) -> ViewController { presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.CreateGroup_ErrorLocatedGroupsTooMuch, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) } })) + }, contextAction: { peer, node, gesture in + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + let chatController = context.sharedContext.makeChatController(context: context, chatLocation: .peer(peer.id), subject: nil, botStart: nil, mode: .standard(previewing: true)) + chatController.canReadHistory.set(false) + let contextController = ContextController(account: context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: peerNearbyContextMenuItems(context: context, peerId: peer.id, present: { c in + presentControllerImpl?(c, nil) + }), reactionItems: [], gesture: gesture) + presentInGlobalOverlayImpl?(contextController) }) - let dataSignal: Signal = currentLocationManagerCoordinate(manager: context.sharedContext.locationManager!, timeout: 5.0) + let dataSignal: Signal = coordinatePromise.get() |> mapToSignal { coordinate -> Signal in guard let coordinate = coordinate else { return .single(nil) } return Signal { subscriber in - let peersNearbyContext = PeersNearbyContext(network: context.account.network, accountStateManager: context.account.stateManager, coordinate: (latitude: coordinate.latitude, longitude: coordinate.longitude)) + let peersNearbyContext = PeersNearbyContext(network: context.account.network, stateManager: context.account.stateManager, coordinate: (latitude: coordinate.latitude, longitude: coordinate.longitude)) let peersNearby: Signal = combineLatest(peersNearbyContext.get(), addressPromise.get()) |> mapToSignal { peersNearby, address -> Signal<([PeerNearby]?, String?), NoError> in @@ -379,17 +527,26 @@ public func peersNearbyController(context: AccountContext) -> ViewController { return context.account.postbox.transaction { transaction -> PeersNearbyData? in var users: [PeerNearbyEntry] = [] var groups: [PeerNearbyEntry] = [] + var visible = false for peerNearby in peersNearby { - if peerNearby.id != context.account.peerId, let peer = transaction.getPeer(peerNearby.id) { - if peerNearby.id.namespace == Namespaces.Peer.CloudUser { - users.append(PeerNearbyEntry(peer: (peer, nil), expires: peerNearby.expires, distance: peerNearby.distance)) - } else { - let cachedData = transaction.getPeerCachedData(peerId: peerNearby.id) as? CachedChannelData - groups.append(PeerNearbyEntry(peer: (peer, cachedData), expires: peerNearby.expires, distance: peerNearby.distance)) - } + switch peerNearby { + case let .peer(id, expires, distance): + if let peer = transaction.getPeer(id) { + if id.namespace == Namespaces.Peer.CloudUser { + users.append(PeerNearbyEntry(peer: (peer, nil), expires: expires, distance: distance)) + } else { + let cachedData = transaction.getPeerCachedData(peerId: id) as? CachedChannelData + groups.append(PeerNearbyEntry(peer: (peer, cachedData), expires: expires, distance: distance)) + } + } + case let .selfPeer(expires): + visible = true + if let peer = transaction.getPeer(context.account.peerId) { + users.append(PeerNearbyEntry(peer: (peer, nil), expires: expires, distance: 0)) + } } } - return PeersNearbyData(latitude: coordinate.latitude, longitude: coordinate.longitude, address: address, users: users, groups: groups, channels: []) + return PeersNearbyData(latitude: coordinate.latitude, longitude: coordinate.longitude, address: address, visible: visible, users: users, groups: groups, channels: []) } } @@ -438,6 +595,11 @@ public func peersNearbyController(context: AccountContext) -> ViewController { controller.didDisappear = { [weak controller] _ in controller?.clearItemNodesHighlight(animated: true) } + navigateToProfileImpl = { [weak controller] peer in + if let navigationController = controller?.navigationController as? NavigationController, let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic) { + (navigationController as? NavigationController)?.pushViewController(controller) + } + } navigateToChatImpl = { [weak controller] peer in if let navigationController = controller?.navigationController as? NavigationController { context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer.id), keepStack: .always, purposefulAction: { [weak navigationController] in @@ -467,6 +629,10 @@ public func peersNearbyController(context: AccountContext) -> ViewController { controller.present(c, in: .window(.root), with: p) } } - + presentInGlobalOverlayImpl = { [weak controller] c in + if let controller = controller { + controller.presentInGlobalOverlay(c) + } + } return controller } diff --git a/submodules/PeersNearbyUI/Sources/PeersNearbyHeaderItem.swift b/submodules/PeersNearbyUI/Sources/PeersNearbyHeaderItem.swift index 7bbb9e9428..ed5a84dc13 100644 --- a/submodules/PeersNearbyUI/Sources/PeersNearbyHeaderItem.swift +++ b/submodules/PeersNearbyUI/Sources/PeersNearbyHeaderItem.swift @@ -6,7 +6,8 @@ import SwiftSignalKit import TelegramPresentationData import ItemListUI import PresentationDataUtils -import PeersNearbyIconNode +import AnimatedStickerNode +import AppBundle class PeersNearbyHeaderItem: ListViewItem, ItemListItem { let theme: PresentationTheme @@ -60,7 +61,7 @@ private let titleFont = Font.regular(13.0) class PeersNearbyHeaderItemNode: ListViewItemNode { private let titleNode: TextNode - private var iconNode: PeersNearbyIconNode? + private var animationNode: AnimatedStickerNode private var item: PeersNearbyHeaderItem? @@ -70,24 +71,29 @@ class PeersNearbyHeaderItemNode: ListViewItemNode { self.titleNode.contentMode = .left self.titleNode.contentsScale = UIScreen.main.scale + self.animationNode = AnimatedStickerNode() + if let path = getAppBundle().path(forResource: "Compass", ofType: "tgs") { + self.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(path: path), width: 192, height: 192, playbackMode: .once, mode: .direct) + self.animationNode.visibility = true + } + super.init(layerBacked: false, dynamicBounce: false) self.addSubnode(self.titleNode) + self.addSubnode(self.animationNode) } func asyncLayout() -> (_ item: PeersNearbyHeaderItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) { let makeTitleLayout = TextNode.asyncLayout(self.titleNode) return { item, params, neighbors in - let leftInset: CGFloat = 48.0 + params.leftInset + let leftInset: CGFloat = 32.0 + params.leftInset let topInset: CGFloat = 92.0 let attributedText = NSAttributedString(string: item.text, font: titleFont, textColor: item.theme.list.freeTextColor) let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - leftInset * 2.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) - let contentSize: CGSize - - contentSize = CGSize(width: params.width, height: topInset + titleLayout.size.height) + let contentSize = CGSize(width: params.width, height: topInset + titleLayout.size.height) let insets = itemListNeighborsGroupedInsets(neighbors) let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets) @@ -96,22 +102,13 @@ class PeersNearbyHeaderItemNode: ListViewItemNode { if let strongSelf = self { strongSelf.item = item strongSelf.accessibilityLabel = attributedText.string - - let iconNode: PeersNearbyIconNode - if let node = strongSelf.iconNode { - iconNode = node - iconNode.updateTheme(item.theme) - } else { - iconNode = PeersNearbyIconNode(theme: item.theme) - strongSelf.iconNode = iconNode - strongSelf.addSubnode(iconNode) - } - - let iconSize = CGSize(width: 60.0, height: 60.0) - iconNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0), y: 5.0), size: iconSize) + + let iconSize = CGSize(width: 96.0, height: 96.0) + strongSelf.animationNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0), y: -10.0), size: iconSize) + strongSelf.animationNode.updateLayout(size: iconSize) let _ = titleApply() - strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleLayout.size.width) / 2.0), y: topInset), size: titleLayout.size) + strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleLayout.size.width) / 2.0), y: topInset + 8.0), size: titleLayout.size) } }) } diff --git a/submodules/PresentationDataUtils/Sources/SpecialTabBarIcons.swift b/submodules/PresentationDataUtils/Sources/SpecialTabBarIcons.swift new file mode 100644 index 0000000000..0fa053ebd0 --- /dev/null +++ b/submodules/PresentationDataUtils/Sources/SpecialTabBarIcons.swift @@ -0,0 +1,5 @@ +import Foundation + +public func useSpecialTabBarIcons() -> Bool { + return (Date(timeIntervalSince1970: 1581638400)...Date(timeIntervalSince1970: 1581724799)).contains(Date()) +} diff --git a/submodules/SettingsUI/Sources/SettingsController.swift b/submodules/SettingsUI/Sources/SettingsController.swift index 280b6055f8..e304b7390c 100644 --- a/submodules/SettingsUI/Sources/SettingsController.swift +++ b/submodules/SettingsUI/Sources/SettingsController.swift @@ -17,7 +17,6 @@ import AccountContext import OverlayStatusController import AvatarNode import AlertUI -import PresentationDataUtils import TelegramNotices import GalleryUI import LegacyUI @@ -1436,7 +1435,12 @@ public func settingsController(context: AccountContext, accountManager: AccountM actionsDisposable.dispose() } - let icon = UIImage(bundleImageName: "Chat List/Tabs/IconSettings") + let icon: UIImage? + if useSpecialTabBarIcons() { + icon = UIImage(bundleImageName: "Chat List/Tabs/Holiday/IconSettings") + } else { + icon = UIImage(bundleImageName: "Chat List/Tabs/IconSettings") + } let notificationsFromAllAccounts = accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.inAppNotificationSettings]) |> map { sharedData -> Bool in diff --git a/submodules/StatisticsUI/BUCK b/submodules/StatisticsUI/BUCK new file mode 100644 index 0000000000..911a9fff4a --- /dev/null +++ b/submodules/StatisticsUI/BUCK @@ -0,0 +1,31 @@ +load("//Config:buck_rule_macros.bzl", "static_library") + +static_library( + name = "StatisticsUI", + srcs = glob([ + "Sources/**/*.swift", + ]), + deps = [ + "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared", + "//submodules/AsyncDisplayKit:AsyncDisplayKit#shared", + "//submodules/Display:Display#shared", + "//submodules/Postbox:Postbox#shared", + "//submodules/TelegramCore:TelegramCore#shared", + "//submodules/SyncCore:SyncCore#shared", + "//submodules/TelegramPresentationData:TelegramPresentationData", + "//submodules/TelegramUIPreferences:TelegramUIPreferences", + "//submodules/AccountContext:AccountContext", + "//submodules/ItemListUI:ItemListUI", + "//submodules/AvatarNode:AvatarNode", + "//submodules/TelegramStringFormatting:TelegramStringFormatting", + "//submodules/AlertUI:AlertUI", + "//submodules/PresentationDataUtils:PresentationDataUtils", + "//submodules/TelegramNotices:TelegramNotices", + "//submodules/MergeLists:MergeLists", + "//submodules/Charts:Charts", + ], + frameworks = [ + "$SDKROOT/System/Library/Frameworks/Foundation.framework", + "$SDKROOT/System/Library/Frameworks/UIKit.framework", + ], +) diff --git a/submodules/StatisticsUI/Info.plist b/submodules/StatisticsUI/Info.plist new file mode 100644 index 0000000000..e1fe4cfb7b --- /dev/null +++ b/submodules/StatisticsUI/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + + diff --git a/submodules/StatisticsUI/Sources/StatisticsUI.h b/submodules/StatisticsUI/Sources/StatisticsUI.h new file mode 100644 index 0000000000..89573b3f16 --- /dev/null +++ b/submodules/StatisticsUI/Sources/StatisticsUI.h @@ -0,0 +1,19 @@ +// +// StatisticsUI.h +// StatisticsUI +// +// Created by Peter on 8/13/19. +// Copyright © 2019 Telegram Messenger LLP. All rights reserved. +// + +#import + +//! Project version number for StatisticsUI. +FOUNDATION_EXPORT double StatisticsUIVersionNumber; + +//! Project version string for StatisticsUI. +FOUNDATION_EXPORT const unsigned char StatisticsUIVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/submodules/StatisticsUI/Sources/StatsController.swift b/submodules/StatisticsUI/Sources/StatsController.swift new file mode 100644 index 0000000000..440d29cf02 --- /dev/null +++ b/submodules/StatisticsUI/Sources/StatsController.swift @@ -0,0 +1,351 @@ +import Foundation +import UIKit +import Display +import SwiftSignalKit +import Postbox +import TelegramCore +import SyncCore +import MapKit +import TelegramPresentationData +import TelegramUIPreferences +import ItemListUI +import PresentationDataUtils +import AccountContext +import PresentationDataUtils +import AppBundle +import ContextUI +import TelegramNotices + +private final class StatsArguments { + init() { + } +} + +private enum StatsSection: Int32 { + case overview + case growth + case followers + case notifications + case viewsByHour + case postInteractions + case viewsBySource + case followersBySource + case languages +} + +private enum StatsEntry: ItemListNodeEntry { + case overviewHeader(PresentationTheme, String) + case overview(PresentationTheme, ChannelStats) + + case growthTitle(PresentationTheme, String) + case growthGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph) + + case followersTitle(PresentationTheme, String) + case followersGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph) + + case notificationsTitle(PresentationTheme, String) + case notificationsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph) + + case viewsByHourTitle(PresentationTheme, String) + case viewsByHourGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph) + + case postInteractionsTitle(PresentationTheme, String) + case postInteractionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph) + + case viewsBySourceTitle(PresentationTheme, String) + case viewsBySourceGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph) + + case followersBySourceTitle(PresentationTheme, String) + case followersBySourceGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph) + + case languagesTitle(PresentationTheme, String) + case languagesGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph) + + var section: ItemListSectionId { + switch self { + case .overviewHeader, .overview: + return StatsSection.overview.rawValue + case .growthTitle, .growthGraph: + return StatsSection.growth.rawValue + case .followersTitle, .followersGraph: + return StatsSection.followers.rawValue + case .notificationsTitle, .notificationsGraph: + return StatsSection.notifications.rawValue + case .viewsByHourTitle, .viewsByHourGraph: + return StatsSection.viewsByHour.rawValue + case .postInteractionsTitle, .postInteractionsGraph: + return StatsSection.postInteractions.rawValue + case .viewsBySourceTitle, .viewsBySourceGraph: + return StatsSection.viewsBySource.rawValue + case .followersBySourceTitle, .followersBySourceGraph: + return StatsSection.followersBySource.rawValue + case .languagesTitle, .languagesGraph: + return StatsSection.languages.rawValue + } + } + + var stableId: Int32 { + switch self { + case .overviewHeader: + return 0 + case .overview: + return 1 + case .growthTitle: + return 2 + case .growthGraph: + return 3 + case .followersTitle: + return 4 + case .followersGraph: + return 5 + case .notificationsTitle: + return 6 + case .notificationsGraph: + return 7 + case .viewsByHourTitle: + return 8 + case .viewsByHourGraph: + return 9 + case .postInteractionsTitle: + return 10 + case .postInteractionsGraph: + return 11 + case .viewsBySourceTitle: + return 12 + case .viewsBySourceGraph: + return 13 + case .followersBySourceTitle: + return 14 + case .followersBySourceGraph: + return 15 + case .languagesTitle: + return 16 + case .languagesGraph: + return 17 + } + } + + static func ==(lhs: StatsEntry, rhs: StatsEntry) -> Bool { + switch lhs { + case let .overviewHeader(lhsTheme, lhsText): + if case let .overviewHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .overview(lhsTheme, lhsStats): + if case let .overview(rhsTheme, rhsStats) = rhs, lhsTheme === rhsTheme, lhsStats == rhsStats { + return true + } else { + return false + } + case let .growthTitle(lhsTheme, lhsText): + if case let .growthTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .growthGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph): + if case let .growthGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph { + return true + } else { + return false + } + case let .followersTitle(lhsTheme, lhsText): + if case let .followersTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .followersGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph): + if case let .followersGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph { + return true + } else { + return false + } + case let .notificationsTitle(lhsTheme, lhsText): + if case let .notificationsTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .notificationsGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph): + if case let .notificationsGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph { + return true + } else { + return false + } + case let .viewsByHourTitle(lhsTheme, lhsText): + if case let .viewsByHourTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .viewsByHourGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph): + if case let .viewsByHourGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph { + return true + } else { + return false + } + case let .postInteractionsTitle(lhsTheme, lhsText): + if case let .postInteractionsTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .postInteractionsGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph): + if case let .postInteractionsGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph { + return true + } else { + return false + } + case let .viewsBySourceTitle(lhsTheme, lhsText): + if case let .viewsBySourceTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .viewsBySourceGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph): + if case let .viewsBySourceGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph { + return true + } else { + return false + } + case let .followersBySourceTitle(lhsTheme, lhsText): + if case let .followersBySourceTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .followersBySourceGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph): + if case let .followersBySourceGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph { + return true + } else { + return false + } + case let .languagesTitle(lhsTheme, lhsText): + if case let .languagesTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .languagesGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph): + if case let .languagesGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph { + return true + } else { + return false + } + } + } + + static func <(lhs: StatsEntry, rhs: StatsEntry) -> Bool { + return lhs.stableId < rhs.stableId + } + + func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem { + switch self { + case let .overviewHeader(theme, text), + let .growthTitle(theme, text), + let .followersTitle(theme, text), + let .notificationsTitle(theme, text), + let .viewsByHourTitle(theme, text), + let .postInteractionsTitle(theme, text), + let .viewsBySourceTitle(theme, text), + let .followersBySourceTitle(theme, text), + let .languagesTitle(theme, text): + return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) + case let .overview(theme, stats): + return StatsOverviewItem(presentationData: presentationData, stats: stats, sectionId: self.section, style: .blocks) + case let .growthGraph(theme, strings, dateTimeFormat, title, graph), + let .followersGraph(theme, strings, dateTimeFormat, title, graph), + let .notificationsGraph(theme, strings, dateTimeFormat, title, graph), + let .viewsByHourGraph(theme, strings, dateTimeFormat, title, graph), + let .postInteractionsGraph(theme, strings, dateTimeFormat, title, graph), + let .viewsBySourceGraph(theme, strings, dateTimeFormat, title, graph), + let .followersBySourceGraph(theme, strings, dateTimeFormat, title, graph), + let .languagesGraph(theme, strings, dateTimeFormat, title, graph): + return StatsGraphItem(presentationData: presentationData, title: title, graph: graph, sectionId: self.section, style: .blocks) + } + } +} + +private func statsControllerEntries(data: ChannelStats?, presentationData: PresentationData) -> [StatsEntry] { + var entries: [StatsEntry] = [] + + if let data = data { + entries.append(.overviewHeader(presentationData.theme, "OVERVIEW")) + entries.append(.overview(presentationData.theme, data)) + + entries.append(.growthTitle(presentationData.theme, "GROWTH")) + entries.append(.growthGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, "Growth", data.growthGraph)) + + entries.append(.followersTitle(presentationData.theme, "FOLLOWERS")) + entries.append(.followersGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, "Followers", data.followersGraph)) + + entries.append(.notificationsTitle(presentationData.theme, "NOTIFICATIONS")) + entries.append(.notificationsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, "Notifications", data.muteGraph)) + } + + return entries +} + +public func channelStatsController(context: AccountContext, peer: Peer, cachedPeerData: CachedPeerData) -> ViewController { + var pushControllerImpl: ((ViewController) -> Void)? + var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)? + var navigateToChatImpl: ((Peer) -> Void)? + + let actionsDisposable = DisposableSet() + let checkCreationAvailabilityDisposable = MetaDisposable() + actionsDisposable.add(checkCreationAvailabilityDisposable) + + let dataPromise = Promise(nil) + + var datacenterId: Int32 = 0 + if let cachedData = cachedPeerData as? CachedChannelData { + datacenterId = cachedData.statsDatacenterId + } + + let statsContext = ChannelStatsContext(network: context.account.network, datacenterId: datacenterId, peer: peer) + let dataSignal: Signal = statsContext.state + |> map { state in + return state.stats + } |> afterNext({ [weak statsContext] a in + if let w = statsContext, let a = a { + if case .OnDemand = a.interactionsGraph { + w.loadInteractionsGraph() + } + } + }) + dataPromise.set(.single(nil) |> then(dataSignal)) + + let arguments = StatsArguments() + + let signal = combineLatest(context.sharedContext.presentationData, dataPromise.get()) + |> deliverOnMainQueue + |> map { presentationData, data -> (ItemListControllerState, (ItemListNodeState, Any)) in + let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.ChannelInfo_Stats), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true) + let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: statsControllerEntries(data: data, presentationData: presentationData), style: .blocks, emptyStateItem: nil, crossfadeState: false, animateChanges: false) + + return (controllerState, (listState, arguments)) + } + |> afterDisposed { + actionsDisposable.dispose() + let _ = statsContext.state + } + + let controller = ItemListController(context: context, state: signal) + controller.didDisappear = { [weak controller] _ in + controller?.clearItemNodesHighlight(animated: true) + } + pushControllerImpl = { [weak controller] c in + if let controller = controller { + (controller.navigationController as? NavigationController)?.pushViewController(c, animated: true) + } + } + presentControllerImpl = { [weak controller] c, a in + if let controller = controller { + controller.present(c, in: .window(.root), with: a) + } + } + return controller +} diff --git a/submodules/StatisticsUI/Sources/StatsGraphItem.swift b/submodules/StatisticsUI/Sources/StatsGraphItem.swift new file mode 100644 index 0000000000..a800baf8e9 --- /dev/null +++ b/submodules/StatisticsUI/Sources/StatsGraphItem.swift @@ -0,0 +1,205 @@ +import Foundation +import UIKit +import Display +import AsyncDisplayKit +import SwiftSignalKit +import TelegramCore +import SyncCore +import TelegramPresentationData +import ItemListUI +import PresentationDataUtils +import Charts + +class StatsGraphItem: ListViewItem, ItemListItem { + let presentationData: ItemListPresentationData + let title: String + let graph: ChannelStatsGraph + let sectionId: ItemListSectionId + let style: ItemListStyle + + init(presentationData: ItemListPresentationData, title: String, graph: ChannelStatsGraph, sectionId: ItemListSectionId, style: ItemListStyle) { + self.presentationData = presentationData + self.title = title + self.graph = graph + self.sectionId = sectionId + self.style = style + } + + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, (ListViewItemApply) -> Void)) -> Void) { + async { + let node = StatsGraphItemNode() + let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) + + node.contentSize = layout.contentSize + node.insets = layout.insets + + Queue.mainQueue().async { + completion(node, { + return (nil, { _ in apply() }) + }) + } + } + } + + func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) { + Queue.mainQueue().async { + if let nodeValue = node() as? StatsGraphItemNode { + let makeLayout = nodeValue.asyncLayout() + + async { + let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) + Queue.mainQueue().async { + completion(layout, { _ in + apply() + }) + } + } + } + } + } + + var selectable: Bool = false +} + +class StatsGraphItemNode: ListViewItemNode { + private let backgroundNode: ASDisplayNode + private let topStripeNode: ASDisplayNode + private let bottomStripeNode: ASDisplayNode + + let chartNode: ChartNode + + private var item: StatsGraphItem? + + init() { + self.backgroundNode = ASDisplayNode() + self.backgroundNode.isLayerBacked = true + self.backgroundNode.backgroundColor = .white + + self.topStripeNode = ASDisplayNode() + self.topStripeNode.isLayerBacked = true + + self.bottomStripeNode = ASDisplayNode() + self.bottomStripeNode.isLayerBacked = true + + self.chartNode = ChartNode() + + super.init(layerBacked: false, dynamicBounce: false) + + self.clipsToBounds = true + + self.addSubnode(self.chartNode) + } + + func asyncLayout() -> (_ item: StatsGraphItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) { + let currentItem = self.item + + return { item, params, neighbors in + let leftInset = params.leftInset + let rightInset: CGFloat = params.rightInset + var updatedTheme: PresentationTheme? + var updatedGraph: ChannelStatsGraph? + + if currentItem?.presentationData.theme !== item.presentationData.theme { + updatedTheme = item.presentationData.theme + } + + if currentItem?.graph != item.graph { + updatedGraph = item.graph + } + + let contentSize: CGSize + let insets: UIEdgeInsets + let separatorHeight = UIScreenPixel + let itemBackgroundColor: UIColor + let itemSeparatorColor: UIColor + + switch item.style { + case .plain: + itemBackgroundColor = item.presentationData.theme.list.plainBackgroundColor + itemSeparatorColor = item.presentationData.theme.list.itemPlainSeparatorColor + contentSize = CGSize(width: params.width, height: 320.0) + insets = itemListNeighborsPlainInsets(neighbors) + case .blocks: + itemBackgroundColor = item.presentationData.theme.list.itemBlocksBackgroundColor + itemSeparatorColor = item.presentationData.theme.list.itemBlocksSeparatorColor + contentSize = CGSize(width: params.width, height: 320.0) + insets = itemListNeighborsGroupedInsets(neighbors) + } + + let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets) + + return (ListViewItemNodeLayout(contentSize: contentSize, insets: insets), { [weak self] in + if let strongSelf = self { + strongSelf.item = item + + if let _ = updatedTheme { + strongSelf.topStripeNode.backgroundColor = itemSeparatorColor + strongSelf.bottomStripeNode.backgroundColor = itemSeparatorColor + strongSelf.backgroundNode.backgroundColor = itemBackgroundColor + } + + if let updatedGraph = updatedGraph, case let .Loaded(data) = updatedGraph { + strongSelf.chartNode.setup(data) + } + + switch item.style { + case .plain: + if strongSelf.backgroundNode.supernode != nil { + strongSelf.backgroundNode.removeFromSupernode() + } + if strongSelf.topStripeNode.supernode != nil { + strongSelf.topStripeNode.removeFromSupernode() + } + if strongSelf.bottomStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0) + } + + strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight)) + case .blocks: + if strongSelf.backgroundNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0) + } + if strongSelf.topStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1) + } + if strongSelf.bottomStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) + } + switch neighbors.top { + case .sameSection(false): + strongSelf.topStripeNode.isHidden = true + default: + strongSelf.topStripeNode.isHidden = false + } + let bottomStripeInset: CGFloat + switch neighbors.bottom { + case .sameSection(false): + bottomStripeInset = leftInset + default: + bottomStripeInset = 0.0 + } + + strongSelf.chartNode.frame = CGRect(origin: CGPoint(x: leftInset, y: -30.0), size: CGSize(width: layout.size.width - leftInset - rightInset, height: 350.0)) + + strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight))) + strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight)) + strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight)) + } + } + }) + } + } + + override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) { + self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4) + } + + override func animateAdded(_ currentTimestamp: Double, duration: Double) { + self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + } + + override func animateRemoved(_ currentTimestamp: Double, duration: Double) { + self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) + } +} + diff --git a/submodules/StatisticsUI/Sources/StatsOverviewItem.swift b/submodules/StatisticsUI/Sources/StatsOverviewItem.swift new file mode 100644 index 0000000000..5e85186e30 --- /dev/null +++ b/submodules/StatisticsUI/Sources/StatsOverviewItem.swift @@ -0,0 +1,292 @@ +import Foundation +import UIKit +import Display +import AsyncDisplayKit +import SwiftSignalKit +import TelegramCore +import SyncCore +import TelegramPresentationData +import ItemListUI +import PresentationDataUtils +import Charts + +class StatsOverviewItem: ListViewItem, ItemListItem { + let presentationData: ItemListPresentationData + let stats: ChannelStats + let sectionId: ItemListSectionId + let style: ItemListStyle + + init(presentationData: ItemListPresentationData, stats: ChannelStats, sectionId: ItemListSectionId, style: ItemListStyle) { + self.presentationData = presentationData + self.stats = stats + self.sectionId = sectionId + self.style = style + } + + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, (ListViewItemApply) -> Void)) -> Void) { + async { + let node = StatsOverviewItemNode() + let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) + + node.contentSize = layout.contentSize + node.insets = layout.insets + + Queue.mainQueue().async { + completion(node, { + return (nil, { _ in apply() }) + }) + } + } + } + + func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) { + Queue.mainQueue().async { + if let nodeValue = node() as? StatsOverviewItemNode { + let makeLayout = nodeValue.asyncLayout() + + async { + let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) + Queue.mainQueue().async { + completion(layout, { _ in + apply() + }) + } + } + } + } + } + + var selectable: Bool = false +} + +class StatsOverviewItemNode: ListViewItemNode { + private let backgroundNode: ASDisplayNode + private let topStripeNode: ASDisplayNode + private let bottomStripeNode: ASDisplayNode + + private let followersValueLabel: ImmediateTextNode + private let viewsPerPostValueLabel: ImmediateTextNode + private let sharesPerPostValueLabel: ImmediateTextNode + private let enabledNotificationsValueLabel: ImmediateTextNode + + private let followersTitleLabel: ImmediateTextNode + private let viewsPerPostTitleLabel: ImmediateTextNode + private let sharesPerPostTitleLabel: ImmediateTextNode + private let enabledNotificationsTitleLabel: ImmediateTextNode + + private let followersDeltaLabel: ImmediateTextNode + private let viewsPerPostDeltaLabel: ImmediateTextNode + private let sharesPerPostDeltaLabel: ImmediateTextNode + + private var item: StatsOverviewItem? + + init() { + self.backgroundNode = ASDisplayNode() + self.backgroundNode.isLayerBacked = true + self.backgroundNode.backgroundColor = .white + + self.topStripeNode = ASDisplayNode() + self.topStripeNode.isLayerBacked = true + + self.bottomStripeNode = ASDisplayNode() + self.bottomStripeNode.isLayerBacked = true + + self.followersValueLabel = ImmediateTextNode() + self.viewsPerPostValueLabel = ImmediateTextNode() + self.sharesPerPostValueLabel = ImmediateTextNode() + self.enabledNotificationsValueLabel = ImmediateTextNode() + + self.followersTitleLabel = ImmediateTextNode() + self.viewsPerPostTitleLabel = ImmediateTextNode() + self.sharesPerPostTitleLabel = ImmediateTextNode() + self.enabledNotificationsTitleLabel = ImmediateTextNode() + + self.followersDeltaLabel = ImmediateTextNode() + self.viewsPerPostDeltaLabel = ImmediateTextNode() + self.sharesPerPostDeltaLabel = ImmediateTextNode() + + super.init(layerBacked: false, dynamicBounce: false) + + self.clipsToBounds = true + + self.addSubnode(self.followersValueLabel) + self.addSubnode(self.viewsPerPostValueLabel) + self.addSubnode(self.sharesPerPostValueLabel) + self.addSubnode(self.enabledNotificationsValueLabel) + + self.addSubnode(self.followersTitleLabel) + self.addSubnode(self.viewsPerPostTitleLabel) + self.addSubnode(self.sharesPerPostTitleLabel) + self.addSubnode(self.enabledNotificationsTitleLabel) + + self.addSubnode(self.followersDeltaLabel) + self.addSubnode(self.viewsPerPostDeltaLabel) + self.addSubnode(self.sharesPerPostDeltaLabel) + } + + func asyncLayout() -> (_ item: StatsOverviewItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) { + let makeFollowersValueLabelLayout = TextNode.asyncLayout(self.followersValueLabel) + let makeViewsPerPostValueLabelLayout = TextNode.asyncLayout(self.viewsPerPostValueLabel) + let makeSharesPerPostValueLabelLayout = TextNode.asyncLayout(self.sharesPerPostValueLabel) + let makeEnabledNotificationsValueLabelLayout = TextNode.asyncLayout(self.enabledNotificationsValueLabel) + + let makeFollowersTitleLabelLayout = TextNode.asyncLayout(self.followersTitleLabel) + let makeViewsPerPostTitleLabelLayout = TextNode.asyncLayout(self.viewsPerPostTitleLabel) + let makeSharesPerPostTitleLabelLayout = TextNode.asyncLayout(self.sharesPerPostTitleLabel) + let makeEnabledNotificationsTitleLabelLayout = TextNode.asyncLayout(self.enabledNotificationsTitleLabel) + + let makeFollowersDeltaLabelLayout = TextNode.asyncLayout(self.followersDeltaLabel) + let makeViewsPerPostDeltaLabelLayout = TextNode.asyncLayout(self.viewsPerPostDeltaLabel) + let makeSharesPerPostDeltaLabelLayout = TextNode.asyncLayout(self.sharesPerPostDeltaLabel) + + let currentItem = self.item + + return { item, params, neighbors in + let leftInset = params.leftInset + let rightInset: CGFloat = params.rightInset + var updatedTheme: PresentationTheme? + var updatedGraph: ChannelStatsGraph? + + if currentItem?.presentationData.theme !== item.presentationData.theme { + updatedTheme = item.presentationData.theme + } + + let valueFont = Font.regular(item.presentationData.fontSize.itemListBaseHeaderFontSize) + let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseHeaderFontSize) + let deltaFont = Font.regular(item.presentationData.fontSize.itemListBaseHeaderFontSize) + + let (followersValueLabelLayout, followersValueLabelApply) = makeFollowersValueLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "221K", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let (viewsPerPostValueLabelLayout, viewsPerPostValueLabelApply) = makeViewsPerPostValueLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "120K", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let (sharesPerPostValueLabelLayout, sharesPerPostValueLabelApply) = makeSharesPerPostValueLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "350", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let (enabledNotificationsValueLabelLayout, enabledNotificationsValueLabelApply) = makeEnabledNotificationsValueLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "22.77%", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + + let (followersTitleLabelLayout, followersTitleLabelApply) = makeFollowersTitleLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Followers", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let (viewsPerPostTitleLabelLayout, viewsPerPostTitleLabelApply) = makeViewsPerPostTitleLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Views Per Post", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let (sharesPerPostTitleLabelLayout, sharesPerPostTitleLabelApply) = makeSharesPerPostTitleLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Shares Per Post", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let (enabledNotificationsTitleLabelLayout, enabledNotificationsTitleLabelApply) = makeEnabledNotificationsTitleLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Enabled Notifications", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let (followersDeltaLabelLayout, followersDeltaLabelApply) = makeFollowersDeltaLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "+474 (0.21%)", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let (viewsPerPostDeltaLabelLayout, viewsPerPostDeltaLabelApply) = makeViewsPerPostDeltaLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "-14K (10.68%)", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let (sharesPerPostDeltaLabelLayout, sharesPerPostDeltaLabelApply) = makeSharesPerPostDeltaLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "-134 (27.68%)", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let contentSize: CGSize + let insets: UIEdgeInsets + let separatorHeight = UIScreenPixel + let itemBackgroundColor: UIColor + let itemSeparatorColor: UIColor + + switch item.style { + case .plain: + itemBackgroundColor = item.presentationData.theme.list.plainBackgroundColor + itemSeparatorColor = item.presentationData.theme.list.itemPlainSeparatorColor + contentSize = CGSize(width: params.width, height: 120.0) + insets = itemListNeighborsPlainInsets(neighbors) + case .blocks: + itemBackgroundColor = item.presentationData.theme.list.itemBlocksBackgroundColor + itemSeparatorColor = item.presentationData.theme.list.itemBlocksSeparatorColor + contentSize = CGSize(width: params.width, height: 120.0) + insets = itemListNeighborsGroupedInsets(neighbors) + } + + let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets) + + return (ListViewItemNodeLayout(contentSize: contentSize, insets: insets), { [weak self] in + if let strongSelf = self { + strongSelf.item = item + + let _ = followersValueLabelApply() + let _ = viewsPerPostValueLabelApply() + let _ = sharesPerPostValueLabelApply() + let _ = enabledNotificationsValueLabelApply() + + let _ = followersTitleLabelApply() + let _ = viewsPerPostTitleLabelApply() + let _ = sharesPerPostTitleLabelApply() + let _ = enabledNotificationsTitleLabelApply() + + let _ = followersDeltaLabelApply() + let _ = viewsPerPostDeltaLabelApply() + let _ = sharesPerPostDeltaLabelApply() + + if let _ = updatedTheme { + strongSelf.topStripeNode.backgroundColor = itemSeparatorColor + strongSelf.bottomStripeNode.backgroundColor = itemSeparatorColor + strongSelf.backgroundNode.backgroundColor = itemBackgroundColor + } + + switch item.style { + case .plain: + if strongSelf.backgroundNode.supernode != nil { + strongSelf.backgroundNode.removeFromSupernode() + } + if strongSelf.topStripeNode.supernode != nil { + strongSelf.topStripeNode.removeFromSupernode() + } + if strongSelf.bottomStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0) + } + + strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight)) + case .blocks: + if strongSelf.backgroundNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0) + } + if strongSelf.topStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1) + } + if strongSelf.bottomStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) + } + switch neighbors.top { + case .sameSection(false): + strongSelf.topStripeNode.isHidden = true + default: + strongSelf.topStripeNode.isHidden = false + } + let bottomStripeInset: CGFloat + switch neighbors.bottom { + case .sameSection(false): + bottomStripeInset = leftInset + default: + bottomStripeInset = 0.0 + } + + strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight))) + strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight)) + strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight)) + } + + strongSelf.followersValueLabel.frame = CGRect(origin: CGPoint(x: leftInset, y: 7.0), size: followersValueLabelLayout.size) + + strongSelf.viewsPerPostValueLabel.frame = CGRect(origin: CGPoint(x: leftInset, y: 44.0), size: viewsPerPostValueLabelLayout.size) + + strongSelf.sharesPerPostValueLabel.frame = CGRect(origin: CGPoint(x: layout.size.width / 2.0, y: 44.0), size: sharesPerPostValueLabelLayout.size) + + strongSelf.enabledNotificationsValueLabel.frame = CGRect(origin: CGPoint(x: layout.size.width / 2.0, y: 7.0), size: enabledNotificationsValueLabelLayout.size) + } + }) + } + } + + override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) { + self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4) + } + + override func animateAdded(_ currentTimestamp: Double, duration: Double) { + self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + } + + override func animateRemoved(_ currentTimestamp: Double, duration: Double) { + self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) + } +} + diff --git a/submodules/SyncCore/Sources/CachedChannelData.swift b/submodules/SyncCore/Sources/CachedChannelData.swift index c00a913477..49bcb7c71c 100644 --- a/submodules/SyncCore/Sources/CachedChannelData.swift +++ b/submodules/SyncCore/Sources/CachedChannelData.swift @@ -166,6 +166,7 @@ public final class CachedChannelData: CachedPeerData { public let slowModeTimeout: Int32? public let slowModeValidUntilTimestamp: Int32? public let hasScheduledMessages: Bool + public let statsDatacenterId: Int32 public let peerIds: Set public let messageIds: Set @@ -192,9 +193,10 @@ public final class CachedChannelData: CachedPeerData { self.slowModeTimeout = nil self.slowModeValidUntilTimestamp = nil self.hasScheduledMessages = false + self.statsDatacenterId = 0 } - public init(isNotAccessible: Bool, flags: CachedChannelFlags, about: String?, participantsSummary: CachedChannelParticipantsSummary, exportedInvitation: ExportedInvitation?, botInfos: [CachedPeerBotInfo], peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, stickerPack: StickerPackCollectionInfo?, minAvailableMessageId: MessageId?, migrationReference: ChannelMigrationReference?, linkedDiscussionPeerId: PeerId?, peerGeoLocation: PeerGeoLocation?, slowModeTimeout: Int32?, slowModeValidUntilTimestamp: Int32?, hasScheduledMessages: Bool) { + public init(isNotAccessible: Bool, flags: CachedChannelFlags, about: String?, participantsSummary: CachedChannelParticipantsSummary, exportedInvitation: ExportedInvitation?, botInfos: [CachedPeerBotInfo], peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, stickerPack: StickerPackCollectionInfo?, minAvailableMessageId: MessageId?, migrationReference: ChannelMigrationReference?, linkedDiscussionPeerId: PeerId?, peerGeoLocation: PeerGeoLocation?, slowModeTimeout: Int32?, slowModeValidUntilTimestamp: Int32?, hasScheduledMessages: Bool, statsDatacenterId: Int32) { self.isNotAccessible = isNotAccessible self.flags = flags self.about = about @@ -211,6 +213,7 @@ public final class CachedChannelData: CachedPeerData { self.slowModeTimeout = slowModeTimeout self.slowModeValidUntilTimestamp = slowModeValidUntilTimestamp self.hasScheduledMessages = hasScheduledMessages + self.statsDatacenterId = statsDatacenterId var peerIds = Set() for botInfo in botInfos { @@ -231,67 +234,71 @@ public final class CachedChannelData: CachedPeerData { } public func withUpdatedIsNotAccessible(_ isNotAccessible: Bool) -> CachedChannelData { - return CachedChannelData(isNotAccessible: isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedFlags(_ flags: CachedChannelFlags) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedAbout(_ about: String?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedParticipantsSummary(_ participantsSummary: CachedChannelParticipantsSummary) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedExportedInvitation(_ exportedInvitation: ExportedInvitation?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedBotInfos(_ botInfos: [CachedPeerBotInfo]) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedPeerStatusSettings(_ peerStatusSettings: PeerStatusSettings?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedStickerPack(_ stickerPack: StickerPackCollectionInfo?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedMinAvailableMessageId(_ minAvailableMessageId: MessageId?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedMigrationReference(_ migrationReference: ChannelMigrationReference?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedLinkedDiscussionPeerId(_ linkedDiscussionPeerId: PeerId?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedPeerGeoLocation(_ peerGeoLocation: PeerGeoLocation?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedSlowModeTimeout(_ slowModeTimeout: Int32?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedSlowModeValidUntilTimestamp(_ slowModeValidUntilTimestamp: Int32?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedHasScheduledMessages(_ hasScheduledMessages: Bool) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) + } + + public func withUpdatedStatsDatacenterId(_ statsDatacenterId: Int32) -> CachedChannelData { + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: statsDatacenterId) } public init(decoder: PostboxDecoder) { @@ -346,6 +353,7 @@ public final class CachedChannelData: CachedPeerData { self.slowModeTimeout = decoder.decodeOptionalInt32ForKey("smt") self.slowModeValidUntilTimestamp = decoder.decodeOptionalInt32ForKey("smv") self.hasScheduledMessages = decoder.decodeBoolForKey("hsm", orElse: false) + self.statsDatacenterId = decoder.decodeInt32ForKey("sdi", orElse: 0) if let linkedDiscussionPeerId = self.linkedDiscussionPeerId { peerIds.insert(linkedDiscussionPeerId) @@ -430,6 +438,7 @@ public final class CachedChannelData: CachedPeerData { encoder.encodeNil(forKey: "smv") } encoder.encodeBool(self.hasScheduledMessages, forKey: "hsm") + encoder.encodeInt32(self.statsDatacenterId, forKey: "sdi") } public func isEqual(to: CachedPeerData) -> Bool { @@ -497,6 +506,14 @@ public final class CachedChannelData: CachedPeerData { return false } + if other.hasScheduledMessages != self.hasScheduledMessages { + return false + } + + if other.statsDatacenterId != self.statsDatacenterId { + return false + } + return true } } diff --git a/submodules/SyncCore/Sources/TextEntitiesMessageAttribute.swift b/submodules/SyncCore/Sources/TextEntitiesMessageAttribute.swift index 79fe68a5ed..e0c3f565a9 100644 --- a/submodules/SyncCore/Sources/TextEntitiesMessageAttribute.swift +++ b/submodules/SyncCore/Sources/TextEntitiesMessageAttribute.swift @@ -19,6 +19,7 @@ public enum MessageTextEntityType: Equatable { case Strikethrough case BlockQuote case Underline + case BankCard case Custom(type: CustomEntityType) } @@ -65,6 +66,8 @@ public struct MessageTextEntity: PostboxCoding, Equatable { self.type = .BlockQuote case 15: self.type = .Underline + case 16: + self.type = .BankCard case Int32.max: self.type = .Custom(type: decoder.decodeInt32ForKey("type", orElse: 0)) default: @@ -110,6 +113,8 @@ public struct MessageTextEntity: PostboxCoding, Equatable { encoder.encodeInt32(14, forKey: "_rawValue") case .Underline: encoder.encodeInt32(15, forKey: "_rawValue") + case .BankCard: + encoder.encodeInt32(16, forKey: "_rawValue") case let .Custom(type): encoder.encodeInt32(Int32.max, forKey: "_rawValue") encoder.encodeInt32(type, forKey: "type") diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index ab2f4a7b7b..be3e05a869 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -412,6 +412,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[2103482845] = { return Api.SecurePlainData.parse_securePlainPhone($0) } dict[569137759] = { return Api.SecurePlainData.parse_securePlainEmail($0) } dict[-1269012015] = { return Api.messages.AffectedHistory.parse_affectedHistory($0) } + dict[1244130093] = { return Api.StatsGraph.parse_statsGraphAsync($0) } + dict[-1092839390] = { return Api.StatsGraph.parse_statsGraphError($0) } + dict[-1057809608] = { return Api.StatsGraph.parse_statsGraph($0) } dict[-1036572727] = { return Api.account.PasswordInputSettings.parse_passwordInputSettings($0) } dict[878078826] = { return Api.PageTableCell.parse_pageTableCell($0) } dict[-1626209256] = { return Api.ChatBannedRights.parse_chatBannedRights($0) } @@ -480,6 +483,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-668391402] = { return Api.InputUser.parse_inputUser($0) } dict[-1366746132] = { return Api.Page.parse_page($0) } dict[871426631] = { return Api.SecureCredentialsEncrypted.parse_secureCredentialsEncrypted($0) } + dict[-875679776] = { return Api.StatsPercentValue.parse_statsPercentValue($0) } dict[157948117] = { return Api.upload.File.parse_file($0) } dict[-242427324] = { return Api.upload.File.parse_fileCdnRedirect($0) } dict[-1078612597] = { return Api.ChannelLocation.parse_channelLocationEmpty($0) } @@ -506,6 +510,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1160215659] = { return Api.InputMessage.parse_inputMessageReplyTo($0) } dict[-2037963464] = { return Api.InputMessage.parse_inputMessagePinned($0) } dict[-1564789301] = { return Api.PhoneCallProtocol.parse_phoneCallProtocol($0) } + dict[-1237848657] = { return Api.StatsDateRangeDays.parse_statsDateRangeDays($0) } dict[-1567175714] = { return Api.MessageFwdAuthor.parse_messageFwdAuthor($0) } dict[-1539849235] = { return Api.WallPaper.parse_wallPaper($0) } dict[-1963717851] = { return Api.WallPaper.parse_wallPaperNoFile($0) } @@ -520,6 +525,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1837345356] = { return Api.InputChatPhoto.parse_inputChatUploadedPhoto($0) } dict[-1991004873] = { return Api.InputChatPhoto.parse_inputChatPhoto($0) } dict[-368917890] = { return Api.PaymentCharge.parse_paymentCharge($0) } + dict[205195937] = { return Api.stats.BroadcastStats.parse_broadcastStats($0) } dict[-484987010] = { return Api.Updates.parse_updatesTooLong($0) } dict[-1857044719] = { return Api.Updates.parse_updateShortMessage($0) } dict[377562760] = { return Api.Updates.parse_updateShortChatMessage($0) } @@ -527,6 +533,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1918567619] = { return Api.Updates.parse_updatesCombined($0) } dict[1957577280] = { return Api.Updates.parse_updates($0) } dict[301019932] = { return Api.Updates.parse_updateShortSentMessage($0) } + dict[-884757282] = { return Api.StatsAbsValueAndPrev.parse_statsAbsValueAndPrev($0) } dict[1038967584] = { return Api.MessageMedia.parse_messageMediaEmpty($0) } dict[1457575028] = { return Api.MessageMedia.parse_messageMediaGeo($0) } dict[-1618676578] = { return Api.MessageMedia.parse_messageMediaUnsupported($0) } @@ -608,6 +615,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1421174295] = { return Api.WebPageAttribute.parse_webPageAttributeTheme($0) } dict[82699215] = { return Api.messages.FeaturedStickers.parse_featuredStickersNotModified($0) } dict[-123893531] = { return Api.messages.FeaturedStickers.parse_featuredStickers($0) } + dict[1375940666] = { return Api.auth.LoginTokenInfo.parse_loginTokenInfo($0) } dict[-2048646399] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonMissed($0) } dict[-527056480] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonDisconnect($0) } dict[1471006352] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonHangup($0) } @@ -678,8 +686,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-395967805] = { return Api.messages.AllStickers.parse_allStickersNotModified($0) } dict[-302170017] = { return Api.messages.AllStickers.parse_allStickers($0) } dict[-1655957568] = { return Api.PhoneConnection.parse_phoneConnection($0) } - dict[-206688531] = { return Api.help.UserInfo.parse_userInfoEmpty($0) } - dict[32192344] = { return Api.help.UserInfo.parse_userInfo($0) } dict[-1194283041] = { return Api.AccountDaysTTL.parse_accountDaysTTL($0) } dict[-1658158621] = { return Api.SecureValueType.parse_secureValueTypePersonalDetails($0) } dict[1034709504] = { return Api.SecureValueType.parse_secureValueTypePassport($0) } @@ -746,6 +752,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1363483106] = { return Api.DialogPeer.parse_dialogPeerFolder($0) } dict[-104284986] = { return Api.WebDocument.parse_webDocumentNoProxy($0) } dict[475467473] = { return Api.WebDocument.parse_webDocument($0) } + dict[1211967244] = { return Api.Theme.parse_themeDocumentNotModified($0) } dict[42930452] = { return Api.Theme.parse_theme($0) } dict[-1290580579] = { return Api.contacts.Found.parse_found($0) } dict[-368018716] = { return Api.ChannelAdminLogEventsFilter.parse_channelAdminLogEventsFilter($0) } @@ -761,6 +768,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1041346555] = { return Api.updates.ChannelDifference.parse_channelDifferenceEmpty($0) } dict[543450958] = { return Api.updates.ChannelDifference.parse_channelDifference($0) } dict[-1531132162] = { return Api.updates.ChannelDifference.parse_channelDifferenceTooLong($0) } + dict[-581804346] = { return Api.StatsRowAbsValueAndPrev.parse_statsRowAbsValueAndPrev($0) } dict[-309659827] = { return Api.channels.AdminLogResults.parse_adminLogResults($0) } dict[-264117680] = { return Api.ChatOnlines.parse_chatOnlines($0) } dict[488313413] = { return Api.InputAppEvent.parse_inputAppEvent($0) } @@ -782,6 +790,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1672577397] = { return Api.MessageEntity.parse_messageEntityUnderline($0) } dict[-1090087980] = { return Api.MessageEntity.parse_messageEntityStrike($0) } dict[34469328] = { return Api.MessageEntity.parse_messageEntityBlockquote($0) } + dict[1981704948] = { return Api.MessageEntity.parse_messageEntityBankCard($0) } dict[483901197] = { return Api.InputPhoto.parse_inputPhotoEmpty($0) } dict[1001634122] = { return Api.InputPhoto.parse_inputPhoto($0) } dict[-567906571] = { return Api.contacts.TopPeers.parse_topPeersNotModified($0) } @@ -799,11 +808,13 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-94974410] = { return Api.EncryptedChat.parse_encryptedChat($0) } dict[332848423] = { return Api.EncryptedChat.parse_encryptedChatDiscarded($0) } dict[-901375139] = { return Api.PeerLocated.parse_peerLocated($0) } + dict[-118740917] = { return Api.PeerLocated.parse_peerSelfLocated($0) } dict[922273905] = { return Api.Document.parse_documentEmpty($0) } dict[-1683841855] = { return Api.Document.parse_document($0) } dict[-1707344487] = { return Api.messages.HighScores.parse_highScores($0) } dict[-892779534] = { return Api.WebAuthorization.parse_webAuthorization($0) } dict[-805141448] = { return Api.ImportedContact.parse_importedContact($0) } + dict[-419239361] = { return Api.payments.BankCardData.parse_bankCardData($0) } return dict }() @@ -1081,6 +1092,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.messages.AffectedHistory: _1.serialize(buffer, boxed) + case let _1 as Api.StatsGraph: + _1.serialize(buffer, boxed) case let _1 as Api.account.PasswordInputSettings: _1.serialize(buffer, boxed) case let _1 as Api.PageTableCell: @@ -1151,6 +1164,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.SecureCredentialsEncrypted: _1.serialize(buffer, boxed) + case let _1 as Api.StatsPercentValue: + _1.serialize(buffer, boxed) case let _1 as Api.upload.File: _1.serialize(buffer, boxed) case let _1 as Api.ChannelLocation: @@ -1185,6 +1200,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.PhoneCallProtocol: _1.serialize(buffer, boxed) + case let _1 as Api.StatsDateRangeDays: + _1.serialize(buffer, boxed) case let _1 as Api.MessageFwdAuthor: _1.serialize(buffer, boxed) case let _1 as Api.WallPaper: @@ -1201,8 +1218,12 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.PaymentCharge: _1.serialize(buffer, boxed) + case let _1 as Api.stats.BroadcastStats: + _1.serialize(buffer, boxed) case let _1 as Api.Updates: _1.serialize(buffer, boxed) + case let _1 as Api.StatsAbsValueAndPrev: + _1.serialize(buffer, boxed) case let _1 as Api.MessageMedia: _1.serialize(buffer, boxed) case let _1 as Api.PaymentSavedCredentials: @@ -1273,6 +1294,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.messages.FeaturedStickers: _1.serialize(buffer, boxed) + case let _1 as Api.auth.LoginTokenInfo: + _1.serialize(buffer, boxed) case let _1 as Api.PhoneCallDiscardReason: _1.serialize(buffer, boxed) case let _1 as Api.NearestDc: @@ -1331,8 +1354,6 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.PhoneConnection: _1.serialize(buffer, boxed) - case let _1 as Api.help.UserInfo: - _1.serialize(buffer, boxed) case let _1 as Api.AccountDaysTTL: _1.serialize(buffer, boxed) case let _1 as Api.SecureValueType: @@ -1381,6 +1402,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.updates.ChannelDifference: _1.serialize(buffer, boxed) + case let _1 as Api.StatsRowAbsValueAndPrev: + _1.serialize(buffer, boxed) case let _1 as Api.channels.AdminLogResults: _1.serialize(buffer, boxed) case let _1 as Api.ChatOnlines: @@ -1409,6 +1432,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.ImportedContact: _1.serialize(buffer, boxed) + case let _1 as Api.payments.BankCardData: + _1.serialize(buffer, boxed) default: break } diff --git a/submodules/TelegramApi/Sources/Api1.swift b/submodules/TelegramApi/Sources/Api1.swift index 9e6d38f6d1..09dc6c09b6 100644 --- a/submodules/TelegramApi/Sources/Api1.swift +++ b/submodules/TelegramApi/Sources/Api1.swift @@ -11956,6 +11956,82 @@ public extension Api { } } + } + public enum StatsGraph: TypeConstructorDescription { + case statsGraphAsync(token: String) + case statsGraphError(error: String) + case statsGraph(json: Api.DataJSON) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .statsGraphAsync(let token): + if boxed { + buffer.appendInt32(1244130093) + } + serializeString(token, buffer: buffer, boxed: false) + break + case .statsGraphError(let error): + if boxed { + buffer.appendInt32(-1092839390) + } + serializeString(error, buffer: buffer, boxed: false) + break + case .statsGraph(let json): + if boxed { + buffer.appendInt32(-1057809608) + } + json.serialize(buffer, true) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .statsGraphAsync(let token): + return ("statsGraphAsync", [("token", token)]) + case .statsGraphError(let error): + return ("statsGraphError", [("error", error)]) + case .statsGraph(let json): + return ("statsGraph", [("json", json)]) + } + } + + public static func parse_statsGraphAsync(_ reader: BufferReader) -> StatsGraph? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.StatsGraph.statsGraphAsync(token: _1!) + } + else { + return nil + } + } + public static func parse_statsGraphError(_ reader: BufferReader) -> StatsGraph? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.StatsGraph.statsGraphError(error: _1!) + } + else { + return nil + } + } + public static func parse_statsGraph(_ reader: BufferReader) -> StatsGraph? { + var _1: Api.DataJSON? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.DataJSON + } + let _c1 = _1 != nil + if _c1 { + return Api.StatsGraph.statsGraph(json: _1!) + } + else { + return nil + } + } + } public enum PageTableCell: TypeConstructorDescription { case pageTableCell(flags: Int32, text: Api.RichText?, colspan: Int32?, rowspan: Int32?) @@ -13662,6 +13738,44 @@ public extension Api { } } + } + public enum StatsPercentValue: TypeConstructorDescription { + case statsPercentValue(part: Double, total: Double) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .statsPercentValue(let part, let total): + if boxed { + buffer.appendInt32(-875679776) + } + serializeDouble(part, buffer: buffer, boxed: false) + serializeDouble(total, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .statsPercentValue(let part, let total): + return ("statsPercentValue", [("part", part), ("total", total)]) + } + } + + public static func parse_statsPercentValue(_ reader: BufferReader) -> StatsPercentValue? { + var _1: Double? + _1 = reader.readDouble() + var _2: Double? + _2 = reader.readDouble() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.StatsPercentValue.statsPercentValue(part: _1!, total: _2!) + } + else { + return nil + } + } + } public enum ChannelLocation: TypeConstructorDescription { case channelLocationEmpty @@ -14434,6 +14548,44 @@ public extension Api { } } + } + public enum StatsDateRangeDays: TypeConstructorDescription { + case statsDateRangeDays(minDate: Int32, maxDate: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .statsDateRangeDays(let minDate, let maxDate): + if boxed { + buffer.appendInt32(-1237848657) + } + serializeInt32(minDate, buffer: buffer, boxed: false) + serializeInt32(maxDate, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .statsDateRangeDays(let minDate, let maxDate): + return ("statsDateRangeDays", [("minDate", minDate), ("maxDate", maxDate)]) + } + } + + public static func parse_statsDateRangeDays(_ reader: BufferReader) -> StatsDateRangeDays? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.StatsDateRangeDays.statsDateRangeDays(minDate: _1!, maxDate: _2!) + } + else { + return nil + } + } + } public enum MessageFwdAuthor: TypeConstructorDescription { case messageFwdAuthor(channelId: Int32) @@ -15098,6 +15250,44 @@ public extension Api { } } + } + public enum StatsAbsValueAndPrev: TypeConstructorDescription { + case statsAbsValueAndPrev(current: Double, previous: Double) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .statsAbsValueAndPrev(let current, let previous): + if boxed { + buffer.appendInt32(-884757282) + } + serializeDouble(current, buffer: buffer, boxed: false) + serializeDouble(previous, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .statsAbsValueAndPrev(let current, let previous): + return ("statsAbsValueAndPrev", [("current", current), ("previous", previous)]) + } + } + + public static func parse_statsAbsValueAndPrev(_ reader: BufferReader) -> StatsAbsValueAndPrev? { + var _1: Double? + _1 = reader.readDouble() + var _2: Double? + _2 = reader.readDouble() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.StatsAbsValueAndPrev.statsAbsValueAndPrev(current: _1!, previous: _2!) + } + else { + return nil + } + } + } public enum MessageMedia: TypeConstructorDescription { case messageMediaEmpty @@ -20448,10 +20638,17 @@ public extension Api { } public enum Theme: TypeConstructorDescription { + case themeDocumentNotModified case theme(flags: Int32, id: Int64, accessHash: Int64, slug: String, title: String, document: Api.Document?, settings: Api.ThemeSettings?, installsCount: Int32) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { + case .themeDocumentNotModified: + if boxed { + buffer.appendInt32(1211967244) + } + + break case .theme(let flags, let id, let accessHash, let slug, let title, let document, let settings, let installsCount): if boxed { buffer.appendInt32(42930452) @@ -20470,11 +20667,16 @@ public extension Api { public func descriptionFields() -> (String, [(String, Any)]) { switch self { + case .themeDocumentNotModified: + return ("themeDocumentNotModified", []) case .theme(let flags, let id, let accessHash, let slug, let title, let document, let settings, let installsCount): return ("theme", [("flags", flags), ("id", id), ("accessHash", accessHash), ("slug", slug), ("title", title), ("document", document), ("settings", settings), ("installsCount", installsCount)]) } } + public static func parse_themeDocumentNotModified(_ reader: BufferReader) -> Theme? { + return Api.Theme.themeDocumentNotModified + } public static func parse_theme(_ reader: BufferReader) -> Theme? { var _1: Int32? _1 = reader.readInt32() @@ -20880,6 +21082,54 @@ public extension Api { } } + } + public enum StatsRowAbsValueAndPrev: TypeConstructorDescription { + case statsRowAbsValueAndPrev(id: String, title: String, shortTitle: String, values: Api.StatsAbsValueAndPrev) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .statsRowAbsValueAndPrev(let id, let title, let shortTitle, let values): + if boxed { + buffer.appendInt32(-581804346) + } + serializeString(id, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + serializeString(shortTitle, buffer: buffer, boxed: false) + values.serialize(buffer, true) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .statsRowAbsValueAndPrev(let id, let title, let shortTitle, let values): + return ("statsRowAbsValueAndPrev", [("id", id), ("title", title), ("shortTitle", shortTitle), ("values", values)]) + } + } + + public static func parse_statsRowAbsValueAndPrev(_ reader: BufferReader) -> StatsRowAbsValueAndPrev? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.StatsRowAbsValueAndPrev.statsRowAbsValueAndPrev(id: _1!, title: _2!, shortTitle: _3!, values: _4!) + } + else { + return nil + } + } + } public enum ChatOnlines: TypeConstructorDescription { case chatOnlines(onlines: Int32) @@ -20982,6 +21232,7 @@ public extension Api { case messageEntityUnderline(offset: Int32, length: Int32) case messageEntityStrike(offset: Int32, length: Int32) case messageEntityBlockquote(offset: Int32, length: Int32) + case messageEntityBankCard(offset: Int32, length: Int32) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -21115,6 +21366,13 @@ public extension Api { serializeInt32(offset, buffer: buffer, boxed: false) serializeInt32(length, buffer: buffer, boxed: false) break + case .messageEntityBankCard(let offset, let length): + if boxed { + buffer.appendInt32(1981704948) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break } } @@ -21156,6 +21414,8 @@ public extension Api { return ("messageEntityStrike", [("offset", offset), ("length", length)]) case .messageEntityBlockquote(let offset, let length): return ("messageEntityBlockquote", [("offset", offset), ("length", length)]) + case .messageEntityBankCard(let offset, let length): + return ("messageEntityBankCard", [("offset", offset), ("length", length)]) } } @@ -21425,6 +21685,20 @@ public extension Api { return nil } } + public static func parse_messageEntityBankCard(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageEntity.messageEntityBankCard(offset: _1!, length: _2!) + } + else { + return nil + } + } } public enum InputPhoto: TypeConstructorDescription { @@ -21727,6 +22001,7 @@ public extension Api { } public enum PeerLocated: TypeConstructorDescription { case peerLocated(peer: Api.Peer, expires: Int32, distance: Int32) + case peerSelfLocated(expires: Int32) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -21738,6 +22013,12 @@ public extension Api { serializeInt32(expires, buffer: buffer, boxed: false) serializeInt32(distance, buffer: buffer, boxed: false) break + case .peerSelfLocated(let expires): + if boxed { + buffer.appendInt32(-118740917) + } + serializeInt32(expires, buffer: buffer, boxed: false) + break } } @@ -21745,6 +22026,8 @@ public extension Api { switch self { case .peerLocated(let peer, let expires, let distance): return ("peerLocated", [("peer", peer), ("expires", expires), ("distance", distance)]) + case .peerSelfLocated(let expires): + return ("peerSelfLocated", [("expires", expires)]) } } @@ -21767,6 +22050,17 @@ public extension Api { return nil } } + public static func parse_peerSelfLocated(_ reader: BufferReader) -> PeerLocated? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.PeerLocated.peerSelfLocated(expires: _1!) + } + else { + return nil + } + } } public enum Document: TypeConstructorDescription { diff --git a/submodules/TelegramApi/Sources/Api2.swift b/submodules/TelegramApi/Sources/Api2.swift index f0cb6195e9..4f499c6615 100644 --- a/submodules/TelegramApi/Sources/Api2.swift +++ b/submodules/TelegramApi/Sources/Api2.swift @@ -490,6 +490,176 @@ public struct payments { } } + public enum BankCardData: TypeConstructorDescription { + case bankCardData(flags: Int32, title: String, url: String?, urlName: String?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .bankCardData(let flags, let title, let url, let urlName): + if boxed { + buffer.appendInt32(-419239361) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(url!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 0) != 0 {serializeString(urlName!, buffer: buffer, boxed: false)} + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .bankCardData(let flags, let title, let url, let urlName): + return ("bankCardData", [("flags", flags), ("title", title), ("url", url), ("urlName", urlName)]) + } + } + + public static func parse_bankCardData(_ reader: BufferReader) -> BankCardData? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + if Int(_1!) & Int(1 << 0) != 0 {_3 = parseString(reader) } + var _4: String? + if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.payments.BankCardData.bankCardData(flags: _1!, title: _2!, url: _3, urlName: _4) + } + else { + return nil + } + } + + } +} +} +public extension Api { +public struct stats { + public enum BroadcastStats: TypeConstructorDescription { + case broadcastStats(period: Api.StatsDateRangeDays, followers: Api.StatsAbsValueAndPrev, viewsPerPost: Api.StatsAbsValueAndPrev, sharesPerPost: Api.StatsAbsValueAndPrev, enabledNotifications: Api.StatsPercentValue, viewsBySource: [Api.StatsRowAbsValueAndPrev], newFollowersBySource: [Api.StatsRowAbsValueAndPrev], languages: [Api.StatsRowAbsValueAndPrev], growthGraph: Api.StatsGraph, followersGraph: Api.StatsGraph, muteGraph: Api.StatsGraph, topHoursGraph: Api.StatsGraph, interactionsGraph: Api.StatsGraph) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let enabledNotifications, let viewsBySource, let newFollowersBySource, let languages, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph): + if boxed { + buffer.appendInt32(205195937) + } + period.serialize(buffer, true) + followers.serialize(buffer, true) + viewsPerPost.serialize(buffer, true) + sharesPerPost.serialize(buffer, true) + enabledNotifications.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(viewsBySource.count)) + for item in viewsBySource { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(newFollowersBySource.count)) + for item in newFollowersBySource { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(languages.count)) + for item in languages { + item.serialize(buffer, true) + } + growthGraph.serialize(buffer, true) + followersGraph.serialize(buffer, true) + muteGraph.serialize(buffer, true) + topHoursGraph.serialize(buffer, true) + interactionsGraph.serialize(buffer, true) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let enabledNotifications, let viewsBySource, let newFollowersBySource, let languages, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph): + return ("broadcastStats", [("period", period), ("followers", followers), ("viewsPerPost", viewsPerPost), ("sharesPerPost", sharesPerPost), ("enabledNotifications", enabledNotifications), ("viewsBySource", viewsBySource), ("newFollowersBySource", newFollowersBySource), ("languages", languages), ("growthGraph", growthGraph), ("followersGraph", followersGraph), ("muteGraph", muteGraph), ("topHoursGraph", topHoursGraph), ("interactionsGraph", interactionsGraph)]) + } + } + + public static func parse_broadcastStats(_ reader: BufferReader) -> BroadcastStats? { + var _1: Api.StatsDateRangeDays? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.StatsDateRangeDays + } + var _2: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _3: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _4: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _5: Api.StatsPercentValue? + if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.StatsPercentValue + } + var _6: [Api.StatsRowAbsValueAndPrev]? + if let _ = reader.readInt32() { + _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsRowAbsValueAndPrev.self) + } + var _7: [Api.StatsRowAbsValueAndPrev]? + if let _ = reader.readInt32() { + _7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsRowAbsValueAndPrev.self) + } + var _8: [Api.StatsRowAbsValueAndPrev]? + if let _ = reader.readInt32() { + _8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsRowAbsValueAndPrev.self) + } + var _9: Api.StatsGraph? + if let signature = reader.readInt32() { + _9 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _10: Api.StatsGraph? + if let signature = reader.readInt32() { + _10 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _11: Api.StatsGraph? + if let signature = reader.readInt32() { + _11 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _12: Api.StatsGraph? + if let signature = reader.readInt32() { + _12 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _13: Api.StatsGraph? + if let signature = reader.readInt32() { + _13 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + let _c10 = _10 != nil + let _c11 = _11 != nil + let _c12 = _12 != nil + let _c13 = _13 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 { + return Api.stats.BroadcastStats.broadcastStats(period: _1!, followers: _2!, viewsPerPost: _3!, sharesPerPost: _4!, enabledNotifications: _5!, viewsBySource: _6!, newFollowersBySource: _7!, languages: _8!, growthGraph: _9!, followersGraph: _10!, muteGraph: _11!, topHoursGraph: _12!, interactionsGraph: _13!) + } + else { + return nil + } + } + + } } } public extension Api { @@ -859,6 +1029,76 @@ public struct auth { return Api.auth.CodeType.codeTypeFlashCall } + } + public enum LoginTokenInfo: TypeConstructorDescription { + case loginTokenInfo(dcId: Int32, authKeyId: Int64, deviceModel: String, platform: String, systemVersion: String, apiId: Int32, appName: String, appVersion: String, ip: String, region: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .loginTokenInfo(let dcId, let authKeyId, let deviceModel, let platform, let systemVersion, let apiId, let appName, let appVersion, let ip, let region): + if boxed { + buffer.appendInt32(1375940666) + } + serializeInt32(dcId, buffer: buffer, boxed: false) + serializeInt64(authKeyId, buffer: buffer, boxed: false) + serializeString(deviceModel, buffer: buffer, boxed: false) + serializeString(platform, buffer: buffer, boxed: false) + serializeString(systemVersion, buffer: buffer, boxed: false) + serializeInt32(apiId, buffer: buffer, boxed: false) + serializeString(appName, buffer: buffer, boxed: false) + serializeString(appVersion, buffer: buffer, boxed: false) + serializeString(ip, buffer: buffer, boxed: false) + serializeString(region, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .loginTokenInfo(let dcId, let authKeyId, let deviceModel, let platform, let systemVersion, let apiId, let appName, let appVersion, let ip, let region): + return ("loginTokenInfo", [("dcId", dcId), ("authKeyId", authKeyId), ("deviceModel", deviceModel), ("platform", platform), ("systemVersion", systemVersion), ("apiId", apiId), ("appName", appName), ("appVersion", appVersion), ("ip", ip), ("region", region)]) + } + } + + public static func parse_loginTokenInfo(_ reader: BufferReader) -> LoginTokenInfo? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + var _5: String? + _5 = parseString(reader) + var _6: Int32? + _6 = reader.readInt32() + var _7: String? + _7 = parseString(reader) + var _8: String? + _8 = parseString(reader) + var _9: String? + _9 = parseString(reader) + var _10: String? + _10 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + let _c10 = _10 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 { + return Api.auth.LoginTokenInfo.loginTokenInfo(dcId: _1!, authKeyId: _2!, deviceModel: _3!, platform: _4!, systemVersion: _5!, apiId: _6!, appName: _7!, appVersion: _8!, ip: _9!, region: _10!) + } + else { + return nil + } + } + } public enum SentCodeType: TypeConstructorDescription { case sentCodeTypeApp(length: Int32) @@ -1859,70 +2099,6 @@ public struct help { } } - } - public enum UserInfo: TypeConstructorDescription { - case userInfoEmpty - case userInfo(message: String, entities: [Api.MessageEntity], author: String, date: Int32) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .userInfoEmpty: - if boxed { - buffer.appendInt32(-206688531) - } - - break - case .userInfo(let message, let entities, let author, let date): - if boxed { - buffer.appendInt32(32192344) - } - serializeString(message, buffer: buffer, boxed: false) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(entities.count)) - for item in entities { - item.serialize(buffer, true) - } - serializeString(author, buffer: buffer, boxed: false) - serializeInt32(date, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .userInfoEmpty: - return ("userInfoEmpty", []) - case .userInfo(let message, let entities, let author, let date): - return ("userInfo", [("message", message), ("entities", entities), ("author", author), ("date", date)]) - } - } - - public static func parse_userInfoEmpty(_ reader: BufferReader) -> UserInfo? { - return Api.help.UserInfo.userInfoEmpty - } - public static func parse_userInfo(_ reader: BufferReader) -> UserInfo? { - var _1: String? - _1 = parseString(reader) - var _2: [Api.MessageEntity]? - if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) - } - var _3: String? - _3 = parseString(reader) - var _4: Int32? - _4 = reader.readInt32() - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.help.UserInfo.userInfo(message: _1!, entities: _2!, author: _3!, date: _4!) - } - else { - return nil - } - } - } public enum TermsOfServiceUpdate: TypeConstructorDescription { case termsOfServiceUpdateEmpty(expires: Int32) diff --git a/submodules/TelegramApi/Sources/Api3.swift b/submodules/TelegramApi/Sources/Api3.swift index 74e4884bf6..aee22f1e04 100644 --- a/submodules/TelegramApi/Sources/Api3.swift +++ b/submodules/TelegramApi/Sources/Api3.swift @@ -3196,6 +3196,25 @@ public extension Api { }) } + public static func toggleStickerSets(flags: Int32, stickersets: [Api.InputStickerSet]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1257951254) + serializeInt32(flags, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(stickersets.count)) + for item in stickersets { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "messages.toggleStickerSets", parameters: [("flags", flags), ("stickersets", stickersets)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + public static func getPollVotes(flags: Int32, peer: Api.InputPeer, id: Int32, option: Buffer?, offset: String?, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() buffer.appendInt32(-1200736242) @@ -3885,6 +3904,50 @@ public extension Api { return result }) } + + public static func getBankCardData(number: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(779736953) + serializeString(number, buffer: buffer, boxed: false) + return (FunctionDescription(name: "payments.getBankCardData", parameters: [("number", number)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.BankCardData? in + let reader = BufferReader(buffer) + var result: Api.payments.BankCardData? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.payments.BankCardData + } + return result + }) + } + } + public struct stats { + public static func getBroadcastStats(flags: Int32, channel: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1421720550) + serializeInt32(flags, buffer: buffer, boxed: false) + channel.serialize(buffer, true) + return (FunctionDescription(name: "stats.getBroadcastStats", parameters: [("flags", flags), ("channel", channel)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.stats.BroadcastStats? in + let reader = BufferReader(buffer) + var result: Api.stats.BroadcastStats? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.stats.BroadcastStats + } + return result + }) + } + + public static func loadAsyncGraph(token: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1749505346) + serializeString(token, buffer: buffer, boxed: false) + return (FunctionDescription(name: "stats.loadAsyncGraph", parameters: [("token", token)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.StatsGraph? in + let reader = BufferReader(buffer) + var result: Api.StatsGraph? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + return result + }) + } } public struct auth { public static func checkPhone(phoneNumber: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { @@ -4558,11 +4621,13 @@ public extension Api { }) } - public static func getLocated(geoPoint: Api.InputGeoPoint) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + public static func getLocated(flags: Int32, geoPoint: Api.InputGeoPoint, selfExpires: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(171270230) + buffer.appendInt32(-750207932) + serializeInt32(flags, buffer: buffer, boxed: false) geoPoint.serialize(buffer, true) - return (FunctionDescription(name: "contacts.getLocated", parameters: [("geoPoint", geoPoint)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(selfExpires!, buffer: buffer, boxed: false)} + return (FunctionDescription(name: "contacts.getLocated", parameters: [("flags", flags), ("geoPoint", geoPoint), ("selfExpires", selfExpires)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in let reader = BufferReader(buffer) var result: Api.Updates? if let signature = reader.readInt32() { @@ -4815,40 +4880,6 @@ public extension Api { return result }) } - - public static func editUserInfo(userId: Api.InputUser, message: String, entities: [Api.MessageEntity]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { - let buffer = Buffer() - buffer.appendInt32(1723407216) - userId.serialize(buffer, true) - serializeString(message, buffer: buffer, boxed: false) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(entities.count)) - for item in entities { - item.serialize(buffer, true) - } - return (FunctionDescription(name: "help.editUserInfo", parameters: [("userId", userId), ("message", message), ("entities", entities)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.help.UserInfo? in - let reader = BufferReader(buffer) - var result: Api.help.UserInfo? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.help.UserInfo - } - return result - }) - } - - public static func getUserInfo(userId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { - let buffer = Buffer() - buffer.appendInt32(59377875) - userId.serialize(buffer, true) - return (FunctionDescription(name: "help.getUserInfo", parameters: [("userId", userId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.help.UserInfo? in - let reader = BufferReader(buffer) - var result: Api.help.UserInfo? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.help.UserInfo - } - return result - }) - } } public struct updates { public static func getState() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { diff --git a/submodules/TelegramCore/Sources/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/AccountStateManagementUtils.swift index ad168e7d01..4e870b88ce 100644 --- a/submodules/TelegramCore/Sources/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/AccountStateManagementUtils.swift @@ -1295,8 +1295,13 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo } case let .updatePeerLocated(peers): var peersNearby: [PeerNearby] = [] - for case let .peerLocated(peer, expires, distance) in peers { - peersNearby.append(PeerNearby(id: peer.peerId, expires: expires, distance: distance)) + for peer in peers { + switch peer { + case let .peerLocated(peer, expires, distance): + peersNearby.append(.peer(id: peer.peerId, expires: expires, distance: distance)) + case let .peerSelfLocated(expires): + peersNearby.append(.selfPeer(expires: expires)) + } } updatedState.updatePeersNearby(peersNearby) case let .updateNewScheduledMessage(apiMessage): diff --git a/submodules/TelegramCore/Sources/BankCards.swift b/submodules/TelegramCore/Sources/BankCards.swift new file mode 100644 index 0000000000..f0db9d6304 --- /dev/null +++ b/submodules/TelegramCore/Sources/BankCards.swift @@ -0,0 +1,34 @@ +import Foundation +import Postbox +import TelegramApi +import SyncCore +import SwiftSignalKit + +public struct BankCardInfo { + public let title: String + public let url: String? + public let actionTitle: String? +} + +public func getBankCardInfo(account: Account, cardNumber: String) -> Signal { + return account.network.request(Api.functions.payments.getBankCardData(number: cardNumber)) + |> map { result -> BankCardInfo? in + return BankCardInfo(apiBankCardData: result) + } + |> `catch` { _ -> Signal in + return .single(nil) + } +} + +extension BankCardInfo { + init(apiBankCardData: Api.payments.BankCardData) { + switch apiBankCardData { + case let .bankCardData(flags, title, url, urlName): + self.title = title + self.url = url + self.actionTitle = urlName + } + } +} + + diff --git a/submodules/TelegramCore/Sources/ChannelStatistics.swift b/submodules/TelegramCore/Sources/ChannelStatistics.swift new file mode 100644 index 0000000000..1e501b535b --- /dev/null +++ b/submodules/TelegramCore/Sources/ChannelStatistics.swift @@ -0,0 +1,424 @@ +import Foundation +import SwiftSignalKit +import Postbox +import TelegramApi +import MtProtoKit +import SyncCore + +public struct ChannelStatsDateRange: Equatable { + public let minDate: Int32 + public let maxDate: Int32 +} + +public struct ChannelStatsValue: Equatable { + public let current: Double + public let previous: Double +} + +public struct ChannelStatsPercentValue: Equatable { + public let fraction: Double + public let total: Double +} + +public struct ChannelStatsNamedValue: Equatable { + public let id: String + public let title: String + public let shortTitle: String + public let value: ChannelStatsValue +} + +public enum ChannelStatsGraph: Equatable { + case OnDemand(token: String) + case Failed(error: String) + case Loaded(data: String) +} + +public final class ChannelStats: Equatable { + public let period: ChannelStatsDateRange + public let followers: ChannelStatsValue + public let viewsPerPost: ChannelStatsValue + public let sharesPerPost: ChannelStatsValue + public let enabledNotifications: ChannelStatsPercentValue + public let viewsBySource: [ChannelStatsNamedValue] + public let newFollowersBySource: [ChannelStatsNamedValue] + public let languages: [ChannelStatsNamedValue] + public let growthGraph: ChannelStatsGraph + public let followersGraph: ChannelStatsGraph + public let muteGraph: ChannelStatsGraph + public let topHoursGraph: ChannelStatsGraph + public let interactionsGraph: ChannelStatsGraph + + public init(period: ChannelStatsDateRange, followers: ChannelStatsValue, viewsPerPost: ChannelStatsValue, sharesPerPost: ChannelStatsValue, enabledNotifications: ChannelStatsPercentValue, viewsBySource: [ChannelStatsNamedValue], newFollowersBySource: [ChannelStatsNamedValue], languages: [ChannelStatsNamedValue], growthGraph: ChannelStatsGraph, followersGraph: ChannelStatsGraph, muteGraph: ChannelStatsGraph, topHoursGraph: ChannelStatsGraph, interactionsGraph: ChannelStatsGraph) { + self.period = period + self.followers = followers + self.viewsPerPost = viewsPerPost + self.sharesPerPost = sharesPerPost + self.enabledNotifications = enabledNotifications + self.viewsBySource = viewsBySource + self.newFollowersBySource = newFollowersBySource + self.languages = languages + self.growthGraph = growthGraph + self.followersGraph = followersGraph + self.muteGraph = muteGraph + self.topHoursGraph = topHoursGraph + self.interactionsGraph = interactionsGraph + } + + public static func == (lhs: ChannelStats, rhs: ChannelStats) -> Bool { + if lhs.period != rhs.period { + return false + } + if lhs.followers != rhs.followers { + return false + } + if lhs.viewsPerPost != rhs.viewsPerPost { + return false + } + if lhs.sharesPerPost != rhs.sharesPerPost { + return false + } + if lhs.enabledNotifications != rhs.enabledNotifications { + return false + } + if lhs.viewsBySource != rhs.viewsBySource { + return false + } + if lhs.newFollowersBySource != rhs.newFollowersBySource { + return false + } + if lhs.languages != rhs.languages { + return false + } + if lhs.growthGraph != rhs.growthGraph { + return false + } + if lhs.followersGraph != rhs.followersGraph { + return false + } + if lhs.muteGraph != rhs.muteGraph { + return false + } + if lhs.topHoursGraph != rhs.topHoursGraph { + return false + } + if lhs.interactionsGraph != rhs.interactionsGraph { + return false + } + return true + } + + public func withUpdatedGrowthGraph(_ growthGraph: ChannelStatsGraph) -> ChannelStats { + return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, viewsBySource: self.viewsBySource, newFollowersBySource: self.newFollowersBySource, languages: self.languages, growthGraph: growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph) + } + + public func withUpdatedFollowersGraph(_ followersGraph: ChannelStatsGraph) -> ChannelStats { + return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, viewsBySource: self.viewsBySource, newFollowersBySource: self.newFollowersBySource, languages: self.languages, growthGraph: self.growthGraph, followersGraph: followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph) + } + + public func withUpdatedMuteGraph(_ muteGraph: ChannelStatsGraph) -> ChannelStats { + return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, viewsBySource: self.viewsBySource, newFollowersBySource: self.newFollowersBySource, languages: self.languages, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph) + } + + public func withUpdatedTopHoursGraph(_ viewsByHourGraph: ChannelStatsGraph) -> ChannelStats { + return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, viewsBySource: self.viewsBySource, newFollowersBySource: self.newFollowersBySource, languages: self.languages, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: viewsByHourGraph, interactionsGraph: self.interactionsGraph) + } + + public func withUpdatedInteractionsGraph(_ interactionsGraph: ChannelStatsGraph) -> ChannelStats { + return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, viewsBySource: self.viewsBySource, newFollowersBySource: self.newFollowersBySource, languages: self.languages, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: interactionsGraph) + } +} + +public struct ChannelStatsContextState: Equatable { + public var stats: ChannelStats? +} + +private func requestStats(network: Network, datacenterId: Int32, peer: Peer, dark: Bool = false) -> Signal { + guard let inputChannel = apiInputChannel(peer) else { + return .never() + } + + var flags: Int32 = 0 + if dark { + flags |= (1 << 1) + } + + let signal: Signal + if network.datacenterId != datacenterId { + signal = network.download(datacenterId: Int(datacenterId), isMedia: false, tag: nil) + |> castError(MTRpcError.self) + |> mapToSignal { worker in + return worker.request(Api.functions.stats.getBroadcastStats(flags: flags, channel: inputChannel)) + } + } else { + signal = network.request(Api.functions.stats.getBroadcastStats(flags: flags, channel: inputChannel)) + } + + return signal + |> map { result -> ChannelStats? in + return ChannelStats(apiBroadcastStats: result) + } + |> `catch` { _ -> Signal in + return .single(nil) + } +} + +private func requestGraph(network: Network, datacenterId: Int32, token: String) -> Signal { + let signal: Signal + if network.datacenterId != datacenterId { + signal = network.download(datacenterId: Int(datacenterId), isMedia: false, tag: nil) + |> castError(MTRpcError.self) + |> mapToSignal { worker in + return worker.request(Api.functions.stats.loadAsyncGraph(token: token)) + } + } else { + signal = network.request(Api.functions.stats.loadAsyncGraph(token: token)) + } + + return signal + |> map { result -> ChannelStatsGraph? in + return ChannelStatsGraph(apiStatsGraph: result) + } + |> `catch` { _ -> Signal in + return .single(nil) + } +} + +private final class ChannelStatsContextImpl { + private let network: Network + private let peer: Peer + private let datacenterId: Int32 + + private var _state: ChannelStatsContextState { + didSet { + if self._state != oldValue { + self._statePromise.set(.single(self._state)) + } + } + } + private let _statePromise = Promise() + var state: Signal { + return self._statePromise.get() + } + + private let disposable = MetaDisposable() + private let disposables = DisposableDict() + + init(network: Network, datacenterId: Int32, peer: Peer) { + assert(Queue.mainQueue().isCurrent()) + + self.network = network + self.peer = peer + self.datacenterId = datacenterId + self._state = ChannelStatsContextState(stats: nil) + self._statePromise.set(.single(self._state)) + + self.load() + } + + deinit { + assert(Queue.mainQueue().isCurrent()) + self.disposable.dispose() + self.disposables.dispose() + } + + private func load() { + assert(Queue.mainQueue().isCurrent()) + + self.disposable.set((requestStats(network: self.network, datacenterId: self.datacenterId, peer: self.peer) + |> deliverOnMainQueue).start(next: { [weak self] stats in + if let strongSelf = self { + strongSelf._state = ChannelStatsContextState(stats: stats) + strongSelf._statePromise.set(.single(strongSelf._state)) + } + })) + } + + func loadGrowthGraph() { + guard let stats = self._state.stats else { + return + } + if case let .OnDemand(token) = stats.growthGraph { + self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token) + |> deliverOnMainQueue).start(next: { [weak self] graph in + if let strongSelf = self, let graph = graph { + strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedGrowthGraph(graph)) + strongSelf._statePromise.set(.single(strongSelf._state)) + } + }), forKey: token) + } + } + + func loadFollowersGraph() { + guard let stats = self._state.stats else { + return + } + if case let .OnDemand(token) = stats.followersGraph { + self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token) + |> deliverOnMainQueue).start(next: { [weak self] graph in + if let strongSelf = self, let graph = graph { + strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedFollowersGraph(graph)) + strongSelf._statePromise.set(.single(strongSelf._state)) + } + }), forKey: token) + } + } + + func loadMuteGraph() { + guard let stats = self._state.stats else { + return + } + if case let .OnDemand(token) = stats.muteGraph { + self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token) + |> deliverOnMainQueue).start(next: { [weak self] graph in + if let strongSelf = self, let graph = graph { + strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedMuteGraph(graph)) + strongSelf._statePromise.set(.single(strongSelf._state)) + } + }), forKey: token) + } + } + + func loadTopHoursGraph() { + guard let stats = self._state.stats else { + return + } + if case let .OnDemand(token) = stats.topHoursGraph { + self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token) + |> deliverOnMainQueue).start(next: { [weak self] graph in + if let strongSelf = self, let graph = graph { + strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedTopHoursGraph(graph)) + strongSelf._statePromise.set(.single(strongSelf._state)) + } + }), forKey: token) + } + } + + func loadInteractionsGraph() { + guard let stats = self._state.stats else { + return + } + if case let .OnDemand(token) = stats.interactionsGraph { + self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token) + |> deliverOnMainQueue).start(next: { [weak self] graph in + if let strongSelf = self, let graph = graph { + strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedInteractionsGraph(graph)) + strongSelf._statePromise.set(.single(strongSelf._state)) + } + }), forKey: token) + } + } +} + +public final class ChannelStatsContext { + private let impl: QueueLocalObject + + public var state: Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + self.impl.with { impl in + disposable.set(impl.state.start(next: { value in + subscriber.putNext(value) + })) + } + return disposable + } + } + + public init(network: Network, datacenterId: Int32, peer: Peer) { + self.impl = QueueLocalObject(queue: Queue.mainQueue(), generate: { + return ChannelStatsContextImpl(network: network, datacenterId: datacenterId, peer: peer) + }) + } + + public func loadGrowthGraph() { + self.impl.with { impl in + impl.loadGrowthGraph() + } + } + + public func loadFollowersGraph() { + self.impl.with { impl in + impl.loadFollowersGraph() + } + } + + public func loadMuteGraph() { + self.impl.with { impl in + impl.loadMuteGraph() + } + } + + public func loadTopHoursGraph() { + self.impl.with { impl in + impl.loadTopHoursGraph() + } + } + + public func loadInteractionsGraph() { + self.impl.with { impl in + impl.loadInteractionsGraph() + } + } +} + +extension ChannelStatsGraph { + init(apiStatsGraph: Api.StatsGraph) { + switch apiStatsGraph { + case let .statsGraph(json): + if case let .dataJSON(string) = json { + self = .Loaded(data: string) + } else { + self = .Failed(error: "") + } + case let .statsGraphError(error): + self = .Failed(error: error) + case let .statsGraphAsync(token): + self = .OnDemand(token: token) + } + } +} + +extension ChannelStatsDateRange { + init(apiStatsDateRangeDays: Api.StatsDateRangeDays) { + switch apiStatsDateRangeDays { + case let .statsDateRangeDays(minDate, maxDate): + self = ChannelStatsDateRange(minDate: minDate, maxDate: maxDate) + } + } +} + +extension ChannelStatsValue { + init(apiStatsAbsValueAndPrev: Api.StatsAbsValueAndPrev) { + switch apiStatsAbsValueAndPrev { + case let .statsAbsValueAndPrev(current, previous): + self = ChannelStatsValue(current: current, previous: previous) + } + } +} + +extension ChannelStatsNamedValue { + init(apiStatsRowAbsValueAndPrev: Api.StatsRowAbsValueAndPrev) { + switch apiStatsRowAbsValueAndPrev { + case let .statsRowAbsValueAndPrev(id, title, shortTitle, values): + self = ChannelStatsNamedValue(id: id, title: title, shortTitle: shortTitle, value: ChannelStatsValue(apiStatsAbsValueAndPrev: values)) + } + } +} + +extension ChannelStatsPercentValue { + init(apiPercentValue: Api.StatsPercentValue) { + switch apiPercentValue { + case let .statsPercentValue(part, total): + self = ChannelStatsPercentValue(fraction: part, total: total) + } + } +} + +extension ChannelStats { + convenience init(apiBroadcastStats: Api.stats.BroadcastStats) { + switch apiBroadcastStats { + case let .broadcastStats(period, followers, viewsPerPost, sharesPerPost, enabledNotifications, viewsBySource, newFollowersBySource, languages, growthGraph, followersGraph, muteGraph, topHoursGraph, interactionsGraph): + self.init(period: ChannelStatsDateRange(apiStatsDateRangeDays: period), followers: ChannelStatsValue(apiStatsAbsValueAndPrev: followers), viewsPerPost: ChannelStatsValue(apiStatsAbsValueAndPrev: viewsPerPost), sharesPerPost: ChannelStatsValue(apiStatsAbsValueAndPrev: sharesPerPost), enabledNotifications: ChannelStatsPercentValue(apiPercentValue: enabledNotifications), viewsBySource: viewsBySource.map { ChannelStatsNamedValue(apiStatsRowAbsValueAndPrev: $0) }, newFollowersBySource: newFollowersBySource.map { ChannelStatsNamedValue(apiStatsRowAbsValueAndPrev: $0) }, languages: languages.map { ChannelStatsNamedValue(apiStatsRowAbsValueAndPrev: $0) }, growthGraph: ChannelStatsGraph(apiStatsGraph: growthGraph), followersGraph: ChannelStatsGraph(apiStatsGraph: followersGraph), muteGraph: ChannelStatsGraph(apiStatsGraph: muteGraph), topHoursGraph: ChannelStatsGraph(apiStatsGraph: topHoursGraph), interactionsGraph: ChannelStatsGraph(apiStatsGraph: interactionsGraph)) + } + } +} diff --git a/submodules/TelegramCore/Sources/JSON.swift b/submodules/TelegramCore/Sources/JSON.swift index 556085328b..43dd62bebd 100644 --- a/submodules/TelegramCore/Sources/JSON.swift +++ b/submodules/TelegramCore/Sources/JSON.swift @@ -28,8 +28,7 @@ extension JSON { } } self = .array(values) - } - else if let value = object as? String { + } else if let value = object as? String { self = .string(value) } else if let value = object as? Int { self = .number(Double(value)) diff --git a/submodules/TelegramCore/Sources/ManagedSecretChatOutgoingOperations.swift b/submodules/TelegramCore/Sources/ManagedSecretChatOutgoingOperations.swift index 7754b00b97..d490602165 100644 --- a/submodules/TelegramCore/Sources/ManagedSecretChatOutgoingOperations.swift +++ b/submodules/TelegramCore/Sources/ManagedSecretChatOutgoingOperations.swift @@ -676,6 +676,8 @@ private func decryptedEntities73(_ entities: [MessageTextEntity]?) -> [SecretApi break case .Underline: break + case .BankCard: + break case .Custom: break } @@ -723,6 +725,8 @@ private func decryptedEntities101(_ entities: [MessageTextEntity]?) -> [SecretAp result.append(.messageEntityBlockquote(offset: Int32(entity.range.lowerBound), length: Int32(entity.range.count))) case .Underline: result.append(.messageEntityUnderline(offset: Int32(entity.range.lowerBound), length: Int32(entity.range.count))) + case .BankCard: + break case .Custom: break } diff --git a/submodules/TelegramCore/Sources/PeersNearby.swift b/submodules/TelegramCore/Sources/PeersNearby.swift index b872ec5837..4ea533867d 100644 --- a/submodules/TelegramCore/Sources/PeersNearby.swift +++ b/submodules/TelegramCore/Sources/PeersNearby.swift @@ -7,12 +7,57 @@ import SyncCore private typealias SignalKitTimer = SwiftSignalKit.Timer +public enum PeerNearby { + case selfPeer(expires: Int32) + case peer(id: PeerId, expires: Int32, distance: Int32) + + var expires: Int32 { + switch self { + case let .selfPeer(expires), let .peer(_, expires, _): + return expires + } + } +} +public enum PeerNearbyVisibilityUpdate { + case visible(latitude: Double, longitude: Double) + case location(latitude: Double, longitude: Double) + case invisible +} -public struct PeerNearby { - public let id: PeerId - public let expires: Int32 - public let distance: Int32 +public func peersNearbyUpdateVisibility(network: Network, stateManager: AccountStateManager, update: PeerNearbyVisibilityUpdate, background: Bool) -> Signal { + var flags: Int32 = 0 + var geoPoint: Api.InputGeoPoint + var selfExpires: Int32? + + switch update { + case let .visible(latitude, longitude): + flags |= (1 << 0) + geoPoint = .inputGeoPoint(lat: latitude, long: longitude) + selfExpires = 86400 + case let .location(latitude, longitude): + geoPoint = .inputGeoPoint(lat: latitude, long: longitude) + case .invisible: + flags |= (1 << 0) + geoPoint = .inputGeoPointEmpty + selfExpires = 0 + } + + if background { + flags |= (1 << 1) + } + + return network.request(Api.functions.contacts.getLocated(flags: flags, geoPoint: geoPoint, selfExpires: selfExpires)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { updates -> Signal in + if let updates = updates { + stateManager.addUpdates(updates) + } + return .complete() + } } public final class PeersNearbyContext { @@ -23,10 +68,10 @@ public final class PeersNearbyContext { private var entries: [PeerNearby]? - public init(network: Network, accountStateManager: AccountStateManager, coordinate: (latitude: Double, longitude: Double)) { + public init(network: Network, stateManager: AccountStateManager, coordinate: (latitude: Double, longitude: Double)) { let expiryExtension: Double = 10.0 - let poll = network.request(Api.functions.contacts.getLocated(geoPoint: .inputGeoPoint(lat: coordinate.latitude, long: coordinate.longitude))) + let poll = network.request(Api.functions.contacts.getLocated(flags: 0, geoPoint: .inputGeoPoint(lat: coordinate.latitude, long: coordinate.longitude), selfExpires: nil)) |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) @@ -39,23 +84,28 @@ public final class PeersNearbyContext { case let .updates(updates, _, _, _, _): for update in updates { if case let .updatePeerLocated(peers) = update { - for case let .peerLocated(peer, expires, distance) in peers { - peersNearby.append(PeerNearby(id: peer.peerId, expires: expires, distance: distance)) + for peer in peers { + switch peer { + case let .peerLocated(peer, expires, distance): + peersNearby.append(.peer(id: peer.peerId, expires: expires, distance: distance)) + case let .peerSelfLocated(expires): + peersNearby.append(.selfPeer(expires: expires)) + } } } } default: break } - accountStateManager.addUpdates(updates) + stateManager.addUpdates(updates) } return .single(peersNearby) |> then( - accountStateManager.updatedPeersNearby() + stateManager.updatedPeersNearby() |> castError(Void.self) ) } - + let error: Signal = .single(Void()) |> then(Signal.fail(Void()) |> suspendAwareDelay(25.0, queue: self.queue)) let combined = combineLatest(poll, error) |> map { data, _ -> [PeerNearby] in @@ -77,18 +127,37 @@ public final class PeersNearbyContext { let updatedEntries = updatedEntries.filter { Double($0.expires) + expiryExtension > timestamp } var existingPeerIds: [PeerId: Int] = [:] + var existingSelfPeer: Int? for i in 0 ..< entries.count { - existingPeerIds[entries[i].id] = i + if case let .peer(id, _, _) = entries[i] { + existingPeerIds[id] = i + } else if case .selfPeer = entries[i] { + existingSelfPeer = i + } } + var selfPeer: PeerNearby? for entry in updatedEntries { - if let index = existingPeerIds[entry.id] { - entries[index] = entry - } else { - entries.append(entry) + switch entry { + case let .selfPeer: + if let index = existingSelfPeer { + entries[index] = entry + } else { + selfPeer = entry + } + case let .peer(id, _, _): + if let index = existingPeerIds[id] { + entries[index] = entry + } else { + entries.append(entry) + } } } + if let peer = selfPeer { + entries.insert(peer, at: 0) + } + strongSelf.entries = entries for subscriber in strongSelf.subscribers.copyItems() { subscriber(strongSelf.entries) diff --git a/submodules/TelegramCore/Sources/Serialization.swift b/submodules/TelegramCore/Sources/Serialization.swift index 02470ccbac..15b20dd3d8 100644 --- a/submodules/TelegramCore/Sources/Serialization.swift +++ b/submodules/TelegramCore/Sources/Serialization.swift @@ -210,7 +210,7 @@ public class BoxedMessage: NSObject { public class Serialization: NSObject, MTSerialization { public func currentLayer() -> UInt { - return 109 + return 110 } public func parseMessage(_ data: Data!) -> Any! { diff --git a/submodules/TelegramCore/Sources/StoreMessage_Telegram.swift b/submodules/TelegramCore/Sources/StoreMessage_Telegram.swift index d5c0b31029..44751ce910 100644 --- a/submodules/TelegramCore/Sources/StoreMessage_Telegram.swift +++ b/submodules/TelegramCore/Sources/StoreMessage_Telegram.swift @@ -386,6 +386,8 @@ func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [Mes result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Strikethrough)) case let .messageEntityBlockquote(offset, length): result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .BlockQuote)) + case let .messageEntityBankCard(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .BankCard)) } } return result diff --git a/submodules/TelegramCore/Sources/TextEntitiesMessageAttribute.swift b/submodules/TelegramCore/Sources/TextEntitiesMessageAttribute.swift index c898bed30f..1702002184 100644 --- a/submodules/TelegramCore/Sources/TextEntitiesMessageAttribute.swift +++ b/submodules/TelegramCore/Sources/TextEntitiesMessageAttribute.swift @@ -45,6 +45,8 @@ func apiEntitiesFromMessageTextEntities(_ entities: [MessageTextEntity], associa apiEntities.append(.messageEntityBlockquote(offset: offset, length: length)) case .Underline: apiEntities.append(.messageEntityUnderline(offset: offset, length: length)) + case .BankCard: + apiEntities.append(.messageEntityBankCard(offset: offset, length: length)) case .Custom: break } diff --git a/submodules/TelegramCore/Sources/UpdateCachedPeerData.swift b/submodules/TelegramCore/Sources/UpdateCachedPeerData.swift index 1050b92be7..d0f10bfb51 100644 --- a/submodules/TelegramCore/Sources/UpdateCachedPeerData.swift +++ b/submodules/TelegramCore/Sources/UpdateCachedPeerData.swift @@ -450,6 +450,7 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI .withUpdatedSlowModeTimeout(slowmodeSeconds) .withUpdatedSlowModeValidUntilTimestamp(slowmodeNextSendDate) .withUpdatedHasScheduledMessages(hasScheduledMessages) +// .withUpdatedStatsDatacenterId(statsDc ?? 0) }) if let minAvailableMessageId = minAvailableMessageId, minAvailableMessageIdUpdated { diff --git a/submodules/TelegramPresentationData/Sources/PresentationStrings.swift b/submodules/TelegramPresentationData/Sources/PresentationStrings.swift index f55acaf222..188fb8bab7 100644 --- a/submodules/TelegramPresentationData/Sources/PresentationStrings.swift +++ b/submodules/TelegramPresentationData/Sources/PresentationStrings.swift @@ -334,4899 +334,4909 @@ public final class PresentationStrings: Equatable { public var SettingsSearch_Synonyms_EditProfile_Username: String { return self._s[136]! } public var Group_Username_InvalidStartsWithNumber: String { return self._s[137]! } public var UserInfo_NotificationsEnabled: String { return self._s[138]! } - public var Map_Search: String { return self._s[139]! } - public var ClearCache_StorageFree: String { return self._s[141]! } - public var Login_TermsOfServiceHeader: String { return self._s[142]! } + public var PeopleNearby_MakeVisibleDescription: String { return self._s[139]! } + public var Map_Search: String { return self._s[140]! } + public var ClearCache_StorageFree: String { return self._s[142]! } + public var Login_TermsOfServiceHeader: String { return self._s[143]! } public func Notification_PinnedVideoMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[143]!, self._r[143]!, [_0]) + return formatWithArgumentRanges(self._s[144]!, self._r[144]!, [_0]) } public func Channel_AdminLog_MessageToggleSignaturesOn(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[145]!, self._r[145]!, [_0]) + return formatWithArgumentRanges(self._s[146]!, self._r[146]!, [_0]) } - public var Wallet_Sent_Title: String { return self._s[146]! } - public var TwoStepAuth_SetupPasswordConfirmPassword: String { return self._s[147]! } - public var Weekday_Today: String { return self._s[148]! } + public var Wallet_Sent_Title: String { return self._s[147]! } + public var TwoStepAuth_SetupPasswordConfirmPassword: String { return self._s[148]! } + public var Weekday_Today: String { return self._s[149]! } public func InstantPage_AuthorAndDateTitle(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[150]!, self._r[150]!, [_1, _2]) + return formatWithArgumentRanges(self._s[151]!, self._r[151]!, [_1, _2]) } public func Conversation_MessageDialogRetryAll(_ _1: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[151]!, self._r[151]!, ["\(_1)"]) + return formatWithArgumentRanges(self._s[152]!, self._r[152]!, ["\(_1)"]) } - public var Notification_PassportValuePersonalDetails: String { return self._s[153]! } - public var Channel_AdminLog_MessagePreviousLink: String { return self._s[154]! } - public var ChangePhoneNumberNumber_NewNumber: String { return self._s[155]! } - public var ApplyLanguage_LanguageNotSupportedError: String { return self._s[156]! } - public var TwoStepAuth_ChangePasswordDescription: String { return self._s[157]! } - public var PhotoEditor_BlurToolLinear: String { return self._s[158]! } - public var Contacts_PermissionsAllowInSettings: String { return self._s[159]! } - public var Weekday_ShortMonday: String { return self._s[160]! } - public var Cache_KeepMedia: String { return self._s[161]! } - public var Passport_FieldIdentitySelfieHelp: String { return self._s[162]! } + public var Notification_PassportValuePersonalDetails: String { return self._s[154]! } + public var Channel_AdminLog_MessagePreviousLink: String { return self._s[155]! } + public var ChangePhoneNumberNumber_NewNumber: String { return self._s[156]! } + public var ApplyLanguage_LanguageNotSupportedError: String { return self._s[157]! } + public var TwoStepAuth_ChangePasswordDescription: String { return self._s[158]! } + public var PhotoEditor_BlurToolLinear: String { return self._s[159]! } + public var Contacts_PermissionsAllowInSettings: String { return self._s[160]! } + public var Weekday_ShortMonday: String { return self._s[161]! } + public var Cache_KeepMedia: String { return self._s[162]! } + public var Passport_FieldIdentitySelfieHelp: String { return self._s[163]! } public func PUSH_PINNED_STICKER(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[163]!, self._r[163]!, [_1, _2]) + return formatWithArgumentRanges(self._s[164]!, self._r[164]!, [_1, _2]) } public func Chat_SlowmodeTooltip(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[164]!, self._r[164]!, [_0]) + return formatWithArgumentRanges(self._s[165]!, self._r[165]!, [_0]) } - public var Wallet_Receive_ShareUrlInfo: String { return self._s[165]! } - public var Conversation_ClousStorageInfo_Description4: String { return self._s[166]! } - public var Wallet_RestoreFailed_Title: String { return self._s[167]! } - public var Passport_Language_ru: String { return self._s[168]! } + public var Wallet_Receive_ShareUrlInfo: String { return self._s[166]! } + public var Conversation_ClousStorageInfo_Description4: String { return self._s[167]! } + public var Wallet_RestoreFailed_Title: String { return self._s[168]! } + public var Passport_Language_ru: String { return self._s[169]! } public func Notification_CreatedChatWithTitle(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[169]!, self._r[169]!, [_0, _1]) + return formatWithArgumentRanges(self._s[170]!, self._r[170]!, [_0, _1]) } - public var WallpaperPreview_PatternIntensity: String { return self._s[170]! } - public var WebBrowser_InAppSafari: String { return self._s[173]! } - public var TwoStepAuth_RecoveryUnavailable: String { return self._s[174]! } - public var EnterPasscode_TouchId: String { return self._s[175]! } - public var PhotoEditor_QualityVeryHigh: String { return self._s[178]! } - public var Checkout_NewCard_SaveInfo: String { return self._s[180]! } - public var Gif_NoGifsPlaceholder: String { return self._s[182]! } + public var WallpaperPreview_PatternIntensity: String { return self._s[171]! } + public var WebBrowser_InAppSafari: String { return self._s[174]! } + public var TwoStepAuth_RecoveryUnavailable: String { return self._s[175]! } + public var EnterPasscode_TouchId: String { return self._s[176]! } + public var PhotoEditor_QualityVeryHigh: String { return self._s[179]! } + public var Checkout_NewCard_SaveInfo: String { return self._s[181]! } + public var Gif_NoGifsPlaceholder: String { return self._s[183]! } public func Notification_InvitedMultiple(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[184]!, self._r[184]!, [_0, _1]) + return formatWithArgumentRanges(self._s[185]!, self._r[185]!, [_0, _1]) } - public var ChatSettings_AutoDownloadEnabled: String { return self._s[185]! } - public var NetworkUsageSettings_BytesSent: String { return self._s[186]! } - public var Checkout_PasswordEntry_Pay: String { return self._s[187]! } - public var AuthSessions_TerminateSession: String { return self._s[188]! } - public var Message_File: String { return self._s[189]! } - public var MediaPicker_VideoMuteDescription: String { return self._s[190]! } - public var SocksProxySetup_ProxyStatusConnected: String { return self._s[191]! } - public var TwoStepAuth_RecoveryCode: String { return self._s[192]! } - public var EnterPasscode_EnterCurrentPasscode: String { return self._s[193]! } + public var ChatSettings_AutoDownloadEnabled: String { return self._s[186]! } + public var NetworkUsageSettings_BytesSent: String { return self._s[187]! } + public var Checkout_PasswordEntry_Pay: String { return self._s[188]! } + public var AuthSessions_TerminateSession: String { return self._s[189]! } + public var Message_File: String { return self._s[190]! } + public var MediaPicker_VideoMuteDescription: String { return self._s[191]! } + public var SocksProxySetup_ProxyStatusConnected: String { return self._s[192]! } + public var TwoStepAuth_RecoveryCode: String { return self._s[193]! } + public var EnterPasscode_EnterCurrentPasscode: String { return self._s[194]! } public func TwoStepAuth_EnterPasswordHint(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[194]!, self._r[194]!, [_0]) + return formatWithArgumentRanges(self._s[195]!, self._r[195]!, [_0]) } - public var Conversation_Moderate_Report: String { return self._s[196]! } - public var TwoStepAuth_EmailInvalid: String { return self._s[197]! } - public var Passport_Language_ms: String { return self._s[198]! } - public var Channel_Edit_AboutItem: String { return self._s[200]! } - public var DialogList_SearchSectionGlobal: String { return self._s[204]! } - public var AttachmentMenu_WebSearch: String { return self._s[205]! } - public var PasscodeSettings_TurnPasscodeOn: String { return self._s[206]! } - public var Channel_BanUser_Title: String { return self._s[207]! } - public var WallpaperPreview_SwipeTopText: String { return self._s[208]! } - public var ChatList_DeleteSavedMessagesConfirmationText: String { return self._s[209]! } - public var ArchivedChats_IntroText2: String { return self._s[210]! } - public var Conversation_OpenBotLinkTitle: String { return self._s[211]! } - public var ChatSearch_SearchPlaceholder: String { return self._s[213]! } - public var Notification_Exceptions_DeleteAll: String { return self._s[214]! } - public var Passport_FieldAddressTranslationHelp: String { return self._s[215]! } - public var NotificationsSound_Aurora: String { return self._s[216]! } + public var Conversation_Moderate_Report: String { return self._s[197]! } + public var TwoStepAuth_EmailInvalid: String { return self._s[198]! } + public var Passport_Language_ms: String { return self._s[199]! } + public var Channel_Edit_AboutItem: String { return self._s[201]! } + public var DialogList_SearchSectionGlobal: String { return self._s[205]! } + public var AttachmentMenu_WebSearch: String { return self._s[206]! } + public var PasscodeSettings_TurnPasscodeOn: String { return self._s[207]! } + public var Channel_BanUser_Title: String { return self._s[208]! } + public var WallpaperPreview_SwipeTopText: String { return self._s[209]! } + public var ChatList_DeleteSavedMessagesConfirmationText: String { return self._s[210]! } + public var ArchivedChats_IntroText2: String { return self._s[211]! } + public var Conversation_OpenBotLinkTitle: String { return self._s[212]! } + public var ChatSearch_SearchPlaceholder: String { return self._s[214]! } + public var Notification_Exceptions_DeleteAll: String { return self._s[215]! } + public var Passport_FieldAddressTranslationHelp: String { return self._s[216]! } + public var NotificationsSound_Aurora: String { return self._s[217]! } public func Channel_AdminLog_MessageTransferedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[217]!, self._r[217]!, [_1, _2]) + return formatWithArgumentRanges(self._s[218]!, self._r[218]!, [_1, _2]) } public func FileSize_GB(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[218]!, self._r[218]!, [_0]) + return formatWithArgumentRanges(self._s[219]!, self._r[219]!, [_0]) } - public var AuthSessions_LoggedInWithTelegram: String { return self._s[221]! } + public var AuthSessions_LoggedInWithTelegram: String { return self._s[222]! } public func Privacy_GroupsAndChannels_InviteToGroupError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[222]!, self._r[222]!, [_0, _1]) + return formatWithArgumentRanges(self._s[223]!, self._r[223]!, [_0, _1]) } - public var Passport_PasswordNext: String { return self._s[223]! } - public var Bot_GroupStatusReadsHistory: String { return self._s[224]! } - public var EmptyGroupInfo_Line2: String { return self._s[225]! } - public var VoiceOver_Chat_SeenByRecipients: String { return self._s[226]! } - public var Settings_FAQ_Intro: String { return self._s[229]! } - public var PrivacySettings_PasscodeAndTouchId: String { return self._s[231]! } - public var FeaturedStickerPacks_Title: String { return self._s[232]! } - public var TwoStepAuth_PasswordRemoveConfirmation: String { return self._s[234]! } - public var Username_Title: String { return self._s[235]! } + public var Passport_PasswordNext: String { return self._s[224]! } + public var Bot_GroupStatusReadsHistory: String { return self._s[225]! } + public var EmptyGroupInfo_Line2: String { return self._s[226]! } + public var VoiceOver_Chat_SeenByRecipients: String { return self._s[227]! } + public var Settings_FAQ_Intro: String { return self._s[230]! } + public var PrivacySettings_PasscodeAndTouchId: String { return self._s[232]! } + public var FeaturedStickerPacks_Title: String { return self._s[233]! } + public var TwoStepAuth_PasswordRemoveConfirmation: String { return self._s[235]! } + public var Username_Title: String { return self._s[236]! } public func Message_StickerText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[236]!, self._r[236]!, [_0]) + return formatWithArgumentRanges(self._s[237]!, self._r[237]!, [_0]) } - public var PasscodeSettings_AlphanumericCode: String { return self._s[237]! } - public var Localization_LanguageOther: String { return self._s[238]! } - public var Stickers_SuggestStickers: String { return self._s[239]! } + public var PasscodeSettings_AlphanumericCode: String { return self._s[238]! } + public var Localization_LanguageOther: String { return self._s[239]! } + public var Stickers_SuggestStickers: String { return self._s[240]! } public func Channel_AdminLog_MessageRemovedGroupUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[240]!, self._r[240]!, [_0]) + return formatWithArgumentRanges(self._s[241]!, self._r[241]!, [_0]) } - public var NotificationSettings_ShowNotificationsFromAccountsSection: String { return self._s[241]! } - public var Channel_AdminLogFilter_EventsAdmins: String { return self._s[242]! } - public var Conversation_DefaultRestrictedStickers: String { return self._s[243]! } + public var NotificationSettings_ShowNotificationsFromAccountsSection: String { return self._s[242]! } + public var Channel_AdminLogFilter_EventsAdmins: String { return self._s[243]! } + public var Conversation_DefaultRestrictedStickers: String { return self._s[244]! } public func Notification_PinnedDeletedMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[244]!, self._r[244]!, [_0]) + return formatWithArgumentRanges(self._s[245]!, self._r[245]!, [_0]) } - public var Wallet_TransactionInfo_CopyAddress: String { return self._s[246]! } - public var Group_UpgradeConfirmation: String { return self._s[247]! } - public var DialogList_Unpin: String { return self._s[248]! } - public var Passport_Identity_DateOfBirth: String { return self._s[249]! } - public var Month_ShortOctober: String { return self._s[250]! } - public var SettingsSearch_Synonyms_Privacy_Data_ContactsSync: String { return self._s[251]! } - public var TwoFactorSetup_Done_Text: String { return self._s[252]! } - public var Notification_CallCanceledShort: String { return self._s[253]! } - public var Conversation_StopQuiz: String { return self._s[254]! } - public var Passport_Phone_Help: String { return self._s[255]! } - public var Passport_Language_az: String { return self._s[257]! } - public var CreatePoll_TextPlaceholder: String { return self._s[259]! } - public var VoiceOver_Chat_AnonymousPoll: String { return self._s[260]! } - public var Passport_Identity_DocumentNumber: String { return self._s[261]! } - public var PhotoEditor_CurvesRed: String { return self._s[262]! } - public var PhoneNumberHelp_Alert: String { return self._s[264]! } - public var SocksProxySetup_Port: String { return self._s[265]! } - public var Checkout_PayNone: String { return self._s[266]! } - public var AutoDownloadSettings_WiFi: String { return self._s[267]! } - public var GroupInfo_GroupType: String { return self._s[268]! } - public var StickerSettings_ContextHide: String { return self._s[269]! } - public var Passport_Address_OneOfTypeTemporaryRegistration: String { return self._s[270]! } - public var Group_Setup_HistoryTitle: String { return self._s[272]! } - public var Passport_Identity_FilesUploadNew: String { return self._s[273]! } - public var PasscodeSettings_AutoLock: String { return self._s[274]! } - public var Passport_Title: String { return self._s[275]! } - public var VoiceOver_Chat_ContactPhoneNumber: String { return self._s[276]! } - public var Channel_AdminLogFilter_EventsNewSubscribers: String { return self._s[277]! } - public var GroupPermission_NoSendGifs: String { return self._s[278]! } - public var PrivacySettings_PasscodeOn: String { return self._s[279]! } + public var Wallet_TransactionInfo_CopyAddress: String { return self._s[247]! } + public var Group_UpgradeConfirmation: String { return self._s[248]! } + public var DialogList_Unpin: String { return self._s[249]! } + public var Passport_Identity_DateOfBirth: String { return self._s[250]! } + public var Month_ShortOctober: String { return self._s[251]! } + public var SettingsSearch_Synonyms_Privacy_Data_ContactsSync: String { return self._s[252]! } + public var TwoFactorSetup_Done_Text: String { return self._s[253]! } + public var Notification_CallCanceledShort: String { return self._s[254]! } + public var Conversation_StopQuiz: String { return self._s[255]! } + public var Passport_Phone_Help: String { return self._s[256]! } + public var Passport_Language_az: String { return self._s[258]! } + public var CreatePoll_TextPlaceholder: String { return self._s[260]! } + public var VoiceOver_Chat_AnonymousPoll: String { return self._s[261]! } + public var Passport_Identity_DocumentNumber: String { return self._s[262]! } + public var PhotoEditor_CurvesRed: String { return self._s[263]! } + public var PhoneNumberHelp_Alert: String { return self._s[265]! } + public var SocksProxySetup_Port: String { return self._s[266]! } + public var Checkout_PayNone: String { return self._s[267]! } + public var AutoDownloadSettings_WiFi: String { return self._s[268]! } + public var GroupInfo_GroupType: String { return self._s[269]! } + public var StickerSettings_ContextHide: String { return self._s[270]! } + public var Passport_Address_OneOfTypeTemporaryRegistration: String { return self._s[271]! } + public var Group_Setup_HistoryTitle: String { return self._s[273]! } + public var Passport_Identity_FilesUploadNew: String { return self._s[274]! } + public var PasscodeSettings_AutoLock: String { return self._s[275]! } + public var Passport_Title: String { return self._s[276]! } + public var VoiceOver_Chat_ContactPhoneNumber: String { return self._s[277]! } + public var Channel_AdminLogFilter_EventsNewSubscribers: String { return self._s[278]! } + public var GroupPermission_NoSendGifs: String { return self._s[279]! } + public var PrivacySettings_PasscodeOn: String { return self._s[280]! } public func Conversation_ScheduleMessage_SendTomorrow(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[280]!, self._r[280]!, [_0]) + return formatWithArgumentRanges(self._s[281]!, self._r[281]!, [_0]) } - public var State_WaitingForNetwork: String { return self._s[283]! } + public var State_WaitingForNetwork: String { return self._s[284]! } public func Notification_Invited(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[284]!, self._r[284]!, [_0, _1]) + return formatWithArgumentRanges(self._s[285]!, self._r[285]!, [_0, _1]) } - public var Calls_NotNow: String { return self._s[286]! } + public var Calls_NotNow: String { return self._s[287]! } public func Channel_DiscussionGroup_HeaderSet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[287]!, self._r[287]!, [_0]) + return formatWithArgumentRanges(self._s[288]!, self._r[288]!, [_0]) } - public var UserInfo_SendMessage: String { return self._s[288]! } - public var TwoStepAuth_PasswordSet: String { return self._s[289]! } - public var Passport_DeleteDocument: String { return self._s[290]! } - public var SocksProxySetup_AddProxyTitle: String { return self._s[291]! } + public var UserInfo_SendMessage: String { return self._s[289]! } + public var TwoStepAuth_PasswordSet: String { return self._s[290]! } + public var Passport_DeleteDocument: String { return self._s[291]! } + public var SocksProxySetup_AddProxyTitle: String { return self._s[292]! } public func PUSH_MESSAGE_VIDEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[292]!, self._r[292]!, [_1]) + return formatWithArgumentRanges(self._s[293]!, self._r[293]!, [_1]) } - public var AuthSessions_AddedDeviceTitle: String { return self._s[293]! } - public var GroupRemoved_Remove: String { return self._s[294]! } - public var Passport_FieldIdentity: String { return self._s[295]! } - public var Group_Setup_TypePrivateHelp: String { return self._s[296]! } - public var Conversation_Processing: String { return self._s[299]! } - public var Wallet_Settings_BackupWallet: String { return self._s[301]! } - public var ChatSettings_AutoPlayAnimations: String { return self._s[302]! } - public var AuthSessions_LogOutApplicationsHelp: String { return self._s[305]! } - public var Forward_ErrorPublicQuizDisabledInChannels: String { return self._s[306]! } - public var Month_GenFebruary: String { return self._s[307]! } - public var Wallet_Send_NetworkErrorTitle: String { return self._s[308]! } + public var AuthSessions_AddedDeviceTitle: String { return self._s[294]! } + public var GroupRemoved_Remove: String { return self._s[295]! } + public var Passport_FieldIdentity: String { return self._s[296]! } + public var Group_Setup_TypePrivateHelp: String { return self._s[297]! } + public var Conversation_Processing: String { return self._s[300]! } + public var Wallet_Settings_BackupWallet: String { return self._s[302]! } + public var ChatSettings_AutoPlayAnimations: String { return self._s[303]! } + public var AuthSessions_LogOutApplicationsHelp: String { return self._s[306]! } + public var Forward_ErrorPublicQuizDisabledInChannels: String { return self._s[307]! } + public var Month_GenFebruary: String { return self._s[308]! } + public var Wallet_Send_NetworkErrorTitle: String { return self._s[309]! } public func Login_InvalidPhoneEmailBody(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[310]!, self._r[310]!, [_1, _2, _3, _4, _5]) + return formatWithArgumentRanges(self._s[311]!, self._r[311]!, [_1, _2, _3, _4, _5]) } - public var Passport_Identity_TypeIdentityCard: String { return self._s[311]! } - public var Wallet_Month_ShortJune: String { return self._s[313]! } - public var AutoDownloadSettings_DataUsageMedium: String { return self._s[314]! } - public var GroupInfo_AddParticipant: String { return self._s[315]! } - public var KeyCommand_SendMessage: String { return self._s[316]! } - public var VoiceOver_Chat_YourContact: String { return self._s[318]! } - public var Map_LiveLocationShowAll: String { return self._s[319]! } - public var WallpaperSearch_ColorOrange: String { return self._s[321]! } - public var Appearance_AppIconDefaultX: String { return self._s[322]! } - public var Checkout_Receipt_Title: String { return self._s[323]! } - public var Group_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[324]! } - public var WallpaperPreview_PreviewTopText: String { return self._s[325]! } - public var Message_Contact: String { return self._s[326]! } - public var Call_StatusIncoming: String { return self._s[327]! } - public var Wallet_TransactionInfo_StorageFeeInfo: String { return self._s[328]! } + public var Passport_Identity_TypeIdentityCard: String { return self._s[312]! } + public var Wallet_Month_ShortJune: String { return self._s[314]! } + public var AutoDownloadSettings_DataUsageMedium: String { return self._s[315]! } + public var GroupInfo_AddParticipant: String { return self._s[316]! } + public var KeyCommand_SendMessage: String { return self._s[317]! } + public var VoiceOver_Chat_YourContact: String { return self._s[319]! } + public var Map_LiveLocationShowAll: String { return self._s[320]! } + public var WallpaperSearch_ColorOrange: String { return self._s[322]! } + public var Appearance_AppIconDefaultX: String { return self._s[323]! } + public var Checkout_Receipt_Title: String { return self._s[324]! } + public var Group_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[325]! } + public var WallpaperPreview_PreviewTopText: String { return self._s[326]! } + public var Message_Contact: String { return self._s[327]! } + public var Call_StatusIncoming: String { return self._s[328]! } + public var Wallet_TransactionInfo_StorageFeeInfo: String { return self._s[329]! } public func Channel_AdminLog_MessageKickedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[329]!, self._r[329]!, [_1]) + return formatWithArgumentRanges(self._s[330]!, self._r[330]!, [_1]) } public func PUSH_ENCRYPTED_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[331]!, self._r[331]!, [_1]) + return formatWithArgumentRanges(self._s[332]!, self._r[332]!, [_1]) } - public var VoiceOver_Media_PlaybackRate: String { return self._s[332]! } - public var Passport_FieldIdentityDetailsHelp: String { return self._s[333]! } - public var Conversation_ViewChannel: String { return self._s[334]! } + public var VoiceOver_Media_PlaybackRate: String { return self._s[333]! } + public var Passport_FieldIdentityDetailsHelp: String { return self._s[334]! } + public var Conversation_ViewChannel: String { return self._s[335]! } public func Time_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[335]!, self._r[335]!, [_0]) + return formatWithArgumentRanges(self._s[336]!, self._r[336]!, [_0]) } - public var Theme_Colors_Accent: String { return self._s[336]! } - public var Passport_Language_nl: String { return self._s[338]! } - public var Camera_Retake: String { return self._s[339]! } + public var Theme_Colors_Accent: String { return self._s[337]! } + public var Passport_Language_nl: String { return self._s[339]! } + public var Camera_Retake: String { return self._s[340]! } public func UserInfo_BlockActionTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[340]!, self._r[340]!, [_0]) + return formatWithArgumentRanges(self._s[341]!, self._r[341]!, [_0]) } - public var AuthSessions_LogOutApplications: String { return self._s[341]! } - public var ApplyLanguage_ApplySuccess: String { return self._s[342]! } - public var Tour_Title6: String { return self._s[343]! } - public var Map_ChooseAPlace: String { return self._s[344]! } - public var CallSettings_Never: String { return self._s[346]! } + public var AuthSessions_LogOutApplications: String { return self._s[342]! } + public var ApplyLanguage_ApplySuccess: String { return self._s[343]! } + public var Tour_Title6: String { return self._s[344]! } + public var Map_ChooseAPlace: String { return self._s[345]! } + public var CallSettings_Never: String { return self._s[347]! } public func Notification_ChangedGroupPhoto(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[347]!, self._r[347]!, [_0]) + return formatWithArgumentRanges(self._s[348]!, self._r[348]!, [_0]) } - public var ChannelRemoved_RemoveInfo: String { return self._s[348]! } + public var ChannelRemoved_RemoveInfo: String { return self._s[349]! } public func AutoDownloadSettings_PreloadVideoInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[349]!, self._r[349]!, [_0]) + return formatWithArgumentRanges(self._s[350]!, self._r[350]!, [_0]) } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsExceptions: String { return self._s[350]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsExceptions: String { return self._s[351]! } public func Conversation_ClearChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[351]!, self._r[351]!, [_0]) + return formatWithArgumentRanges(self._s[352]!, self._r[352]!, [_0]) } - public var GroupInfo_InviteLink_Title: String { return self._s[352]! } + public var GroupInfo_InviteLink_Title: String { return self._s[353]! } public func Channel_AdminLog_MessageUnkickedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[353]!, self._r[353]!, [_1, _2]) + return formatWithArgumentRanges(self._s[354]!, self._r[354]!, [_1, _2]) } - public var KeyCommand_ScrollUp: String { return self._s[354]! } - public var ContactInfo_URLLabelHomepage: String { return self._s[355]! } - public var Channel_OwnershipTransfer_ChangeOwner: String { return self._s[356]! } + public var KeyCommand_ScrollUp: String { return self._s[355]! } + public var ContactInfo_URLLabelHomepage: String { return self._s[356]! } + public var Channel_OwnershipTransfer_ChangeOwner: String { return self._s[357]! } public func Channel_AdminLog_DisabledSlowmode(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[357]!, self._r[357]!, [_0]) + return formatWithArgumentRanges(self._s[358]!, self._r[358]!, [_0]) } - public var TwoFactorSetup_Done_Title: String { return self._s[358]! } + public var TwoFactorSetup_Done_Title: String { return self._s[359]! } public func Conversation_EncryptedPlaceholderTitleOutgoing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[359]!, self._r[359]!, [_0]) + return formatWithArgumentRanges(self._s[360]!, self._r[360]!, [_0]) } - public var CallFeedback_ReasonDistortedSpeech: String { return self._s[360]! } - public var Watch_LastSeen_WithinAWeek: String { return self._s[361]! } - public var ContactList_Context_SendMessage: String { return self._s[363]! } - public var Weekday_Tuesday: String { return self._s[364]! } - public var Wallet_Created_Title: String { return self._s[366]! } - public var ScheduledMessages_Delete: String { return self._s[367]! } - public var UserInfo_StartSecretChat: String { return self._s[368]! } - public var Passport_Identity_FilesTitle: String { return self._s[369]! } - public var Permissions_NotificationsAllow_v0: String { return self._s[370]! } - public var DialogList_DeleteConversationConfirmation: String { return self._s[372]! } - public var ChatList_UndoArchiveRevealedTitle: String { return self._s[373]! } + public var CallFeedback_ReasonDistortedSpeech: String { return self._s[361]! } + public var Watch_LastSeen_WithinAWeek: String { return self._s[362]! } + public var ContactList_Context_SendMessage: String { return self._s[364]! } + public var Weekday_Tuesday: String { return self._s[365]! } + public var Wallet_Created_Title: String { return self._s[367]! } + public var ScheduledMessages_Delete: String { return self._s[368]! } + public var UserInfo_StartSecretChat: String { return self._s[369]! } + public var Passport_Identity_FilesTitle: String { return self._s[370]! } + public var Permissions_NotificationsAllow_v0: String { return self._s[371]! } + public var DialogList_DeleteConversationConfirmation: String { return self._s[373]! } + public var ChatList_UndoArchiveRevealedTitle: String { return self._s[374]! } public func Wallet_Configuration_ApplyErrorTextURLUnreachable(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[374]!, self._r[374]!, [_0]) + return formatWithArgumentRanges(self._s[375]!, self._r[375]!, [_0]) } - public var AuthSessions_Sessions: String { return self._s[375]! } + public var AuthSessions_Sessions: String { return self._s[376]! } public func Settings_KeepPhoneNumber(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[377]!, self._r[377]!, [_0]) + return formatWithArgumentRanges(self._s[378]!, self._r[378]!, [_0]) } - public var TwoStepAuth_RecoveryEmailChangeDescription: String { return self._s[378]! } - public var Call_StatusWaiting: String { return self._s[379]! } - public var CreateGroup_SoftUserLimitAlert: String { return self._s[380]! } - public var FastTwoStepSetup_HintHelp: String { return self._s[381]! } - public var WallpaperPreview_CustomColorBottomText: String { return self._s[382]! } - public var EditTheme_Expand_Preview_OutgoingText: String { return self._s[383]! } - public var LogoutOptions_AddAccountText: String { return self._s[384]! } - public var PasscodeSettings_6DigitCode: String { return self._s[385]! } - public var Settings_LogoutConfirmationText: String { return self._s[386]! } - public var Passport_Identity_TypePassport: String { return self._s[388]! } - public var Map_Work: String { return self._s[391]! } + public var TwoStepAuth_RecoveryEmailChangeDescription: String { return self._s[379]! } + public var Call_StatusWaiting: String { return self._s[380]! } + public var CreateGroup_SoftUserLimitAlert: String { return self._s[381]! } + public var FastTwoStepSetup_HintHelp: String { return self._s[382]! } + public var WallpaperPreview_CustomColorBottomText: String { return self._s[383]! } + public var EditTheme_Expand_Preview_OutgoingText: String { return self._s[384]! } + public var LogoutOptions_AddAccountText: String { return self._s[385]! } + public var PasscodeSettings_6DigitCode: String { return self._s[386]! } + public var Settings_LogoutConfirmationText: String { return self._s[387]! } + public var Passport_Identity_TypePassport: String { return self._s[389]! } + public var Map_Work: String { return self._s[392]! } public func PUSH_MESSAGE_VIDEOS(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[392]!, self._r[392]!, [_1, _2]) + return formatWithArgumentRanges(self._s[393]!, self._r[393]!, [_1, _2]) } - public var SocksProxySetup_SaveProxy: String { return self._s[393]! } - public var AccessDenied_SaveMedia: String { return self._s[394]! } - public var Checkout_ErrorInvoiceAlreadyPaid: String { return self._s[396]! } - public var CreatePoll_MultipleChoice: String { return self._s[397]! } - public var Settings_Title: String { return self._s[399]! } - public var VoiceOver_Chat_RecordModeVideoMessageInfo: String { return self._s[400]! } - public var Contacts_InviteSearchLabel: String { return self._s[402]! } - public var PrivacySettings_WebSessions: String { return self._s[403]! } - public var ConvertToSupergroup_Title: String { return self._s[404]! } + public var SocksProxySetup_SaveProxy: String { return self._s[394]! } + public var AccessDenied_SaveMedia: String { return self._s[395]! } + public var Checkout_ErrorInvoiceAlreadyPaid: String { return self._s[397]! } + public var CreatePoll_MultipleChoice: String { return self._s[398]! } + public var Settings_Title: String { return self._s[400]! } + public var VoiceOver_Chat_RecordModeVideoMessageInfo: String { return self._s[401]! } + public var Contacts_InviteSearchLabel: String { return self._s[403]! } + public var PrivacySettings_WebSessions: String { return self._s[404]! } + public var ConvertToSupergroup_Title: String { return self._s[405]! } public func Channel_AdminLog_CaptionEdited(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[405]!, self._r[405]!, [_0]) + return formatWithArgumentRanges(self._s[406]!, self._r[406]!, [_0]) } - public var TwoFactorSetup_Hint_Text: String { return self._s[406]! } - public var InfoPlist_NSSiriUsageDescription: String { return self._s[407]! } + public var TwoFactorSetup_Hint_Text: String { return self._s[407]! } + public var InfoPlist_NSSiriUsageDescription: String { return self._s[408]! } public func PUSH_MESSAGE_CHANNEL_MESSAGE_GAME_SCORE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[408]!, self._r[408]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[409]!, self._r[409]!, [_1, _2, _3]) } - public var ChatSettings_AutomaticPhotoDownload: String { return self._s[409]! } - public var UserInfo_BotHelp: String { return self._s[410]! } - public var PrivacySettings_LastSeenEverybody: String { return self._s[411]! } - public var Checkout_Name: String { return self._s[412]! } - public var AutoDownloadSettings_DataUsage: String { return self._s[413]! } - public var Channel_BanUser_BlockFor: String { return self._s[414]! } - public var Checkout_ShippingAddress: String { return self._s[415]! } - public var AutoDownloadSettings_MaxVideoSize: String { return self._s[416]! } - public var Privacy_PaymentsClearInfoDoneHelp: String { return self._s[417]! } - public var Privacy_Forwards: String { return self._s[418]! } - public var Channel_BanUser_PermissionSendPolls: String { return self._s[419]! } - public var Appearance_ThemeCarouselNewNight: String { return self._s[420]! } + public var ChatSettings_AutomaticPhotoDownload: String { return self._s[410]! } + public var UserInfo_BotHelp: String { return self._s[411]! } + public var PrivacySettings_LastSeenEverybody: String { return self._s[412]! } + public var Checkout_Name: String { return self._s[413]! } + public var AutoDownloadSettings_DataUsage: String { return self._s[414]! } + public var Channel_BanUser_BlockFor: String { return self._s[415]! } + public var Checkout_ShippingAddress: String { return self._s[416]! } + public var AutoDownloadSettings_MaxVideoSize: String { return self._s[417]! } + public var Privacy_PaymentsClearInfoDoneHelp: String { return self._s[418]! } + public var Privacy_Forwards: String { return self._s[419]! } + public var Channel_BanUser_PermissionSendPolls: String { return self._s[420]! } + public var Appearance_ThemeCarouselNewNight: String { return self._s[421]! } public func SecretVideo_NotViewedYet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[423]!, self._r[423]!, [_0]) + return formatWithArgumentRanges(self._s[424]!, self._r[424]!, [_0]) } - public var Contacts_SortedByName: String { return self._s[424]! } - public var Group_OwnershipTransfer_Title: String { return self._s[425]! } - public var VoiceOver_Chat_OpenHint: String { return self._s[427]! } - public var Group_LeaveGroup: String { return self._s[428]! } - public var Settings_UsernameEmpty: String { return self._s[429]! } + public var Contacts_SortedByName: String { return self._s[425]! } + public var Group_OwnershipTransfer_Title: String { return self._s[426]! } + public var VoiceOver_Chat_OpenHint: String { return self._s[428]! } + public var Group_LeaveGroup: String { return self._s[429]! } + public var Settings_UsernameEmpty: String { return self._s[430]! } public func Notification_PinnedPollMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[430]!, self._r[430]!, [_0]) + return formatWithArgumentRanges(self._s[431]!, self._r[431]!, [_0]) } public func TwoStepAuth_ConfirmEmailDescription(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[431]!, self._r[431]!, [_1]) + return formatWithArgumentRanges(self._s[432]!, self._r[432]!, [_1]) } public func Channel_OwnershipTransfer_DescriptionInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[432]!, self._r[432]!, [_1, _2]) + return formatWithArgumentRanges(self._s[433]!, self._r[433]!, [_1, _2]) } - public var Message_ImageExpired: String { return self._s[433]! } - public var TwoStepAuth_RecoveryFailed: String { return self._s[435]! } - public var EditTheme_Edit_Preview_OutgoingText: String { return self._s[436]! } - public var UserInfo_AddToExisting: String { return self._s[437]! } - public var TwoStepAuth_EnabledSuccess: String { return self._s[438]! } - public var Wallet_Send_SyncInProgress: String { return self._s[439]! } - public var SettingsSearch_Synonyms_Appearance_ChatBackground_SetColor: String { return self._s[440]! } + public var Message_ImageExpired: String { return self._s[434]! } + public var TwoStepAuth_RecoveryFailed: String { return self._s[436]! } + public var EditTheme_Edit_Preview_OutgoingText: String { return self._s[437]! } + public var UserInfo_AddToExisting: String { return self._s[438]! } + public var TwoStepAuth_EnabledSuccess: String { return self._s[439]! } + public var Wallet_Send_SyncInProgress: String { return self._s[440]! } + public var SettingsSearch_Synonyms_Appearance_ChatBackground_SetColor: String { return self._s[441]! } public func PUSH_CHANNEL_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[441]!, self._r[441]!, [_1]) + return formatWithArgumentRanges(self._s[442]!, self._r[442]!, [_1]) } - public var Notifications_GroupNotificationsAlert: String { return self._s[442]! } - public var Passport_Language_km: String { return self._s[443]! } - public var SocksProxySetup_AdNoticeHelp: String { return self._s[445]! } - public var VoiceOver_Media_PlaybackPlay: String { return self._s[446]! } - public var Notification_CallMissedShort: String { return self._s[447]! } - public var Wallet_Info_YourBalance: String { return self._s[448]! } - public var ReportPeer_ReasonOther_Send: String { return self._s[449]! } - public var Watch_Compose_Send: String { return self._s[450]! } - public var Passport_Identity_TypeInternalPassportUploadScan: String { return self._s[453]! } - public var TwoFactorSetup_Email_Action: String { return self._s[454]! } - public var Conversation_HoldForVideo: String { return self._s[455]! } - public var Wallet_Configuration_ApplyErrorTextURLInvalidData: String { return self._s[456]! } - public var AuthSessions_OtherDevices: String { return self._s[457]! } - public var Wallet_TransactionInfo_CommentHeader: String { return self._s[458]! } - public var CheckoutInfo_ErrorCityInvalid: String { return self._s[460]! } - public var Appearance_AutoNightThemeDisabled: String { return self._s[462]! } - public var Channel_LinkItem: String { return self._s[463]! } + public var Notifications_GroupNotificationsAlert: String { return self._s[443]! } + public var Passport_Language_km: String { return self._s[444]! } + public var SocksProxySetup_AdNoticeHelp: String { return self._s[446]! } + public var VoiceOver_Media_PlaybackPlay: String { return self._s[447]! } + public var Notification_CallMissedShort: String { return self._s[448]! } + public var Wallet_Info_YourBalance: String { return self._s[449]! } + public var ReportPeer_ReasonOther_Send: String { return self._s[451]! } + public var Watch_Compose_Send: String { return self._s[452]! } + public var Passport_Identity_TypeInternalPassportUploadScan: String { return self._s[455]! } + public var TwoFactorSetup_Email_Action: String { return self._s[456]! } + public var Conversation_HoldForVideo: String { return self._s[457]! } + public var Wallet_Configuration_ApplyErrorTextURLInvalidData: String { return self._s[458]! } + public var AuthSessions_OtherDevices: String { return self._s[459]! } + public var Wallet_TransactionInfo_CommentHeader: String { return self._s[460]! } + public var CheckoutInfo_ErrorCityInvalid: String { return self._s[462]! } + public var Appearance_AutoNightThemeDisabled: String { return self._s[464]! } + public var Channel_LinkItem: String { return self._s[465]! } public func PrivacySettings_LastSeenContactsMinusPlus(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[464]!, self._r[464]!, [_0, _1]) + return formatWithArgumentRanges(self._s[466]!, self._r[466]!, [_0, _1]) } public func Passport_Identity_NativeNameTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[467]!, self._r[467]!, [_0]) + return formatWithArgumentRanges(self._s[469]!, self._r[469]!, [_0]) } - public var VoiceOver_Recording_StopAndPreview: String { return self._s[468]! } - public var Passport_Language_dv: String { return self._s[469]! } - public var Undo_LeftChannel: String { return self._s[470]! } - public var Notifications_ExceptionsMuted: String { return self._s[471]! } - public var ChatList_UnhideAction: String { return self._s[472]! } - public var Conversation_ContextMenuShare: String { return self._s[473]! } - public var Conversation_ContextMenuStickerPackInfo: String { return self._s[474]! } - public var ShareFileTip_Title: String { return self._s[475]! } - public var NotificationsSound_Chord: String { return self._s[476]! } - public var Wallet_TransactionInfo_OtherFeeHeader: String { return self._s[477]! } + public var VoiceOver_Recording_StopAndPreview: String { return self._s[470]! } + public var Passport_Language_dv: String { return self._s[471]! } + public var Undo_LeftChannel: String { return self._s[472]! } + public var Notifications_ExceptionsMuted: String { return self._s[473]! } + public var ChatList_UnhideAction: String { return self._s[474]! } + public var Conversation_ContextMenuShare: String { return self._s[475]! } + public var Conversation_ContextMenuStickerPackInfo: String { return self._s[476]! } + public var ShareFileTip_Title: String { return self._s[477]! } + public var NotificationsSound_Chord: String { return self._s[478]! } + public var Wallet_TransactionInfo_OtherFeeHeader: String { return self._s[479]! } public func PUSH_CHAT_RETURNED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[478]!, self._r[478]!, [_1, _2]) + return formatWithArgumentRanges(self._s[480]!, self._r[480]!, [_1, _2]) } - public var Passport_Address_EditTemporaryRegistration: String { return self._s[479]! } + public var Passport_Address_EditTemporaryRegistration: String { return self._s[481]! } public func Notification_Joined(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[480]!, self._r[480]!, [_0]) + return formatWithArgumentRanges(self._s[482]!, self._r[482]!, [_0]) } public func Wallet_Time_PreciseDate_m3(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[481]!, self._r[481]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[483]!, self._r[483]!, [_1, _2, _3]) } - public var Wallet_Settings_ConfigurationInfo: String { return self._s[482]! } - public var Wallpaper_ErrorNotFound: String { return self._s[483]! } - public var Notification_CallOutgoingShort: String { return self._s[485]! } - public var Wallet_WordImport_IncorrectText: String { return self._s[486]! } + public var Wallet_Settings_ConfigurationInfo: String { return self._s[484]! } + public var Wallpaper_ErrorNotFound: String { return self._s[485]! } + public var Notification_CallOutgoingShort: String { return self._s[487]! } + public var Wallet_WordImport_IncorrectText: String { return self._s[488]! } public func Watch_Time_ShortFullAt(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[487]!, self._r[487]!, [_1, _2]) + return formatWithArgumentRanges(self._s[489]!, self._r[489]!, [_1, _2]) } - public var Passport_Address_TypeUtilityBill: String { return self._s[488]! } - public var Privacy_Forwards_LinkIfAllowed: String { return self._s[489]! } - public var ReportPeer_Report: String { return self._s[490]! } - public var SettingsSearch_Synonyms_Proxy_Title: String { return self._s[491]! } - public var GroupInfo_DeactivatedStatus: String { return self._s[492]! } + public var Passport_Address_TypeUtilityBill: String { return self._s[490]! } + public var Privacy_Forwards_LinkIfAllowed: String { return self._s[491]! } + public var ReportPeer_Report: String { return self._s[492]! } + public var SettingsSearch_Synonyms_Proxy_Title: String { return self._s[493]! } + public var GroupInfo_DeactivatedStatus: String { return self._s[494]! } public func VoiceOver_Chat_MusicTitle(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[493]!, self._r[493]!, [_1, _2]) + return formatWithArgumentRanges(self._s[495]!, self._r[495]!, [_1, _2]) } - public var StickerPack_Send: String { return self._s[494]! } - public var Login_CodeSentInternal: String { return self._s[495]! } - public var Wallet_Month_GenJanuary: String { return self._s[496]! } - public var GroupInfo_InviteLink_LinkSection: String { return self._s[497]! } + public var StickerPack_Send: String { return self._s[496]! } + public var Login_CodeSentInternal: String { return self._s[497]! } + public var Wallet_Month_GenJanuary: String { return self._s[498]! } + public var GroupInfo_InviteLink_LinkSection: String { return self._s[499]! } public func Channel_AdminLog_MessageDeleted(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[498]!, self._r[498]!, [_0]) - } - public func Conversation_EncryptionWaiting(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[500]!, self._r[500]!, [_0]) } - public var Channel_BanUser_PermissionSendStickersAndGifs: String { return self._s[501]! } - public func PUSH_PINNED_GAME(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[502]!, self._r[502]!, [_1]) + public func Conversation_EncryptionWaiting(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[502]!, self._r[502]!, [_0]) } - public var ReportPeer_ReasonViolence: String { return self._s[504]! } - public var Appearance_ShareThemeColor: String { return self._s[505]! } - public var Map_Locating: String { return self._s[506]! } + public var Channel_BanUser_PermissionSendStickersAndGifs: String { return self._s[503]! } + public func PUSH_PINNED_GAME(_ _1: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[504]!, self._r[504]!, [_1]) + } + public var ReportPeer_ReasonViolence: String { return self._s[506]! } + public var Appearance_ShareThemeColor: String { return self._s[507]! } + public var Map_Locating: String { return self._s[508]! } public func VoiceOver_Chat_VideoFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[507]!, self._r[507]!, [_0]) + return formatWithArgumentRanges(self._s[509]!, self._r[509]!, [_0]) } public func PUSH_ALBUM(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[508]!, self._r[508]!, [_1]) + return formatWithArgumentRanges(self._s[510]!, self._r[510]!, [_1]) } - public var AutoDownloadSettings_GroupChats: String { return self._s[510]! } - public var CheckoutInfo_SaveInfo: String { return self._s[511]! } - public var SharedMedia_EmptyLinksText: String { return self._s[513]! } - public var Passport_Address_CityPlaceholder: String { return self._s[514]! } - public var CheckoutInfo_ErrorStateInvalid: String { return self._s[515]! } - public var Privacy_ProfilePhoto_CustomHelp: String { return self._s[516]! } - public var Wallet_Send_OwnAddressAlertTitle: String { return self._s[518]! } - public var Channel_AdminLog_CanAddAdmins: String { return self._s[519]! } + public var AutoDownloadSettings_GroupChats: String { return self._s[512]! } + public var CheckoutInfo_SaveInfo: String { return self._s[513]! } + public var SharedMedia_EmptyLinksText: String { return self._s[515]! } + public var Passport_Address_CityPlaceholder: String { return self._s[516]! } + public var CheckoutInfo_ErrorStateInvalid: String { return self._s[517]! } + public var Privacy_ProfilePhoto_CustomHelp: String { return self._s[518]! } + public var Wallet_Send_OwnAddressAlertTitle: String { return self._s[520]! } + public var Channel_AdminLog_CanAddAdmins: String { return self._s[521]! } public func PUSH_CHANNEL_MESSAGE_FWD(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[520]!, self._r[520]!, [_1]) + return formatWithArgumentRanges(self._s[522]!, self._r[522]!, [_1]) } public func Time_MonthOfYear_m8(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[521]!, self._r[521]!, [_0]) + return formatWithArgumentRanges(self._s[523]!, self._r[523]!, [_0]) } - public var InfoPlist_NSLocationWhenInUseUsageDescription: String { return self._s[522]! } - public var GroupInfo_InviteLink_RevokeAlert_Success: String { return self._s[523]! } - public var ChangePhoneNumberCode_Code: String { return self._s[524]! } - public var Appearance_CreateTheme: String { return self._s[525]! } + public var InfoPlist_NSLocationWhenInUseUsageDescription: String { return self._s[524]! } + public var GroupInfo_InviteLink_RevokeAlert_Success: String { return self._s[525]! } + public var ChangePhoneNumberCode_Code: String { return self._s[526]! } + public var Appearance_CreateTheme: String { return self._s[527]! } public func UserInfo_NotificationsDefaultSound(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[526]!, self._r[526]!, [_0]) + return formatWithArgumentRanges(self._s[528]!, self._r[528]!, [_0]) } - public var TwoStepAuth_SetupEmail: String { return self._s[527]! } - public var HashtagSearch_AllChats: String { return self._s[528]! } - public var MediaPlayer_UnknownTrack: String { return self._s[529]! } - public var SettingsSearch_Synonyms_Data_AutoDownloadUsingCellular: String { return self._s[531]! } + public var TwoStepAuth_SetupEmail: String { return self._s[529]! } + public var HashtagSearch_AllChats: String { return self._s[530]! } + public var MediaPlayer_UnknownTrack: String { return self._s[531]! } + public var SettingsSearch_Synonyms_Data_AutoDownloadUsingCellular: String { return self._s[533]! } public func ChatList_DeleteForEveryone(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[532]!, self._r[532]!, [_0]) + return formatWithArgumentRanges(self._s[534]!, self._r[534]!, [_0]) } - public var PhotoEditor_QualityHigh: String { return self._s[534]! } + public var PhotoEditor_QualityHigh: String { return self._s[536]! } public func Passport_Phone_UseTelegramNumber(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[535]!, self._r[535]!, [_0]) + return formatWithArgumentRanges(self._s[537]!, self._r[537]!, [_0]) } - public var ApplyLanguage_ApplyLanguageAction: String { return self._s[536]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsPreview: String { return self._s[537]! } - public var Message_LiveLocation: String { return self._s[538]! } - public var Cache_LowDiskSpaceText: String { return self._s[539]! } - public var Wallet_Receive_ShareAddress: String { return self._s[540]! } - public var EditTheme_ErrorLinkTaken: String { return self._s[541]! } - public var Conversation_SendMessage: String { return self._s[542]! } - public var AuthSessions_EmptyTitle: String { return self._s[543]! } - public var Privacy_PhoneNumber: String { return self._s[544]! } - public var PeopleNearby_CreateGroup: String { return self._s[545]! } - public var CallSettings_UseLessData: String { return self._s[546]! } - public var NetworkUsageSettings_MediaDocumentDataSection: String { return self._s[547]! } - public var Stickers_AddToFavorites: String { return self._s[548]! } - public var Wallet_WordImport_Title: String { return self._s[549]! } - public var PhotoEditor_QualityLow: String { return self._s[550]! } - public var Watch_UserInfo_Unblock: String { return self._s[551]! } - public var Settings_Logout: String { return self._s[552]! } + public var ApplyLanguage_ApplyLanguageAction: String { return self._s[538]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsPreview: String { return self._s[539]! } + public var Message_LiveLocation: String { return self._s[540]! } + public var Cache_LowDiskSpaceText: String { return self._s[541]! } + public var Wallet_Receive_ShareAddress: String { return self._s[542]! } + public var EditTheme_ErrorLinkTaken: String { return self._s[543]! } + public var Conversation_SendMessage: String { return self._s[544]! } + public var AuthSessions_EmptyTitle: String { return self._s[545]! } + public var Privacy_PhoneNumber: String { return self._s[546]! } + public var PeopleNearby_CreateGroup: String { return self._s[547]! } + public var CallSettings_UseLessData: String { return self._s[549]! } + public var NetworkUsageSettings_MediaDocumentDataSection: String { return self._s[550]! } + public var Stickers_AddToFavorites: String { return self._s[551]! } + public var Wallet_WordImport_Title: String { return self._s[552]! } + public var PhotoEditor_QualityLow: String { return self._s[553]! } + public var Watch_UserInfo_Unblock: String { return self._s[554]! } + public var Settings_Logout: String { return self._s[555]! } public func PUSH_MESSAGE_ROUND(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[553]!, self._r[553]!, [_1]) + return formatWithArgumentRanges(self._s[556]!, self._r[556]!, [_1]) } - public var ContactInfo_PhoneLabelWork: String { return self._s[554]! } - public var ChannelInfo_Stats: String { return self._s[555]! } - public var TextFormat_Link: String { return self._s[556]! } + public var ContactInfo_PhoneLabelWork: String { return self._s[557]! } + public var ChannelInfo_Stats: String { return self._s[558]! } + public var TextFormat_Link: String { return self._s[559]! } public func Date_ChatDateHeader(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[557]!, self._r[557]!, [_1, _2]) + return formatWithArgumentRanges(self._s[560]!, self._r[560]!, [_1, _2]) } - public var Wallet_TransactionInfo_Title: String { return self._s[558]! } + public var Wallet_TransactionInfo_Title: String { return self._s[561]! } public func Message_ForwardedMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[559]!, self._r[559]!, [_0]) + return formatWithArgumentRanges(self._s[562]!, self._r[562]!, [_0]) } - public var Watch_Notification_Joined: String { return self._s[560]! } - public var Group_Setup_TypePublicHelp: String { return self._s[561]! } - public var Passport_Scans_UploadNew: String { return self._s[562]! } - public var Checkout_LiabilityAlertTitle: String { return self._s[563]! } - public var DialogList_Title: String { return self._s[566]! } - public var NotificationSettings_ContactJoined: String { return self._s[567]! } - public var GroupInfo_LabelAdmin: String { return self._s[568]! } - public var KeyCommand_ChatInfo: String { return self._s[569]! } - public var Conversation_EditingCaptionPanelTitle: String { return self._s[570]! } - public var Call_ReportIncludeLog: String { return self._s[571]! } + public var Watch_Notification_Joined: String { return self._s[563]! } + public var Group_Setup_TypePublicHelp: String { return self._s[564]! } + public var Passport_Scans_UploadNew: String { return self._s[565]! } + public var Checkout_LiabilityAlertTitle: String { return self._s[566]! } + public var DialogList_Title: String { return self._s[569]! } + public var NotificationSettings_ContactJoined: String { return self._s[570]! } + public var GroupInfo_LabelAdmin: String { return self._s[571]! } + public var KeyCommand_ChatInfo: String { return self._s[572]! } + public var Conversation_EditingCaptionPanelTitle: String { return self._s[573]! } + public var Call_ReportIncludeLog: String { return self._s[574]! } public func Notifications_ExceptionsChangeSound(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[574]!, self._r[574]!, [_0]) + return formatWithArgumentRanges(self._s[577]!, self._r[577]!, [_0]) } - public var Channel_AdminLog_InfoPanelChannelAlertText: String { return self._s[575]! } - public var ChatAdmins_AllMembersAreAdmins: String { return self._s[576]! } - public var LocalGroup_IrrelevantWarning: String { return self._s[577]! } - public var Conversation_DefaultRestrictedInline: String { return self._s[578]! } - public var Message_Sticker: String { return self._s[579]! } - public var LastSeen_JustNow: String { return self._s[581]! } - public var Passport_Email_EmailPlaceholder: String { return self._s[583]! } - public var SettingsSearch_Synonyms_AppLanguage: String { return self._s[584]! } - public var Channel_AdminLogFilter_EventsEditedMessages: String { return self._s[585]! } - public var Channel_EditAdmin_PermissionsHeader: String { return self._s[586]! } - public var TwoStepAuth_Email: String { return self._s[587]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsSound: String { return self._s[588]! } - public var PhotoEditor_BlurToolOff: String { return self._s[589]! } - public var Message_PinnedStickerMessage: String { return self._s[590]! } - public var ContactInfo_PhoneLabelPager: String { return self._s[591]! } - public var SettingsSearch_Synonyms_Appearance_TextSize: String { return self._s[592]! } - public var Passport_DiscardMessageTitle: String { return self._s[593]! } - public var Privacy_PaymentsTitle: String { return self._s[594]! } - public var EditTheme_Edit_Preview_IncomingReplyName: String { return self._s[595]! } - public var ClearCache_StorageCache: String { return self._s[596]! } - public var Appearance_TextSizeSetting: String { return self._s[597]! } - public var Channel_DiscussionGroup_Header: String { return self._s[599]! } - public var VoiceOver_Chat_OptionSelected: String { return self._s[600]! } - public var Appearance_ColorTheme: String { return self._s[601]! } - public var UserInfo_ShareContact: String { return self._s[602]! } - public var Passport_Address_TypePassportRegistration: String { return self._s[603]! } - public var Common_More: String { return self._s[604]! } - public var Watch_Message_Call: String { return self._s[605]! } - public var Profile_EncryptionKey: String { return self._s[608]! } - public var Privacy_TopPeers: String { return self._s[609]! } - public var Conversation_StopPollConfirmation: String { return self._s[610]! } - public var Wallet_Words_NotDoneText: String { return self._s[612]! } - public var Privacy_TopPeersWarning: String { return self._s[614]! } - public var SettingsSearch_Synonyms_Data_DownloadInBackground: String { return self._s[615]! } - public var SettingsSearch_Synonyms_Data_Storage_KeepMedia: String { return self._s[616]! } - public var Wallet_RestoreFailed_EnterWords: String { return self._s[619]! } - public var DialogList_SearchSectionMessages: String { return self._s[620]! } - public var Notifications_ChannelNotifications: String { return self._s[621]! } - public var CheckoutInfo_ShippingInfoAddress1Placeholder: String { return self._s[622]! } - public var Passport_Language_sk: String { return self._s[623]! } - public var Notification_MessageLifetime1h: String { return self._s[624]! } - public var Wallpaper_ResetWallpapersInfo: String { return self._s[625]! } - public var Appearance_ThemePreview_Chat_5_Text: String { return self._s[626]! } - public var Call_ReportSkip: String { return self._s[628]! } - public var Cache_ServiceFiles: String { return self._s[629]! } - public var Group_ErrorAddTooMuchAdmins: String { return self._s[630]! } - public var VoiceOver_Chat_YourFile: String { return self._s[631]! } - public var Map_Hybrid: String { return self._s[632]! } - public var Contacts_SearchUsersAndGroupsLabel: String { return self._s[634]! } - public var ChatSettings_AutoDownloadVideos: String { return self._s[636]! } - public var Channel_BanUser_PermissionEmbedLinks: String { return self._s[637]! } - public var InfoPlist_NSLocationAlwaysAndWhenInUseUsageDescription: String { return self._s[638]! } - public var SocksProxySetup_ProxyTelegram: String { return self._s[641]! } + public var Channel_AdminLog_InfoPanelChannelAlertText: String { return self._s[578]! } + public var ChatAdmins_AllMembersAreAdmins: String { return self._s[579]! } + public var LocalGroup_IrrelevantWarning: String { return self._s[580]! } + public var Conversation_DefaultRestrictedInline: String { return self._s[581]! } + public var Message_Sticker: String { return self._s[582]! } + public var LastSeen_JustNow: String { return self._s[584]! } + public var Passport_Email_EmailPlaceholder: String { return self._s[586]! } + public var SettingsSearch_Synonyms_AppLanguage: String { return self._s[587]! } + public var Channel_AdminLogFilter_EventsEditedMessages: String { return self._s[588]! } + public var Channel_EditAdmin_PermissionsHeader: String { return self._s[589]! } + public var TwoStepAuth_Email: String { return self._s[590]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsSound: String { return self._s[591]! } + public var PhotoEditor_BlurToolOff: String { return self._s[592]! } + public var Message_PinnedStickerMessage: String { return self._s[593]! } + public var ContactInfo_PhoneLabelPager: String { return self._s[594]! } + public var SettingsSearch_Synonyms_Appearance_TextSize: String { return self._s[595]! } + public var Passport_DiscardMessageTitle: String { return self._s[596]! } + public var Privacy_PaymentsTitle: String { return self._s[597]! } + public var EditTheme_Edit_Preview_IncomingReplyName: String { return self._s[598]! } + public var ClearCache_StorageCache: String { return self._s[599]! } + public var Appearance_TextSizeSetting: String { return self._s[600]! } + public var Channel_DiscussionGroup_Header: String { return self._s[602]! } + public var VoiceOver_Chat_OptionSelected: String { return self._s[603]! } + public var Appearance_ColorTheme: String { return self._s[604]! } + public var UserInfo_ShareContact: String { return self._s[605]! } + public var Passport_Address_TypePassportRegistration: String { return self._s[606]! } + public var Common_More: String { return self._s[607]! } + public var Watch_Message_Call: String { return self._s[608]! } + public var Profile_EncryptionKey: String { return self._s[611]! } + public var Privacy_TopPeers: String { return self._s[612]! } + public var Conversation_StopPollConfirmation: String { return self._s[613]! } + public var Wallet_Words_NotDoneText: String { return self._s[615]! } + public var Privacy_TopPeersWarning: String { return self._s[617]! } + public var SettingsSearch_Synonyms_Data_DownloadInBackground: String { return self._s[618]! } + public var SettingsSearch_Synonyms_Data_Storage_KeepMedia: String { return self._s[619]! } + public var Wallet_RestoreFailed_EnterWords: String { return self._s[622]! } + public var DialogList_SearchSectionMessages: String { return self._s[623]! } + public var Notifications_ChannelNotifications: String { return self._s[624]! } + public var CheckoutInfo_ShippingInfoAddress1Placeholder: String { return self._s[625]! } + public var Passport_Language_sk: String { return self._s[626]! } + public var Notification_MessageLifetime1h: String { return self._s[627]! } + public var Wallpaper_ResetWallpapersInfo: String { return self._s[628]! } + public var Appearance_ThemePreview_Chat_5_Text: String { return self._s[629]! } + public var Call_ReportSkip: String { return self._s[631]! } + public var Cache_ServiceFiles: String { return self._s[632]! } + public var Group_ErrorAddTooMuchAdmins: String { return self._s[633]! } + public var VoiceOver_Chat_YourFile: String { return self._s[634]! } + public var Map_Hybrid: String { return self._s[635]! } + public var Contacts_SearchUsersAndGroupsLabel: String { return self._s[637]! } + public var ChatSettings_AutoDownloadVideos: String { return self._s[639]! } + public var Channel_BanUser_PermissionEmbedLinks: String { return self._s[640]! } + public var InfoPlist_NSLocationAlwaysAndWhenInUseUsageDescription: String { return self._s[641]! } + public var SocksProxySetup_ProxyTelegram: String { return self._s[644]! } public func PUSH_MESSAGE_AUDIO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[642]!, self._r[642]!, [_1]) + return formatWithArgumentRanges(self._s[645]!, self._r[645]!, [_1]) } - public var Channel_Username_CreatePrivateLinkHelp: String { return self._s[644]! } - public var ScheduledMessages_ScheduledToday: String { return self._s[645]! } + public var Channel_Username_CreatePrivateLinkHelp: String { return self._s[647]! } + public var ScheduledMessages_ScheduledToday: String { return self._s[648]! } public func PUSH_CHAT_TITLE_EDITED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[646]!, self._r[646]!, [_1, _2]) + return formatWithArgumentRanges(self._s[649]!, self._r[649]!, [_1, _2]) } - public var Conversation_LiveLocationYou: String { return self._s[647]! } - public var SettingsSearch_Synonyms_Privacy_Calls: String { return self._s[648]! } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsPreview: String { return self._s[649]! } - public var UserInfo_ShareBot: String { return self._s[652]! } + public var Conversation_LiveLocationYou: String { return self._s[650]! } + public var SettingsSearch_Synonyms_Privacy_Calls: String { return self._s[651]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsPreview: String { return self._s[652]! } + public var UserInfo_ShareBot: String { return self._s[655]! } public func PUSH_AUTH_REGION(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[653]!, self._r[653]!, [_1, _2]) + return formatWithArgumentRanges(self._s[656]!, self._r[656]!, [_1, _2]) } - public var Conversation_ClearCache: String { return self._s[654]! } - public var PhotoEditor_ShadowsTint: String { return self._s[655]! } - public var Message_Audio: String { return self._s[656]! } - public var Passport_Language_lt: String { return self._s[657]! } + public var Conversation_ClearCache: String { return self._s[657]! } + public var PhotoEditor_ShadowsTint: String { return self._s[658]! } + public var Message_Audio: String { return self._s[659]! } + public var Passport_Language_lt: String { return self._s[660]! } public func Message_PinnedTextMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[658]!, self._r[658]!, [_0]) + return formatWithArgumentRanges(self._s[661]!, self._r[661]!, [_0]) } - public var Permissions_SiriText_v0: String { return self._s[659]! } - public var Conversation_FileICloudDrive: String { return self._s[660]! } - public var ChatList_DeleteForEveryoneConfirmationTitle: String { return self._s[661]! } - public var Notifications_Badge_IncludeMutedChats: String { return self._s[662]! } + public var Permissions_SiriText_v0: String { return self._s[662]! } + public var Conversation_FileICloudDrive: String { return self._s[663]! } + public var ChatList_DeleteForEveryoneConfirmationTitle: String { return self._s[664]! } + public var Notifications_Badge_IncludeMutedChats: String { return self._s[665]! } public func Notification_NewAuthDetected(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String, _ _6: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[663]!, self._r[663]!, [_1, _2, _3, _4, _5, _6]) + return formatWithArgumentRanges(self._s[666]!, self._r[666]!, [_1, _2, _3, _4, _5, _6]) } - public var DialogList_ProxyConnectionIssuesTooltip: String { return self._s[664]! } + public var DialogList_ProxyConnectionIssuesTooltip: String { return self._s[667]! } public func Time_MonthOfYear_m5(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[665]!, self._r[665]!, [_0]) + return formatWithArgumentRanges(self._s[668]!, self._r[668]!, [_0]) } - public var Channel_SignMessages: String { return self._s[666]! } + public var Channel_SignMessages: String { return self._s[669]! } public func PUSH_MESSAGE_NOTEXT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[667]!, self._r[667]!, [_1]) + return formatWithArgumentRanges(self._s[670]!, self._r[670]!, [_1]) } - public var Compose_ChannelTokenListPlaceholder: String { return self._s[668]! } - public var Passport_ScanPassport: String { return self._s[669]! } - public var Watch_Suggestion_Thanks: String { return self._s[670]! } - public var BlockedUsers_AddNew: String { return self._s[671]! } + public var Compose_ChannelTokenListPlaceholder: String { return self._s[671]! } + public var Passport_ScanPassport: String { return self._s[672]! } + public var Watch_Suggestion_Thanks: String { return self._s[673]! } + public var BlockedUsers_AddNew: String { return self._s[674]! } public func PUSH_CHAT_MESSAGE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[672]!, self._r[672]!, [_1, _2]) + return formatWithArgumentRanges(self._s[675]!, self._r[675]!, [_1, _2]) } - public var Watch_Message_Invoice: String { return self._s[673]! } - public var SettingsSearch_Synonyms_Privacy_LastSeen: String { return self._s[674]! } - public var Month_GenJuly: String { return self._s[675]! } - public var CreatePoll_QuizInfo: String { return self._s[676]! } - public var UserInfo_StartSecretChatStart: String { return self._s[677]! } - public var SocksProxySetup_ProxySocks5: String { return self._s[678]! } - public var IntentsSettings_SuggestByShare: String { return self._s[680]! } - public var Notification_Exceptions_DeleteAllConfirmation: String { return self._s[681]! } - public var Notification_ChannelInviterSelf: String { return self._s[682]! } - public var CheckoutInfo_ReceiverInfoEmail: String { return self._s[683]! } + public var Watch_Message_Invoice: String { return self._s[676]! } + public var SettingsSearch_Synonyms_Privacy_LastSeen: String { return self._s[677]! } + public var Month_GenJuly: String { return self._s[678]! } + public var CreatePoll_QuizInfo: String { return self._s[679]! } + public var UserInfo_StartSecretChatStart: String { return self._s[680]! } + public var SocksProxySetup_ProxySocks5: String { return self._s[681]! } + public var IntentsSettings_SuggestByShare: String { return self._s[683]! } + public var Notification_Exceptions_DeleteAllConfirmation: String { return self._s[684]! } + public var Notification_ChannelInviterSelf: String { return self._s[685]! } + public var CheckoutInfo_ReceiverInfoEmail: String { return self._s[686]! } public func ApplyLanguage_ChangeLanguageUnofficialText(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[684]!, self._r[684]!, [_1, _2]) + return formatWithArgumentRanges(self._s[687]!, self._r[687]!, [_1, _2]) } - public var CheckoutInfo_Title: String { return self._s[685]! } - public var Watch_Stickers_RecentPlaceholder: String { return self._s[686]! } + public var CheckoutInfo_Title: String { return self._s[688]! } + public var Watch_Stickers_RecentPlaceholder: String { return self._s[689]! } public func Map_DistanceAway(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[687]!, self._r[687]!, [_0]) + return formatWithArgumentRanges(self._s[690]!, self._r[690]!, [_0]) } - public var Passport_Identity_MainPage: String { return self._s[688]! } - public var TwoStepAuth_ConfirmEmailResendCode: String { return self._s[689]! } - public var Passport_Language_de: String { return self._s[690]! } - public var Update_Title: String { return self._s[691]! } - public var ContactInfo_PhoneLabelWorkFax: String { return self._s[692]! } - public var Channel_AdminLog_BanEmbedLinks: String { return self._s[693]! } - public var Passport_Email_UseTelegramEmailHelp: String { return self._s[694]! } - public var Notifications_ChannelNotificationsPreview: String { return self._s[695]! } - public var NotificationsSound_Telegraph: String { return self._s[696]! } - public var Watch_LastSeen_ALongTimeAgo: String { return self._s[697]! } - public var ChannelMembers_WhoCanAddMembers: String { return self._s[698]! } + public var Passport_Identity_MainPage: String { return self._s[691]! } + public var TwoStepAuth_ConfirmEmailResendCode: String { return self._s[692]! } + public var Passport_Language_de: String { return self._s[693]! } + public var Update_Title: String { return self._s[694]! } + public var ContactInfo_PhoneLabelWorkFax: String { return self._s[695]! } + public var Channel_AdminLog_BanEmbedLinks: String { return self._s[696]! } + public var Passport_Email_UseTelegramEmailHelp: String { return self._s[697]! } + public var Notifications_ChannelNotificationsPreview: String { return self._s[698]! } + public var NotificationsSound_Telegraph: String { return self._s[699]! } + public var Watch_LastSeen_ALongTimeAgo: String { return self._s[700]! } + public var ChannelMembers_WhoCanAddMembers: String { return self._s[701]! } public func AutoDownloadSettings_UpTo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[699]!, self._r[699]!, [_0]) + return formatWithArgumentRanges(self._s[702]!, self._r[702]!, [_0]) } - public var ClearCache_Description: String { return self._s[700]! } - public var Stickers_SuggestAll: String { return self._s[701]! } - public var Conversation_ForwardTitle: String { return self._s[702]! } - public var Appearance_ThemePreview_ChatList_7_Name: String { return self._s[703]! } + public var ClearCache_Description: String { return self._s[703]! } + public var Stickers_SuggestAll: String { return self._s[704]! } + public var Conversation_ForwardTitle: String { return self._s[705]! } + public var Appearance_ThemePreview_ChatList_7_Name: String { return self._s[706]! } public func Notification_JoinedChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[704]!, self._r[704]!, [_0]) + return formatWithArgumentRanges(self._s[707]!, self._r[707]!, [_0]) } - public var Calls_NewCall: String { return self._s[705]! } - public var Call_StatusEnded: String { return self._s[706]! } - public var AutoDownloadSettings_DataUsageLow: String { return self._s[707]! } - public var Settings_ProxyConnected: String { return self._s[708]! } - public var Channel_AdminLogFilter_EventsPinned: String { return self._s[709]! } - public var PhotoEditor_QualityVeryLow: String { return self._s[710]! } - public var Channel_AdminLogFilter_EventsDeletedMessages: String { return self._s[711]! } - public var Passport_PasswordPlaceholder: String { return self._s[712]! } - public var Message_PinnedInvoice: String { return self._s[713]! } - public var Passport_Identity_IssueDate: String { return self._s[714]! } - public var Passport_Language_pl: String { return self._s[715]! } + public var Calls_NewCall: String { return self._s[708]! } + public var Call_StatusEnded: String { return self._s[709]! } + public var AutoDownloadSettings_DataUsageLow: String { return self._s[710]! } + public var Settings_ProxyConnected: String { return self._s[711]! } + public var Channel_AdminLogFilter_EventsPinned: String { return self._s[712]! } + public var PhotoEditor_QualityVeryLow: String { return self._s[713]! } + public var Channel_AdminLogFilter_EventsDeletedMessages: String { return self._s[714]! } + public var Passport_PasswordPlaceholder: String { return self._s[715]! } + public var Message_PinnedInvoice: String { return self._s[716]! } + public var Passport_Identity_IssueDate: String { return self._s[717]! } + public var Passport_Language_pl: String { return self._s[718]! } public func ChannelInfo_ChannelForbidden(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[716]!, self._r[716]!, [_0]) - } - public var SocksProxySetup_PasteFromClipboard: String { return self._s[717]! } - public var Call_StatusConnecting: String { return self._s[718]! } - public func Username_UsernameIsAvailable(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[719]!, self._r[719]!, [_0]) } - public var ChatSettings_ConnectionType_UseProxy: String { return self._s[721]! } - public var Common_Edit: String { return self._s[722]! } - public var PrivacySettings_LastSeenNobody: String { return self._s[723]! } + public var SocksProxySetup_PasteFromClipboard: String { return self._s[720]! } + public var Call_StatusConnecting: String { return self._s[721]! } + public func Username_UsernameIsAvailable(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[722]!, self._r[722]!, [_0]) + } + public var ChatSettings_ConnectionType_UseProxy: String { return self._s[724]! } + public var Common_Edit: String { return self._s[725]! } + public var PrivacySettings_LastSeenNobody: String { return self._s[726]! } public func Notification_LeftChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[724]!, self._r[724]!, [_0]) + return formatWithArgumentRanges(self._s[727]!, self._r[727]!, [_0]) } - public var GroupInfo_ChatAdmins: String { return self._s[725]! } - public var PrivateDataSettings_Title: String { return self._s[726]! } - public var Login_CancelPhoneVerificationStop: String { return self._s[727]! } - public var ChatList_Read: String { return self._s[728]! } - public var Wallet_WordImport_Text: String { return self._s[729]! } - public var Undo_ChatClearedForBothSides: String { return self._s[730]! } - public var GroupPermission_SectionTitle: String { return self._s[731]! } - public var TwoFactorSetup_Intro_Title: String { return self._s[733]! } + public var GroupInfo_ChatAdmins: String { return self._s[728]! } + public var PrivateDataSettings_Title: String { return self._s[729]! } + public var Login_CancelPhoneVerificationStop: String { return self._s[730]! } + public var ChatList_Read: String { return self._s[731]! } + public var Wallet_WordImport_Text: String { return self._s[732]! } + public var Undo_ChatClearedForBothSides: String { return self._s[733]! } + public var GroupPermission_SectionTitle: String { return self._s[734]! } + public var TwoFactorSetup_Intro_Title: String { return self._s[736]! } public func PUSH_CHAT_LEFT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[734]!, self._r[734]!, [_1, _2]) + return formatWithArgumentRanges(self._s[737]!, self._r[737]!, [_1, _2]) } - public var Checkout_ErrorPaymentFailed: String { return self._s[735]! } - public var Update_UpdateApp: String { return self._s[736]! } - public var Group_Username_RevokeExistingUsernamesInfo: String { return self._s[737]! } - public var Settings_Appearance: String { return self._s[738]! } - public var SettingsSearch_Synonyms_Stickers_SuggestStickers: String { return self._s[742]! } - public var Watch_Location_Access: String { return self._s[743]! } - public var ShareMenu_CopyShareLink: String { return self._s[745]! } - public var TwoStepAuth_SetupHintTitle: String { return self._s[746]! } - public var Conversation_Theme: String { return self._s[748]! } + public var Checkout_ErrorPaymentFailed: String { return self._s[738]! } + public var Update_UpdateApp: String { return self._s[739]! } + public var Group_Username_RevokeExistingUsernamesInfo: String { return self._s[740]! } + public var Settings_Appearance: String { return self._s[741]! } + public var SettingsSearch_Synonyms_Stickers_SuggestStickers: String { return self._s[745]! } + public var Watch_Location_Access: String { return self._s[746]! } + public var ShareMenu_CopyShareLink: String { return self._s[748]! } + public var TwoStepAuth_SetupHintTitle: String { return self._s[749]! } + public var Conversation_Theme: String { return self._s[751]! } public func DialogList_SingleRecordingVideoMessageSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[749]!, self._r[749]!, [_0]) + return formatWithArgumentRanges(self._s[752]!, self._r[752]!, [_0]) } - public var Notifications_ClassicTones: String { return self._s[750]! } - public var Weekday_ShortWednesday: String { return self._s[751]! } - public var WallpaperPreview_SwipeColorsBottomText: String { return self._s[752]! } - public var Undo_LeftGroup: String { return self._s[755]! } - public var Wallet_RestoreFailed_Text: String { return self._s[756]! } - public var Conversation_LinkDialogCopy: String { return self._s[757]! } - public var Wallet_TransactionInfo_NoAddress: String { return self._s[759]! } - public var Wallet_Navigation_Back: String { return self._s[760]! } - public var KeyCommand_FocusOnInputField: String { return self._s[761]! } - public var Contacts_SelectAll: String { return self._s[762]! } - public var Preview_SaveToCameraRoll: String { return self._s[763]! } - public var PrivacySettings_PasscodeOff: String { return self._s[764]! } - public var Appearance_ThemePreview_ChatList_6_Name: String { return self._s[765]! } - public var Wallpaper_Title: String { return self._s[766]! } - public var Conversation_FilePhotoOrVideo: String { return self._s[767]! } - public var AccessDenied_Camera: String { return self._s[768]! } - public var Watch_Compose_CurrentLocation: String { return self._s[769]! } - public var Channel_DiscussionGroup_MakeHistoryPublicProceed: String { return self._s[771]! } + public var Notifications_ClassicTones: String { return self._s[753]! } + public var Weekday_ShortWednesday: String { return self._s[754]! } + public var WallpaperPreview_SwipeColorsBottomText: String { return self._s[755]! } + public var Undo_LeftGroup: String { return self._s[758]! } + public var Wallet_RestoreFailed_Text: String { return self._s[759]! } + public var Conversation_LinkDialogCopy: String { return self._s[760]! } + public var Wallet_TransactionInfo_NoAddress: String { return self._s[762]! } + public var Wallet_Navigation_Back: String { return self._s[763]! } + public var KeyCommand_FocusOnInputField: String { return self._s[764]! } + public var Contacts_SelectAll: String { return self._s[765]! } + public var Preview_SaveToCameraRoll: String { return self._s[766]! } + public var PrivacySettings_PasscodeOff: String { return self._s[767]! } + public var Appearance_ThemePreview_ChatList_6_Name: String { return self._s[768]! } + public var Wallpaper_Title: String { return self._s[769]! } + public var Conversation_FilePhotoOrVideo: String { return self._s[770]! } + public var AccessDenied_Camera: String { return self._s[771]! } + public var Watch_Compose_CurrentLocation: String { return self._s[772]! } + public var Channel_DiscussionGroup_MakeHistoryPublicProceed: String { return self._s[774]! } public func SecretImage_NotViewedYet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[772]!, self._r[772]!, [_0]) + return formatWithArgumentRanges(self._s[775]!, self._r[775]!, [_0]) } - public var GroupInfo_InvitationLinkDoesNotExist: String { return self._s[773]! } - public var Passport_Language_ro: String { return self._s[774]! } - public var EditTheme_UploadNewTheme: String { return self._s[775]! } - public var CheckoutInfo_SaveInfoHelp: String { return self._s[776]! } - public var Wallet_Intro_Terms: String { return self._s[777]! } + public var GroupInfo_InvitationLinkDoesNotExist: String { return self._s[776]! } + public var Passport_Language_ro: String { return self._s[777]! } + public var EditTheme_UploadNewTheme: String { return self._s[778]! } + public var CheckoutInfo_SaveInfoHelp: String { return self._s[779]! } + public var Wallet_Intro_Terms: String { return self._s[780]! } public func Notification_SecretChatMessageScreenshot(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[778]!, self._r[778]!, [_0]) + return formatWithArgumentRanges(self._s[781]!, self._r[781]!, [_0]) } - public var Login_CancelPhoneVerification: String { return self._s[779]! } - public var State_ConnectingToProxy: String { return self._s[780]! } - public var Calls_RatingTitle: String { return self._s[781]! } - public var Generic_ErrorMoreInfo: String { return self._s[782]! } - public var ChatList_Search_ShowMore: String { return self._s[783]! } - public var Appearance_PreviewReplyText: String { return self._s[784]! } - public var CheckoutInfo_ShippingInfoPostcodePlaceholder: String { return self._s[785]! } + public var Login_CancelPhoneVerification: String { return self._s[782]! } + public var State_ConnectingToProxy: String { return self._s[783]! } + public var Calls_RatingTitle: String { return self._s[784]! } + public var Generic_ErrorMoreInfo: String { return self._s[785]! } + public var ChatList_Search_ShowMore: String { return self._s[786]! } + public var Appearance_PreviewReplyText: String { return self._s[787]! } + public var CheckoutInfo_ShippingInfoPostcodePlaceholder: String { return self._s[788]! } public func Wallet_Send_Balance(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[786]!, self._r[786]!, [_0]) + return formatWithArgumentRanges(self._s[789]!, self._r[789]!, [_0]) } - public var IntentsSettings_SuggestedChatsContacts: String { return self._s[787]! } - public var SharedMedia_CategoryLinks: String { return self._s[788]! } - public var Calls_Missed: String { return self._s[789]! } - public var Cache_Photos: String { return self._s[793]! } - public var GroupPermission_NoAddMembers: String { return self._s[794]! } - public var ScheduledMessages_Title: String { return self._s[795]! } + public var IntentsSettings_SuggestedChatsContacts: String { return self._s[790]! } + public var SharedMedia_CategoryLinks: String { return self._s[791]! } + public var Calls_Missed: String { return self._s[792]! } + public var Cache_Photos: String { return self._s[796]! } + public var GroupPermission_NoAddMembers: String { return self._s[797]! } + public var ScheduledMessages_Title: String { return self._s[798]! } public func Channel_AdminLog_MessageUnpinned(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[796]!, self._r[796]!, [_0]) + return formatWithArgumentRanges(self._s[799]!, self._r[799]!, [_0]) } - public var Conversation_ShareBotLocationConfirmationTitle: String { return self._s[797]! } - public var Settings_ProxyDisabled: String { return self._s[798]! } + public var Conversation_ShareBotLocationConfirmationTitle: String { return self._s[800]! } + public var Settings_ProxyDisabled: String { return self._s[801]! } public func Settings_ApplyProxyAlertCredentials(_ _1: String, _ _2: String, _ _3: String, _ _4: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[799]!, self._r[799]!, [_1, _2, _3, _4]) + return formatWithArgumentRanges(self._s[802]!, self._r[802]!, [_1, _2, _3, _4]) } public func Conversation_RestrictedMediaTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[800]!, self._r[800]!, [_0]) + return formatWithArgumentRanges(self._s[803]!, self._r[803]!, [_0]) } - public var ChatList_Context_RemoveFromRecents: String { return self._s[802]! } - public var Appearance_Title: String { return self._s[803]! } + public var ChatList_Context_RemoveFromRecents: String { return self._s[805]! } + public var Appearance_Title: String { return self._s[806]! } public func Time_MonthOfYear_m2(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[805]!, self._r[805]!, [_0]) + return formatWithArgumentRanges(self._s[808]!, self._r[808]!, [_0]) } - public var Conversation_WalletRequiredText: String { return self._s[806]! } - public var StickerPacksSettings_ShowStickersButtonHelp: String { return self._s[807]! } - public var OldChannels_NoticeCreateText: String { return self._s[808]! } - public var Channel_EditMessageErrorGeneric: String { return self._s[809]! } - public var Privacy_Calls_IntegrationHelp: String { return self._s[810]! } - public var Preview_DeletePhoto: String { return self._s[811]! } - public var Appearance_AppIconFilledX: String { return self._s[812]! } - public var PrivacySettings_PrivacyTitle: String { return self._s[813]! } + public var Conversation_WalletRequiredText: String { return self._s[809]! } + public var StickerPacksSettings_ShowStickersButtonHelp: String { return self._s[810]! } + public var OldChannels_NoticeCreateText: String { return self._s[811]! } + public var Channel_EditMessageErrorGeneric: String { return self._s[812]! } + public var Privacy_Calls_IntegrationHelp: String { return self._s[813]! } + public var Preview_DeletePhoto: String { return self._s[814]! } + public var Appearance_AppIconFilledX: String { return self._s[815]! } + public var PrivacySettings_PrivacyTitle: String { return self._s[816]! } public func Conversation_BotInteractiveUrlAlert(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[814]!, self._r[814]!, [_0]) + return formatWithArgumentRanges(self._s[817]!, self._r[817]!, [_0]) } - public var Coub_TapForSound: String { return self._s[817]! } - public var Map_LocatingError: String { return self._s[818]! } - public var TwoStepAuth_EmailChangeSuccess: String { return self._s[820]! } - public var Conversation_SendMessage_SendSilently: String { return self._s[821]! } - public var VoiceOver_MessageContextOpenMessageMenu: String { return self._s[822]! } + public var Coub_TapForSound: String { return self._s[820]! } + public var Map_LocatingError: String { return self._s[821]! } + public var TwoStepAuth_EmailChangeSuccess: String { return self._s[823]! } + public var Conversation_SendMessage_SendSilently: String { return self._s[824]! } + public var VoiceOver_MessageContextOpenMessageMenu: String { return self._s[825]! } public func Wallet_Time_PreciseDate_m8(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[823]!, self._r[823]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[826]!, self._r[826]!, [_1, _2, _3]) } - public var Passport_ForgottenPassword: String { return self._s[824]! } - public var GroupInfo_InviteLink_RevokeLink: String { return self._s[825]! } - public var StickerPacksSettings_ArchivedPacks: String { return self._s[826]! } - public var Login_TermsOfServiceSignupDecline: String { return self._s[828]! } - public var Channel_Moderator_AccessLevelRevoke: String { return self._s[829]! } - public var Message_Location: String { return self._s[830]! } - public var Passport_Identity_NamePlaceholder: String { return self._s[831]! } - public var Channel_Management_Title: String { return self._s[832]! } - public var DialogList_SearchSectionDialogs: String { return self._s[834]! } - public var Compose_NewChannel_Members: String { return self._s[835]! } + public var Passport_ForgottenPassword: String { return self._s[827]! } + public var GroupInfo_InviteLink_RevokeLink: String { return self._s[828]! } + public var StickerPacksSettings_ArchivedPacks: String { return self._s[829]! } + public var Login_TermsOfServiceSignupDecline: String { return self._s[831]! } + public var Channel_Moderator_AccessLevelRevoke: String { return self._s[832]! } + public var Message_Location: String { return self._s[833]! } + public var Passport_Identity_NamePlaceholder: String { return self._s[834]! } + public var Channel_Management_Title: String { return self._s[835]! } + public var DialogList_SearchSectionDialogs: String { return self._s[837]! } + public var Compose_NewChannel_Members: String { return self._s[838]! } public func DialogList_SingleUploadingFileSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[836]!, self._r[836]!, [_0]) + return formatWithArgumentRanges(self._s[839]!, self._r[839]!, [_0]) } - public var GroupInfo_Location: String { return self._s[837]! } - public var Appearance_ThemePreview_ChatList_5_Name: String { return self._s[838]! } - public var ClearCache_Clear: String { return self._s[839]! } - public var AutoNightTheme_ScheduledFrom: String { return self._s[840]! } - public var PhotoEditor_WarmthTool: String { return self._s[841]! } - public var Passport_Language_tr: String { return self._s[842]! } + public var GroupInfo_Location: String { return self._s[840]! } + public var Appearance_ThemePreview_ChatList_5_Name: String { return self._s[841]! } + public var ClearCache_Clear: String { return self._s[842]! } + public var AutoNightTheme_ScheduledFrom: String { return self._s[843]! } + public var PhotoEditor_WarmthTool: String { return self._s[844]! } + public var Passport_Language_tr: String { return self._s[845]! } public func PUSH_MESSAGE_GAME_SCORE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[843]!, self._r[843]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[846]!, self._r[846]!, [_1, _2, _3]) } - public var OldChannels_NoticeUpgradeText: String { return self._s[844]! } - public var Login_ResetAccountProtected_Reset: String { return self._s[846]! } - public var Watch_PhotoView_Title: String { return self._s[847]! } - public var Passport_Phone_Delete: String { return self._s[848]! } - public var Undo_ChatDeletedForBothSides: String { return self._s[849]! } - public var Conversation_EditingMessageMediaEditCurrentPhoto: String { return self._s[850]! } - public var GroupInfo_Permissions: String { return self._s[851]! } - public var PasscodeSettings_TurnPasscodeOff: String { return self._s[852]! } - public var Profile_ShareContactButton: String { return self._s[853]! } - public var ChatSettings_Other: String { return self._s[854]! } - public var UserInfo_NotificationsDisabled: String { return self._s[855]! } - public var CheckoutInfo_ShippingInfoCity: String { return self._s[856]! } - public var LastSeen_WithinAMonth: String { return self._s[857]! } - public var VoiceOver_Chat_PlayHint: String { return self._s[858]! } - public var Conversation_ReportGroupLocation: String { return self._s[859]! } - public var Conversation_EncryptionCanceled: String { return self._s[860]! } - public var MediaPicker_GroupDescription: String { return self._s[861]! } - public var WebSearch_Images: String { return self._s[862]! } + public var OldChannels_NoticeUpgradeText: String { return self._s[847]! } + public var Login_ResetAccountProtected_Reset: String { return self._s[849]! } + public var Watch_PhotoView_Title: String { return self._s[850]! } + public var Passport_Phone_Delete: String { return self._s[851]! } + public var Undo_ChatDeletedForBothSides: String { return self._s[852]! } + public var Conversation_EditingMessageMediaEditCurrentPhoto: String { return self._s[853]! } + public var GroupInfo_Permissions: String { return self._s[854]! } + public var PasscodeSettings_TurnPasscodeOff: String { return self._s[855]! } + public var Profile_ShareContactButton: String { return self._s[856]! } + public var ChatSettings_Other: String { return self._s[857]! } + public var UserInfo_NotificationsDisabled: String { return self._s[858]! } + public var CheckoutInfo_ShippingInfoCity: String { return self._s[859]! } + public var LastSeen_WithinAMonth: String { return self._s[860]! } + public var VoiceOver_Chat_PlayHint: String { return self._s[861]! } + public var Conversation_ReportGroupLocation: String { return self._s[862]! } + public var Conversation_EncryptionCanceled: String { return self._s[863]! } + public var MediaPicker_GroupDescription: String { return self._s[864]! } + public var WebSearch_Images: String { return self._s[865]! } public func Channel_Management_PromotedBy(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[863]!, self._r[863]!, [_0]) + return formatWithArgumentRanges(self._s[866]!, self._r[866]!, [_0]) } - public var Message_Photo: String { return self._s[864]! } - public var PasscodeSettings_HelpBottom: String { return self._s[865]! } - public var AutoDownloadSettings_VideosTitle: String { return self._s[866]! } - public var VoiceOver_Media_PlaybackRateChange: String { return self._s[867]! } - public var Passport_Identity_AddDriversLicense: String { return self._s[868]! } - public var TwoStepAuth_EnterPasswordPassword: String { return self._s[869]! } - public var NotificationsSound_Calypso: String { return self._s[870]! } - public var Map_Map: String { return self._s[871]! } + public var Message_Photo: String { return self._s[867]! } + public var PasscodeSettings_HelpBottom: String { return self._s[868]! } + public var AutoDownloadSettings_VideosTitle: String { return self._s[869]! } + public var VoiceOver_Media_PlaybackRateChange: String { return self._s[870]! } + public var Passport_Identity_AddDriversLicense: String { return self._s[871]! } + public var TwoStepAuth_EnterPasswordPassword: String { return self._s[872]! } + public var NotificationsSound_Calypso: String { return self._s[873]! } + public var Map_Map: String { return self._s[874]! } public func Conversation_LiveLocationYouAndOther(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[872]!, self._r[872]!, [_0]) + return formatWithArgumentRanges(self._s[875]!, self._r[875]!, [_0]) } - public var CheckoutInfo_ReceiverInfoTitle: String { return self._s[874]! } - public var ChatSettings_TextSizeUnits: String { return self._s[875]! } + public var CheckoutInfo_ReceiverInfoTitle: String { return self._s[877]! } + public var ChatSettings_TextSizeUnits: String { return self._s[878]! } public func VoiceOver_Chat_FileFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[876]!, self._r[876]!, [_0]) + return formatWithArgumentRanges(self._s[879]!, self._r[879]!, [_0]) } - public var Common_of: String { return self._s[877]! } - public var Conversation_ForwardContacts: String { return self._s[880]! } - public var IntentsSettings_SuggestByAll: String { return self._s[882]! } + public var Common_of: String { return self._s[880]! } + public var Conversation_ForwardContacts: String { return self._s[883]! } + public var IntentsSettings_SuggestByAll: String { return self._s[885]! } public func Call_AnsweringWithAccount(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[883]!, self._r[883]!, [_0]) + return formatWithArgumentRanges(self._s[886]!, self._r[886]!, [_0]) } - public var Passport_Language_hy: String { return self._s[884]! } - public var Notifications_MessageNotificationsHelp: String { return self._s[885]! } - public var AutoDownloadSettings_Reset: String { return self._s[886]! } - public var Wallet_TransactionInfo_AddressCopied: String { return self._s[887]! } - public var Paint_ClearConfirm: String { return self._s[888]! } - public var Camera_VideoMode: String { return self._s[889]! } + public var Passport_Language_hy: String { return self._s[887]! } + public var Notifications_MessageNotificationsHelp: String { return self._s[888]! } + public var AutoDownloadSettings_Reset: String { return self._s[889]! } + public var Wallet_TransactionInfo_AddressCopied: String { return self._s[890]! } + public var Paint_ClearConfirm: String { return self._s[891]! } + public var Camera_VideoMode: String { return self._s[892]! } public func Conversation_RestrictedStickersTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[890]!, self._r[890]!, [_0]) + return formatWithArgumentRanges(self._s[893]!, self._r[893]!, [_0]) } - public var Privacy_Calls_AlwaysAllow_Placeholder: String { return self._s[891]! } - public var Conversation_ViewBackground: String { return self._s[892]! } + public var Privacy_Calls_AlwaysAllow_Placeholder: String { return self._s[894]! } + public var Conversation_ViewBackground: String { return self._s[895]! } public func Wallet_Info_TransactionDateHeaderYear(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[893]!, self._r[893]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[896]!, self._r[896]!, [_1, _2, _3]) } - public var Passport_Language_el: String { return self._s[894]! } - public var PhotoEditor_Original: String { return self._s[895]! } - public var Settings_FAQ_Button: String { return self._s[897]! } - public var Channel_Setup_PublicNoLink: String { return self._s[899]! } - public var Conversation_UnsupportedMedia: String { return self._s[900]! } - public var Conversation_SlideToCancel: String { return self._s[901]! } - public var Appearance_ThemePreview_ChatList_4_Name: String { return self._s[902]! } - public var Passport_Identity_OneOfTypeInternalPassport: String { return self._s[903]! } - public var CheckoutInfo_ShippingInfoPostcode: String { return self._s[904]! } - public var Conversation_ReportSpamChannelConfirmation: String { return self._s[905]! } - public var AutoNightTheme_NotAvailable: String { return self._s[906]! } - public var Conversation_Owner: String { return self._s[907]! } - public var Common_Create: String { return self._s[908]! } - public var Settings_ApplyProxyAlertEnable: String { return self._s[909]! } - public var ContactList_Context_Call: String { return self._s[910]! } - public var Localization_ChooseLanguage: String { return self._s[912]! } - public var ChatList_Context_AddToContacts: String { return self._s[914]! } - public var OldChannels_NoticeTitle: String { return self._s[915]! } - public var Settings_Proxy: String { return self._s[917]! } - public var Privacy_TopPeersHelp: String { return self._s[918]! } - public var CheckoutInfo_ShippingInfoCountryPlaceholder: String { return self._s[919]! } - public var Chat_UnsendMyMessages: String { return self._s[920]! } + public var Passport_Language_el: String { return self._s[897]! } + public var PhotoEditor_Original: String { return self._s[898]! } + public var Settings_FAQ_Button: String { return self._s[900]! } + public var Channel_Setup_PublicNoLink: String { return self._s[902]! } + public var Conversation_UnsupportedMedia: String { return self._s[903]! } + public var Conversation_SlideToCancel: String { return self._s[904]! } + public var Appearance_ThemePreview_ChatList_4_Name: String { return self._s[905]! } + public var Passport_Identity_OneOfTypeInternalPassport: String { return self._s[906]! } + public var CheckoutInfo_ShippingInfoPostcode: String { return self._s[907]! } + public var Conversation_ReportSpamChannelConfirmation: String { return self._s[908]! } + public var AutoNightTheme_NotAvailable: String { return self._s[909]! } + public var Conversation_Owner: String { return self._s[910]! } + public var Common_Create: String { return self._s[911]! } + public var Settings_ApplyProxyAlertEnable: String { return self._s[912]! } + public var ContactList_Context_Call: String { return self._s[913]! } + public var Localization_ChooseLanguage: String { return self._s[915]! } + public var ChatList_Context_AddToContacts: String { return self._s[917]! } + public var OldChannels_NoticeTitle: String { return self._s[918]! } + public var Settings_Proxy: String { return self._s[920]! } + public var Privacy_TopPeersHelp: String { return self._s[921]! } + public var CheckoutInfo_ShippingInfoCountryPlaceholder: String { return self._s[922]! } + public var Chat_UnsendMyMessages: String { return self._s[923]! } public func VoiceOver_Chat_Duration(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[921]!, self._r[921]!, [_0]) - } - public var TwoStepAuth_ConfirmationAbort: String { return self._s[922]! } - public func Contacts_AccessDeniedHelpPortrait(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[924]!, self._r[924]!, [_0]) } - public var Contacts_SortedByPresence: String { return self._s[925]! } - public var Passport_Identity_SurnamePlaceholder: String { return self._s[926]! } - public var Cache_Title: String { return self._s[927]! } + public var TwoStepAuth_ConfirmationAbort: String { return self._s[925]! } + public func Contacts_AccessDeniedHelpPortrait(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[927]!, self._r[927]!, [_0]) + } + public var Contacts_SortedByPresence: String { return self._s[928]! } + public var Passport_Identity_SurnamePlaceholder: String { return self._s[929]! } + public var Cache_Title: String { return self._s[930]! } public func Login_PhoneBannedEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[928]!, self._r[928]!, [_0]) + return formatWithArgumentRanges(self._s[931]!, self._r[931]!, [_0]) } - public var TwoStepAuth_EmailCodeExpired: String { return self._s[929]! } - public var Channel_Moderator_Title: String { return self._s[930]! } - public var InstantPage_AutoNightTheme: String { return self._s[932]! } + public var TwoStepAuth_EmailCodeExpired: String { return self._s[932]! } + public var Channel_Moderator_Title: String { return self._s[933]! } + public var InstantPage_AutoNightTheme: String { return self._s[935]! } public func PUSH_MESSAGE_POLL(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[935]!, self._r[935]!, [_1]) + return formatWithArgumentRanges(self._s[938]!, self._r[938]!, [_1]) } - public var Passport_Scans_Upload: String { return self._s[936]! } - public var Undo_Undo: String { return self._s[938]! } - public var Contacts_AccessDeniedHelpON: String { return self._s[939]! } - public var TwoStepAuth_RemovePassword: String { return self._s[940]! } - public var Common_Delete: String { return self._s[941]! } - public var Contacts_AddPeopleNearby: String { return self._s[943]! } - public var Conversation_ContextMenuDelete: String { return self._s[944]! } - public var SocksProxySetup_Credentials: String { return self._s[945]! } - public var Appearance_EditTheme: String { return self._s[947]! } - public var ClearCache_StorageOtherApps: String { return self._s[948]! } - public var PasscodeSettings_AutoLock_Disabled: String { return self._s[949]! } - public var Wallet_Send_NetworkErrorText: String { return self._s[950]! } - public var AuthSessions_DevicesTitle: String { return self._s[952]! } - public var Passport_Address_OneOfTypeRentalAgreement: String { return self._s[954]! } - public var Conversation_ShareBotContactConfirmationTitle: String { return self._s[955]! } - public var Passport_Language_id: String { return self._s[957]! } - public var WallpaperSearch_ColorTeal: String { return self._s[958]! } - public var ChannelIntro_Title: String { return self._s[959]! } + public var Passport_Scans_Upload: String { return self._s[939]! } + public var Undo_Undo: String { return self._s[941]! } + public var Contacts_AccessDeniedHelpON: String { return self._s[942]! } + public var TwoStepAuth_RemovePassword: String { return self._s[943]! } + public var Common_Delete: String { return self._s[944]! } + public var Contacts_AddPeopleNearby: String { return self._s[946]! } + public var Conversation_ContextMenuDelete: String { return self._s[947]! } + public var SocksProxySetup_Credentials: String { return self._s[948]! } + public var Appearance_EditTheme: String { return self._s[950]! } + public var ClearCache_StorageOtherApps: String { return self._s[951]! } + public var PasscodeSettings_AutoLock_Disabled: String { return self._s[952]! } + public var Wallet_Send_NetworkErrorText: String { return self._s[953]! } + public var AuthSessions_DevicesTitle: String { return self._s[955]! } + public var Passport_Address_OneOfTypeRentalAgreement: String { return self._s[957]! } + public var Conversation_ShareBotContactConfirmationTitle: String { return self._s[958]! } + public var Passport_Language_id: String { return self._s[960]! } + public var WallpaperSearch_ColorTeal: String { return self._s[961]! } + public var ChannelIntro_Title: String { return self._s[962]! } public func Channel_AdminLog_MessageToggleSignaturesOff(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[960]!, self._r[960]!, [_0]) + return formatWithArgumentRanges(self._s[963]!, self._r[963]!, [_0]) } - public var VoiceOver_Chat_OpenLinkHint: String { return self._s[962]! } - public var VoiceOver_Chat_Reply: String { return self._s[963]! } - public var ScheduledMessages_BotActionUnavailable: String { return self._s[964]! } - public var Channel_Info_Description: String { return self._s[965]! } - public var Stickers_FavoriteStickers: String { return self._s[966]! } - public var Channel_BanUser_PermissionAddMembers: String { return self._s[967]! } - public var Notifications_DisplayNamesOnLockScreen: String { return self._s[968]! } - public var ChatSearch_ResultsTooltip: String { return self._s[969]! } - public var Wallet_VoiceOver_Editing_ClearText: String { return self._s[970]! } - public var Calls_NoMissedCallsPlacehoder: String { return self._s[971]! } - public var Group_PublicLink_Placeholder: String { return self._s[972]! } - public var Notifications_ExceptionsDefaultSound: String { return self._s[973]! } + public var VoiceOver_Chat_OpenLinkHint: String { return self._s[965]! } + public var VoiceOver_Chat_Reply: String { return self._s[966]! } + public var ScheduledMessages_BotActionUnavailable: String { return self._s[967]! } + public var Channel_Info_Description: String { return self._s[968]! } + public var Stickers_FavoriteStickers: String { return self._s[969]! } + public var Channel_BanUser_PermissionAddMembers: String { return self._s[970]! } + public var Notifications_DisplayNamesOnLockScreen: String { return self._s[971]! } + public var ChatSearch_ResultsTooltip: String { return self._s[972]! } + public var Wallet_VoiceOver_Editing_ClearText: String { return self._s[973]! } + public var Calls_NoMissedCallsPlacehoder: String { return self._s[974]! } + public var Group_PublicLink_Placeholder: String { return self._s[975]! } + public var Notifications_ExceptionsDefaultSound: String { return self._s[976]! } public func PUSH_CHANNEL_MESSAGE_POLL(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[974]!, self._r[974]!, [_1]) + return formatWithArgumentRanges(self._s[977]!, self._r[977]!, [_1]) } - public var TextFormat_Underline: String { return self._s[975]! } + public var TextFormat_Underline: String { return self._s[978]! } public func DialogList_SearchSubtitleFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[977]!, self._r[977]!, [_1, _2]) - } - public func Channel_AdminLog_MessageRemovedGroupStickerPack(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[978]!, self._r[978]!, [_0]) - } - public var Appearance_ThemePreview_ChatList_3_Name: String { return self._s[979]! } - public func Channel_OwnershipTransfer_TransferCompleted(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[980]!, self._r[980]!, [_1, _2]) } - public var Wallet_Intro_ImportExisting: String { return self._s[981]! } - public var GroupPermission_Delete: String { return self._s[982]! } - public var Passport_Language_uk: String { return self._s[983]! } - public var StickerPack_HideStickers: String { return self._s[985]! } - public var ChangePhoneNumberNumber_NumberPlaceholder: String { return self._s[986]! } + public func Channel_AdminLog_MessageRemovedGroupStickerPack(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[981]!, self._r[981]!, [_0]) + } + public var Appearance_ThemePreview_ChatList_3_Name: String { return self._s[982]! } + public func Channel_OwnershipTransfer_TransferCompleted(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[983]!, self._r[983]!, [_1, _2]) + } + public var Wallet_Intro_ImportExisting: String { return self._s[984]! } + public var GroupPermission_Delete: String { return self._s[985]! } + public var Passport_Language_uk: String { return self._s[986]! } + public var StickerPack_HideStickers: String { return self._s[988]! } + public var ChangePhoneNumberNumber_NumberPlaceholder: String { return self._s[989]! } public func PUSH_CHAT_MESSAGE_PHOTO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[987]!, self._r[987]!, [_1, _2]) + return formatWithArgumentRanges(self._s[990]!, self._r[990]!, [_1, _2]) } - public var Activity_UploadingVideoMessage: String { return self._s[988]! } + public var Activity_UploadingVideoMessage: String { return self._s[991]! } public func GroupPermission_ApplyAlertText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[989]!, self._r[989]!, [_0]) + return formatWithArgumentRanges(self._s[992]!, self._r[992]!, [_0]) } - public var Channel_TitleInfo: String { return self._s[990]! } - public var StickerPacksSettings_ArchivedPacks_Info: String { return self._s[991]! } - public var Settings_CallSettings: String { return self._s[992]! } - public var Camera_SquareMode: String { return self._s[993]! } - public var Conversation_SendMessage_ScheduleMessage: String { return self._s[994]! } - public var GroupInfo_SharedMediaNone: String { return self._s[995]! } + public var Channel_TitleInfo: String { return self._s[993]! } + public var StickerPacksSettings_ArchivedPacks_Info: String { return self._s[994]! } + public var Settings_CallSettings: String { return self._s[995]! } + public var Camera_SquareMode: String { return self._s[996]! } + public var Conversation_SendMessage_ScheduleMessage: String { return self._s[997]! } + public var GroupInfo_SharedMediaNone: String { return self._s[998]! } public func PUSH_MESSAGE_VIDEO_SECRET(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[996]!, self._r[996]!, [_1]) + return formatWithArgumentRanges(self._s[999]!, self._r[999]!, [_1]) } - public var Bot_GenericBotStatus: String { return self._s[997]! } - public var Application_Update: String { return self._s[999]! } - public var Month_ShortJanuary: String { return self._s[1000]! } - public var Contacts_PermissionsKeepDisabled: String { return self._s[1001]! } - public var Channel_AdminLog_BanReadMessages: String { return self._s[1002]! } - public var Settings_AppLanguage_Unofficial: String { return self._s[1003]! } - public var Passport_Address_Street2Placeholder: String { return self._s[1004]! } + public var Bot_GenericBotStatus: String { return self._s[1000]! } + public var Application_Update: String { return self._s[1002]! } + public var Month_ShortJanuary: String { return self._s[1003]! } + public var Contacts_PermissionsKeepDisabled: String { return self._s[1004]! } + public var Channel_AdminLog_BanReadMessages: String { return self._s[1005]! } + public var Settings_AppLanguage_Unofficial: String { return self._s[1006]! } + public var Passport_Address_Street2Placeholder: String { return self._s[1007]! } public func Map_LiveLocationShortHour(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1005]!, self._r[1005]!, [_0]) - } - public var NetworkUsageSettings_Cellular: String { return self._s[1006]! } - public var Appearance_PreviewOutgoingText: String { return self._s[1007]! } - public func StickerPackActionInfo_RemovedText(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1008]!, self._r[1008]!, [_0]) } - public var Notifications_PermissionsAllowInSettings: String { return self._s[1009]! } - public var AutoDownloadSettings_OnForAll: String { return self._s[1011]! } - public var Map_Directions: String { return self._s[1012]! } - public var Passport_FieldIdentityTranslationHelp: String { return self._s[1014]! } - public var Appearance_ThemeDay: String { return self._s[1015]! } - public var LogoutOptions_LogOut: String { return self._s[1016]! } - public var Group_PublicLink_Title: String { return self._s[1018]! } - public var Channel_AddBotErrorNoRights: String { return self._s[1019]! } - public var ChatList_Search_ShowLess: String { return self._s[1020]! } - public var Passport_Identity_AddPassport: String { return self._s[1021]! } - public var LocalGroup_ButtonTitle: String { return self._s[1022]! } - public var Call_Message: String { return self._s[1023]! } - public var PhotoEditor_ExposureTool: String { return self._s[1024]! } - public var Wallet_Receive_CommentInfo: String { return self._s[1026]! } - public var Passport_FieldOneOf_Delimeter: String { return self._s[1027]! } - public var Channel_AdminLog_CanBanUsers: String { return self._s[1029]! } - public var Appearance_ThemePreview_ChatList_2_Name: String { return self._s[1030]! } - public var Appearance_Preview: String { return self._s[1031]! } - public var Compose_ChannelMembers: String { return self._s[1032]! } - public var Conversation_DeleteManyMessages: String { return self._s[1033]! } - public var ReportPeer_ReasonOther_Title: String { return self._s[1034]! } - public var Checkout_ErrorProviderAccountTimeout: String { return self._s[1035]! } - public var TwoStepAuth_ResetAccountConfirmation: String { return self._s[1036]! } - public var Channel_Stickers_CreateYourOwn: String { return self._s[1039]! } - public var Conversation_UpdateTelegram: String { return self._s[1040]! } - public var EditTheme_Create_TopInfo: String { return self._s[1041]! } + public var NetworkUsageSettings_Cellular: String { return self._s[1009]! } + public var Appearance_PreviewOutgoingText: String { return self._s[1010]! } + public func StickerPackActionInfo_RemovedText(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1011]!, self._r[1011]!, [_0]) + } + public var Notifications_PermissionsAllowInSettings: String { return self._s[1012]! } + public var AutoDownloadSettings_OnForAll: String { return self._s[1014]! } + public var Map_Directions: String { return self._s[1015]! } + public var Passport_FieldIdentityTranslationHelp: String { return self._s[1017]! } + public var Appearance_ThemeDay: String { return self._s[1018]! } + public var LogoutOptions_LogOut: String { return self._s[1019]! } + public var Group_PublicLink_Title: String { return self._s[1021]! } + public var Channel_AddBotErrorNoRights: String { return self._s[1022]! } + public var ChatList_Search_ShowLess: String { return self._s[1023]! } + public var Passport_Identity_AddPassport: String { return self._s[1024]! } + public var LocalGroup_ButtonTitle: String { return self._s[1025]! } + public var Call_Message: String { return self._s[1026]! } + public var PhotoEditor_ExposureTool: String { return self._s[1027]! } + public var Wallet_Receive_CommentInfo: String { return self._s[1029]! } + public var Passport_FieldOneOf_Delimeter: String { return self._s[1030]! } + public var Channel_AdminLog_CanBanUsers: String { return self._s[1032]! } + public var Appearance_ThemePreview_ChatList_2_Name: String { return self._s[1033]! } + public var Appearance_Preview: String { return self._s[1034]! } + public var Compose_ChannelMembers: String { return self._s[1035]! } + public var Conversation_DeleteManyMessages: String { return self._s[1036]! } + public var ReportPeer_ReasonOther_Title: String { return self._s[1037]! } + public var Checkout_ErrorProviderAccountTimeout: String { return self._s[1038]! } + public var TwoStepAuth_ResetAccountConfirmation: String { return self._s[1039]! } + public var Channel_Stickers_CreateYourOwn: String { return self._s[1042]! } + public var Conversation_UpdateTelegram: String { return self._s[1043]! } + public var EditTheme_Create_TopInfo: String { return self._s[1044]! } public func Notification_PinnedPhotoMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1042]!, self._r[1042]!, [_0]) + return formatWithArgumentRanges(self._s[1045]!, self._r[1045]!, [_0]) } - public var Wallet_WordCheck_Continue: String { return self._s[1043]! } - public var TwoFactorSetup_Hint_Action: String { return self._s[1044]! } - public var IntentsSettings_ResetAll: String { return self._s[1045]! } + public var Wallet_WordCheck_Continue: String { return self._s[1046]! } + public var TwoFactorSetup_Hint_Action: String { return self._s[1047]! } + public var IntentsSettings_ResetAll: String { return self._s[1048]! } public func PUSH_PINNED_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1046]!, self._r[1046]!, [_1]) + return formatWithArgumentRanges(self._s[1049]!, self._r[1049]!, [_1]) } - public var GroupInfo_Administrators_Title: String { return self._s[1047]! } - public var Privacy_Forwards_PreviewMessageText: String { return self._s[1048]! } + public var GroupInfo_Administrators_Title: String { return self._s[1050]! } + public var Privacy_Forwards_PreviewMessageText: String { return self._s[1051]! } public func PrivacySettings_LastSeenNobodyPlus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1049]!, self._r[1049]!, [_0]) + return formatWithArgumentRanges(self._s[1052]!, self._r[1052]!, [_0]) } - public var Tour_Title3: String { return self._s[1050]! } - public var Channel_EditAdmin_PermissionInviteSubscribers: String { return self._s[1051]! } - public var Clipboard_SendPhoto: String { return self._s[1055]! } - public var MediaPicker_Videos: String { return self._s[1056]! } - public var Passport_Email_Title: String { return self._s[1057]! } + public var Tour_Title3: String { return self._s[1053]! } + public var Channel_EditAdmin_PermissionInviteSubscribers: String { return self._s[1054]! } + public var Clipboard_SendPhoto: String { return self._s[1058]! } + public var MediaPicker_Videos: String { return self._s[1059]! } + public var Passport_Email_Title: String { return self._s[1060]! } public func PrivacySettings_LastSeenEverybodyMinus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1058]!, self._r[1058]!, [_0]) + return formatWithArgumentRanges(self._s[1061]!, self._r[1061]!, [_0]) } - public var StickerPacksSettings_Title: String { return self._s[1059]! } - public var Conversation_MessageDialogDelete: String { return self._s[1060]! } - public var Privacy_Calls_CustomHelp: String { return self._s[1062]! } - public var Message_Wallpaper: String { return self._s[1063]! } - public var MemberSearch_BotSection: String { return self._s[1064]! } - public var GroupInfo_SetSound: String { return self._s[1065]! } - public var Core_ServiceUserStatus: String { return self._s[1066]! } - public var LiveLocationUpdated_JustNow: String { return self._s[1067]! } - public var Call_StatusFailed: String { return self._s[1068]! } - public var TwoFactorSetup_Email_Placeholder: String { return self._s[1069]! } - public var TwoStepAuth_SetupPasswordDescription: String { return self._s[1070]! } - public var TwoStepAuth_SetPassword: String { return self._s[1071]! } - public var Permissions_PeopleNearbyText_v0: String { return self._s[1072]! } + public var StickerPacksSettings_Title: String { return self._s[1062]! } + public var Conversation_MessageDialogDelete: String { return self._s[1063]! } + public var Privacy_Calls_CustomHelp: String { return self._s[1065]! } + public var Message_Wallpaper: String { return self._s[1066]! } + public var MemberSearch_BotSection: String { return self._s[1067]! } + public var GroupInfo_SetSound: String { return self._s[1068]! } + public func Time_TomorrowAt(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1069]!, self._r[1069]!, [_0]) + } + public var Core_ServiceUserStatus: String { return self._s[1070]! } + public var LiveLocationUpdated_JustNow: String { return self._s[1071]! } + public var Call_StatusFailed: String { return self._s[1072]! } + public var TwoFactorSetup_Email_Placeholder: String { return self._s[1073]! } + public var TwoStepAuth_SetupPasswordDescription: String { return self._s[1074]! } + public var TwoStepAuth_SetPassword: String { return self._s[1075]! } + public var Permissions_PeopleNearbyText_v0: String { return self._s[1076]! } public func SocksProxySetup_ProxyStatusPing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1074]!, self._r[1074]!, [_0]) + return formatWithArgumentRanges(self._s[1078]!, self._r[1078]!, [_0]) } - public var Calls_SubmitRating: String { return self._s[1075]! } - public var Map_NoPlacesNearby: String { return self._s[1076]! } - public var Profile_Username: String { return self._s[1077]! } - public var Bot_DescriptionTitle: String { return self._s[1078]! } - public var MaskStickerSettings_Title: String { return self._s[1079]! } - public var SharedMedia_CategoryOther: String { return self._s[1080]! } - public var GroupInfo_SetGroupPhoto: String { return self._s[1081]! } - public var Common_NotNow: String { return self._s[1082]! } - public var CallFeedback_IncludeLogsInfo: String { return self._s[1083]! } - public var Conversation_ShareMyPhoneNumber: String { return self._s[1084]! } - public var Map_Location: String { return self._s[1085]! } - public var Invitation_JoinGroup: String { return self._s[1086]! } - public var AutoDownloadSettings_Title: String { return self._s[1088]! } - public var Conversation_DiscardVoiceMessageDescription: String { return self._s[1089]! } - public var Channel_ErrorAddBlocked: String { return self._s[1090]! } - public var Conversation_UnblockUser: String { return self._s[1091]! } - public var EditTheme_Edit_TopInfo: String { return self._s[1092]! } - public var Watch_Bot_Restart: String { return self._s[1093]! } - public var TwoStepAuth_Title: String { return self._s[1094]! } - public var Channel_AdminLog_BanSendMessages: String { return self._s[1095]! } - public var Checkout_ShippingMethod: String { return self._s[1096]! } - public var Passport_Identity_OneOfTypeIdentityCard: String { return self._s[1097]! } + public var Calls_SubmitRating: String { return self._s[1079]! } + public var Map_NoPlacesNearby: String { return self._s[1080]! } + public var Profile_Username: String { return self._s[1081]! } + public var Bot_DescriptionTitle: String { return self._s[1082]! } + public var MaskStickerSettings_Title: String { return self._s[1083]! } + public var SharedMedia_CategoryOther: String { return self._s[1084]! } + public var GroupInfo_SetGroupPhoto: String { return self._s[1085]! } + public var Common_NotNow: String { return self._s[1086]! } + public var CallFeedback_IncludeLogsInfo: String { return self._s[1087]! } + public var Conversation_ShareMyPhoneNumber: String { return self._s[1088]! } + public var Map_Location: String { return self._s[1089]! } + public var Invitation_JoinGroup: String { return self._s[1090]! } + public var AutoDownloadSettings_Title: String { return self._s[1092]! } + public var Conversation_DiscardVoiceMessageDescription: String { return self._s[1093]! } + public var Channel_ErrorAddBlocked: String { return self._s[1094]! } + public var Conversation_UnblockUser: String { return self._s[1095]! } + public var EditTheme_Edit_TopInfo: String { return self._s[1096]! } + public var Watch_Bot_Restart: String { return self._s[1097]! } + public var TwoStepAuth_Title: String { return self._s[1098]! } + public var Channel_AdminLog_BanSendMessages: String { return self._s[1099]! } + public var Checkout_ShippingMethod: String { return self._s[1100]! } + public var Passport_Identity_OneOfTypeIdentityCard: String { return self._s[1101]! } public func PUSH_CHAT_MESSAGE_STICKER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1098]!, self._r[1098]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1102]!, self._r[1102]!, [_1, _2, _3]) } - public var EditTheme_ChangeColors: String { return self._s[1100]! } + public var EditTheme_ChangeColors: String { return self._s[1104]! } public func Chat_UnsendMyMessagesAlertTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1101]!, self._r[1101]!, [_0]) + return formatWithArgumentRanges(self._s[1105]!, self._r[1105]!, [_0]) } public func Channel_Username_LinkHint(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1102]!, self._r[1102]!, [_0]) + return formatWithArgumentRanges(self._s[1106]!, self._r[1106]!, [_0]) } - public var Appearance_ThemePreview_ChatList_1_Name: String { return self._s[1103]! } - public var SettingsSearch_Synonyms_Data_AutoplayGifs: String { return self._s[1104]! } - public var AuthSessions_TerminateOtherSessions: String { return self._s[1105]! } - public var Contacts_FailedToSendInvitesMessage: String { return self._s[1106]! } - public var PrivacySettings_TwoStepAuth: String { return self._s[1107]! } - public var Notification_Exceptions_PreviewAlwaysOn: String { return self._s[1108]! } - public var SettingsSearch_Synonyms_Privacy_Passcode: String { return self._s[1109]! } - public var Conversation_EditingMessagePanelMedia: String { return self._s[1110]! } - public var Checkout_PaymentMethod_Title: String { return self._s[1111]! } - public var SocksProxySetup_Connection: String { return self._s[1112]! } - public var Group_MessagePhotoRemoved: String { return self._s[1113]! } - public var Channel_Stickers_NotFound: String { return self._s[1116]! } - public var Group_About_Help: String { return self._s[1117]! } - public var Notification_PassportValueProofOfIdentity: String { return self._s[1118]! } - public var PeopleNearby_Title: String { return self._s[1120]! } + public var Appearance_ThemePreview_ChatList_1_Name: String { return self._s[1107]! } + public var SettingsSearch_Synonyms_Data_AutoplayGifs: String { return self._s[1108]! } + public var AuthSessions_TerminateOtherSessions: String { return self._s[1109]! } + public var Contacts_FailedToSendInvitesMessage: String { return self._s[1110]! } + public var PrivacySettings_TwoStepAuth: String { return self._s[1111]! } + public var Notification_Exceptions_PreviewAlwaysOn: String { return self._s[1112]! } + public var SettingsSearch_Synonyms_Privacy_Passcode: String { return self._s[1113]! } + public var Conversation_EditingMessagePanelMedia: String { return self._s[1114]! } + public var Checkout_PaymentMethod_Title: String { return self._s[1115]! } + public var SocksProxySetup_Connection: String { return self._s[1116]! } + public var Group_MessagePhotoRemoved: String { return self._s[1117]! } + public var PeopleNearby_MakeInvisible: String { return self._s[1119]! } + public var Channel_Stickers_NotFound: String { return self._s[1121]! } + public var Group_About_Help: String { return self._s[1122]! } + public var Notification_PassportValueProofOfIdentity: String { return self._s[1123]! } + public var PeopleNearby_Title: String { return self._s[1125]! } public func ApplyLanguage_ChangeLanguageOfficialText(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1121]!, self._r[1121]!, [_1]) + return formatWithArgumentRanges(self._s[1126]!, self._r[1126]!, [_1]) } - public var Map_Home: String { return self._s[1122]! } - public var CheckoutInfo_ShippingInfoStatePlaceholder: String { return self._s[1124]! } - public var Notifications_GroupNotificationsExceptionsHelp: String { return self._s[1125]! } - public var SocksProxySetup_Password: String { return self._s[1126]! } - public var Notifications_PermissionsEnable: String { return self._s[1127]! } - public var TwoStepAuth_ChangeEmail: String { return self._s[1129]! } + public var Map_Home: String { return self._s[1127]! } + public var CheckoutInfo_ShippingInfoStatePlaceholder: String { return self._s[1129]! } + public var Notifications_GroupNotificationsExceptionsHelp: String { return self._s[1130]! } + public var SocksProxySetup_Password: String { return self._s[1131]! } + public var Notifications_PermissionsEnable: String { return self._s[1132]! } + public var TwoStepAuth_ChangeEmail: String { return self._s[1134]! } public func Channel_AdminLog_MessageInvitedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1130]!, self._r[1130]!, [_1]) + return formatWithArgumentRanges(self._s[1135]!, self._r[1135]!, [_1]) } public func Time_MonthOfYear_m10(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1132]!, self._r[1132]!, [_0]) + return formatWithArgumentRanges(self._s[1137]!, self._r[1137]!, [_0]) } - public var Passport_Identity_TypeDriversLicense: String { return self._s[1133]! } - public var ArchivedPacksAlert_Title: String { return self._s[1134]! } - public var Wallet_Receive_InvoiceUrlCopied: String { return self._s[1135]! } - public var Map_PlacesNearby: String { return self._s[1136]! } + public var Passport_Identity_TypeDriversLicense: String { return self._s[1138]! } + public var ArchivedPacksAlert_Title: String { return self._s[1139]! } + public var Wallet_Receive_InvoiceUrlCopied: String { return self._s[1140]! } + public var Map_PlacesNearby: String { return self._s[1141]! } public func Time_PreciseDate_m7(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1137]!, self._r[1137]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1142]!, self._r[1142]!, [_1, _2, _3]) } - public var PrivacyLastSeenSettings_GroupsAndChannelsHelp: String { return self._s[1138]! } - public var Privacy_Calls_NeverAllow_Placeholder: String { return self._s[1140]! } - public var Conversation_StatusTyping: String { return self._s[1141]! } - public var Broadcast_AdminLog_EmptyText: String { return self._s[1142]! } - public var Notification_PassportValueProofOfAddress: String { return self._s[1143]! } - public var UserInfo_CreateNewContact: String { return self._s[1144]! } - public var Passport_Identity_FrontSide: String { return self._s[1145]! } - public var Login_PhoneNumberAlreadyAuthorizedSwitch: String { return self._s[1146]! } - public var Calls_CallTabTitle: String { return self._s[1147]! } - public var Channel_AdminLog_ChannelEmptyText: String { return self._s[1148]! } + public var PrivacyLastSeenSettings_GroupsAndChannelsHelp: String { return self._s[1143]! } + public var Privacy_Calls_NeverAllow_Placeholder: String { return self._s[1145]! } + public var Conversation_StatusTyping: String { return self._s[1146]! } + public var Broadcast_AdminLog_EmptyText: String { return self._s[1147]! } + public var Notification_PassportValueProofOfAddress: String { return self._s[1148]! } + public var UserInfo_CreateNewContact: String { return self._s[1149]! } + public var Passport_Identity_FrontSide: String { return self._s[1150]! } + public var Login_PhoneNumberAlreadyAuthorizedSwitch: String { return self._s[1151]! } + public var Calls_CallTabTitle: String { return self._s[1152]! } + public var Channel_AdminLog_ChannelEmptyText: String { return self._s[1153]! } public func Login_BannedPhoneBody(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1150]!, self._r[1150]!, [_0]) + return formatWithArgumentRanges(self._s[1155]!, self._r[1155]!, [_0]) } - public var Watch_UserInfo_MuteTitle: String { return self._s[1151]! } - public var Group_EditAdmin_RankAdminPlaceholder: String { return self._s[1152]! } - public var SharedMedia_EmptyMusicText: String { return self._s[1153]! } - public var Wallet_Completed_Text: String { return self._s[1154]! } - public var PasscodeSettings_AutoLock_IfAwayFor_1minute: String { return self._s[1155]! } - public var Paint_Stickers: String { return self._s[1156]! } - public var Privacy_GroupsAndChannels: String { return self._s[1157]! } - public var ChatList_Context_Delete: String { return self._s[1159]! } - public var UserInfo_AddContact: String { return self._s[1160]! } + public var Watch_UserInfo_MuteTitle: String { return self._s[1156]! } + public var Group_EditAdmin_RankAdminPlaceholder: String { return self._s[1157]! } + public var SharedMedia_EmptyMusicText: String { return self._s[1158]! } + public var Wallet_Completed_Text: String { return self._s[1159]! } + public var PasscodeSettings_AutoLock_IfAwayFor_1minute: String { return self._s[1160]! } + public var Paint_Stickers: String { return self._s[1161]! } + public var Privacy_GroupsAndChannels: String { return self._s[1162]! } + public var ChatList_Context_Delete: String { return self._s[1164]! } + public var UserInfo_AddContact: String { return self._s[1165]! } public func Conversation_MessageViaUser(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1161]!, self._r[1161]!, [_0]) + return formatWithArgumentRanges(self._s[1166]!, self._r[1166]!, [_0]) } - public var PhoneNumberHelp_ChangeNumber: String { return self._s[1163]! } + public var PhoneNumberHelp_ChangeNumber: String { return self._s[1168]! } public func ChatList_ClearChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1165]!, self._r[1165]!, [_0]) + return formatWithArgumentRanges(self._s[1170]!, self._r[1170]!, [_0]) } - public var DialogList_NoMessagesTitle: String { return self._s[1166]! } - public var EditProfile_NameAndPhotoHelp: String { return self._s[1167]! } - public var BlockedUsers_BlockUser: String { return self._s[1168]! } - public var Notifications_PermissionsOpenSettings: String { return self._s[1169]! } - public var MediaPicker_UngroupDescription: String { return self._s[1171]! } - public var Watch_NoConnection: String { return self._s[1172]! } - public var Month_GenSeptember: String { return self._s[1173]! } - public var Conversation_ViewGroup: String { return self._s[1175]! } - public var Channel_AdminLogFilter_EventsLeavingSubscribers: String { return self._s[1178]! } - public var Privacy_Forwards_AlwaysLink: String { return self._s[1179]! } - public var Channel_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[1180]! } - public var Passport_FieldOneOf_FinalDelimeter: String { return self._s[1181]! } - public var Wallet_WordCheck_IncorrectHeader: String { return self._s[1182]! } - public var MediaPicker_CameraRoll: String { return self._s[1184]! } - public var Month_GenAugust: String { return self._s[1185]! } - public var Wallet_Configuration_SourceHeader: String { return self._s[1186]! } - public var AccessDenied_VideoMessageMicrophone: String { return self._s[1187]! } - public var SharedMedia_EmptyText: String { return self._s[1188]! } - public var Map_ShareLiveLocation: String { return self._s[1189]! } - public var Calls_All: String { return self._s[1190]! } - public var Map_SendThisPlace: String { return self._s[1192]! } - public var Appearance_ThemeNight: String { return self._s[1194]! } - public var Conversation_HoldForAudio: String { return self._s[1195]! } - public var SettingsSearch_Synonyms_Support: String { return self._s[1198]! } - public var GroupInfo_GroupHistoryHidden: String { return self._s[1199]! } - public var SocksProxySetup_Secret: String { return self._s[1200]! } + public var DialogList_NoMessagesTitle: String { return self._s[1171]! } + public var EditProfile_NameAndPhotoHelp: String { return self._s[1172]! } + public var BlockedUsers_BlockUser: String { return self._s[1173]! } + public var Notifications_PermissionsOpenSettings: String { return self._s[1174]! } + public var MediaPicker_UngroupDescription: String { return self._s[1176]! } + public var Watch_NoConnection: String { return self._s[1177]! } + public var Month_GenSeptember: String { return self._s[1178]! } + public var Conversation_ViewGroup: String { return self._s[1180]! } + public var Channel_AdminLogFilter_EventsLeavingSubscribers: String { return self._s[1183]! } + public var Privacy_Forwards_AlwaysLink: String { return self._s[1184]! } + public var Channel_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[1185]! } + public var Passport_FieldOneOf_FinalDelimeter: String { return self._s[1186]! } + public var Wallet_WordCheck_IncorrectHeader: String { return self._s[1187]! } + public var MediaPicker_CameraRoll: String { return self._s[1189]! } + public var Month_GenAugust: String { return self._s[1190]! } + public var Wallet_Configuration_SourceHeader: String { return self._s[1191]! } + public var AccessDenied_VideoMessageMicrophone: String { return self._s[1192]! } + public var SharedMedia_EmptyText: String { return self._s[1193]! } + public var Map_ShareLiveLocation: String { return self._s[1194]! } + public var Calls_All: String { return self._s[1195]! } + public var Map_SendThisPlace: String { return self._s[1197]! } + public var Appearance_ThemeNight: String { return self._s[1199]! } + public var Conversation_HoldForAudio: String { return self._s[1200]! } + public var SettingsSearch_Synonyms_Support: String { return self._s[1203]! } + public var GroupInfo_GroupHistoryHidden: String { return self._s[1204]! } + public var SocksProxySetup_Secret: String { return self._s[1205]! } public func Activity_RemindAboutChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1201]!, self._r[1201]!, [_0]) + return formatWithArgumentRanges(self._s[1206]!, self._r[1206]!, [_0]) } - public var Channel_BanList_RestrictedTitle: String { return self._s[1203]! } - public var Conversation_Location: String { return self._s[1204]! } + public var Channel_BanList_RestrictedTitle: String { return self._s[1208]! } + public var Conversation_Location: String { return self._s[1209]! } public func AutoDownloadSettings_UpToFor(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1205]!, self._r[1205]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1210]!, self._r[1210]!, [_1, _2]) } - public var ChatSettings_AutoDownloadPhotos: String { return self._s[1207]! } - public var SettingsSearch_Synonyms_Privacy_Title: String { return self._s[1208]! } - public var Notifications_PermissionsText: String { return self._s[1209]! } - public var SettingsSearch_Synonyms_Data_SaveIncomingPhotos: String { return self._s[1210]! } - public var Call_Flip: String { return self._s[1211]! } - public var Channel_AdminLog_CanDeleteMessagesOfOthers: String { return self._s[1213]! } - public var SocksProxySetup_ProxyStatusConnecting: String { return self._s[1214]! } - public var Wallet_TransactionInfo_StorageFeeInfoUrl: String { return self._s[1215]! } - public var PrivacyPhoneNumberSettings_DiscoveryHeader: String { return self._s[1216]! } - public var Channel_EditAdmin_PermissionPinMessages: String { return self._s[1218]! } - public var TwoStepAuth_ReEnterPasswordDescription: String { return self._s[1220]! } - public var Channel_TooMuchBots: String { return self._s[1222]! } - public var Passport_DeletePassportConfirmation: String { return self._s[1223]! } - public var Login_InvalidCodeError: String { return self._s[1224]! } - public var StickerPacksSettings_FeaturedPacks: String { return self._s[1225]! } + public var ChatSettings_AutoDownloadPhotos: String { return self._s[1212]! } + public var SettingsSearch_Synonyms_Privacy_Title: String { return self._s[1213]! } + public var Notifications_PermissionsText: String { return self._s[1214]! } + public var SettingsSearch_Synonyms_Data_SaveIncomingPhotos: String { return self._s[1215]! } + public var Call_Flip: String { return self._s[1216]! } + public var Channel_AdminLog_CanDeleteMessagesOfOthers: String { return self._s[1218]! } + public var SocksProxySetup_ProxyStatusConnecting: String { return self._s[1219]! } + public var Wallet_TransactionInfo_StorageFeeInfoUrl: String { return self._s[1220]! } + public var PrivacyPhoneNumberSettings_DiscoveryHeader: String { return self._s[1221]! } + public var Channel_EditAdmin_PermissionPinMessages: String { return self._s[1223]! } + public var TwoStepAuth_ReEnterPasswordDescription: String { return self._s[1225]! } + public var Channel_TooMuchBots: String { return self._s[1227]! } + public var Passport_DeletePassportConfirmation: String { return self._s[1228]! } + public var Login_InvalidCodeError: String { return self._s[1229]! } + public var StickerPacksSettings_FeaturedPacks: String { return self._s[1230]! } public func ChatList_DeleteSecretChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1226]!, self._r[1226]!, [_0]) + return formatWithArgumentRanges(self._s[1231]!, self._r[1231]!, [_0]) } public func GroupInfo_InvitationLinkAcceptChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1227]!, self._r[1227]!, [_0]) + return formatWithArgumentRanges(self._s[1232]!, self._r[1232]!, [_0]) } - public var VoiceOver_Navigation_ProxySettings: String { return self._s[1228]! } - public var Call_CallInProgressTitle: String { return self._s[1229]! } - public var Month_ShortSeptember: String { return self._s[1230]! } - public var Watch_ChannelInfo_Title: String { return self._s[1231]! } - public var ChatList_DeleteSavedMessagesConfirmation: String { return self._s[1234]! } - public var DialogList_PasscodeLockHelp: String { return self._s[1235]! } - public var Chat_MultipleTextMessagesDisabled: String { return self._s[1236]! } - public var Wallet_Receive_Title: String { return self._s[1237]! } - public var Notifications_Badge_IncludePublicGroups: String { return self._s[1238]! } - public var Channel_AdminLogFilter_EventsTitle: String { return self._s[1239]! } - public var PhotoEditor_CropReset: String { return self._s[1240]! } - public var Group_Username_CreatePrivateLinkHelp: String { return self._s[1242]! } - public var Channel_Management_LabelEditor: String { return self._s[1243]! } - public var Passport_Identity_LatinNameHelp: String { return self._s[1245]! } - public var PhotoEditor_HighlightsTool: String { return self._s[1246]! } - public var Wallet_Info_WalletCreated: String { return self._s[1247]! } - public var UserInfo_Title: String { return self._s[1248]! } - public var ChatList_HideAction: String { return self._s[1249]! } - public var AccessDenied_Title: String { return self._s[1250]! } - public var DialogList_SearchLabel: String { return self._s[1251]! } - public var Group_Setup_HistoryHidden: String { return self._s[1252]! } - public var TwoStepAuth_PasswordChangeSuccess: String { return self._s[1253]! } - public var State_Updating: String { return self._s[1255]! } - public var Contacts_TabTitle: String { return self._s[1256]! } - public var Notifications_Badge_CountUnreadMessages: String { return self._s[1258]! } - public var GroupInfo_GroupHistory: String { return self._s[1259]! } - public var Conversation_UnsupportedMediaPlaceholder: String { return self._s[1260]! } - public var Wallpaper_SetColor: String { return self._s[1261]! } - public var CheckoutInfo_ShippingInfoCountry: String { return self._s[1262]! } - public var SettingsSearch_Synonyms_SavedMessages: String { return self._s[1263]! } - public var Chat_AttachmentLimitReached: String { return self._s[1264]! } - public var Passport_Identity_OneOfTypeDriversLicense: String { return self._s[1265]! } - public var Contacts_NotRegisteredSection: String { return self._s[1266]! } + public var VoiceOver_Navigation_ProxySettings: String { return self._s[1233]! } + public var Call_CallInProgressTitle: String { return self._s[1234]! } + public var Month_ShortSeptember: String { return self._s[1235]! } + public var Watch_ChannelInfo_Title: String { return self._s[1236]! } + public var ChatList_DeleteSavedMessagesConfirmation: String { return self._s[1239]! } + public var DialogList_PasscodeLockHelp: String { return self._s[1240]! } + public var Chat_MultipleTextMessagesDisabled: String { return self._s[1241]! } + public var Wallet_Receive_Title: String { return self._s[1242]! } + public var Notifications_Badge_IncludePublicGroups: String { return self._s[1243]! } + public var Channel_AdminLogFilter_EventsTitle: String { return self._s[1244]! } + public var PhotoEditor_CropReset: String { return self._s[1245]! } + public var Group_Username_CreatePrivateLinkHelp: String { return self._s[1247]! } + public var Channel_Management_LabelEditor: String { return self._s[1248]! } + public var Passport_Identity_LatinNameHelp: String { return self._s[1250]! } + public var PhotoEditor_HighlightsTool: String { return self._s[1251]! } + public var Wallet_Info_WalletCreated: String { return self._s[1252]! } + public var UserInfo_Title: String { return self._s[1253]! } + public var ChatList_HideAction: String { return self._s[1254]! } + public var AccessDenied_Title: String { return self._s[1255]! } + public var DialogList_SearchLabel: String { return self._s[1256]! } + public var Group_Setup_HistoryHidden: String { return self._s[1257]! } + public var TwoStepAuth_PasswordChangeSuccess: String { return self._s[1258]! } + public var State_Updating: String { return self._s[1260]! } + public var Contacts_TabTitle: String { return self._s[1261]! } + public var Notifications_Badge_CountUnreadMessages: String { return self._s[1263]! } + public var GroupInfo_GroupHistory: String { return self._s[1264]! } + public var Conversation_UnsupportedMediaPlaceholder: String { return self._s[1265]! } + public var Wallpaper_SetColor: String { return self._s[1266]! } + public var CheckoutInfo_ShippingInfoCountry: String { return self._s[1267]! } + public var SettingsSearch_Synonyms_SavedMessages: String { return self._s[1268]! } + public var Chat_AttachmentLimitReached: String { return self._s[1269]! } + public var Passport_Identity_OneOfTypeDriversLicense: String { return self._s[1270]! } + public var Contacts_NotRegisteredSection: String { return self._s[1271]! } public func Time_PreciseDate_m4(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1267]!, self._r[1267]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1272]!, self._r[1272]!, [_1, _2, _3]) } - public var Paint_Clear: String { return self._s[1268]! } - public var StickerPacksSettings_ArchivedMasks: String { return self._s[1269]! } - public var SocksProxySetup_Connecting: String { return self._s[1270]! } - public var ExplicitContent_AlertChannel: String { return self._s[1271]! } - public var CreatePoll_AllOptionsAdded: String { return self._s[1272]! } - public var Conversation_Contact: String { return self._s[1273]! } - public var Login_CodeExpired: String { return self._s[1274]! } - public var Passport_DiscardMessageAction: String { return self._s[1275]! } - public var ChatList_Context_Unpin: String { return self._s[1276]! } - public var Channel_AdminLog_MessagePreviousDescription: String { return self._s[1277]! } + public var Paint_Clear: String { return self._s[1273]! } + public var StickerPacksSettings_ArchivedMasks: String { return self._s[1274]! } + public var SocksProxySetup_Connecting: String { return self._s[1275]! } + public var ExplicitContent_AlertChannel: String { return self._s[1276]! } + public var CreatePoll_AllOptionsAdded: String { return self._s[1277]! } + public var Conversation_Contact: String { return self._s[1278]! } + public var Login_CodeExpired: String { return self._s[1279]! } + public var Passport_DiscardMessageAction: String { return self._s[1280]! } + public var ChatList_Context_Unpin: String { return self._s[1281]! } + public var Channel_AdminLog_MessagePreviousDescription: String { return self._s[1282]! } public func VoiceOver_Chat_MusicFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1278]!, self._r[1278]!, [_0]) + return formatWithArgumentRanges(self._s[1283]!, self._r[1283]!, [_0]) } - public var Channel_AdminLog_EmptyMessageText: String { return self._s[1279]! } - public var SettingsSearch_Synonyms_Data_NetworkUsage: String { return self._s[1280]! } + public var Channel_AdminLog_EmptyMessageText: String { return self._s[1284]! } + public var SettingsSearch_Synonyms_Data_NetworkUsage: String { return self._s[1285]! } public func Group_EditAdmin_RankInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1281]!, self._r[1281]!, [_0]) + return formatWithArgumentRanges(self._s[1286]!, self._r[1286]!, [_0]) } - public var Month_ShortApril: String { return self._s[1282]! } - public var AuthSessions_CurrentSession: String { return self._s[1283]! } - public var Chat_AttachmentMultipleFilesDisabled: String { return self._s[1286]! } - public var Wallet_Navigation_Cancel: String { return self._s[1288]! } - public var WallpaperPreview_CropTopText: String { return self._s[1289]! } - public var PrivacySettings_DeleteAccountIfAwayFor: String { return self._s[1290]! } - public var CheckoutInfo_ShippingInfoTitle: String { return self._s[1291]! } + public var Month_ShortApril: String { return self._s[1287]! } + public var AuthSessions_CurrentSession: String { return self._s[1288]! } + public var Chat_AttachmentMultipleFilesDisabled: String { return self._s[1291]! } + public var Wallet_Navigation_Cancel: String { return self._s[1293]! } + public var WallpaperPreview_CropTopText: String { return self._s[1294]! } + public var PrivacySettings_DeleteAccountIfAwayFor: String { return self._s[1295]! } + public var CheckoutInfo_ShippingInfoTitle: String { return self._s[1296]! } public func Conversation_ScheduleMessage_SendOn(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1292]!, self._r[1292]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1297]!, self._r[1297]!, [_0, _1]) } - public var Appearance_ThemePreview_Chat_2_Text: String { return self._s[1293]! } - public var Channel_Setup_TypePrivate: String { return self._s[1295]! } - public var Forward_ChannelReadOnly: String { return self._s[1298]! } - public var PhotoEditor_CurvesBlue: String { return self._s[1299]! } - public var AddContact_SharedContactException: String { return self._s[1300]! } - public var UserInfo_BotPrivacy: String { return self._s[1302]! } - public var Wallet_CreateInvoice_Title: String { return self._s[1303]! } - public var Notification_PassportValueEmail: String { return self._s[1304]! } - public var EmptyGroupInfo_Subtitle: String { return self._s[1305]! } - public var GroupPermission_NewTitle: String { return self._s[1306]! } - public var CallFeedback_ReasonDropped: String { return self._s[1307]! } - public var GroupInfo_Permissions_AddException: String { return self._s[1308]! } - public var Channel_SignMessages_Help: String { return self._s[1310]! } - public var Undo_ChatDeleted: String { return self._s[1312]! } - public var Conversation_ChatBackground: String { return self._s[1313]! } + public var Appearance_ThemePreview_Chat_2_Text: String { return self._s[1298]! } + public var Channel_Setup_TypePrivate: String { return self._s[1300]! } + public var Forward_ChannelReadOnly: String { return self._s[1303]! } + public var PhotoEditor_CurvesBlue: String { return self._s[1304]! } + public var AddContact_SharedContactException: String { return self._s[1305]! } + public var UserInfo_BotPrivacy: String { return self._s[1307]! } + public var Wallet_CreateInvoice_Title: String { return self._s[1308]! } + public var Notification_PassportValueEmail: String { return self._s[1309]! } + public var EmptyGroupInfo_Subtitle: String { return self._s[1310]! } + public var GroupPermission_NewTitle: String { return self._s[1311]! } + public var CallFeedback_ReasonDropped: String { return self._s[1312]! } + public var GroupInfo_Permissions_AddException: String { return self._s[1313]! } + public var Channel_SignMessages_Help: String { return self._s[1315]! } + public var Undo_ChatDeleted: String { return self._s[1317]! } + public var Conversation_ChatBackground: String { return self._s[1318]! } public func Wallet_WordCheck_Text(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1314]!, self._r[1314]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1319]!, self._r[1319]!, [_1, _2, _3]) } - public var ChannelMembers_WhoCanAddMembers_Admins: String { return self._s[1315]! } - public var FastTwoStepSetup_EmailPlaceholder: String { return self._s[1316]! } - public var Passport_Language_pt: String { return self._s[1317]! } - public var VoiceOver_Chat_YourVoiceMessage: String { return self._s[1318]! } - public var NotificationsSound_Popcorn: String { return self._s[1321]! } - public var AutoNightTheme_Disabled: String { return self._s[1322]! } - public var BlockedUsers_LeavePrefix: String { return self._s[1323]! } - public var WallpaperPreview_CustomColorTopText: String { return self._s[1324]! } - public var Contacts_PermissionsSuppressWarningText: String { return self._s[1325]! } - public var WallpaperSearch_ColorBlue: String { return self._s[1326]! } + public var ChannelMembers_WhoCanAddMembers_Admins: String { return self._s[1320]! } + public var FastTwoStepSetup_EmailPlaceholder: String { return self._s[1321]! } + public var Passport_Language_pt: String { return self._s[1322]! } + public var VoiceOver_Chat_YourVoiceMessage: String { return self._s[1323]! } + public var NotificationsSound_Popcorn: String { return self._s[1326]! } + public var AutoNightTheme_Disabled: String { return self._s[1327]! } + public var BlockedUsers_LeavePrefix: String { return self._s[1328]! } + public var WallpaperPreview_CustomColorTopText: String { return self._s[1329]! } + public var Contacts_PermissionsSuppressWarningText: String { return self._s[1330]! } + public var WallpaperSearch_ColorBlue: String { return self._s[1331]! } public func CancelResetAccount_TextSMS(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1327]!, self._r[1327]!, [_0]) + return formatWithArgumentRanges(self._s[1332]!, self._r[1332]!, [_0]) } - public var CheckoutInfo_ErrorNameInvalid: String { return self._s[1328]! } - public var SocksProxySetup_UseForCalls: String { return self._s[1329]! } - public var Passport_DeleteDocumentConfirmation: String { return self._s[1331]! } + public var CheckoutInfo_ErrorNameInvalid: String { return self._s[1333]! } + public var SocksProxySetup_UseForCalls: String { return self._s[1334]! } + public var Passport_DeleteDocumentConfirmation: String { return self._s[1336]! } public func Conversation_Megabytes(_ _0: Float) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1332]!, self._r[1332]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[1337]!, self._r[1337]!, ["\(_0)"]) } - public var SocksProxySetup_Hostname: String { return self._s[1335]! } - public var ChatSettings_AutoDownloadSettings_OffForAll: String { return self._s[1336]! } - public var Compose_NewEncryptedChat: String { return self._s[1337]! } - public var Login_CodeFloodError: String { return self._s[1338]! } - public var Calls_TabTitle: String { return self._s[1339]! } - public var Privacy_ProfilePhoto: String { return self._s[1340]! } - public var Passport_Language_he: String { return self._s[1341]! } + public var SocksProxySetup_Hostname: String { return self._s[1340]! } + public var ChatSettings_AutoDownloadSettings_OffForAll: String { return self._s[1341]! } + public var Compose_NewEncryptedChat: String { return self._s[1342]! } + public var Login_CodeFloodError: String { return self._s[1343]! } + public var Calls_TabTitle: String { return self._s[1344]! } + public var Privacy_ProfilePhoto: String { return self._s[1345]! } + public var Passport_Language_he: String { return self._s[1346]! } public func Conversation_SetReminder_RemindToday(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1342]!, self._r[1342]!, [_0]) + return formatWithArgumentRanges(self._s[1347]!, self._r[1347]!, [_0]) } - public var GroupPermission_Title: String { return self._s[1343]! } + public var GroupPermission_Title: String { return self._s[1348]! } public func Channel_AdminLog_MessageGroupPreHistoryHidden(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1344]!, self._r[1344]!, [_0]) + return formatWithArgumentRanges(self._s[1349]!, self._r[1349]!, [_0]) } - public var Wallet_TransactionInfo_SenderHeader: String { return self._s[1345]! } - public var GroupPermission_NoChangeInfo: String { return self._s[1346]! } - public var ChatList_DeleteForCurrentUser: String { return self._s[1347]! } - public var Tour_Text1: String { return self._s[1348]! } - public var Channel_EditAdmin_TransferOwnership: String { return self._s[1349]! } - public var Month_ShortFebruary: String { return self._s[1350]! } - public var TwoStepAuth_EmailSkip: String { return self._s[1351]! } + public var Wallet_TransactionInfo_SenderHeader: String { return self._s[1350]! } + public var GroupPermission_NoChangeInfo: String { return self._s[1351]! } + public var ChatList_DeleteForCurrentUser: String { return self._s[1352]! } + public var Tour_Text1: String { return self._s[1353]! } + public var Channel_EditAdmin_TransferOwnership: String { return self._s[1354]! } + public var Month_ShortFebruary: String { return self._s[1355]! } + public var TwoStepAuth_EmailSkip: String { return self._s[1356]! } public func Wallet_Time_PreciseDate_m4(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1352]!, self._r[1352]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1357]!, self._r[1357]!, [_1, _2, _3]) } - public var NotificationsSound_Glass: String { return self._s[1353]! } - public var Appearance_ThemeNightBlue: String { return self._s[1354]! } - public var CheckoutInfo_Pay: String { return self._s[1355]! } - public var Invite_LargeRecipientsCountWarning: String { return self._s[1357]! } - public var Call_CallAgain: String { return self._s[1359]! } - public var AttachmentMenu_SendAsFile: String { return self._s[1360]! } - public var AccessDenied_MicrophoneRestricted: String { return self._s[1361]! } - public var Passport_InvalidPasswordError: String { return self._s[1362]! } - public var Watch_Message_Game: String { return self._s[1363]! } - public var Stickers_Install: String { return self._s[1364]! } - public var VoiceOver_Chat_Message: String { return self._s[1365]! } - public var PrivacyLastSeenSettings_NeverShareWith: String { return self._s[1366]! } - public var Passport_Identity_ResidenceCountry: String { return self._s[1368]! } - public var Notifications_GroupNotificationsHelp: String { return self._s[1369]! } - public var AuthSessions_OtherSessions: String { return self._s[1370]! } - public var Channel_Username_Help: String { return self._s[1371]! } - public var Camera_Title: String { return self._s[1372]! } - public var IntentsSettings_Title: String { return self._s[1373]! } - public var GroupInfo_SetGroupPhotoDelete: String { return self._s[1375]! } - public var Privacy_ProfilePhoto_NeverShareWith_Title: String { return self._s[1376]! } - public var Channel_AdminLog_SendPolls: String { return self._s[1377]! } - public var Channel_AdminLog_TitleAllEvents: String { return self._s[1378]! } - public var Channel_EditAdmin_PermissionInviteMembers: String { return self._s[1379]! } - public var Contacts_MemberSearchSectionTitleGroup: String { return self._s[1380]! } - public var ScheduledMessages_DeleteMany: String { return self._s[1381]! } - public var Conversation_RestrictedStickers: String { return self._s[1382]! } - public var Notifications_ExceptionsResetToDefaults: String { return self._s[1384]! } - public var UserInfo_TelegramCall: String { return self._s[1386]! } - public var TwoStepAuth_SetupResendEmailCode: String { return self._s[1387]! } - public var CreatePoll_OptionsHeader: String { return self._s[1388]! } - public var SettingsSearch_Synonyms_Data_CallsUseLessData: String { return self._s[1389]! } - public var ArchivedChats_IntroTitle1: String { return self._s[1390]! } - public var Privacy_GroupsAndChannels_AlwaysAllow_Title: String { return self._s[1391]! } - public var Theme_Colors_Proceed: String { return self._s[1392]! } - public var Passport_Identity_EditPersonalDetails: String { return self._s[1393]! } + public var NotificationsSound_Glass: String { return self._s[1358]! } + public var Appearance_ThemeNightBlue: String { return self._s[1359]! } + public var CheckoutInfo_Pay: String { return self._s[1360]! } + public var Invite_LargeRecipientsCountWarning: String { return self._s[1362]! } + public var Call_CallAgain: String { return self._s[1364]! } + public var AttachmentMenu_SendAsFile: String { return self._s[1365]! } + public var AccessDenied_MicrophoneRestricted: String { return self._s[1366]! } + public var Passport_InvalidPasswordError: String { return self._s[1367]! } + public var Watch_Message_Game: String { return self._s[1368]! } + public var Stickers_Install: String { return self._s[1369]! } + public var VoiceOver_Chat_Message: String { return self._s[1370]! } + public var PrivacyLastSeenSettings_NeverShareWith: String { return self._s[1371]! } + public var Passport_Identity_ResidenceCountry: String { return self._s[1373]! } + public var Notifications_GroupNotificationsHelp: String { return self._s[1374]! } + public var AuthSessions_OtherSessions: String { return self._s[1375]! } + public var Channel_Username_Help: String { return self._s[1376]! } + public var Camera_Title: String { return self._s[1377]! } + public var IntentsSettings_Title: String { return self._s[1378]! } + public var GroupInfo_SetGroupPhotoDelete: String { return self._s[1380]! } + public var Privacy_ProfilePhoto_NeverShareWith_Title: String { return self._s[1381]! } + public var Channel_AdminLog_SendPolls: String { return self._s[1382]! } + public var Channel_AdminLog_TitleAllEvents: String { return self._s[1383]! } + public var Channel_EditAdmin_PermissionInviteMembers: String { return self._s[1384]! } + public var Contacts_MemberSearchSectionTitleGroup: String { return self._s[1385]! } + public var ScheduledMessages_DeleteMany: String { return self._s[1386]! } + public var Conversation_RestrictedStickers: String { return self._s[1387]! } + public var Notifications_ExceptionsResetToDefaults: String { return self._s[1389]! } + public var UserInfo_TelegramCall: String { return self._s[1391]! } + public var TwoStepAuth_SetupResendEmailCode: String { return self._s[1392]! } + public var CreatePoll_OptionsHeader: String { return self._s[1393]! } + public var SettingsSearch_Synonyms_Data_CallsUseLessData: String { return self._s[1394]! } + public var ArchivedChats_IntroTitle1: String { return self._s[1395]! } + public var Privacy_GroupsAndChannels_AlwaysAllow_Title: String { return self._s[1396]! } + public var Theme_Colors_Proceed: String { return self._s[1397]! } + public var Passport_Identity_EditPersonalDetails: String { return self._s[1398]! } public func Time_PreciseDate_m1(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1394]!, self._r[1394]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1399]!, self._r[1399]!, [_1, _2, _3]) } - public var Wallet_Month_GenAugust: String { return self._s[1395]! } - public var Settings_SaveEditedPhotos: String { return self._s[1396]! } - public var TwoStepAuth_ConfirmationTitle: String { return self._s[1397]! } - public var Privacy_GroupsAndChannels_NeverAllow_Title: String { return self._s[1398]! } - public var Conversation_MessageDialogRetry: String { return self._s[1399]! } - public var ChatList_Context_MarkAsUnread: String { return self._s[1400]! } - public var MessagePoll_SubmitVote: String { return self._s[1401]! } - public var Conversation_DiscardVoiceMessageAction: String { return self._s[1402]! } - public var Permissions_PeopleNearbyTitle_v0: String { return self._s[1403]! } - public var Group_Setup_TypeHeader: String { return self._s[1404]! } - public var Paint_RecentStickers: String { return self._s[1405]! } - public var PhotoEditor_GrainTool: String { return self._s[1406]! } - public var CheckoutInfo_ShippingInfoState: String { return self._s[1407]! } - public var EmptyGroupInfo_Line4: String { return self._s[1408]! } - public var Watch_AuthRequired: String { return self._s[1410]! } + public var Wallet_Month_GenAugust: String { return self._s[1400]! } + public var Settings_SaveEditedPhotos: String { return self._s[1401]! } + public var TwoStepAuth_ConfirmationTitle: String { return self._s[1402]! } + public var Privacy_GroupsAndChannels_NeverAllow_Title: String { return self._s[1403]! } + public var Conversation_MessageDialogRetry: String { return self._s[1404]! } + public var ChatList_Context_MarkAsUnread: String { return self._s[1405]! } + public var MessagePoll_SubmitVote: String { return self._s[1406]! } + public var Conversation_DiscardVoiceMessageAction: String { return self._s[1407]! } + public var Permissions_PeopleNearbyTitle_v0: String { return self._s[1408]! } + public var Group_Setup_TypeHeader: String { return self._s[1409]! } + public var Paint_RecentStickers: String { return self._s[1410]! } + public var PhotoEditor_GrainTool: String { return self._s[1411]! } + public var CheckoutInfo_ShippingInfoState: String { return self._s[1412]! } + public var EmptyGroupInfo_Line4: String { return self._s[1413]! } + public var Watch_AuthRequired: String { return self._s[1415]! } public func Passport_Email_UseTelegramEmail(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1411]!, self._r[1411]!, [_0]) + return formatWithArgumentRanges(self._s[1416]!, self._r[1416]!, [_0]) } - public var Conversation_EncryptedDescriptionTitle: String { return self._s[1412]! } - public var ChannelIntro_Text: String { return self._s[1413]! } - public var DialogList_DeleteBotConfirmation: String { return self._s[1414]! } - public var GroupPermission_NoSendMedia: String { return self._s[1415]! } - public var Calls_AddTab: String { return self._s[1416]! } - public var Message_ReplyActionButtonShowReceipt: String { return self._s[1417]! } - public var Channel_AdminLog_EmptyFilterText: String { return self._s[1418]! } - public var Conversation_WalletRequiredSetup: String { return self._s[1419]! } - public var Notification_MessageLifetime1d: String { return self._s[1420]! } - public var Notifications_ChannelNotificationsExceptionsHelp: String { return self._s[1421]! } - public var Channel_BanUser_PermissionsHeader: String { return self._s[1422]! } - public var Passport_Identity_GenderFemale: String { return self._s[1423]! } - public var BlockedUsers_BlockTitle: String { return self._s[1424]! } + public var Conversation_EncryptedDescriptionTitle: String { return self._s[1417]! } + public var ChannelIntro_Text: String { return self._s[1418]! } + public var DialogList_DeleteBotConfirmation: String { return self._s[1419]! } + public var GroupPermission_NoSendMedia: String { return self._s[1420]! } + public var Calls_AddTab: String { return self._s[1421]! } + public var Message_ReplyActionButtonShowReceipt: String { return self._s[1422]! } + public var Channel_AdminLog_EmptyFilterText: String { return self._s[1423]! } + public var Conversation_WalletRequiredSetup: String { return self._s[1424]! } + public var Notification_MessageLifetime1d: String { return self._s[1425]! } + public var Notifications_ChannelNotificationsExceptionsHelp: String { return self._s[1426]! } + public var Channel_BanUser_PermissionsHeader: String { return self._s[1427]! } + public var Passport_Identity_GenderFemale: String { return self._s[1428]! } + public var BlockedUsers_BlockTitle: String { return self._s[1429]! } public func PUSH_CHANNEL_MESSAGE_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1425]!, self._r[1425]!, [_1]) + return formatWithArgumentRanges(self._s[1430]!, self._r[1430]!, [_1]) } - public var Weekday_Yesterday: String { return self._s[1426]! } - public var WallpaperSearch_ColorBlack: String { return self._s[1427]! } - public var Settings_Context_Logout: String { return self._s[1428]! } - public var Wallet_Info_UnknownTransaction: String { return self._s[1429]! } - public var ChatList_ArchiveAction: String { return self._s[1430]! } - public var AutoNightTheme_Scheduled: String { return self._s[1431]! } - public var TwoFactorSetup_Email_SkipAction: String { return self._s[1432]! } - public var Settings_Devices: String { return self._s[1433]! } - public var ContactInfo_Note: String { return self._s[1434]! } + public var Weekday_Yesterday: String { return self._s[1431]! } + public var WallpaperSearch_ColorBlack: String { return self._s[1432]! } + public var Settings_Context_Logout: String { return self._s[1433]! } + public var Wallet_Info_UnknownTransaction: String { return self._s[1434]! } + public var ChatList_ArchiveAction: String { return self._s[1435]! } + public var AutoNightTheme_Scheduled: String { return self._s[1436]! } + public var TwoFactorSetup_Email_SkipAction: String { return self._s[1437]! } + public var Settings_Devices: String { return self._s[1438]! } + public var ContactInfo_Note: String { return self._s[1439]! } public func Login_PhoneGenericEmailBody(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String, _ _6: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1435]!, self._r[1435]!, [_1, _2, _3, _4, _5, _6]) + return formatWithArgumentRanges(self._s[1440]!, self._r[1440]!, [_1, _2, _3, _4, _5, _6]) } - public var EditTheme_ThemeTemplateAlertTitle: String { return self._s[1436]! } - public var Wallet_Receive_CreateInvoice: String { return self._s[1437]! } - public var PrivacyPolicy_DeclineDeleteNow: String { return self._s[1438]! } - public var Theme_Colors_ColorWallpaperWarningProceed: String { return self._s[1439]! } + public var EditTheme_ThemeTemplateAlertTitle: String { return self._s[1441]! } + public var Wallet_Receive_CreateInvoice: String { return self._s[1442]! } + public var PrivacyPolicy_DeclineDeleteNow: String { return self._s[1443]! } + public var Theme_Colors_ColorWallpaperWarningProceed: String { return self._s[1444]! } public func PUSH_CHAT_JOINED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1440]!, self._r[1440]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1445]!, self._r[1445]!, [_1, _2]) } - public var CreatePoll_Create: String { return self._s[1441]! } - public var Channel_Members_AddBannedErrorAdmin: String { return self._s[1442]! } + public var CreatePoll_Create: String { return self._s[1446]! } + public var Channel_Members_AddBannedErrorAdmin: String { return self._s[1447]! } public func Notification_CallFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1443]!, self._r[1443]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1448]!, self._r[1448]!, [_1, _2]) } - public var ScheduledMessages_ClearAllConfirmation: String { return self._s[1444]! } - public var Checkout_ErrorProviderAccountInvalid: String { return self._s[1445]! } - public var Notifications_InAppNotificationsSounds: String { return self._s[1447]! } + public var ScheduledMessages_ClearAllConfirmation: String { return self._s[1449]! } + public var Checkout_ErrorProviderAccountInvalid: String { return self._s[1450]! } + public var Notifications_InAppNotificationsSounds: String { return self._s[1452]! } public func PUSH_PINNED_GAME_SCORE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1448]!, self._r[1448]!, [_1]) + return formatWithArgumentRanges(self._s[1453]!, self._r[1453]!, [_1]) } - public var Preview_OpenInInstagram: String { return self._s[1449]! } - public var Notification_MessageLifetimeRemovedOutgoing: String { return self._s[1450]! } + public var Preview_OpenInInstagram: String { return self._s[1454]! } + public var Notification_MessageLifetimeRemovedOutgoing: String { return self._s[1455]! } public func PUSH_CHAT_ADD_MEMBER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1451]!, self._r[1451]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1456]!, self._r[1456]!, [_1, _2, _3]) } public func Passport_PrivacyPolicy(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1452]!, self._r[1452]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1457]!, self._r[1457]!, [_1, _2]) } - public var Channel_AdminLog_InfoPanelAlertTitle: String { return self._s[1453]! } - public var ArchivedChats_IntroText3: String { return self._s[1454]! } - public var ChatList_UndoArchiveHiddenText: String { return self._s[1455]! } - public var NetworkUsageSettings_TotalSection: String { return self._s[1456]! } - public var Wallet_Month_GenSeptember: String { return self._s[1457]! } - public var Channel_Setup_TypePrivateHelp: String { return self._s[1458]! } + public var Channel_AdminLog_InfoPanelAlertTitle: String { return self._s[1458]! } + public var ArchivedChats_IntroText3: String { return self._s[1459]! } + public var ChatList_UndoArchiveHiddenText: String { return self._s[1460]! } + public var NetworkUsageSettings_TotalSection: String { return self._s[1461]! } + public var Wallet_Month_GenSeptember: String { return self._s[1462]! } + public var Channel_Setup_TypePrivateHelp: String { return self._s[1463]! } public func PUSH_CHAT_MESSAGE_POLL(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1459]!, self._r[1459]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1464]!, self._r[1464]!, [_1, _2, _3]) } - public var Privacy_GroupsAndChannels_NeverAllow_Placeholder: String { return self._s[1461]! } - public var FastTwoStepSetup_HintSection: String { return self._s[1462]! } - public var Wallpaper_PhotoLibrary: String { return self._s[1463]! } - public var TwoStepAuth_SetupResendEmailCodeAlert: String { return self._s[1464]! } - public var Gif_NoGifsFound: String { return self._s[1465]! } - public var Watch_LastSeen_WithinAMonth: String { return self._s[1466]! } - public var VoiceOver_MessageContextDelete: String { return self._s[1467]! } - public var EditTheme_Preview: String { return self._s[1468]! } + public var Privacy_GroupsAndChannels_NeverAllow_Placeholder: String { return self._s[1466]! } + public var FastTwoStepSetup_HintSection: String { return self._s[1467]! } + public var Wallpaper_PhotoLibrary: String { return self._s[1468]! } + public var TwoStepAuth_SetupResendEmailCodeAlert: String { return self._s[1469]! } + public var Gif_NoGifsFound: String { return self._s[1470]! } + public var Watch_LastSeen_WithinAMonth: String { return self._s[1471]! } + public var VoiceOver_MessageContextDelete: String { return self._s[1472]! } + public var EditTheme_Preview: String { return self._s[1473]! } public func ClearCache_StorageTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1469]!, self._r[1469]!, [_0]) + return formatWithArgumentRanges(self._s[1474]!, self._r[1474]!, [_0]) } - public var GroupInfo_ActionPromote: String { return self._s[1470]! } - public var PasscodeSettings_SimplePasscode: String { return self._s[1471]! } - public var GroupInfo_Permissions_Title: String { return self._s[1472]! } - public var Permissions_ContactsText_v0: String { return self._s[1473]! } - public var PrivacyPhoneNumberSettings_CustomDisabledHelp: String { return self._s[1474]! } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedPublicGroups: String { return self._s[1475]! } - public var PrivacySettings_DataSettingsHelp: String { return self._s[1478]! } - public var Passport_FieldEmailHelp: String { return self._s[1479]! } + public var GroupInfo_ActionPromote: String { return self._s[1475]! } + public var PasscodeSettings_SimplePasscode: String { return self._s[1476]! } + public var GroupInfo_Permissions_Title: String { return self._s[1477]! } + public var Permissions_ContactsText_v0: String { return self._s[1478]! } + public var PrivacyPhoneNumberSettings_CustomDisabledHelp: String { return self._s[1479]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedPublicGroups: String { return self._s[1480]! } + public var PrivacySettings_DataSettingsHelp: String { return self._s[1483]! } + public var Passport_FieldEmailHelp: String { return self._s[1484]! } public func Activity_RemindAboutUser(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1480]!, self._r[1480]!, [_0]) + return formatWithArgumentRanges(self._s[1485]!, self._r[1485]!, [_0]) } - public var Passport_Identity_GenderPlaceholder: String { return self._s[1481]! } - public var Weekday_ShortSaturday: String { return self._s[1482]! } - public var ContactInfo_PhoneLabelMain: String { return self._s[1483]! } - public var Watch_Conversation_UserInfo: String { return self._s[1484]! } - public var CheckoutInfo_ShippingInfoCityPlaceholder: String { return self._s[1485]! } - public var GroupPermission_PermissionDisabledByDefault: String { return self._s[1486]! } - public var PrivacyLastSeenSettings_Title: String { return self._s[1487]! } - public var Conversation_ShareBotLocationConfirmation: String { return self._s[1488]! } - public var PhotoEditor_VignetteTool: String { return self._s[1489]! } - public var Passport_Address_Street1Placeholder: String { return self._s[1490]! } - public var Passport_Language_et: String { return self._s[1491]! } - public var AppUpgrade_Running: String { return self._s[1492]! } - public var Channel_DiscussionGroup_Info: String { return self._s[1494]! } - public var EditTheme_Create_Preview_IncomingReplyName: String { return self._s[1495]! } - public var Passport_Language_bg: String { return self._s[1496]! } - public var Stickers_NoStickersFound: String { return self._s[1498]! } + public var Passport_Identity_GenderPlaceholder: String { return self._s[1486]! } + public var Weekday_ShortSaturday: String { return self._s[1487]! } + public var ContactInfo_PhoneLabelMain: String { return self._s[1488]! } + public var Watch_Conversation_UserInfo: String { return self._s[1489]! } + public var CheckoutInfo_ShippingInfoCityPlaceholder: String { return self._s[1490]! } + public var GroupPermission_PermissionDisabledByDefault: String { return self._s[1491]! } + public var PrivacyLastSeenSettings_Title: String { return self._s[1492]! } + public var Conversation_ShareBotLocationConfirmation: String { return self._s[1493]! } + public var PhotoEditor_VignetteTool: String { return self._s[1494]! } + public var Passport_Address_Street1Placeholder: String { return self._s[1495]! } + public var Passport_Language_et: String { return self._s[1496]! } + public var AppUpgrade_Running: String { return self._s[1497]! } + public var Channel_DiscussionGroup_Info: String { return self._s[1499]! } + public var EditTheme_Create_Preview_IncomingReplyName: String { return self._s[1500]! } + public var Passport_Language_bg: String { return self._s[1501]! } + public var Stickers_NoStickersFound: String { return self._s[1503]! } public func PUSH_CHANNEL_MESSAGE_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1500]!, self._r[1500]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1505]!, self._r[1505]!, [_1, _2]) } public func VoiceOver_Chat_ContactFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1501]!, self._r[1501]!, [_0]) + return formatWithArgumentRanges(self._s[1506]!, self._r[1506]!, [_0]) } - public var Wallet_Month_GenJuly: String { return self._s[1502]! } - public var Wallet_Receive_AddressHeader: String { return self._s[1503]! } - public var Wallet_Send_AmountText: String { return self._s[1504]! } - public var Settings_About: String { return self._s[1505]! } + public var Wallet_Month_GenJuly: String { return self._s[1507]! } + public var Wallet_Receive_AddressHeader: String { return self._s[1508]! } + public var Wallet_Send_AmountText: String { return self._s[1509]! } + public var Settings_About: String { return self._s[1510]! } public func Channel_AdminLog_MessageRestricted(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1506]!, self._r[1506]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[1511]!, self._r[1511]!, [_0, _1, _2]) } - public var ChatList_Context_MarkAsRead: String { return self._s[1508]! } - public var KeyCommand_NewMessage: String { return self._s[1509]! } - public var Group_ErrorAddBlocked: String { return self._s[1510]! } + public var ChatList_Context_MarkAsRead: String { return self._s[1513]! } + public var KeyCommand_NewMessage: String { return self._s[1514]! } + public var Group_ErrorAddBlocked: String { return self._s[1515]! } public func Message_PaymentSent(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1511]!, self._r[1511]!, [_0]) - } - public var Map_LocationTitle: String { return self._s[1512]! } - public var ReportGroupLocation_Title: String { return self._s[1513]! } - public var CallSettings_UseLessDataLongDescription: String { return self._s[1514]! } - public var Cache_ClearProgress: String { return self._s[1515]! } - public func Channel_Management_ErrorNotMember(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1516]!, self._r[1516]!, [_0]) } - public var GroupRemoved_AddToGroup: String { return self._s[1517]! } - public var Passport_UpdateRequiredError: String { return self._s[1518]! } - public var Wallet_SecureStorageNotAvailable_Text: String { return self._s[1519]! } + public var Map_LocationTitle: String { return self._s[1517]! } + public var ReportGroupLocation_Title: String { return self._s[1518]! } + public var CallSettings_UseLessDataLongDescription: String { return self._s[1519]! } + public var Cache_ClearProgress: String { return self._s[1520]! } + public func Channel_Management_ErrorNotMember(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1521]!, self._r[1521]!, [_0]) + } + public var GroupRemoved_AddToGroup: String { return self._s[1522]! } + public var Passport_UpdateRequiredError: String { return self._s[1523]! } + public var Wallet_SecureStorageNotAvailable_Text: String { return self._s[1524]! } public func PUSH_MESSAGE_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1520]!, self._r[1520]!, [_1]) + return formatWithArgumentRanges(self._s[1525]!, self._r[1525]!, [_1]) } - public var Notifications_PermissionsSuppressWarningText: String { return self._s[1522]! } - public var Passport_Identity_MainPageHelp: String { return self._s[1523]! } - public var Conversation_StatusKickedFromGroup: String { return self._s[1524]! } - public var Passport_Language_ka: String { return self._s[1525]! } + public var Notifications_PermissionsSuppressWarningText: String { return self._s[1527]! } + public var Passport_Identity_MainPageHelp: String { return self._s[1528]! } + public var Conversation_StatusKickedFromGroup: String { return self._s[1529]! } + public var Passport_Language_ka: String { return self._s[1530]! } public func Wallet_Time_PreciseDate_m12(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1526]!, self._r[1526]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1531]!, self._r[1531]!, [_1, _2, _3]) } - public var Call_Decline: String { return self._s[1527]! } - public var SocksProxySetup_ProxyEnabled: String { return self._s[1528]! } - public var TwoFactorSetup_Email_SkipConfirmationText: String { return self._s[1531]! } + public var Call_Decline: String { return self._s[1532]! } + public var SocksProxySetup_ProxyEnabled: String { return self._s[1533]! } + public var TwoFactorSetup_Email_SkipConfirmationText: String { return self._s[1536]! } public func AuthCode_Alert(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1532]!, self._r[1532]!, [_0]) + return formatWithArgumentRanges(self._s[1537]!, self._r[1537]!, [_0]) } - public var CallFeedback_Send: String { return self._s[1533]! } - public var EditTheme_EditTitle: String { return self._s[1534]! } + public var CallFeedback_Send: String { return self._s[1538]! } + public var EditTheme_EditTitle: String { return self._s[1539]! } public func Channel_AdminLog_MessagePromotedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1535]!, self._r[1535]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1540]!, self._r[1540]!, [_1, _2]) } - public var Passport_Phone_UseTelegramNumberHelp: String { return self._s[1536]! } + public var Passport_Phone_UseTelegramNumberHelp: String { return self._s[1541]! } public func Wallet_Updated_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1538]!, self._r[1538]!, [_0]) + return formatWithArgumentRanges(self._s[1543]!, self._r[1543]!, [_0]) } - public var SettingsSearch_Synonyms_Data_Title: String { return self._s[1539]! } - public var Passport_DeletePassport: String { return self._s[1540]! } - public var Appearance_AppIconFilled: String { return self._s[1541]! } - public var Privacy_Calls_P2PAlways: String { return self._s[1542]! } - public var Month_ShortDecember: String { return self._s[1543]! } - public var Channel_AdminLog_CanEditMessages: String { return self._s[1545]! } + public var SettingsSearch_Synonyms_Data_Title: String { return self._s[1544]! } + public var Passport_DeletePassport: String { return self._s[1545]! } + public var Appearance_AppIconFilled: String { return self._s[1546]! } + public var Privacy_Calls_P2PAlways: String { return self._s[1547]! } + public var Month_ShortDecember: String { return self._s[1548]! } + public var Channel_AdminLog_CanEditMessages: String { return self._s[1550]! } public func Contacts_AccessDeniedHelpLandscape(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1546]!, self._r[1546]!, [_0]) + return formatWithArgumentRanges(self._s[1551]!, self._r[1551]!, [_0]) } - public var Channel_Stickers_Searching: String { return self._s[1547]! } - public var Conversation_EncryptedDescription1: String { return self._s[1548]! } - public var Conversation_EncryptedDescription2: String { return self._s[1549]! } - public var PasscodeSettings_PasscodeOptions: String { return self._s[1550]! } - public var Conversation_EncryptedDescription3: String { return self._s[1552]! } - public var PhotoEditor_SharpenTool: String { return self._s[1553]! } - public var Wallet_Configuration_Title: String { return self._s[1554]! } + public var Channel_Stickers_Searching: String { return self._s[1552]! } + public var Conversation_EncryptedDescription1: String { return self._s[1553]! } + public var Conversation_EncryptedDescription2: String { return self._s[1554]! } + public var PasscodeSettings_PasscodeOptions: String { return self._s[1555]! } + public var Conversation_EncryptedDescription3: String { return self._s[1557]! } + public var PhotoEditor_SharpenTool: String { return self._s[1558]! } + public var Wallet_Configuration_Title: String { return self._s[1559]! } public func Conversation_AddNameToContacts(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1555]!, self._r[1555]!, [_0]) + return formatWithArgumentRanges(self._s[1560]!, self._r[1560]!, [_0]) } - public var Conversation_EncryptedDescription4: String { return self._s[1557]! } - public var Channel_Members_AddMembers: String { return self._s[1558]! } - public var Wallpaper_Search: String { return self._s[1559]! } - public var Weekday_Friday: String { return self._s[1561]! } - public var Privacy_ContactsSync: String { return self._s[1562]! } - public var SettingsSearch_Synonyms_Privacy_Data_ContactsReset: String { return self._s[1563]! } - public var ApplyLanguage_ChangeLanguageAction: String { return self._s[1564]! } + public var Conversation_EncryptedDescription4: String { return self._s[1562]! } + public var Channel_Members_AddMembers: String { return self._s[1563]! } + public var Wallpaper_Search: String { return self._s[1564]! } + public var Weekday_Friday: String { return self._s[1566]! } + public var Privacy_ContactsSync: String { return self._s[1567]! } + public var SettingsSearch_Synonyms_Privacy_Data_ContactsReset: String { return self._s[1568]! } + public var ApplyLanguage_ChangeLanguageAction: String { return self._s[1569]! } public func Channel_Management_RestrictedBy(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1565]!, self._r[1565]!, [_0]) - } - public var Wallet_Configuration_BlockchainIdHeader: String { return self._s[1566]! } - public var GroupInfo_Permissions_Removed: String { return self._s[1567]! } - public var ScheduledMessages_ScheduledOnline: String { return self._s[1568]! } - public var Passport_Identity_GenderMale: String { return self._s[1569]! } - public func Call_StatusBar(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1570]!, self._r[1570]!, [_0]) } - public var Notifications_PermissionsKeepDisabled: String { return self._s[1571]! } - public var Conversation_JumpToDate: String { return self._s[1572]! } - public var Contacts_GlobalSearch: String { return self._s[1573]! } - public var AutoDownloadSettings_ResetHelp: String { return self._s[1574]! } - public var SettingsSearch_Synonyms_FAQ: String { return self._s[1575]! } - public var Profile_MessageLifetime1d: String { return self._s[1576]! } + public var Wallet_Configuration_BlockchainIdHeader: String { return self._s[1571]! } + public var GroupInfo_Permissions_Removed: String { return self._s[1572]! } + public var ScheduledMessages_ScheduledOnline: String { return self._s[1573]! } + public var Passport_Identity_GenderMale: String { return self._s[1574]! } + public func Call_StatusBar(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1575]!, self._r[1575]!, [_0]) + } + public var Notifications_PermissionsKeepDisabled: String { return self._s[1576]! } + public var Conversation_JumpToDate: String { return self._s[1577]! } + public var Contacts_GlobalSearch: String { return self._s[1578]! } + public var AutoDownloadSettings_ResetHelp: String { return self._s[1579]! } + public var SettingsSearch_Synonyms_FAQ: String { return self._s[1580]! } + public var Profile_MessageLifetime1d: String { return self._s[1581]! } public func MESSAGE_INVOICE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1577]!, self._r[1577]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1582]!, self._r[1582]!, [_1, _2]) } - public var StickerPack_BuiltinPackName: String { return self._s[1580]! } + public var StickerPack_BuiltinPackName: String { return self._s[1585]! } public func PUSH_CHAT_MESSAGE_AUDIO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1581]!, self._r[1581]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1586]!, self._r[1586]!, [_1, _2]) } - public var VoiceOver_Chat_RecordModeVoiceMessageInfo: String { return self._s[1582]! } - public var Passport_InfoTitle: String { return self._s[1584]! } - public var Notifications_PermissionsUnreachableText: String { return self._s[1585]! } + public var VoiceOver_Chat_RecordModeVoiceMessageInfo: String { return self._s[1587]! } + public var Passport_InfoTitle: String { return self._s[1589]! } + public var Notifications_PermissionsUnreachableText: String { return self._s[1590]! } public func NetworkUsageSettings_CellularUsageSince(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1589]!, self._r[1589]!, [_0]) + return formatWithArgumentRanges(self._s[1594]!, self._r[1594]!, [_0]) } public func PUSH_CHAT_MESSAGE_GEO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1590]!, self._r[1590]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1595]!, self._r[1595]!, [_1, _2]) } - public var Passport_Address_TypePassportRegistrationUploadScan: String { return self._s[1591]! } - public var Profile_BotInfo: String { return self._s[1592]! } - public var Watch_Compose_CreateMessage: String { return self._s[1593]! } - public var AutoDownloadSettings_VoiceMessagesInfo: String { return self._s[1594]! } - public var Month_ShortNovember: String { return self._s[1595]! } - public var Conversation_ScamWarning: String { return self._s[1596]! } - public var Wallpaper_SetCustomBackground: String { return self._s[1597]! } - public var Appearance_TextSize_Title: String { return self._s[1598]! } - public var Passport_Identity_TranslationsHelp: String { return self._s[1599]! } - public var NotificationsSound_Chime: String { return self._s[1600]! } - public var Passport_Language_ko: String { return self._s[1602]! } - public var InviteText_URL: String { return self._s[1603]! } - public var TextFormat_Monospace: String { return self._s[1604]! } + public var Passport_Address_TypePassportRegistrationUploadScan: String { return self._s[1596]! } + public var Profile_BotInfo: String { return self._s[1597]! } + public var Watch_Compose_CreateMessage: String { return self._s[1598]! } + public var AutoDownloadSettings_VoiceMessagesInfo: String { return self._s[1599]! } + public var Month_ShortNovember: String { return self._s[1600]! } + public var Conversation_ScamWarning: String { return self._s[1601]! } + public var Wallpaper_SetCustomBackground: String { return self._s[1602]! } + public var Appearance_TextSize_Title: String { return self._s[1603]! } + public var Passport_Identity_TranslationsHelp: String { return self._s[1604]! } + public var NotificationsSound_Chime: String { return self._s[1605]! } + public var Passport_Language_ko: String { return self._s[1607]! } + public var InviteText_URL: String { return self._s[1608]! } + public var TextFormat_Monospace: String { return self._s[1609]! } public func Time_PreciseDate_m11(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1605]!, self._r[1605]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1610]!, self._r[1610]!, [_1, _2, _3]) } - public var EditTheme_Edit_BottomInfo: String { return self._s[1606]! } + public var EditTheme_Edit_BottomInfo: String { return self._s[1611]! } public func Login_WillSendSms(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1607]!, self._r[1607]!, [_0]) + return formatWithArgumentRanges(self._s[1612]!, self._r[1612]!, [_0]) } public func Watch_Time_ShortWeekdayAt(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1608]!, self._r[1608]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1613]!, self._r[1613]!, [_1, _2]) } - public var Wallet_Words_Title: String { return self._s[1609]! } - public var Wallet_Month_ShortMay: String { return self._s[1610]! } - public var EditTheme_CreateTitle: String { return self._s[1612]! } - public var Passport_InfoLearnMore: String { return self._s[1613]! } - public var TwoStepAuth_EmailPlaceholder: String { return self._s[1614]! } - public var Passport_Identity_AddIdentityCard: String { return self._s[1615]! } - public var Your_card_has_expired: String { return self._s[1616]! } - public var StickerPacksSettings_StickerPacksSection: String { return self._s[1617]! } - public var GroupInfo_InviteLink_Help: String { return self._s[1618]! } - public var TwoFactorSetup_EmailVerification_ResendAction: String { return self._s[1622]! } - public var Conversation_Report: String { return self._s[1624]! } - public var Notifications_MessageNotificationsSound: String { return self._s[1625]! } - public var Notification_MessageLifetime1m: String { return self._s[1626]! } - public var Privacy_ContactsTitle: String { return self._s[1627]! } - public var Conversation_ShareMyContactInfo: String { return self._s[1628]! } - public var Wallet_WordCheck_Title: String { return self._s[1629]! } - public var ChannelMembers_WhoCanAddMembersAdminsHelp: String { return self._s[1630]! } - public var Channel_Members_Title: String { return self._s[1631]! } - public var Map_OpenInWaze: String { return self._s[1632]! } - public var Appearance_RemoveThemeColorConfirmation: String { return self._s[1633]! } - public var Login_PhoneBannedError: String { return self._s[1634]! } + public var Wallet_Words_Title: String { return self._s[1614]! } + public var Wallet_Month_ShortMay: String { return self._s[1615]! } + public var EditTheme_CreateTitle: String { return self._s[1617]! } + public var Passport_InfoLearnMore: String { return self._s[1618]! } + public var TwoStepAuth_EmailPlaceholder: String { return self._s[1619]! } + public var Passport_Identity_AddIdentityCard: String { return self._s[1620]! } + public var Your_card_has_expired: String { return self._s[1621]! } + public var StickerPacksSettings_StickerPacksSection: String { return self._s[1622]! } + public var GroupInfo_InviteLink_Help: String { return self._s[1623]! } + public var TwoFactorSetup_EmailVerification_ResendAction: String { return self._s[1627]! } + public var Conversation_Report: String { return self._s[1629]! } + public var Notifications_MessageNotificationsSound: String { return self._s[1630]! } + public var Notification_MessageLifetime1m: String { return self._s[1631]! } + public var Privacy_ContactsTitle: String { return self._s[1632]! } + public var Conversation_ShareMyContactInfo: String { return self._s[1633]! } + public var Wallet_WordCheck_Title: String { return self._s[1634]! } + public var ChannelMembers_WhoCanAddMembersAdminsHelp: String { return self._s[1635]! } + public var Channel_Members_Title: String { return self._s[1636]! } + public var Map_OpenInWaze: String { return self._s[1637]! } + public var Appearance_RemoveThemeColorConfirmation: String { return self._s[1638]! } + public var Login_PhoneBannedError: String { return self._s[1639]! } public func LiveLocationUpdated_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1635]!, self._r[1635]!, [_0]) + return formatWithArgumentRanges(self._s[1640]!, self._r[1640]!, [_0]) } - public var IntentsSettings_MainAccount: String { return self._s[1636]! } - public var Group_Management_AddModeratorHelp: String { return self._s[1637]! } - public var AutoDownloadSettings_WifiTitle: String { return self._s[1638]! } - public var Common_OK: String { return self._s[1639]! } - public var Passport_Address_TypeBankStatementUploadScan: String { return self._s[1640]! } - public var Wallet_Words_NotDoneResponse: String { return self._s[1641]! } - public var Cache_Music: String { return self._s[1642]! } - public var Wallet_Configuration_SourceURL: String { return self._s[1643]! } - public var SettingsSearch_Synonyms_EditProfile_PhoneNumber: String { return self._s[1644]! } - public var PasscodeSettings_UnlockWithTouchId: String { return self._s[1646]! } - public var TwoStepAuth_HintPlaceholder: String { return self._s[1647]! } + public var IntentsSettings_MainAccount: String { return self._s[1641]! } + public var Group_Management_AddModeratorHelp: String { return self._s[1642]! } + public var AutoDownloadSettings_WifiTitle: String { return self._s[1643]! } + public var Common_OK: String { return self._s[1644]! } + public var Passport_Address_TypeBankStatementUploadScan: String { return self._s[1645]! } + public var Wallet_Words_NotDoneResponse: String { return self._s[1646]! } + public var Cache_Music: String { return self._s[1647]! } + public var Wallet_Configuration_SourceURL: String { return self._s[1648]! } + public var SettingsSearch_Synonyms_EditProfile_PhoneNumber: String { return self._s[1649]! } + public var PasscodeSettings_UnlockWithTouchId: String { return self._s[1652]! } + public var TwoStepAuth_HintPlaceholder: String { return self._s[1653]! } public func PUSH_PINNED_INVOICE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1648]!, self._r[1648]!, [_1]) + return formatWithArgumentRanges(self._s[1654]!, self._r[1654]!, [_1]) } public func Passport_RequestHeader(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1649]!, self._r[1649]!, [_0]) + return formatWithArgumentRanges(self._s[1655]!, self._r[1655]!, [_0]) } - public var TwoFactorSetup_Done_Action: String { return self._s[1650]! } + public var TwoFactorSetup_Done_Action: String { return self._s[1656]! } public func VoiceOver_Chat_ContactOrganization(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1651]!, self._r[1651]!, [_0]) + return formatWithArgumentRanges(self._s[1657]!, self._r[1657]!, [_0]) } - public var Wallet_Send_ErrorNotEnoughFundsText: String { return self._s[1652]! } - public var Watch_MessageView_ViewOnPhone: String { return self._s[1654]! } - public var Privacy_Calls_CustomShareHelp: String { return self._s[1655]! } - public var Wallet_Receive_CreateInvoiceInfo: String { return self._s[1657]! } - public var ChangePhoneNumberNumber_Title: String { return self._s[1658]! } - public var State_ConnectingToProxyInfo: String { return self._s[1659]! } - public var Conversation_SwipeToReplyHintTitle: String { return self._s[1660]! } - public var Message_VideoMessage: String { return self._s[1662]! } - public var ChannelInfo_DeleteChannel: String { return self._s[1663]! } - public var ContactInfo_PhoneLabelOther: String { return self._s[1664]! } - public var Channel_EditAdmin_CannotEdit: String { return self._s[1665]! } - public var Passport_DeleteAddressConfirmation: String { return self._s[1666]! } + public var Wallet_Send_ErrorNotEnoughFundsText: String { return self._s[1658]! } + public var Watch_MessageView_ViewOnPhone: String { return self._s[1660]! } + public var Privacy_Calls_CustomShareHelp: String { return self._s[1661]! } + public var Wallet_Receive_CreateInvoiceInfo: String { return self._s[1663]! } + public var ChangePhoneNumberNumber_Title: String { return self._s[1664]! } + public var State_ConnectingToProxyInfo: String { return self._s[1665]! } + public var Conversation_SwipeToReplyHintTitle: String { return self._s[1666]! } + public var Message_VideoMessage: String { return self._s[1668]! } + public var ChannelInfo_DeleteChannel: String { return self._s[1669]! } + public var ContactInfo_PhoneLabelOther: String { return self._s[1670]! } + public var Channel_EditAdmin_CannotEdit: String { return self._s[1671]! } + public var Passport_DeleteAddressConfirmation: String { return self._s[1672]! } public func Wallet_Time_PreciseDate_m9(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1667]!, self._r[1667]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1673]!, self._r[1673]!, [_1, _2, _3]) } - public var WallpaperPreview_SwipeBottomText: String { return self._s[1668]! } - public var Activity_RecordingAudio: String { return self._s[1669]! } - public var SettingsSearch_Synonyms_Watch: String { return self._s[1670]! } - public var PasscodeSettings_TryAgainIn1Minute: String { return self._s[1671]! } - public var Wallet_Info_Address: String { return self._s[1672]! } + public var WallpaperPreview_SwipeBottomText: String { return self._s[1674]! } + public var Activity_RecordingAudio: String { return self._s[1675]! } + public var SettingsSearch_Synonyms_Watch: String { return self._s[1676]! } + public var PasscodeSettings_TryAgainIn1Minute: String { return self._s[1677]! } + public var Wallet_Info_Address: String { return self._s[1678]! } public func Notification_ChangedGroupName(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1674]!, self._r[1674]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1680]!, self._r[1680]!, [_0, _1]) } public func EmptyGroupInfo_Line1(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1678]!, self._r[1678]!, [_0]) + return formatWithArgumentRanges(self._s[1684]!, self._r[1684]!, [_0]) } - public var Conversation_ApplyLocalization: String { return self._s[1679]! } - public var TwoFactorSetup_Intro_Action: String { return self._s[1680]! } - public var UserInfo_AddPhone: String { return self._s[1681]! } - public var Map_ShareLiveLocationHelp: String { return self._s[1682]! } + public var Conversation_ApplyLocalization: String { return self._s[1685]! } + public var TwoFactorSetup_Intro_Action: String { return self._s[1686]! } + public var UserInfo_AddPhone: String { return self._s[1687]! } + public var Map_ShareLiveLocationHelp: String { return self._s[1688]! } public func Passport_Identity_NativeNameGenericHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1683]!, self._r[1683]!, [_0]) + return formatWithArgumentRanges(self._s[1689]!, self._r[1689]!, [_0]) } - public var Passport_Scans: String { return self._s[1685]! } - public var BlockedUsers_Unblock: String { return self._s[1686]! } + public var Passport_Scans: String { return self._s[1691]! } + public var BlockedUsers_Unblock: String { return self._s[1692]! } public func PUSH_ENCRYPTION_REQUEST(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1687]!, self._r[1687]!, [_1]) + return formatWithArgumentRanges(self._s[1693]!, self._r[1693]!, [_1]) } - public var Channel_Management_LabelCreator: String { return self._s[1688]! } - public var Conversation_ReportSpamAndLeave: String { return self._s[1689]! } - public var SettingsSearch_Synonyms_EditProfile_Bio: String { return self._s[1690]! } - public var ChatList_UndoArchiveMultipleTitle: String { return self._s[1691]! } - public var Passport_Identity_NativeNameGenericTitle: String { return self._s[1692]! } + public var Channel_Management_LabelCreator: String { return self._s[1694]! } + public var Conversation_ReportSpamAndLeave: String { return self._s[1695]! } + public var SettingsSearch_Synonyms_EditProfile_Bio: String { return self._s[1696]! } + public var ChatList_UndoArchiveMultipleTitle: String { return self._s[1697]! } + public var Passport_Identity_NativeNameGenericTitle: String { return self._s[1698]! } public func Login_EmailPhoneBody(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1693]!, self._r[1693]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[1699]!, self._r[1699]!, [_0, _1, _2]) } - public var Login_PhoneNumberHelp: String { return self._s[1694]! } - public var LastSeen_ALongTimeAgo: String { return self._s[1695]! } - public var Channel_AdminLog_CanPinMessages: String { return self._s[1696]! } - public var ChannelIntro_CreateChannel: String { return self._s[1697]! } - public var Conversation_UnreadMessages: String { return self._s[1698]! } - public var SettingsSearch_Synonyms_Stickers_ArchivedPacks: String { return self._s[1699]! } - public var Channel_AdminLog_EmptyText: String { return self._s[1700]! } - public var Theme_Context_Apply: String { return self._s[1701]! } - public var Notification_GroupActivated: String { return self._s[1702]! } - public var NotificationSettings_ContactJoinedInfo: String { return self._s[1703]! } - public var Wallet_Intro_CreateWallet: String { return self._s[1704]! } + public var Login_PhoneNumberHelp: String { return self._s[1700]! } + public var LastSeen_ALongTimeAgo: String { return self._s[1701]! } + public var Channel_AdminLog_CanPinMessages: String { return self._s[1702]! } + public var ChannelIntro_CreateChannel: String { return self._s[1703]! } + public var Conversation_UnreadMessages: String { return self._s[1704]! } + public var SettingsSearch_Synonyms_Stickers_ArchivedPacks: String { return self._s[1705]! } + public var Channel_AdminLog_EmptyText: String { return self._s[1706]! } + public var Theme_Context_Apply: String { return self._s[1707]! } + public var Notification_GroupActivated: String { return self._s[1708]! } + public var NotificationSettings_ContactJoinedInfo: String { return self._s[1709]! } + public var Wallet_Intro_CreateWallet: String { return self._s[1710]! } public func Notification_PinnedContactMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1705]!, self._r[1705]!, [_0]) + return formatWithArgumentRanges(self._s[1711]!, self._r[1711]!, [_0]) } public func DownloadingStatus(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1706]!, self._r[1706]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1712]!, self._r[1712]!, [_0, _1]) } - public var GroupInfo_ConvertToSupergroup: String { return self._s[1708]! } + public var GroupInfo_ConvertToSupergroup: String { return self._s[1714]! } public func PrivacyPolicy_AgeVerificationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1709]!, self._r[1709]!, [_0]) + return formatWithArgumentRanges(self._s[1715]!, self._r[1715]!, [_0]) } - public var Undo_DeletedChannel: String { return self._s[1710]! } - public var CallFeedback_AddComment: String { return self._s[1711]! } + public var Undo_DeletedChannel: String { return self._s[1716]! } + public var CallFeedback_AddComment: String { return self._s[1717]! } public func Conversation_OpenBotLinkAllowMessages(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1712]!, self._r[1712]!, [_0]) + return formatWithArgumentRanges(self._s[1718]!, self._r[1718]!, [_0]) } - public var Document_TargetConfirmationFormat: String { return self._s[1713]! } + public var Document_TargetConfirmationFormat: String { return self._s[1719]! } public func Call_StatusOngoing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1714]!, self._r[1714]!, [_0]) + return formatWithArgumentRanges(self._s[1720]!, self._r[1720]!, [_0]) } - public var LogoutOptions_SetPasscodeTitle: String { return self._s[1715]! } + public var LogoutOptions_SetPasscodeTitle: String { return self._s[1721]! } public func PUSH_CHAT_MESSAGE_GAME_SCORE(_ _1: String, _ _2: String, _ _3: String, _ _4: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1716]!, self._r[1716]!, [_1, _2, _3, _4]) + return formatWithArgumentRanges(self._s[1722]!, self._r[1722]!, [_1, _2, _3, _4]) } - public var Wallet_SecureStorageChanged_PasscodeText: String { return self._s[1717]! } - public var Theme_ErrorNotFound: String { return self._s[1718]! } - public var Contacts_SortByName: String { return self._s[1719]! } - public var SettingsSearch_Synonyms_Privacy_Forwards: String { return self._s[1720]! } + public var Wallet_SecureStorageChanged_PasscodeText: String { return self._s[1723]! } + public var Theme_ErrorNotFound: String { return self._s[1724]! } + public var Contacts_SortByName: String { return self._s[1725]! } + public var SettingsSearch_Synonyms_Privacy_Forwards: String { return self._s[1726]! } public func CHAT_MESSAGE_INVOICE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1722]!, self._r[1722]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1728]!, self._r[1728]!, [_1, _2, _3]) } - public var Notification_Exceptions_RemoveFromExceptions: String { return self._s[1723]! } - public var ScheduledMessages_EditTime: String { return self._s[1724]! } - public var Conversation_ClearSelfHistory: String { return self._s[1725]! } - public var Checkout_NewCard_PostcodePlaceholder: String { return self._s[1726]! } - public var PasscodeSettings_DoNotMatch: String { return self._s[1727]! } - public var Stickers_SuggestNone: String { return self._s[1728]! } - public var ChatSettings_Cache: String { return self._s[1729]! } - public var Settings_SaveIncomingPhotos: String { return self._s[1730]! } - public var Media_ShareThisPhoto: String { return self._s[1731]! } - public var Chat_SlowmodeTooltipPending: String { return self._s[1732]! } - public var InfoPlist_NSContactsUsageDescription: String { return self._s[1733]! } - public var Conversation_ContextMenuCopyLink: String { return self._s[1734]! } - public var PrivacyPolicy_AgeVerificationTitle: String { return self._s[1735]! } - public var SettingsSearch_Synonyms_Stickers_Masks: String { return self._s[1736]! } - public var TwoStepAuth_SetupPasswordEnterPasswordNew: String { return self._s[1737]! } - public var Appearance_ThemePreview_Chat_6_Text: String { return self._s[1738]! } + public var Notification_Exceptions_RemoveFromExceptions: String { return self._s[1729]! } + public var ScheduledMessages_EditTime: String { return self._s[1730]! } + public var Conversation_ClearSelfHistory: String { return self._s[1731]! } + public var Checkout_NewCard_PostcodePlaceholder: String { return self._s[1732]! } + public var PasscodeSettings_DoNotMatch: String { return self._s[1733]! } + public var Stickers_SuggestNone: String { return self._s[1734]! } + public var ChatSettings_Cache: String { return self._s[1735]! } + public var Settings_SaveIncomingPhotos: String { return self._s[1736]! } + public var Media_ShareThisPhoto: String { return self._s[1737]! } + public var Chat_SlowmodeTooltipPending: String { return self._s[1738]! } + public var InfoPlist_NSContactsUsageDescription: String { return self._s[1739]! } + public var Conversation_ContextMenuCopyLink: String { return self._s[1740]! } + public var PrivacyPolicy_AgeVerificationTitle: String { return self._s[1741]! } + public var SettingsSearch_Synonyms_Stickers_Masks: String { return self._s[1742]! } + public var TwoStepAuth_SetupPasswordEnterPasswordNew: String { return self._s[1743]! } + public var Appearance_ThemePreview_Chat_6_Text: String { return self._s[1744]! } public func Wallet_SecureStorageReset_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1739]!, self._r[1739]!, [_0]) + return formatWithArgumentRanges(self._s[1745]!, self._r[1745]!, [_0]) } - public var Permissions_CellularDataTitle_v0: String { return self._s[1740]! } - public var WallpaperSearch_ColorWhite: String { return self._s[1742]! } - public var Channel_AdminLog_DefaultRestrictionsUpdated: String { return self._s[1743]! } - public var Conversation_ErrorInaccessibleMessage: String { return self._s[1744]! } - public var Map_OpenIn: String { return self._s[1745]! } + public var Permissions_CellularDataTitle_v0: String { return self._s[1746]! } + public var WallpaperSearch_ColorWhite: String { return self._s[1748]! } + public var Channel_AdminLog_DefaultRestrictionsUpdated: String { return self._s[1749]! } + public var Conversation_ErrorInaccessibleMessage: String { return self._s[1750]! } + public var Map_OpenIn: String { return self._s[1751]! } public func PUSH_PHONE_CALL_MISSED(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1748]!, self._r[1748]!, [_1]) + return formatWithArgumentRanges(self._s[1754]!, self._r[1754]!, [_1]) } public func ChannelInfo_AddParticipantConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1749]!, self._r[1749]!, [_0]) + return formatWithArgumentRanges(self._s[1755]!, self._r[1755]!, [_0]) } - public var GroupInfo_Permissions_SlowmodeHeader: String { return self._s[1750]! } - public var MessagePoll_LabelClosed: String { return self._s[1751]! } - public var GroupPermission_PermissionGloballyDisabled: String { return self._s[1753]! } - public var Wallet_Send_SendAnyway: String { return self._s[1754]! } - public var Passport_Identity_MiddleNamePlaceholder: String { return self._s[1755]! } - public var UserInfo_FirstNamePlaceholder: String { return self._s[1756]! } - public var PrivacyLastSeenSettings_WhoCanSeeMyTimestamp: String { return self._s[1757]! } - public var Map_SetThisPlace: String { return self._s[1758]! } - public var Login_SelectCountry_Title: String { return self._s[1759]! } - public var Channel_EditAdmin_PermissionBanUsers: String { return self._s[1760]! } + public var GroupInfo_Permissions_SlowmodeHeader: String { return self._s[1756]! } + public var MessagePoll_LabelClosed: String { return self._s[1757]! } + public var GroupPermission_PermissionGloballyDisabled: String { return self._s[1759]! } + public var Wallet_Send_SendAnyway: String { return self._s[1760]! } + public var Passport_Identity_MiddleNamePlaceholder: String { return self._s[1761]! } + public var UserInfo_FirstNamePlaceholder: String { return self._s[1762]! } + public var PrivacyLastSeenSettings_WhoCanSeeMyTimestamp: String { return self._s[1763]! } + public var Map_SetThisPlace: String { return self._s[1764]! } + public var Login_SelectCountry_Title: String { return self._s[1765]! } + public var Channel_EditAdmin_PermissionBanUsers: String { return self._s[1766]! } public func Conversation_OpenBotLinkLogin(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1761]!, self._r[1761]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1767]!, self._r[1767]!, [_1, _2]) } - public var Channel_AdminLog_ChangeInfo: String { return self._s[1762]! } - public var Watch_Suggestion_BRB: String { return self._s[1763]! } - public var Passport_Identity_EditIdentityCard: String { return self._s[1764]! } - public var Contacts_PermissionsTitle: String { return self._s[1765]! } - public var Conversation_RestrictedInline: String { return self._s[1766]! } - public var Appearance_RemoveThemeColor: String { return self._s[1768]! } - public var StickerPack_ViewPack: String { return self._s[1769]! } - public var Wallet_UnknownError: String { return self._s[1770]! } + public var Channel_AdminLog_ChangeInfo: String { return self._s[1768]! } + public var Watch_Suggestion_BRB: String { return self._s[1769]! } + public var Passport_Identity_EditIdentityCard: String { return self._s[1770]! } + public var Contacts_PermissionsTitle: String { return self._s[1771]! } + public var Conversation_RestrictedInline: String { return self._s[1772]! } + public var Appearance_RemoveThemeColor: String { return self._s[1774]! } + public var StickerPack_ViewPack: String { return self._s[1775]! } + public var Wallet_UnknownError: String { return self._s[1776]! } public func Update_AppVersion(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1771]!, self._r[1771]!, [_0]) + return formatWithArgumentRanges(self._s[1777]!, self._r[1777]!, [_0]) } - public var Compose_NewChannel: String { return self._s[1773]! } - public var ChatSettings_AutoDownloadSettings_TypePhoto: String { return self._s[1776]! } - public var MessagePoll_LabelQuiz: String { return self._s[1778]! } - public var Conversation_ReportSpamGroupConfirmation: String { return self._s[1779]! } - public var Channel_Info_Stickers: String { return self._s[1780]! } - public var AutoNightTheme_PreferredTheme: String { return self._s[1781]! } - public var PrivacyPolicy_AgeVerificationAgree: String { return self._s[1782]! } - public var Passport_DeletePersonalDetails: String { return self._s[1783]! } - public var LogoutOptions_AddAccountTitle: String { return self._s[1784]! } - public var Channel_DiscussionGroupInfo: String { return self._s[1785]! } - public var Group_EditAdmin_RankOwnerPlaceholder: String { return self._s[1786]! } - public var Conversation_SearchNoResults: String { return self._s[1789]! } - public var Wallet_Configuration_ApplyErrorTextURLInvalid: String { return self._s[1790]! } - public var MessagePoll_LabelAnonymous: String { return self._s[1791]! } - public var Channel_Members_AddAdminErrorNotAMember: String { return self._s[1792]! } - public var Login_Code: String { return self._s[1793]! } - public var EditTheme_Create_BottomInfo: String { return self._s[1794]! } - public var Watch_Suggestion_WhatsUp: String { return self._s[1795]! } - public var Weekday_ShortThursday: String { return self._s[1796]! } - public var Resolve_ErrorNotFound: String { return self._s[1798]! } - public var LastSeen_Offline: String { return self._s[1799]! } - public var PeopleNearby_NoMembers: String { return self._s[1800]! } - public var GroupPermission_AddMembersNotAvailable: String { return self._s[1801]! } - public var Privacy_Calls_AlwaysAllow_Title: String { return self._s[1802]! } - public var GroupInfo_Title: String { return self._s[1804]! } - public var NotificationsSound_Note: String { return self._s[1805]! } - public var Conversation_EditingMessagePanelTitle: String { return self._s[1806]! } - public var Watch_Message_Poll: String { return self._s[1807]! } - public var Privacy_Calls: String { return self._s[1808]! } + public var Compose_NewChannel: String { return self._s[1779]! } + public var ChatSettings_AutoDownloadSettings_TypePhoto: String { return self._s[1782]! } + public var MessagePoll_LabelQuiz: String { return self._s[1784]! } + public var Conversation_ReportSpamGroupConfirmation: String { return self._s[1785]! } + public var Channel_Info_Stickers: String { return self._s[1786]! } + public var AutoNightTheme_PreferredTheme: String { return self._s[1787]! } + public var PrivacyPolicy_AgeVerificationAgree: String { return self._s[1788]! } + public var Passport_DeletePersonalDetails: String { return self._s[1789]! } + public var LogoutOptions_AddAccountTitle: String { return self._s[1790]! } + public var Channel_DiscussionGroupInfo: String { return self._s[1791]! } + public var Group_EditAdmin_RankOwnerPlaceholder: String { return self._s[1792]! } + public var Conversation_SearchNoResults: String { return self._s[1795]! } + public var Wallet_Configuration_ApplyErrorTextURLInvalid: String { return self._s[1796]! } + public var MessagePoll_LabelAnonymous: String { return self._s[1797]! } + public var Channel_Members_AddAdminErrorNotAMember: String { return self._s[1798]! } + public var Login_Code: String { return self._s[1799]! } + public var EditTheme_Create_BottomInfo: String { return self._s[1800]! } + public var Watch_Suggestion_WhatsUp: String { return self._s[1801]! } + public var Weekday_ShortThursday: String { return self._s[1802]! } + public var Resolve_ErrorNotFound: String { return self._s[1804]! } + public var LastSeen_Offline: String { return self._s[1805]! } + public var PeopleNearby_NoMembers: String { return self._s[1806]! } + public var GroupPermission_AddMembersNotAvailable: String { return self._s[1807]! } + public var Privacy_Calls_AlwaysAllow_Title: String { return self._s[1808]! } + public var GroupInfo_Title: String { return self._s[1810]! } + public var NotificationsSound_Note: String { return self._s[1811]! } + public var Conversation_EditingMessagePanelTitle: String { return self._s[1812]! } + public var Watch_Message_Poll: String { return self._s[1813]! } + public var Privacy_Calls: String { return self._s[1814]! } public func Channel_AdminLog_MessageRankUsername(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1809]!, self._r[1809]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1815]!, self._r[1815]!, [_1, _2, _3]) } - public var Month_ShortAugust: String { return self._s[1810]! } - public var TwoStepAuth_SetPasswordHelp: String { return self._s[1811]! } - public var Notifications_Reset: String { return self._s[1812]! } - public var Conversation_Pin: String { return self._s[1813]! } - public var Passport_Language_lv: String { return self._s[1814]! } - public var Permissions_PeopleNearbyAllowInSettings_v0: String { return self._s[1815]! } - public var BlockedUsers_Info: String { return self._s[1816]! } - public var SettingsSearch_Synonyms_Data_AutoplayVideos: String { return self._s[1818]! } - public var Watch_Conversation_Unblock: String { return self._s[1820]! } + public var Month_ShortAugust: String { return self._s[1816]! } + public var TwoStepAuth_SetPasswordHelp: String { return self._s[1817]! } + public var Notifications_Reset: String { return self._s[1818]! } + public var Conversation_Pin: String { return self._s[1819]! } + public var Passport_Language_lv: String { return self._s[1820]! } + public var Permissions_PeopleNearbyAllowInSettings_v0: String { return self._s[1821]! } + public var BlockedUsers_Info: String { return self._s[1822]! } + public var SettingsSearch_Synonyms_Data_AutoplayVideos: String { return self._s[1824]! } + public var Watch_Conversation_Unblock: String { return self._s[1826]! } public func Time_MonthOfYear_m9(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1821]!, self._r[1821]!, [_0]) + return formatWithArgumentRanges(self._s[1827]!, self._r[1827]!, [_0]) } - public var CloudStorage_Title: String { return self._s[1822]! } - public var GroupInfo_DeleteAndExitConfirmation: String { return self._s[1823]! } + public var CloudStorage_Title: String { return self._s[1828]! } + public var GroupInfo_DeleteAndExitConfirmation: String { return self._s[1829]! } public func NetworkUsageSettings_WifiUsageSince(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1824]!, self._r[1824]!, [_0]) + return formatWithArgumentRanges(self._s[1830]!, self._r[1830]!, [_0]) } - public var Channel_AdminLogFilter_AdminsTitle: String { return self._s[1825]! } - public var Watch_Suggestion_OnMyWay: String { return self._s[1826]! } - public var TwoStepAuth_RecoveryEmailTitle: String { return self._s[1827]! } - public var Passport_Address_EditBankStatement: String { return self._s[1828]! } + public var Channel_AdminLogFilter_AdminsTitle: String { return self._s[1831]! } + public var Watch_Suggestion_OnMyWay: String { return self._s[1832]! } + public var TwoStepAuth_RecoveryEmailTitle: String { return self._s[1833]! } + public var Passport_Address_EditBankStatement: String { return self._s[1834]! } public func Channel_AdminLog_MessageChangedUnlinkedGroup(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1829]!, self._r[1829]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1835]!, self._r[1835]!, [_1, _2]) } - public var ChatSettings_DownloadInBackgroundInfo: String { return self._s[1830]! } - public var ShareMenu_Comment: String { return self._s[1831]! } - public var Permissions_ContactsTitle_v0: String { return self._s[1832]! } - public var Notifications_PermissionsTitle: String { return self._s[1833]! } - public var GroupPermission_NoSendLinks: String { return self._s[1834]! } - public var Privacy_Forwards_NeverAllow_Title: String { return self._s[1835]! } - public var Wallet_SecureStorageChanged_ImportWallet: String { return self._s[1836]! } - public var Settings_Support: String { return self._s[1837]! } - public var Notifications_ChannelNotificationsSound: String { return self._s[1838]! } - public var SettingsSearch_Synonyms_Data_AutoDownloadReset: String { return self._s[1839]! } - public var Privacy_Forwards_Preview: String { return self._s[1840]! } - public var GroupPermission_ApplyAlertAction: String { return self._s[1841]! } - public var Watch_Stickers_StickerPacks: String { return self._s[1842]! } - public var Common_Select: String { return self._s[1844]! } - public var CheckoutInfo_ErrorEmailInvalid: String { return self._s[1845]! } - public var WallpaperSearch_ColorGray: String { return self._s[1848]! } - public var TwoFactorSetup_Password_PlaceholderPassword: String { return self._s[1849]! } - public var TwoFactorSetup_Hint_SkipAction: String { return self._s[1850]! } - public var ChatAdmins_AllMembersAreAdminsOffHelp: String { return self._s[1851]! } - public var PollResults_Title: String { return self._s[1852]! } - public var PasscodeSettings_AutoLock_IfAwayFor_5hours: String { return self._s[1853]! } - public var Appearance_PreviewReplyAuthor: String { return self._s[1854]! } - public var TwoStepAuth_RecoveryTitle: String { return self._s[1855]! } - public var Widget_AuthRequired: String { return self._s[1856]! } - public var Camera_FlashOn: String { return self._s[1857]! } - public var Conversation_ContextMenuLookUp: String { return self._s[1858]! } - public var Channel_Stickers_NotFoundHelp: String { return self._s[1859]! } - public var Watch_Suggestion_OK: String { return self._s[1860]! } + public var ChatSettings_DownloadInBackgroundInfo: String { return self._s[1836]! } + public var ShareMenu_Comment: String { return self._s[1837]! } + public var Permissions_ContactsTitle_v0: String { return self._s[1838]! } + public var Notifications_PermissionsTitle: String { return self._s[1839]! } + public var GroupPermission_NoSendLinks: String { return self._s[1840]! } + public var Privacy_Forwards_NeverAllow_Title: String { return self._s[1841]! } + public var Wallet_SecureStorageChanged_ImportWallet: String { return self._s[1842]! } + public var Settings_Support: String { return self._s[1843]! } + public var Notifications_ChannelNotificationsSound: String { return self._s[1844]! } + public var SettingsSearch_Synonyms_Data_AutoDownloadReset: String { return self._s[1845]! } + public var Privacy_Forwards_Preview: String { return self._s[1846]! } + public var GroupPermission_ApplyAlertAction: String { return self._s[1847]! } + public var Watch_Stickers_StickerPacks: String { return self._s[1848]! } + public var Common_Select: String { return self._s[1850]! } + public var CheckoutInfo_ErrorEmailInvalid: String { return self._s[1851]! } + public var WallpaperSearch_ColorGray: String { return self._s[1854]! } + public var TwoFactorSetup_Password_PlaceholderPassword: String { return self._s[1855]! } + public var TwoFactorSetup_Hint_SkipAction: String { return self._s[1856]! } + public var ChatAdmins_AllMembersAreAdminsOffHelp: String { return self._s[1857]! } + public var PollResults_Title: String { return self._s[1858]! } + public var PasscodeSettings_AutoLock_IfAwayFor_5hours: String { return self._s[1859]! } + public var Appearance_PreviewReplyAuthor: String { return self._s[1860]! } + public var TwoStepAuth_RecoveryTitle: String { return self._s[1861]! } + public var Widget_AuthRequired: String { return self._s[1862]! } + public var Camera_FlashOn: String { return self._s[1863]! } + public var Conversation_ContextMenuLookUp: String { return self._s[1864]! } + public var Channel_Stickers_NotFoundHelp: String { return self._s[1865]! } + public var Watch_Suggestion_OK: String { return self._s[1866]! } public func Username_LinkHint(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1862]!, self._r[1862]!, [_0]) + return formatWithArgumentRanges(self._s[1868]!, self._r[1868]!, [_0]) } public func Notification_PinnedLiveLocationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1864]!, self._r[1864]!, [_0]) + return formatWithArgumentRanges(self._s[1870]!, self._r[1870]!, [_0]) } - public var TextFormat_Strikethrough: String { return self._s[1865]! } - public var DialogList_AdLabel: String { return self._s[1866]! } - public var WatchRemote_NotificationText: String { return self._s[1867]! } - public var IntentsSettings_SuggestedChatsSavedMessages: String { return self._s[1868]! } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsAlert: String { return self._s[1869]! } - public var Conversation_ReportSpam: String { return self._s[1870]! } - public var SettingsSearch_Synonyms_Privacy_Data_TopPeers: String { return self._s[1871]! } - public var Settings_LogoutConfirmationTitle: String { return self._s[1873]! } - public var PhoneLabel_Title: String { return self._s[1874]! } - public var Passport_Address_EditRentalAgreement: String { return self._s[1875]! } - public var Settings_ChangePhoneNumber: String { return self._s[1876]! } - public var Notifications_ExceptionsTitle: String { return self._s[1877]! } - public var Notifications_AlertTones: String { return self._s[1878]! } - public var Call_ReportIncludeLogDescription: String { return self._s[1879]! } - public var SettingsSearch_Synonyms_Notifications_ResetAllNotifications: String { return self._s[1880]! } - public var AutoDownloadSettings_PrivateChats: String { return self._s[1881]! } - public var VoiceOver_Chat_Photo: String { return self._s[1883]! } - public var TwoStepAuth_AddHintTitle: String { return self._s[1884]! } - public var ReportPeer_ReasonOther: String { return self._s[1885]! } - public var ChatList_Context_JoinChannel: String { return self._s[1886]! } - public var KeyCommand_ScrollDown: String { return self._s[1888]! } - public var Conversation_ScheduleMessage_Title: String { return self._s[1889]! } + public var TextFormat_Strikethrough: String { return self._s[1871]! } + public var DialogList_AdLabel: String { return self._s[1872]! } + public var WatchRemote_NotificationText: String { return self._s[1873]! } + public var IntentsSettings_SuggestedChatsSavedMessages: String { return self._s[1874]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsAlert: String { return self._s[1875]! } + public var Conversation_ReportSpam: String { return self._s[1876]! } + public var SettingsSearch_Synonyms_Privacy_Data_TopPeers: String { return self._s[1877]! } + public var Settings_LogoutConfirmationTitle: String { return self._s[1879]! } + public var PhoneLabel_Title: String { return self._s[1880]! } + public var Passport_Address_EditRentalAgreement: String { return self._s[1881]! } + public var Settings_ChangePhoneNumber: String { return self._s[1882]! } + public var Notifications_ExceptionsTitle: String { return self._s[1883]! } + public var Notifications_AlertTones: String { return self._s[1884]! } + public var Call_ReportIncludeLogDescription: String { return self._s[1885]! } + public var SettingsSearch_Synonyms_Notifications_ResetAllNotifications: String { return self._s[1886]! } + public var AutoDownloadSettings_PrivateChats: String { return self._s[1887]! } + public var VoiceOver_Chat_Photo: String { return self._s[1889]! } + public var TwoStepAuth_AddHintTitle: String { return self._s[1890]! } + public var ReportPeer_ReasonOther: String { return self._s[1891]! } + public var ChatList_Context_JoinChannel: String { return self._s[1892]! } + public var KeyCommand_ScrollDown: String { return self._s[1894]! } + public var Conversation_ScheduleMessage_Title: String { return self._s[1895]! } public func Login_BannedPhoneSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1890]!, self._r[1890]!, [_0]) + return formatWithArgumentRanges(self._s[1896]!, self._r[1896]!, [_0]) } - public var NetworkUsageSettings_MediaVideoDataSection: String { return self._s[1891]! } - public var ChannelInfo_DeleteGroupConfirmation: String { return self._s[1892]! } - public var AuthSessions_LogOut: String { return self._s[1893]! } - public var Passport_Identity_TypeInternalPassport: String { return self._s[1894]! } - public var ChatSettings_AutoDownloadVoiceMessages: String { return self._s[1895]! } - public var Passport_Phone_Title: String { return self._s[1896]! } - public var ContactList_Context_StartSecretChat: String { return self._s[1897]! } - public var Settings_PhoneNumber: String { return self._s[1898]! } + public var NetworkUsageSettings_MediaVideoDataSection: String { return self._s[1897]! } + public var ChannelInfo_DeleteGroupConfirmation: String { return self._s[1898]! } + public var AuthSessions_LogOut: String { return self._s[1899]! } + public var Passport_Identity_TypeInternalPassport: String { return self._s[1900]! } + public var ChatSettings_AutoDownloadVoiceMessages: String { return self._s[1901]! } + public var Passport_Phone_Title: String { return self._s[1902]! } + public var ContactList_Context_StartSecretChat: String { return self._s[1903]! } + public var Settings_PhoneNumber: String { return self._s[1904]! } public func Conversation_ScheduleMessage_SendToday(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1899]!, self._r[1899]!, [_0]) + return formatWithArgumentRanges(self._s[1905]!, self._r[1905]!, [_0]) } - public var NotificationsSound_Alert: String { return self._s[1901]! } - public var Wallet_SecureStorageChanged_CreateWallet: String { return self._s[1902]! } - public var WebSearch_SearchNoResults: String { return self._s[1903]! } - public var Privacy_ProfilePhoto_AlwaysShareWith_Title: String { return self._s[1905]! } - public var Wallet_Configuration_SourceInfo: String { return self._s[1906]! } - public var LogoutOptions_AlternativeOptionsSection: String { return self._s[1907]! } - public var SettingsSearch_Synonyms_Passport: String { return self._s[1908]! } - public var PhotoEditor_CurvesTool: String { return self._s[1909]! } - public var Checkout_PaymentMethod: String { return self._s[1911]! } + public var NotificationsSound_Alert: String { return self._s[1907]! } + public var Wallet_SecureStorageChanged_CreateWallet: String { return self._s[1908]! } + public var WebSearch_SearchNoResults: String { return self._s[1909]! } + public var Privacy_ProfilePhoto_AlwaysShareWith_Title: String { return self._s[1911]! } + public var Wallet_Configuration_SourceInfo: String { return self._s[1912]! } + public var LogoutOptions_AlternativeOptionsSection: String { return self._s[1913]! } + public var SettingsSearch_Synonyms_Passport: String { return self._s[1914]! } + public var PhotoEditor_CurvesTool: String { return self._s[1915]! } + public var Checkout_PaymentMethod: String { return self._s[1917]! } public func PUSH_CHAT_ADD_YOU(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1912]!, self._r[1912]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1918]!, self._r[1918]!, [_1, _2]) } - public var Contacts_AccessDeniedError: String { return self._s[1913]! } - public var Camera_PhotoMode: String { return self._s[1916]! } - public var EditTheme_Expand_Preview_IncomingText: String { return self._s[1917]! } - public var Appearance_TextSize_Apply: String { return self._s[1918]! } - public var Passport_Address_AddUtilityBill: String { return self._s[1920]! } - public var CallSettings_OnMobile: String { return self._s[1921]! } - public var Tour_Text2: String { return self._s[1922]! } + public var Contacts_AccessDeniedError: String { return self._s[1919]! } + public var Camera_PhotoMode: String { return self._s[1922]! } + public var EditTheme_Expand_Preview_IncomingText: String { return self._s[1923]! } + public var Appearance_TextSize_Apply: String { return self._s[1924]! } + public var Passport_Address_AddUtilityBill: String { return self._s[1926]! } + public var CallSettings_OnMobile: String { return self._s[1927]! } + public var Tour_Text2: String { return self._s[1928]! } public func PUSH_CHAT_MESSAGE_ROUND(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1923]!, self._r[1923]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1929]!, self._r[1929]!, [_1, _2]) } - public var DialogList_EncryptionProcessing: String { return self._s[1925]! } - public var Permissions_Skip: String { return self._s[1926]! } - public var Wallet_Words_NotDoneOk: String { return self._s[1927]! } - public var SecretImage_Title: String { return self._s[1928]! } - public var Watch_MessageView_Title: String { return self._s[1929]! } - public var Channel_DiscussionGroupAdd: String { return self._s[1930]! } - public var AttachmentMenu_Poll: String { return self._s[1931]! } + public var DialogList_EncryptionProcessing: String { return self._s[1931]! } + public var Permissions_Skip: String { return self._s[1932]! } + public var Wallet_Words_NotDoneOk: String { return self._s[1933]! } + public var SecretImage_Title: String { return self._s[1934]! } + public var Watch_MessageView_Title: String { return self._s[1935]! } + public var Channel_DiscussionGroupAdd: String { return self._s[1936]! } + public var AttachmentMenu_Poll: String { return self._s[1937]! } public func Notification_GroupInviter(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1932]!, self._r[1932]!, [_0]) + return formatWithArgumentRanges(self._s[1938]!, self._r[1938]!, [_0]) } public func Channel_DiscussionGroup_PrivateChannelLink(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1933]!, self._r[1933]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1939]!, self._r[1939]!, [_1, _2]) } - public var Notification_CallCanceled: String { return self._s[1934]! } - public var WallpaperPreview_Title: String { return self._s[1935]! } - public var Privacy_PaymentsClear_PaymentInfo: String { return self._s[1936]! } - public var Settings_ProxyConnecting: String { return self._s[1937]! } - public var Settings_CheckPhoneNumberText: String { return self._s[1939]! } - public var VoiceOver_Chat_YourVideo: String { return self._s[1940]! } - public var Wallet_Intro_Title: String { return self._s[1941]! } - public var TwoFactorSetup_Password_Action: String { return self._s[1942]! } - public var Profile_MessageLifetime5s: String { return self._s[1943]! } - public var Username_InvalidCharacters: String { return self._s[1944]! } - public var VoiceOver_Media_PlaybackRateFast: String { return self._s[1945]! } - public var ScheduledMessages_ClearAll: String { return self._s[1946]! } - public var WallpaperPreview_CropBottomText: String { return self._s[1947]! } - public var AutoDownloadSettings_LimitBySize: String { return self._s[1948]! } - public var Settings_AddAccount: String { return self._s[1949]! } - public var Notification_CreatedChannel: String { return self._s[1952]! } + public var Notification_CallCanceled: String { return self._s[1940]! } + public var WallpaperPreview_Title: String { return self._s[1941]! } + public var Privacy_PaymentsClear_PaymentInfo: String { return self._s[1942]! } + public var Settings_ProxyConnecting: String { return self._s[1943]! } + public var Settings_CheckPhoneNumberText: String { return self._s[1945]! } + public var VoiceOver_Chat_YourVideo: String { return self._s[1946]! } + public var Wallet_Intro_Title: String { return self._s[1947]! } + public var TwoFactorSetup_Password_Action: String { return self._s[1948]! } + public var Profile_MessageLifetime5s: String { return self._s[1949]! } + public var Username_InvalidCharacters: String { return self._s[1950]! } + public var VoiceOver_Media_PlaybackRateFast: String { return self._s[1951]! } + public var ScheduledMessages_ClearAll: String { return self._s[1952]! } + public var WallpaperPreview_CropBottomText: String { return self._s[1953]! } + public var AutoDownloadSettings_LimitBySize: String { return self._s[1954]! } + public var Settings_AddAccount: String { return self._s[1955]! } + public var Notification_CreatedChannel: String { return self._s[1958]! } public func PUSH_CHAT_DELETE_MEMBER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1953]!, self._r[1953]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1959]!, self._r[1959]!, [_1, _2, _3]) } - public var Passcode_AppLockedAlert: String { return self._s[1955]! } - public var StickerPacksSettings_AnimatedStickersInfo: String { return self._s[1956]! } - public var VoiceOver_Media_PlaybackStop: String { return self._s[1957]! } - public var Contacts_TopSection: String { return self._s[1958]! } - public var ChatList_DeleteForEveryoneConfirmationAction: String { return self._s[1959]! } + public var Passcode_AppLockedAlert: String { return self._s[1961]! } + public var StickerPacksSettings_AnimatedStickersInfo: String { return self._s[1962]! } + public var VoiceOver_Media_PlaybackStop: String { return self._s[1963]! } + public var Contacts_TopSection: String { return self._s[1964]! } + public var ChatList_DeleteForEveryoneConfirmationAction: String { return self._s[1965]! } public func Conversation_SetReminder_RemindOn(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1960]!, self._r[1960]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1966]!, self._r[1966]!, [_0, _1]) } - public var Wallet_Info_Receive: String { return self._s[1961]! } - public var Wallet_Completed_ViewWallet: String { return self._s[1962]! } + public var Wallet_Info_Receive: String { return self._s[1967]! } + public var Wallet_Completed_ViewWallet: String { return self._s[1968]! } public func Time_MonthOfYear_m6(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1963]!, self._r[1963]!, [_0]) + return formatWithArgumentRanges(self._s[1969]!, self._r[1969]!, [_0]) } - public var ReportPeer_ReasonSpam: String { return self._s[1964]! } - public var UserInfo_TapToCall: String { return self._s[1965]! } - public var Conversation_ForwardAuthorHiddenTooltip: String { return self._s[1967]! } - public var AutoDownloadSettings_DataUsageCustom: String { return self._s[1968]! } - public var Common_Search: String { return self._s[1969]! } - public var ScheduledMessages_EmptyPlaceholder: String { return self._s[1970]! } + public var ReportPeer_ReasonSpam: String { return self._s[1970]! } + public var UserInfo_TapToCall: String { return self._s[1971]! } + public var Conversation_ForwardAuthorHiddenTooltip: String { return self._s[1973]! } + public var AutoDownloadSettings_DataUsageCustom: String { return self._s[1974]! } + public var Common_Search: String { return self._s[1975]! } + public var ScheduledMessages_EmptyPlaceholder: String { return self._s[1976]! } public func Channel_AdminLog_MessageChangedGroupGeoLocation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1971]!, self._r[1971]!, [_0]) + return formatWithArgumentRanges(self._s[1977]!, self._r[1977]!, [_0]) } - public var Wallet_Month_ShortJuly: String { return self._s[1972]! } - public var AuthSessions_IncompleteAttemptsInfo: String { return self._s[1974]! } - public var Message_InvoiceLabel: String { return self._s[1975]! } - public var Conversation_InputTextPlaceholder: String { return self._s[1976]! } - public var NetworkUsageSettings_MediaImageDataSection: String { return self._s[1977]! } + public var Wallet_Month_ShortJuly: String { return self._s[1978]! } + public var AuthSessions_IncompleteAttemptsInfo: String { return self._s[1980]! } + public var Message_InvoiceLabel: String { return self._s[1981]! } + public var Conversation_InputTextPlaceholder: String { return self._s[1982]! } + public var NetworkUsageSettings_MediaImageDataSection: String { return self._s[1983]! } public func Passport_Address_UploadOneOfScan(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1978]!, self._r[1978]!, [_0]) + return formatWithArgumentRanges(self._s[1984]!, self._r[1984]!, [_0]) } - public var IntentsSettings_Reset: String { return self._s[1979]! } - public var Conversation_Info: String { return self._s[1980]! } - public var Login_InfoDeletePhoto: String { return self._s[1981]! } - public var Passport_Language_vi: String { return self._s[1983]! } - public var UserInfo_ScamUserWarning: String { return self._s[1984]! } - public var Conversation_Search: String { return self._s[1985]! } - public var DialogList_DeleteBotConversationConfirmation: String { return self._s[1987]! } - public var ReportPeer_ReasonPornography: String { return self._s[1988]! } - public var AutoDownloadSettings_PhotosTitle: String { return self._s[1989]! } - public var Conversation_SendMessageErrorGroupRestricted: String { return self._s[1990]! } - public var Map_LiveLocationGroupDescription: String { return self._s[1991]! } - public var Channel_Setup_TypeHeader: String { return self._s[1992]! } - public var AuthSessions_LoggedIn: String { return self._s[1993]! } - public var Privacy_Forwards_AlwaysAllow_Title: String { return self._s[1994]! } - public var Login_SmsRequestState3: String { return self._s[1995]! } - public var Passport_Address_EditUtilityBill: String { return self._s[1996]! } - public var Appearance_ReduceMotionInfo: String { return self._s[1997]! } - public var Join_ChannelsTooMuch: String { return self._s[1998]! } - public var Channel_Edit_LinkItem: String { return self._s[1999]! } - public var Privacy_Calls_P2PNever: String { return self._s[2000]! } - public var Conversation_AddToReadingList: String { return self._s[2002]! } - public var Share_MultipleMessagesDisabled: String { return self._s[2003]! } - public var Message_Animation: String { return self._s[2004]! } - public var Conversation_DefaultRestrictedMedia: String { return self._s[2005]! } - public var Map_Unknown: String { return self._s[2006]! } - public var AutoDownloadSettings_LastDelimeter: String { return self._s[2007]! } + public var IntentsSettings_Reset: String { return self._s[1985]! } + public var Conversation_Info: String { return self._s[1986]! } + public var Login_InfoDeletePhoto: String { return self._s[1987]! } + public var Passport_Language_vi: String { return self._s[1989]! } + public var UserInfo_ScamUserWarning: String { return self._s[1990]! } + public var Conversation_Search: String { return self._s[1991]! } + public var DialogList_DeleteBotConversationConfirmation: String { return self._s[1993]! } + public var ReportPeer_ReasonPornography: String { return self._s[1994]! } + public var AutoDownloadSettings_PhotosTitle: String { return self._s[1995]! } + public var Conversation_SendMessageErrorGroupRestricted: String { return self._s[1996]! } + public var Map_LiveLocationGroupDescription: String { return self._s[1997]! } + public var Channel_Setup_TypeHeader: String { return self._s[1998]! } + public var AuthSessions_LoggedIn: String { return self._s[1999]! } + public var Privacy_Forwards_AlwaysAllow_Title: String { return self._s[2000]! } + public var Login_SmsRequestState3: String { return self._s[2001]! } + public var Passport_Address_EditUtilityBill: String { return self._s[2002]! } + public var Appearance_ReduceMotionInfo: String { return self._s[2003]! } + public var Join_ChannelsTooMuch: String { return self._s[2004]! } + public var Channel_Edit_LinkItem: String { return self._s[2005]! } + public var Privacy_Calls_P2PNever: String { return self._s[2006]! } + public var Conversation_AddToReadingList: String { return self._s[2008]! } + public var Share_MultipleMessagesDisabled: String { return self._s[2009]! } + public var Message_Animation: String { return self._s[2010]! } + public var Conversation_DefaultRestrictedMedia: String { return self._s[2011]! } + public var Map_Unknown: String { return self._s[2012]! } + public var AutoDownloadSettings_LastDelimeter: String { return self._s[2013]! } public func PUSH_PINNED_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2008]!, self._r[2008]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2014]!, self._r[2014]!, [_1, _2]) } public func Passport_FieldOneOf_Or(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2009]!, self._r[2009]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2015]!, self._r[2015]!, [_1, _2]) } - public var Call_StatusRequesting: String { return self._s[2010]! } - public var Conversation_SecretChatContextBotAlert: String { return self._s[2011]! } - public var SocksProxySetup_ProxyStatusChecking: String { return self._s[2012]! } + public var Call_StatusRequesting: String { return self._s[2016]! } + public var Conversation_SecretChatContextBotAlert: String { return self._s[2017]! } + public var SocksProxySetup_ProxyStatusChecking: String { return self._s[2018]! } public func PUSH_CHAT_MESSAGE_DOC(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2013]!, self._r[2013]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2019]!, self._r[2019]!, [_1, _2]) } public func Notification_PinnedLocationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2014]!, self._r[2014]!, [_0]) + return formatWithArgumentRanges(self._s[2020]!, self._r[2020]!, [_0]) } - public var Update_Skip: String { return self._s[2015]! } - public var Group_Username_RemoveExistingUsernamesInfo: String { return self._s[2016]! } - public var Message_PinnedPollMessage: String { return self._s[2017]! } - public var BlockedUsers_Title: String { return self._s[2018]! } + public var Update_Skip: String { return self._s[2021]! } + public var Group_Username_RemoveExistingUsernamesInfo: String { return self._s[2022]! } + public var Message_PinnedPollMessage: String { return self._s[2023]! } + public var BlockedUsers_Title: String { return self._s[2024]! } public func PUSH_CHANNEL_MESSAGE_AUDIO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2019]!, self._r[2019]!, [_1]) + return formatWithArgumentRanges(self._s[2025]!, self._r[2025]!, [_1]) } - public var Username_CheckingUsername: String { return self._s[2020]! } - public var NotificationsSound_Bell: String { return self._s[2021]! } - public var Conversation_SendMessageErrorFlood: String { return self._s[2022]! } - public var Weekday_Monday: String { return self._s[2023]! } - public var SettingsSearch_Synonyms_Notifications_DisplayNamesOnLockScreen: String { return self._s[2024]! } - public var ChannelMembers_ChannelAdminsTitle: String { return self._s[2025]! } - public var ChatSettings_Groups: String { return self._s[2026]! } - public var WallpaperPreview_PatternPaternDiscard: String { return self._s[2027]! } + public var Username_CheckingUsername: String { return self._s[2026]! } + public var NotificationsSound_Bell: String { return self._s[2027]! } + public var Conversation_SendMessageErrorFlood: String { return self._s[2028]! } + public var Weekday_Monday: String { return self._s[2029]! } + public var SettingsSearch_Synonyms_Notifications_DisplayNamesOnLockScreen: String { return self._s[2030]! } + public var ChannelMembers_ChannelAdminsTitle: String { return self._s[2031]! } + public var ChatSettings_Groups: String { return self._s[2032]! } + public var WallpaperPreview_PatternPaternDiscard: String { return self._s[2033]! } public func Conversation_SetReminder_RemindTomorrow(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2028]!, self._r[2028]!, [_0]) + return formatWithArgumentRanges(self._s[2034]!, self._r[2034]!, [_0]) } - public var Your_card_was_declined: String { return self._s[2029]! } - public var TwoStepAuth_EnterPasswordHelp: String { return self._s[2031]! } - public var Wallet_Month_ShortApril: String { return self._s[2032]! } - public var ChatList_Unmute: String { return self._s[2033]! } - public var AuthSessions_AddDevice_ScanTitle: String { return self._s[2034]! } - public var PhotoEditor_CurvesAll: String { return self._s[2035]! } - public var Weekday_ShortTuesday: String { return self._s[2036]! } - public var DialogList_Read: String { return self._s[2037]! } - public var Appearance_AppIconClassic: String { return self._s[2038]! } - public var ChannelMembers_WhoCanAddMembers_AllMembers: String { return self._s[2039]! } - public var Passport_Identity_Gender: String { return self._s[2040]! } + public var Your_card_was_declined: String { return self._s[2035]! } + public var TwoStepAuth_EnterPasswordHelp: String { return self._s[2037]! } + public var Wallet_Month_ShortApril: String { return self._s[2038]! } + public var ChatList_Unmute: String { return self._s[2039]! } + public var AuthSessions_AddDevice_ScanTitle: String { return self._s[2040]! } + public var PhotoEditor_CurvesAll: String { return self._s[2041]! } + public var Weekday_ShortTuesday: String { return self._s[2042]! } + public var DialogList_Read: String { return self._s[2043]! } + public var Appearance_AppIconClassic: String { return self._s[2044]! } + public var ChannelMembers_WhoCanAddMembers_AllMembers: String { return self._s[2045]! } + public var Passport_Identity_Gender: String { return self._s[2046]! } public func Target_ShareGameConfirmationPrivate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2041]!, self._r[2041]!, [_0]) + return formatWithArgumentRanges(self._s[2047]!, self._r[2047]!, [_0]) } - public var Target_SelectGroup: String { return self._s[2042]! } - public var Map_HomeAndWorkInfo: String { return self._s[2044]! } + public var Target_SelectGroup: String { return self._s[2048]! } + public var Map_HomeAndWorkInfo: String { return self._s[2050]! } public func DialogList_EncryptedChatStartedIncoming(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2045]!, self._r[2045]!, [_0]) + return formatWithArgumentRanges(self._s[2051]!, self._r[2051]!, [_0]) } - public var Passport_Language_en: String { return self._s[2046]! } - public var AutoDownloadSettings_AutodownloadPhotos: String { return self._s[2047]! } - public var Channel_Username_CreatePublicLinkHelp: String { return self._s[2048]! } - public var Login_CancelPhoneVerificationContinue: String { return self._s[2049]! } - public var ScheduledMessages_SendNow: String { return self._s[2050]! } - public var Checkout_NewCard_PaymentCard: String { return self._s[2052]! } - public var Login_InfoHelp: String { return self._s[2053]! } - public var Contacts_PermissionsSuppressWarningTitle: String { return self._s[2054]! } - public var SettingsSearch_Synonyms_Stickers_FeaturedPacks: String { return self._s[2055]! } + public var Passport_Language_en: String { return self._s[2052]! } + public var AutoDownloadSettings_AutodownloadPhotos: String { return self._s[2053]! } + public var Channel_Username_CreatePublicLinkHelp: String { return self._s[2054]! } + public var Login_CancelPhoneVerificationContinue: String { return self._s[2055]! } + public var ScheduledMessages_SendNow: String { return self._s[2056]! } + public var Checkout_NewCard_PaymentCard: String { return self._s[2058]! } + public var Login_InfoHelp: String { return self._s[2059]! } + public var Contacts_PermissionsSuppressWarningTitle: String { return self._s[2060]! } + public var SettingsSearch_Synonyms_Stickers_FeaturedPacks: String { return self._s[2061]! } public func Channel_AdminLog_MessageChangedLinkedChannel(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2056]!, self._r[2056]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2062]!, self._r[2062]!, [_1, _2]) } - public var SocksProxySetup_AddProxy: String { return self._s[2059]! } - public var CreatePoll_Title: String { return self._s[2060]! } - public var MessagePoll_QuizNoUsers: String { return self._s[2061]! } - public var Conversation_ViewTheme: String { return self._s[2062]! } - public var SettingsSearch_Synonyms_Privacy_Data_SecretChatLinkPreview: String { return self._s[2063]! } - public var PasscodeSettings_SimplePasscodeHelp: String { return self._s[2064]! } - public var TwoFactorSetup_Intro_Text: String { return self._s[2065]! } - public var UserInfo_GroupsInCommon: String { return self._s[2066]! } - public var TelegramWallet_Intro_TermsUrl: String { return self._s[2067]! } - public var Call_AudioRouteHide: String { return self._s[2068]! } + public var SocksProxySetup_AddProxy: String { return self._s[2065]! } + public var CreatePoll_Title: String { return self._s[2066]! } + public var MessagePoll_QuizNoUsers: String { return self._s[2067]! } + public var Conversation_ViewTheme: String { return self._s[2068]! } + public var SettingsSearch_Synonyms_Privacy_Data_SecretChatLinkPreview: String { return self._s[2069]! } + public var PasscodeSettings_SimplePasscodeHelp: String { return self._s[2070]! } + public var TwoFactorSetup_Intro_Text: String { return self._s[2071]! } + public var UserInfo_GroupsInCommon: String { return self._s[2072]! } + public var TelegramWallet_Intro_TermsUrl: String { return self._s[2073]! } + public var Call_AudioRouteHide: String { return self._s[2074]! } public func Wallet_Info_TransactionDateHeader(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2070]!, self._r[2070]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2076]!, self._r[2076]!, [_1, _2]) } - public var ContactInfo_PhoneLabelMobile: String { return self._s[2071]! } - public var IntentsSettings_SuggestedChatsInfo: String { return self._s[2072]! } - public var CreatePoll_QuizOptionsHeader: String { return self._s[2073]! } + public var ContactInfo_PhoneLabelMobile: String { return self._s[2077]! } + public var IntentsSettings_SuggestedChatsInfo: String { return self._s[2078]! } + public var CreatePoll_QuizOptionsHeader: String { return self._s[2079]! } public func ChatList_LeaveGroupConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2074]!, self._r[2074]!, [_0]) + return formatWithArgumentRanges(self._s[2080]!, self._r[2080]!, [_0]) } - public var TextFormat_Bold: String { return self._s[2075]! } - public var FastTwoStepSetup_EmailSection: String { return self._s[2076]! } - public var StickerPackActionInfo_AddedTitle: String { return self._s[2077]! } - public var Notifications_Title: String { return self._s[2078]! } - public var Group_Username_InvalidTooShort: String { return self._s[2079]! } - public var Channel_ErrorAddTooMuch: String { return self._s[2080]! } + public var TextFormat_Bold: String { return self._s[2081]! } + public var FastTwoStepSetup_EmailSection: String { return self._s[2082]! } + public var StickerPackActionInfo_AddedTitle: String { return self._s[2083]! } + public var Notifications_Title: String { return self._s[2084]! } + public var Group_Username_InvalidTooShort: String { return self._s[2085]! } + public var Channel_ErrorAddTooMuch: String { return self._s[2086]! } public func DialogList_MultipleTypingSuffix(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2081]!, self._r[2081]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[2087]!, self._r[2087]!, ["\(_0)"]) } - public var VoiceOver_DiscardPreparedContent: String { return self._s[2083]! } - public var Stickers_SuggestAdded: String { return self._s[2084]! } - public var Login_CountryCode: String { return self._s[2085]! } - public var ChatSettings_AutoPlayVideos: String { return self._s[2086]! } - public var Map_GetDirections: String { return self._s[2087]! } - public var Wallet_Receive_ShareInvoiceUrl: String { return self._s[2088]! } - public var Login_PhoneFloodError: String { return self._s[2089]! } + public var VoiceOver_DiscardPreparedContent: String { return self._s[2089]! } + public var Stickers_SuggestAdded: String { return self._s[2090]! } + public var Login_CountryCode: String { return self._s[2091]! } + public var ChatSettings_AutoPlayVideos: String { return self._s[2092]! } + public var Map_GetDirections: String { return self._s[2093]! } + public var Wallet_Receive_ShareInvoiceUrl: String { return self._s[2094]! } + public var Login_PhoneFloodError: String { return self._s[2095]! } public func Time_MonthOfYear_m3(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2090]!, self._r[2090]!, [_0]) + return formatWithArgumentRanges(self._s[2096]!, self._r[2096]!, [_0]) } public func Wallet_Time_PreciseDate_m10(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2091]!, self._r[2091]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2097]!, self._r[2097]!, [_1, _2, _3]) } - public var IntentsSettings_SuggestedChatsPrivateChats: String { return self._s[2092]! } - public var Settings_SetUsername: String { return self._s[2094]! } - public var Group_Location_ChangeLocation: String { return self._s[2095]! } - public var Notification_GroupInviterSelf: String { return self._s[2096]! } - public var InstantPage_TapToOpenLink: String { return self._s[2097]! } + public var IntentsSettings_SuggestedChatsPrivateChats: String { return self._s[2098]! } + public var Settings_SetUsername: String { return self._s[2100]! } + public var Group_Location_ChangeLocation: String { return self._s[2101]! } + public var Notification_GroupInviterSelf: String { return self._s[2102]! } + public var InstantPage_TapToOpenLink: String { return self._s[2103]! } public func Notification_ChannelInviter(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2098]!, self._r[2098]!, [_0]) + return formatWithArgumentRanges(self._s[2104]!, self._r[2104]!, [_0]) } - public var Watch_Suggestion_TalkLater: String { return self._s[2099]! } - public var SecretChat_Title: String { return self._s[2100]! } - public var Group_UpgradeNoticeText1: String { return self._s[2101]! } - public var AuthSessions_Title: String { return self._s[2102]! } + public var Watch_Suggestion_TalkLater: String { return self._s[2105]! } + public var SecretChat_Title: String { return self._s[2106]! } + public var Group_UpgradeNoticeText1: String { return self._s[2107]! } + public var AuthSessions_Title: String { return self._s[2108]! } public func TextFormat_AddLinkText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2103]!, self._r[2103]!, [_0]) + return formatWithArgumentRanges(self._s[2109]!, self._r[2109]!, [_0]) } - public var PhotoEditor_CropAuto: String { return self._s[2104]! } - public var Channel_About_Title: String { return self._s[2105]! } - public var Theme_ThemeChanged: String { return self._s[2106]! } - public var FastTwoStepSetup_EmailHelp: String { return self._s[2107]! } + public var PhotoEditor_CropAuto: String { return self._s[2110]! } + public var Channel_About_Title: String { return self._s[2111]! } + public var Theme_ThemeChanged: String { return self._s[2112]! } + public var FastTwoStepSetup_EmailHelp: String { return self._s[2113]! } public func Conversation_Bytes(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2109]!, self._r[2109]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[2115]!, self._r[2115]!, ["\(_0)"]) } - public var VoiceOver_MessageContextReport: String { return self._s[2110]! } - public var Conversation_PinMessageAlert_OnlyPin: String { return self._s[2112]! } - public var Group_Setup_HistoryVisibleHelp: String { return self._s[2113]! } + public var VoiceOver_MessageContextReport: String { return self._s[2116]! } + public var Conversation_PinMessageAlert_OnlyPin: String { return self._s[2118]! } + public var Group_Setup_HistoryVisibleHelp: String { return self._s[2119]! } public func PUSH_MESSAGE_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2114]!, self._r[2114]!, [_1]) + return formatWithArgumentRanges(self._s[2120]!, self._r[2120]!, [_1]) } public func SharedMedia_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2116]!, self._r[2116]!, [_0]) + return formatWithArgumentRanges(self._s[2122]!, self._r[2122]!, [_0]) } public func TwoStepAuth_RecoveryEmailUnavailable(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2117]!, self._r[2117]!, [_0]) + return formatWithArgumentRanges(self._s[2123]!, self._r[2123]!, [_0]) } - public var Privacy_PaymentsClearInfoHelp: String { return self._s[2118]! } - public var Presence_online: String { return self._s[2121]! } - public var PasscodeSettings_Title: String { return self._s[2122]! } - public var Passport_Identity_ExpiryDatePlaceholder: String { return self._s[2123]! } - public var Web_OpenExternal: String { return self._s[2124]! } - public var AutoDownloadSettings_AutoDownload: String { return self._s[2126]! } - public var Channel_OwnershipTransfer_EnterPasswordText: String { return self._s[2127]! } - public var LocalGroup_Title: String { return self._s[2128]! } + public var Privacy_PaymentsClearInfoHelp: String { return self._s[2124]! } + public var PeopleNearby_DiscoverDescription: String { return self._s[2126]! } + public var Presence_online: String { return self._s[2128]! } + public var PasscodeSettings_Title: String { return self._s[2129]! } + public var Passport_Identity_ExpiryDatePlaceholder: String { return self._s[2130]! } + public var Web_OpenExternal: String { return self._s[2131]! } + public var AutoDownloadSettings_AutoDownload: String { return self._s[2133]! } + public var Channel_OwnershipTransfer_EnterPasswordText: String { return self._s[2134]! } + public var LocalGroup_Title: String { return self._s[2135]! } public func AutoNightTheme_AutomaticHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2129]!, self._r[2129]!, [_0]) + return formatWithArgumentRanges(self._s[2136]!, self._r[2136]!, [_0]) } - public var FastTwoStepSetup_PasswordConfirmationPlaceholder: String { return self._s[2130]! } - public var Conversation_StopQuizConfirmation: String { return self._s[2131]! } - public var Map_YouAreHere: String { return self._s[2132]! } + public var FastTwoStepSetup_PasswordConfirmationPlaceholder: String { return self._s[2137]! } + public var Conversation_StopQuizConfirmation: String { return self._s[2138]! } + public var Map_YouAreHere: String { return self._s[2139]! } public func AuthSessions_Message(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2133]!, self._r[2133]!, [_0]) + return formatWithArgumentRanges(self._s[2140]!, self._r[2140]!, [_0]) } public func ChatList_DeleteChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2134]!, self._r[2134]!, [_0]) + return formatWithArgumentRanges(self._s[2141]!, self._r[2141]!, [_0]) } - public var Theme_Context_ChangeColors: String { return self._s[2135]! } - public var PrivacyLastSeenSettings_AlwaysShareWith: String { return self._s[2136]! } - public var Target_InviteToGroupErrorAlreadyInvited: String { return self._s[2137]! } + public var Theme_Context_ChangeColors: String { return self._s[2142]! } + public var PrivacyLastSeenSettings_AlwaysShareWith: String { return self._s[2143]! } + public var Target_InviteToGroupErrorAlreadyInvited: String { return self._s[2144]! } public func AuthSessions_AppUnofficial(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2138]!, self._r[2138]!, [_0]) + return formatWithArgumentRanges(self._s[2145]!, self._r[2145]!, [_0]) } public func DialogList_LiveLocationSharingTo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2139]!, self._r[2139]!, [_0]) + return formatWithArgumentRanges(self._s[2146]!, self._r[2146]!, [_0]) } - public var SocksProxySetup_Username: String { return self._s[2140]! } - public var Bot_Start: String { return self._s[2141]! } + public var SocksProxySetup_Username: String { return self._s[2147]! } + public var Bot_Start: String { return self._s[2148]! } public func Channel_AdminLog_EmptyFilterQueryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2142]!, self._r[2142]!, [_0]) - } - public func Channel_AdminLog_MessagePinned(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2143]!, self._r[2143]!, [_0]) - } - public var Contacts_SortByPresence: String { return self._s[2144]! } - public var AccentColor_Title: String { return self._s[2146]! } - public var Conversation_DiscardVoiceMessageTitle: String { return self._s[2147]! } - public func PUSH_CHAT_CREATED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2148]!, self._r[2148]!, [_1, _2]) - } - public func PrivacySettings_LastSeenContactsMinus(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2149]!, self._r[2149]!, [_0]) } + public func Channel_AdminLog_MessagePinned(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2150]!, self._r[2150]!, [_0]) + } + public var Contacts_SortByPresence: String { return self._s[2151]! } + public var AccentColor_Title: String { return self._s[2153]! } + public var Conversation_DiscardVoiceMessageTitle: String { return self._s[2154]! } + public func PUSH_CHAT_CREATED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2155]!, self._r[2155]!, [_1, _2]) + } + public func PrivacySettings_LastSeenContactsMinus(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2156]!, self._r[2156]!, [_0]) + } public func Channel_AdminLog_MessageChangedLinkedGroup(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2150]!, self._r[2150]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2157]!, self._r[2157]!, [_1, _2]) } - public var Passport_Email_EnterOtherEmail: String { return self._s[2151]! } - public var Login_InfoAvatarPhoto: String { return self._s[2152]! } - public var Privacy_PaymentsClear_ShippingInfo: String { return self._s[2153]! } - public var Tour_Title4: String { return self._s[2154]! } - public var Passport_Identity_Translation: String { return self._s[2155]! } - public var SettingsSearch_Synonyms_Notifications_ContactJoined: String { return self._s[2156]! } - public var Login_TermsOfServiceLabel: String { return self._s[2158]! } - public var Passport_Language_it: String { return self._s[2159]! } - public var KeyCommand_JumpToNextUnreadChat: String { return self._s[2160]! } - public var Passport_Identity_SelfieHelp: String { return self._s[2161]! } - public var Conversation_ClearAll: String { return self._s[2163]! } - public var Wallet_Send_UninitializedText: String { return self._s[2165]! } - public var Channel_OwnershipTransfer_Title: String { return self._s[2166]! } - public var TwoStepAuth_FloodError: String { return self._s[2167]! } + public var Passport_Email_EnterOtherEmail: String { return self._s[2158]! } + public var Login_InfoAvatarPhoto: String { return self._s[2159]! } + public var Privacy_PaymentsClear_ShippingInfo: String { return self._s[2160]! } + public var Tour_Title4: String { return self._s[2161]! } + public var Passport_Identity_Translation: String { return self._s[2162]! } + public var SettingsSearch_Synonyms_Notifications_ContactJoined: String { return self._s[2163]! } + public var Login_TermsOfServiceLabel: String { return self._s[2165]! } + public var Passport_Language_it: String { return self._s[2166]! } + public var KeyCommand_JumpToNextUnreadChat: String { return self._s[2167]! } + public var Passport_Identity_SelfieHelp: String { return self._s[2168]! } + public var Conversation_ClearAll: String { return self._s[2170]! } + public var Wallet_Send_UninitializedText: String { return self._s[2172]! } + public var Channel_OwnershipTransfer_Title: String { return self._s[2173]! } + public var TwoStepAuth_FloodError: String { return self._s[2174]! } public func PUSH_CHANNEL_MESSAGE_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2168]!, self._r[2168]!, [_1]) + return formatWithArgumentRanges(self._s[2175]!, self._r[2175]!, [_1]) } - public var Paint_Delete: String { return self._s[2169]! } + public var Paint_Delete: String { return self._s[2176]! } public func Wallet_Sent_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2170]!, self._r[2170]!, [_0]) + return formatWithArgumentRanges(self._s[2177]!, self._r[2177]!, [_0]) } - public var Privacy_AddNewPeer: String { return self._s[2171]! } + public var Privacy_AddNewPeer: String { return self._s[2178]! } public func Channel_AdminLog_MessageRank(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2172]!, self._r[2172]!, [_1]) + return formatWithArgumentRanges(self._s[2179]!, self._r[2179]!, [_1]) } - public var LogoutOptions_SetPasscodeText: String { return self._s[2173]! } + public var LogoutOptions_SetPasscodeText: String { return self._s[2180]! } public func Passport_AcceptHelp(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2174]!, self._r[2174]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2181]!, self._r[2181]!, [_1, _2]) } - public var Message_PinnedAudioMessage: String { return self._s[2175]! } + public var Message_PinnedAudioMessage: String { return self._s[2182]! } public func Watch_Time_ShortTodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2176]!, self._r[2176]!, [_0]) + return formatWithArgumentRanges(self._s[2183]!, self._r[2183]!, [_0]) } - public var Notification_Mute1hMin: String { return self._s[2177]! } - public var Notifications_GroupNotificationsSound: String { return self._s[2178]! } - public var Wallet_Month_GenNovember: String { return self._s[2179]! } - public var SocksProxySetup_ShareProxyList: String { return self._s[2180]! } - public var Conversation_MessageEditedLabel: String { return self._s[2181]! } + public var Notification_Mute1hMin: String { return self._s[2184]! } + public var Notifications_GroupNotificationsSound: String { return self._s[2185]! } + public var Wallet_Month_GenNovember: String { return self._s[2186]! } + public var SocksProxySetup_ShareProxyList: String { return self._s[2187]! } + public var Conversation_MessageEditedLabel: String { return self._s[2188]! } public func ClearCache_Success(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2182]!, self._r[2182]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2189]!, self._r[2189]!, [_0, _1]) } - public var Notification_Exceptions_AlwaysOff: String { return self._s[2183]! } - public var Notification_Exceptions_NewException_MessagePreviewHeader: String { return self._s[2184]! } + public var Notification_Exceptions_AlwaysOff: String { return self._s[2190]! } + public var Notification_Exceptions_NewException_MessagePreviewHeader: String { return self._s[2191]! } public func Channel_AdminLog_MessageAdmin(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2185]!, self._r[2185]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[2192]!, self._r[2192]!, [_0, _1, _2]) } - public var NetworkUsageSettings_ResetStats: String { return self._s[2186]! } + public var NetworkUsageSettings_ResetStats: String { return self._s[2193]! } public func PUSH_MESSAGE_GEOLIVE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2187]!, self._r[2187]!, [_1]) + return formatWithArgumentRanges(self._s[2194]!, self._r[2194]!, [_1]) } - public var AccessDenied_LocationTracking: String { return self._s[2188]! } - public var Month_GenOctober: String { return self._s[2189]! } - public var GroupInfo_InviteLink_RevokeAlert_Revoke: String { return self._s[2190]! } - public var EnterPasscode_EnterPasscode: String { return self._s[2191]! } - public var MediaPicker_TimerTooltip: String { return self._s[2193]! } - public var SharedMedia_TitleAll: String { return self._s[2194]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsExceptions: String { return self._s[2197]! } - public var Conversation_RestrictedMedia: String { return self._s[2198]! } - public var AccessDenied_PhotosRestricted: String { return self._s[2199]! } - public var Privacy_Forwards_WhoCanForward: String { return self._s[2201]! } - public var ChangePhoneNumberCode_Called: String { return self._s[2202]! } + public var AccessDenied_LocationTracking: String { return self._s[2195]! } + public var Month_GenOctober: String { return self._s[2196]! } + public var GroupInfo_InviteLink_RevokeAlert_Revoke: String { return self._s[2197]! } + public var EnterPasscode_EnterPasscode: String { return self._s[2198]! } + public var MediaPicker_TimerTooltip: String { return self._s[2200]! } + public var SharedMedia_TitleAll: String { return self._s[2201]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsExceptions: String { return self._s[2204]! } + public var Conversation_RestrictedMedia: String { return self._s[2205]! } + public var AccessDenied_PhotosRestricted: String { return self._s[2206]! } + public var Privacy_Forwards_WhoCanForward: String { return self._s[2208]! } + public var ChangePhoneNumberCode_Called: String { return self._s[2209]! } public func Notification_PinnedDocumentMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2203]!, self._r[2203]!, [_0]) + return formatWithArgumentRanges(self._s[2210]!, self._r[2210]!, [_0]) } - public var Conversation_SavedMessages: String { return self._s[2206]! } - public var Your_cards_expiration_month_is_invalid: String { return self._s[2208]! } - public var FastTwoStepSetup_PasswordPlaceholder: String { return self._s[2209]! } + public var Conversation_SavedMessages: String { return self._s[2213]! } + public var Your_cards_expiration_month_is_invalid: String { return self._s[2215]! } + public var FastTwoStepSetup_PasswordPlaceholder: String { return self._s[2216]! } public func Target_ShareGameConfirmationGroup(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2211]!, self._r[2211]!, [_0]) + return formatWithArgumentRanges(self._s[2218]!, self._r[2218]!, [_0]) } - public var VoiceOver_Chat_YourMessage: String { return self._s[2212]! } + public var VoiceOver_Chat_YourMessage: String { return self._s[2219]! } public func VoiceOver_Chat_Title(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2213]!, self._r[2213]!, [_0]) + return formatWithArgumentRanges(self._s[2220]!, self._r[2220]!, [_0]) } - public var ReportPeer_AlertSuccess: String { return self._s[2214]! } - public var PhotoEditor_CropAspectRatioOriginal: String { return self._s[2215]! } + public var ReportPeer_AlertSuccess: String { return self._s[2221]! } + public var PhotoEditor_CropAspectRatioOriginal: String { return self._s[2222]! } public func InstantPage_RelatedArticleAuthorAndDateTitle(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2216]!, self._r[2216]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2223]!, self._r[2223]!, [_1, _2]) } - public var Checkout_PasswordEntry_Title: String { return self._s[2217]! } - public var PhotoEditor_FadeTool: String { return self._s[2218]! } - public var Privacy_ContactsReset: String { return self._s[2219]! } + public var Checkout_PasswordEntry_Title: String { return self._s[2224]! } + public var PhotoEditor_FadeTool: String { return self._s[2225]! } + public var Privacy_ContactsReset: String { return self._s[2226]! } public func Channel_AdminLog_MessageRestrictedUntil(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2221]!, self._r[2221]!, [_0]) + return formatWithArgumentRanges(self._s[2228]!, self._r[2228]!, [_0]) } - public var Message_PinnedVideoMessage: String { return self._s[2222]! } - public var ChatList_Mute: String { return self._s[2223]! } + public var Message_PinnedVideoMessage: String { return self._s[2229]! } + public var ChatList_Mute: String { return self._s[2230]! } public func Wallet_Time_PreciseDate_m5(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2224]!, self._r[2224]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2231]!, self._r[2231]!, [_1, _2, _3]) } - public var Permissions_CellularDataText_v0: String { return self._s[2225]! } - public var ShareMenu_SelectChats: String { return self._s[2228]! } - public var ChatList_Context_Unarchive: String { return self._s[2229]! } - public var MusicPlayer_VoiceNote: String { return self._s[2230]! } - public var Conversation_RestrictedText: String { return self._s[2231]! } - public var SettingsSearch_Synonyms_Privacy_Data_DeleteDrafts: String { return self._s[2232]! } - public var Wallet_Month_GenApril: String { return self._s[2233]! } - public var Wallet_Month_ShortMarch: String { return self._s[2234]! } - public var TwoStepAuth_DisableSuccess: String { return self._s[2235]! } - public var Cache_Videos: String { return self._s[2236]! } - public var PrivacySettings_PhoneNumber: String { return self._s[2237]! } - public var Wallet_Month_GenFebruary: String { return self._s[2238]! } - public var FeatureDisabled_Oops: String { return self._s[2240]! } - public var Passport_Address_PostcodePlaceholder: String { return self._s[2241]! } + public var Permissions_CellularDataText_v0: String { return self._s[2232]! } + public var ShareMenu_SelectChats: String { return self._s[2235]! } + public var ChatList_Context_Unarchive: String { return self._s[2236]! } + public var MusicPlayer_VoiceNote: String { return self._s[2237]! } + public var Conversation_RestrictedText: String { return self._s[2238]! } + public var SettingsSearch_Synonyms_Privacy_Data_DeleteDrafts: String { return self._s[2239]! } + public var Wallet_Month_GenApril: String { return self._s[2240]! } + public var Wallet_Month_ShortMarch: String { return self._s[2241]! } + public var TwoStepAuth_DisableSuccess: String { return self._s[2242]! } + public var Cache_Videos: String { return self._s[2243]! } + public var PrivacySettings_PhoneNumber: String { return self._s[2244]! } + public var Wallet_Month_GenFebruary: String { return self._s[2245]! } + public var FeatureDisabled_Oops: String { return self._s[2247]! } + public var Passport_Address_PostcodePlaceholder: String { return self._s[2248]! } public func AddContact_StatusSuccess(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2242]!, self._r[2242]!, [_0]) + return formatWithArgumentRanges(self._s[2249]!, self._r[2249]!, [_0]) } - public var Stickers_GroupStickersHelp: String { return self._s[2243]! } - public var GroupPermission_NoSendPolls: String { return self._s[2244]! } - public var Wallet_Qr_ScanCode: String { return self._s[2245]! } - public var Message_VideoExpired: String { return self._s[2247]! } - public var GroupInfo_GroupHistoryVisible: String { return self._s[2248]! } - public var Notifications_Badge: String { return self._s[2249]! } - public var Wallet_Receive_AddressCopied: String { return self._s[2250]! } - public var CreatePoll_OptionPlaceholder: String { return self._s[2251]! } - public var Username_InvalidTooShort: String { return self._s[2252]! } - public var EnterPasscode_EnterNewPasscodeChange: String { return self._s[2253]! } - public var Channel_AdminLog_PinMessages: String { return self._s[2254]! } - public var ArchivedChats_IntroTitle3: String { return self._s[2255]! } + public var Stickers_GroupStickersHelp: String { return self._s[2251]! } + public var GroupPermission_NoSendPolls: String { return self._s[2252]! } + public var Wallet_Qr_ScanCode: String { return self._s[2253]! } + public var Message_VideoExpired: String { return self._s[2255]! } + public var GroupInfo_GroupHistoryVisible: String { return self._s[2256]! } + public var Notifications_Badge: String { return self._s[2257]! } + public var Wallet_Receive_AddressCopied: String { return self._s[2258]! } + public var CreatePoll_OptionPlaceholder: String { return self._s[2259]! } + public var Username_InvalidTooShort: String { return self._s[2260]! } + public var EnterPasscode_EnterNewPasscodeChange: String { return self._s[2261]! } + public var Channel_AdminLog_PinMessages: String { return self._s[2262]! } + public var ArchivedChats_IntroTitle3: String { return self._s[2263]! } public func Notification_MessageLifetimeRemoved(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2256]!, self._r[2256]!, [_1]) + return formatWithArgumentRanges(self._s[2264]!, self._r[2264]!, [_1]) } - public var Permissions_SiriAllowInSettings_v0: String { return self._s[2257]! } - public var Conversation_DefaultRestrictedText: String { return self._s[2258]! } - public var SharedMedia_CategoryDocs: String { return self._s[2261]! } + public var Permissions_SiriAllowInSettings_v0: String { return self._s[2265]! } + public var Conversation_DefaultRestrictedText: String { return self._s[2266]! } + public var SharedMedia_CategoryDocs: String { return self._s[2269]! } public func PUSH_MESSAGE_CONTACT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2262]!, self._r[2262]!, [_1]) + return formatWithArgumentRanges(self._s[2270]!, self._r[2270]!, [_1]) } - public var Wallet_Send_UninitializedTitle: String { return self._s[2263]! } - public var StickerPackActionInfo_ArchivedTitle: String { return self._s[2264]! } - public var Privacy_Forwards_NeverLink: String { return self._s[2266]! } + public var Wallet_Send_UninitializedTitle: String { return self._s[2271]! } + public var StickerPackActionInfo_ArchivedTitle: String { return self._s[2272]! } + public var Privacy_Forwards_NeverLink: String { return self._s[2274]! } public func Notification_MessageLifetimeChangedOutgoing(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2267]!, self._r[2267]!, [_1]) + return formatWithArgumentRanges(self._s[2275]!, self._r[2275]!, [_1]) } - public var CheckoutInfo_ErrorShippingNotAvailable: String { return self._s[2268]! } + public var CheckoutInfo_ErrorShippingNotAvailable: String { return self._s[2276]! } public func Time_MonthOfYear_m12(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2269]!, self._r[2269]!, [_0]) + return formatWithArgumentRanges(self._s[2277]!, self._r[2277]!, [_0]) } - public var ChatSettings_PrivateChats: String { return self._s[2270]! } - public var SettingsSearch_Synonyms_EditProfile_Logout: String { return self._s[2271]! } - public var Conversation_PrivateMessageLinkCopied: String { return self._s[2272]! } - public var Channel_UpdatePhotoItem: String { return self._s[2273]! } - public var GroupInfo_LeftStatus: String { return self._s[2274]! } - public var Watch_MessageView_Forward: String { return self._s[2276]! } - public var ReportPeer_ReasonChildAbuse: String { return self._s[2277]! } - public var Cache_ClearEmpty: String { return self._s[2279]! } - public var Localization_LanguageName: String { return self._s[2280]! } - public var Wallet_AccessDenied_Title: String { return self._s[2281]! } - public var WebSearch_GIFs: String { return self._s[2282]! } - public var Notifications_DisplayNamesOnLockScreenInfoWithLink: String { return self._s[2283]! } - public var Wallet_AccessDenied_Settings: String { return self._s[2284]! } - public var Username_InvalidStartsWithNumber: String { return self._s[2285]! } - public var Common_Back: String { return self._s[2286]! } - public var GroupInfo_Permissions_EditingDisabled: String { return self._s[2287]! } - public var Passport_Identity_DateOfBirthPlaceholder: String { return self._s[2288]! } - public var Wallet_Send_Send: String { return self._s[2289]! } + public var ChatSettings_PrivateChats: String { return self._s[2278]! } + public var SettingsSearch_Synonyms_EditProfile_Logout: String { return self._s[2279]! } + public var Conversation_PrivateMessageLinkCopied: String { return self._s[2280]! } + public var Channel_UpdatePhotoItem: String { return self._s[2281]! } + public var GroupInfo_LeftStatus: String { return self._s[2282]! } + public var Watch_MessageView_Forward: String { return self._s[2284]! } + public var ReportPeer_ReasonChildAbuse: String { return self._s[2285]! } + public var Cache_ClearEmpty: String { return self._s[2287]! } + public var Localization_LanguageName: String { return self._s[2288]! } + public var Wallet_AccessDenied_Title: String { return self._s[2289]! } + public var WebSearch_GIFs: String { return self._s[2290]! } + public var Notifications_DisplayNamesOnLockScreenInfoWithLink: String { return self._s[2291]! } + public var Wallet_AccessDenied_Settings: String { return self._s[2292]! } + public var Username_InvalidStartsWithNumber: String { return self._s[2293]! } + public var Common_Back: String { return self._s[2294]! } + public var GroupInfo_Permissions_EditingDisabled: String { return self._s[2295]! } + public var Passport_Identity_DateOfBirthPlaceholder: String { return self._s[2296]! } + public var Wallet_Send_Send: String { return self._s[2297]! } public func PUSH_CHANNEL_MESSAGE_STICKER(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2291]!, self._r[2291]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2299]!, self._r[2299]!, [_1, _2]) } - public var Wallet_Info_RefreshErrorTitle: String { return self._s[2292]! } - public var Wallet_Month_GenJune: String { return self._s[2293]! } - public var Passport_Email_Help: String { return self._s[2294]! } - public var Watch_Conversation_Reply: String { return self._s[2296]! } - public var Conversation_EditingMessageMediaChange: String { return self._s[2299]! } - public var Passport_Identity_IssueDatePlaceholder: String { return self._s[2300]! } - public var Channel_BanUser_Unban: String { return self._s[2302]! } - public var Channel_EditAdmin_PermissionPostMessages: String { return self._s[2303]! } - public var Group_Username_CreatePublicLinkHelp: String { return self._s[2304]! } - public var TwoStepAuth_ConfirmEmailCodePlaceholder: String { return self._s[2306]! } - public var Wallet_Send_AddressHeader: String { return self._s[2307]! } - public var Passport_Identity_Name: String { return self._s[2308]! } + public var Wallet_Info_RefreshErrorTitle: String { return self._s[2300]! } + public var Wallet_Month_GenJune: String { return self._s[2301]! } + public var Passport_Email_Help: String { return self._s[2302]! } + public var Watch_Conversation_Reply: String { return self._s[2304]! } + public var Conversation_EditingMessageMediaChange: String { return self._s[2307]! } + public var Passport_Identity_IssueDatePlaceholder: String { return self._s[2308]! } + public var Channel_BanUser_Unban: String { return self._s[2310]! } + public var Channel_EditAdmin_PermissionPostMessages: String { return self._s[2311]! } + public var Group_Username_CreatePublicLinkHelp: String { return self._s[2312]! } + public var TwoStepAuth_ConfirmEmailCodePlaceholder: String { return self._s[2314]! } + public var Wallet_Send_AddressHeader: String { return self._s[2315]! } + public var Passport_Identity_Name: String { return self._s[2316]! } public func Channel_DiscussionGroup_HeaderGroupSet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2309]!, self._r[2309]!, [_0]) + return formatWithArgumentRanges(self._s[2317]!, self._r[2317]!, [_0]) } - public var GroupRemoved_ViewUserInfo: String { return self._s[2310]! } - public var Conversation_BlockUser: String { return self._s[2311]! } - public var Month_GenJanuary: String { return self._s[2312]! } - public var ChatSettings_TextSize: String { return self._s[2313]! } - public var Notification_PassportValuePhone: String { return self._s[2314]! } - public var MediaPlayer_UnknownArtist: String { return self._s[2315]! } - public var Passport_Language_ne: String { return self._s[2316]! } - public var Notification_CallBack: String { return self._s[2317]! } - public var Wallet_SecureStorageReset_BiometryTouchId: String { return self._s[2318]! } - public var TwoStepAuth_EmailHelp: String { return self._s[2319]! } + public var GroupRemoved_ViewUserInfo: String { return self._s[2318]! } + public var Conversation_BlockUser: String { return self._s[2319]! } + public var Month_GenJanuary: String { return self._s[2320]! } + public var ChatSettings_TextSize: String { return self._s[2321]! } + public var Notification_PassportValuePhone: String { return self._s[2322]! } + public var MediaPlayer_UnknownArtist: String { return self._s[2323]! } + public var Passport_Language_ne: String { return self._s[2324]! } + public var Notification_CallBack: String { return self._s[2325]! } + public var Wallet_SecureStorageReset_BiometryTouchId: String { return self._s[2326]! } + public var TwoStepAuth_EmailHelp: String { return self._s[2327]! } public func Time_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2320]!, self._r[2320]!, [_0]) + return formatWithArgumentRanges(self._s[2328]!, self._r[2328]!, [_0]) } - public var Channel_Info_Management: String { return self._s[2321]! } - public var Passport_FieldIdentityUploadHelp: String { return self._s[2322]! } - public var Stickers_FrequentlyUsed: String { return self._s[2323]! } - public var Channel_BanUser_PermissionSendMessages: String { return self._s[2324]! } - public var Passport_Address_OneOfTypeUtilityBill: String { return self._s[2326]! } + public var Channel_Info_Management: String { return self._s[2329]! } + public var Passport_FieldIdentityUploadHelp: String { return self._s[2330]! } + public var Stickers_FrequentlyUsed: String { return self._s[2331]! } + public var Channel_BanUser_PermissionSendMessages: String { return self._s[2332]! } + public var Passport_Address_OneOfTypeUtilityBill: String { return self._s[2334]! } public func LOCAL_CHANNEL_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2327]!, self._r[2327]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[2335]!, self._r[2335]!, [_1, "\(_2)"]) } - public var TwoFactorSetup_Password_Title: String { return self._s[2328]! } - public var Passport_Address_EditResidentialAddress: String { return self._s[2329]! } - public var PrivacyPolicy_DeclineTitle: String { return self._s[2330]! } - public var CreatePoll_TextHeader: String { return self._s[2331]! } + public var TwoFactorSetup_Password_Title: String { return self._s[2336]! } + public var Passport_Address_EditResidentialAddress: String { return self._s[2337]! } + public var PrivacyPolicy_DeclineTitle: String { return self._s[2338]! } + public var CreatePoll_TextHeader: String { return self._s[2339]! } public func Checkout_SavePasswordTimeoutAndTouchId(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2332]!, self._r[2332]!, [_0]) + return formatWithArgumentRanges(self._s[2340]!, self._r[2340]!, [_0]) } - public var PhotoEditor_QualityMedium: String { return self._s[2333]! } - public var InfoPlist_NSMicrophoneUsageDescription: String { return self._s[2334]! } - public var Conversation_StatusKickedFromChannel: String { return self._s[2336]! } - public var CheckoutInfo_ReceiverInfoName: String { return self._s[2337]! } - public var Group_ErrorSendRestrictedStickers: String { return self._s[2338]! } + public var PhotoEditor_QualityMedium: String { return self._s[2341]! } + public var InfoPlist_NSMicrophoneUsageDescription: String { return self._s[2342]! } + public var Conversation_StatusKickedFromChannel: String { return self._s[2344]! } + public var CheckoutInfo_ReceiverInfoName: String { return self._s[2345]! } + public var Group_ErrorSendRestrictedStickers: String { return self._s[2346]! } public func Conversation_RestrictedInlineTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2339]!, self._r[2339]!, [_0]) + return formatWithArgumentRanges(self._s[2347]!, self._r[2347]!, [_0]) } public func Channel_AdminLog_MessageTransferedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2340]!, self._r[2340]!, [_1]) + return formatWithArgumentRanges(self._s[2348]!, self._r[2348]!, [_1]) } - public var LogoutOptions_LogOutWalletInfo: String { return self._s[2341]! } - public var TwoFactorSetup_Email_SkipConfirmationTitle: String { return self._s[2342]! } - public var Conversation_LinkDialogOpen: String { return self._s[2344]! } - public var TwoFactorSetup_Hint_Title: String { return self._s[2345]! } - public var VoiceOver_Chat_PollNoVotes: String { return self._s[2346]! } - public var Settings_Username: String { return self._s[2348]! } - public var Conversation_Block: String { return self._s[2350]! } - public var Wallpaper_Wallpaper: String { return self._s[2351]! } - public var SocksProxySetup_UseProxy: String { return self._s[2353]! } - public var Wallet_Send_Confirmation: String { return self._s[2354]! } - public var EditTheme_UploadEditedTheme: String { return self._s[2355]! } - public var UserInfo_ShareMyContactInfo: String { return self._s[2356]! } - public var MessageTimer_Forever: String { return self._s[2357]! } - public var Privacy_Calls_WhoCanCallMe: String { return self._s[2358]! } - public var PhotoEditor_DiscardChanges: String { return self._s[2359]! } - public var AuthSessions_TerminateOtherSessionsHelp: String { return self._s[2360]! } - public var Passport_Language_da: String { return self._s[2361]! } - public var SocksProxySetup_PortPlaceholder: String { return self._s[2362]! } + public var LogoutOptions_LogOutWalletInfo: String { return self._s[2349]! } + public var TwoFactorSetup_Email_SkipConfirmationTitle: String { return self._s[2350]! } + public var Conversation_LinkDialogOpen: String { return self._s[2352]! } + public var TwoFactorSetup_Hint_Title: String { return self._s[2353]! } + public var VoiceOver_Chat_PollNoVotes: String { return self._s[2354]! } + public var Settings_Username: String { return self._s[2356]! } + public var Conversation_Block: String { return self._s[2358]! } + public var Wallpaper_Wallpaper: String { return self._s[2359]! } + public var SocksProxySetup_UseProxy: String { return self._s[2361]! } + public var Wallet_Send_Confirmation: String { return self._s[2362]! } + public var EditTheme_UploadEditedTheme: String { return self._s[2363]! } + public var UserInfo_ShareMyContactInfo: String { return self._s[2364]! } + public var MessageTimer_Forever: String { return self._s[2365]! } + public var Privacy_Calls_WhoCanCallMe: String { return self._s[2366]! } + public var PhotoEditor_DiscardChanges: String { return self._s[2367]! } + public var AuthSessions_TerminateOtherSessionsHelp: String { return self._s[2368]! } + public var Passport_Language_da: String { return self._s[2369]! } + public var SocksProxySetup_PortPlaceholder: String { return self._s[2370]! } public func SecretGIF_NotViewedYet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2363]!, self._r[2363]!, [_0]) + return formatWithArgumentRanges(self._s[2371]!, self._r[2371]!, [_0]) } - public var Passport_Address_EditPassportRegistration: String { return self._s[2364]! } + public var Passport_Address_EditPassportRegistration: String { return self._s[2372]! } public func Channel_AdminLog_MessageChangedGroupAbout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2366]!, self._r[2366]!, [_0]) + return formatWithArgumentRanges(self._s[2374]!, self._r[2374]!, [_0]) } - public var Settings_AddDevice: String { return self._s[2367]! } - public var Passport_Identity_ResidenceCountryPlaceholder: String { return self._s[2369]! } - public var AuthSessions_AddDeviceIntro_Text1: String { return self._s[2370]! } - public var Conversation_SearchByName_Prefix: String { return self._s[2371]! } - public var Conversation_PinnedPoll: String { return self._s[2372]! } - public var AuthSessions_AddDeviceIntro_Text2: String { return self._s[2373]! } - public var Conversation_EmptyGifPanelPlaceholder: String { return self._s[2374]! } - public var AuthSessions_AddDeviceIntro_Text3: String { return self._s[2375]! } + public var Settings_AddDevice: String { return self._s[2375]! } + public var Passport_Identity_ResidenceCountryPlaceholder: String { return self._s[2377]! } + public var AuthSessions_AddDeviceIntro_Text1: String { return self._s[2378]! } + public var Conversation_SearchByName_Prefix: String { return self._s[2379]! } + public var Conversation_PinnedPoll: String { return self._s[2380]! } + public var AuthSessions_AddDeviceIntro_Text2: String { return self._s[2381]! } + public var Conversation_EmptyGifPanelPlaceholder: String { return self._s[2382]! } + public var AuthSessions_AddDeviceIntro_Text3: String { return self._s[2383]! } public func PUSH_ENCRYPTION_ACCEPT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2376]!, self._r[2376]!, [_1]) + return formatWithArgumentRanges(self._s[2384]!, self._r[2384]!, [_1]) } - public var WallpaperSearch_ColorPurple: String { return self._s[2377]! } - public var Cache_ByPeerHeader: String { return self._s[2378]! } + public var WallpaperSearch_ColorPurple: String { return self._s[2385]! } + public var Cache_ByPeerHeader: String { return self._s[2386]! } public func Conversation_EncryptedPlaceholderTitleIncoming(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2379]!, self._r[2379]!, [_0]) + return formatWithArgumentRanges(self._s[2387]!, self._r[2387]!, [_0]) } - public var ChatSettings_AutoDownloadDocuments: String { return self._s[2380]! } - public var Appearance_ThemePreview_Chat_3_Text: String { return self._s[2383]! } - public var Wallet_Completed_Title: String { return self._s[2384]! } - public var Notification_PinnedMessage: String { return self._s[2385]! } - public var TwoFactorSetup_EmailVerification_Placeholder: String { return self._s[2386]! } - public var VoiceOver_Chat_RecordModeVideoMessage: String { return self._s[2388]! } - public var Contacts_SortBy: String { return self._s[2389]! } + public var ChatSettings_AutoDownloadDocuments: String { return self._s[2388]! } + public var Appearance_ThemePreview_Chat_3_Text: String { return self._s[2391]! } + public var Wallet_Completed_Title: String { return self._s[2392]! } + public var Notification_PinnedMessage: String { return self._s[2393]! } + public var TwoFactorSetup_EmailVerification_Placeholder: String { return self._s[2394]! } + public var VoiceOver_Chat_RecordModeVideoMessage: String { return self._s[2396]! } + public var Contacts_SortBy: String { return self._s[2397]! } public func PUSH_CHANNEL_MESSAGE_NOTEXT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2390]!, self._r[2390]!, [_1]) + return formatWithArgumentRanges(self._s[2398]!, self._r[2398]!, [_1]) } - public var Appearance_ColorThemeNight: String { return self._s[2392]! } + public var Appearance_ColorThemeNight: String { return self._s[2400]! } public func PUSH_MESSAGE_GAME(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2393]!, self._r[2393]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2401]!, self._r[2401]!, [_1, _2]) } - public var Call_EncryptionKey_Title: String { return self._s[2394]! } - public var Watch_UserInfo_Service: String { return self._s[2395]! } - public var SettingsSearch_Synonyms_Data_SaveEditedPhotos: String { return self._s[2397]! } - public var Conversation_Unpin: String { return self._s[2399]! } - public var CancelResetAccount_Title: String { return self._s[2400]! } - public var Map_LiveLocationFor15Minutes: String { return self._s[2401]! } + public var Call_EncryptionKey_Title: String { return self._s[2402]! } + public var Watch_UserInfo_Service: String { return self._s[2403]! } + public var SettingsSearch_Synonyms_Data_SaveEditedPhotos: String { return self._s[2405]! } + public var Conversation_Unpin: String { return self._s[2407]! } + public var CancelResetAccount_Title: String { return self._s[2408]! } + public var Map_LiveLocationFor15Minutes: String { return self._s[2409]! } public func Time_PreciseDate_m8(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2403]!, self._r[2403]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2411]!, self._r[2411]!, [_1, _2, _3]) } - public var Group_Members_AddMemberBotErrorNotAllowed: String { return self._s[2404]! } - public var CallSettings_Title: String { return self._s[2405]! } - public var SettingsSearch_Synonyms_Appearance_ChatBackground: String { return self._s[2406]! } - public var PasscodeSettings_EncryptDataHelp: String { return self._s[2408]! } - public var AutoDownloadSettings_Contacts: String { return self._s[2409]! } + public var Group_Members_AddMemberBotErrorNotAllowed: String { return self._s[2412]! } + public var CallSettings_Title: String { return self._s[2413]! } + public var SettingsSearch_Synonyms_Appearance_ChatBackground: String { return self._s[2414]! } + public var PasscodeSettings_EncryptDataHelp: String { return self._s[2416]! } + public var AutoDownloadSettings_Contacts: String { return self._s[2417]! } public func Channel_AdminLog_MessageRankName(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2410]!, self._r[2410]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2418]!, self._r[2418]!, [_1, _2]) } - public var Passport_Identity_DocumentDetails: String { return self._s[2411]! } - public var LoginPassword_PasswordHelp: String { return self._s[2412]! } - public var SettingsSearch_Synonyms_Data_AutoDownloadUsingWifi: String { return self._s[2413]! } - public var PrivacyLastSeenSettings_CustomShareSettings_Delete: String { return self._s[2414]! } - public var ChatContextMenu_TextSelectionTip: String { return self._s[2415]! } - public var Checkout_TotalPaidAmount: String { return self._s[2416]! } + public var Passport_Identity_DocumentDetails: String { return self._s[2419]! } + public var LoginPassword_PasswordHelp: String { return self._s[2420]! } + public var SettingsSearch_Synonyms_Data_AutoDownloadUsingWifi: String { return self._s[2421]! } + public var PrivacyLastSeenSettings_CustomShareSettings_Delete: String { return self._s[2422]! } + public var ChatContextMenu_TextSelectionTip: String { return self._s[2423]! } + public var Checkout_TotalPaidAmount: String { return self._s[2424]! } public func FileSize_KB(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2417]!, self._r[2417]!, [_0]) + return formatWithArgumentRanges(self._s[2425]!, self._r[2425]!, [_0]) } - public var PasscodeSettings_ChangePasscode: String { return self._s[2418]! } - public var Conversation_SecretLinkPreviewAlert: String { return self._s[2420]! } - public var Privacy_SecretChatsLinkPreviews: String { return self._s[2421]! } + public var PasscodeSettings_ChangePasscode: String { return self._s[2426]! } + public var Conversation_SecretLinkPreviewAlert: String { return self._s[2428]! } + public var Privacy_SecretChatsLinkPreviews: String { return self._s[2429]! } public func PUSH_CHANNEL_MESSAGE_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2422]!, self._r[2422]!, [_1]) + return formatWithArgumentRanges(self._s[2430]!, self._r[2430]!, [_1]) } - public var VoiceOver_Chat_ReplyToYourMessage: String { return self._s[2423]! } - public var Contacts_InviteFriends: String { return self._s[2425]! } - public var Map_ChooseLocationTitle: String { return self._s[2426]! } - public var Conversation_StopPoll: String { return self._s[2428]! } + public var VoiceOver_Chat_ReplyToYourMessage: String { return self._s[2431]! } + public var Contacts_InviteFriends: String { return self._s[2433]! } + public var Map_ChooseLocationTitle: String { return self._s[2434]! } + public var Conversation_StopPoll: String { return self._s[2436]! } public func WebSearch_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2429]!, self._r[2429]!, [_0]) + return formatWithArgumentRanges(self._s[2437]!, self._r[2437]!, [_0]) } - public var Call_Camera: String { return self._s[2430]! } - public var LogoutOptions_ChangePhoneNumberTitle: String { return self._s[2431]! } - public var AppWallet_Intro_Text: String { return self._s[2432]! } - public var Calls_RatingFeedback: String { return self._s[2433]! } - public var GroupInfo_BroadcastListNamePlaceholder: String { return self._s[2435]! } - public var Wallet_Alert_OK: String { return self._s[2436]! } - public var NotificationsSound_Pulse: String { return self._s[2437]! } - public var Watch_LastSeen_Lately: String { return self._s[2438]! } - public var ReportGroupLocation_Report: String { return self._s[2441]! } - public var Widget_NoUsers: String { return self._s[2442]! } - public var Conversation_UnvotePoll: String { return self._s[2443]! } - public var SettingsSearch_Synonyms_Privacy_ProfilePhoto: String { return self._s[2445]! } - public var Privacy_ProfilePhoto_WhoCanSeeMyPhoto: String { return self._s[2446]! } - public var NotificationsSound_Circles: String { return self._s[2447]! } - public var PrivacyLastSeenSettings_AlwaysShareWith_Title: String { return self._s[2450]! } - public var Wallet_Settings_DeleteWallet: String { return self._s[2451]! } - public var TwoStepAuth_RecoveryCodeExpired: String { return self._s[2452]! } - public var Proxy_TooltipUnavailable: String { return self._s[2453]! } - public var Passport_Identity_CountryPlaceholder: String { return self._s[2455]! } - public var GroupInfo_Permissions_SlowmodeInfo: String { return self._s[2457]! } - public var Conversation_FileDropbox: String { return self._s[2458]! } - public var Notifications_ExceptionsUnmuted: String { return self._s[2459]! } - public var Tour_Text3: String { return self._s[2461]! } - public var Login_ResetAccountProtected_Title: String { return self._s[2463]! } - public var GroupPermission_NoSendMessages: String { return self._s[2464]! } - public var WallpaperSearch_ColorTitle: String { return self._s[2465]! } - public var ChatAdmins_AllMembersAreAdminsOnHelp: String { return self._s[2466]! } + public var Call_Camera: String { return self._s[2438]! } + public var LogoutOptions_ChangePhoneNumberTitle: String { return self._s[2439]! } + public var AppWallet_Intro_Text: String { return self._s[2440]! } + public var Calls_RatingFeedback: String { return self._s[2441]! } + public var GroupInfo_BroadcastListNamePlaceholder: String { return self._s[2443]! } + public var Wallet_Alert_OK: String { return self._s[2444]! } + public var NotificationsSound_Pulse: String { return self._s[2445]! } + public var Watch_LastSeen_Lately: String { return self._s[2446]! } + public var ReportGroupLocation_Report: String { return self._s[2449]! } + public var Widget_NoUsers: String { return self._s[2450]! } + public var Conversation_UnvotePoll: String { return self._s[2451]! } + public var SettingsSearch_Synonyms_Privacy_ProfilePhoto: String { return self._s[2453]! } + public var Privacy_ProfilePhoto_WhoCanSeeMyPhoto: String { return self._s[2454]! } + public var NotificationsSound_Circles: String { return self._s[2455]! } + public var PrivacyLastSeenSettings_AlwaysShareWith_Title: String { return self._s[2458]! } + public var Wallet_Settings_DeleteWallet: String { return self._s[2459]! } + public var TwoStepAuth_RecoveryCodeExpired: String { return self._s[2460]! } + public var Proxy_TooltipUnavailable: String { return self._s[2461]! } + public var Passport_Identity_CountryPlaceholder: String { return self._s[2463]! } + public var GroupInfo_Permissions_SlowmodeInfo: String { return self._s[2465]! } + public var Conversation_FileDropbox: String { return self._s[2466]! } + public var Notifications_ExceptionsUnmuted: String { return self._s[2467]! } + public var Tour_Text3: String { return self._s[2469]! } + public var Login_ResetAccountProtected_Title: String { return self._s[2471]! } + public var GroupPermission_NoSendMessages: String { return self._s[2472]! } + public var WallpaperSearch_ColorTitle: String { return self._s[2473]! } + public var ChatAdmins_AllMembersAreAdminsOnHelp: String { return self._s[2474]! } public func Conversation_LiveLocationYouAnd(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2468]!, self._r[2468]!, [_0]) + return formatWithArgumentRanges(self._s[2476]!, self._r[2476]!, [_0]) } - public var GroupInfo_AddParticipantTitle: String { return self._s[2469]! } - public var Checkout_ShippingOption_Title: String { return self._s[2470]! } - public var ChatSettings_AutoDownloadTitle: String { return self._s[2471]! } + public var GroupInfo_AddParticipantTitle: String { return self._s[2477]! } + public var Checkout_ShippingOption_Title: String { return self._s[2478]! } + public var ChatSettings_AutoDownloadTitle: String { return self._s[2479]! } public func DialogList_SingleTypingSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2472]!, self._r[2472]!, [_0]) + return formatWithArgumentRanges(self._s[2480]!, self._r[2480]!, [_0]) } public func ChatSettings_AutoDownloadSettings_TypeVideo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2473]!, self._r[2473]!, [_0]) + return formatWithArgumentRanges(self._s[2481]!, self._r[2481]!, [_0]) } - public var Channel_Management_LabelAdministrator: String { return self._s[2474]! } - public var EditTheme_FileReadError: String { return self._s[2475]! } - public var OwnershipTransfer_ComeBackLater: String { return self._s[2476]! } - public var PrivacyLastSeenSettings_NeverShareWith_Placeholder: String { return self._s[2477]! } - public var AutoDownloadSettings_Photos: String { return self._s[2479]! } - public var Appearance_PreviewIncomingText: String { return self._s[2480]! } - public var ChatList_Context_MarkAllAsRead: String { return self._s[2481]! } - public var ChannelInfo_ConfirmLeave: String { return self._s[2482]! } - public var MediaPicker_MomentsDateRangeSameMonthYearFormat: String { return self._s[2483]! } - public var Passport_Identity_DocumentNumberPlaceholder: String { return self._s[2484]! } - public var Channel_AdminLogFilter_EventsNewMembers: String { return self._s[2485]! } - public var PasscodeSettings_AutoLock_IfAwayFor_5minutes: String { return self._s[2486]! } - public var GroupInfo_SetGroupPhotoStop: String { return self._s[2487]! } - public var Notification_SecretChatScreenshot: String { return self._s[2488]! } - public var AccessDenied_Wallpapers: String { return self._s[2489]! } - public var ChatList_Context_Mute: String { return self._s[2491]! } - public var Passport_Address_City: String { return self._s[2492]! } - public var InfoPlist_NSPhotoLibraryAddUsageDescription: String { return self._s[2493]! } - public var Appearance_ThemeCarouselClassic: String { return self._s[2494]! } - public var SocksProxySetup_SecretPlaceholder: String { return self._s[2495]! } - public var AccessDenied_LocationDisabled: String { return self._s[2496]! } - public var Group_Location_Title: String { return self._s[2497]! } - public var SocksProxySetup_HostnamePlaceholder: String { return self._s[2499]! } - public var GroupInfo_Sound: String { return self._s[2500]! } - public var SettingsSearch_Synonyms_ChatSettings_OpenLinksIn: String { return self._s[2501]! } - public var ChannelInfo_ScamChannelWarning: String { return self._s[2502]! } - public var Stickers_RemoveFromFavorites: String { return self._s[2503]! } - public var Contacts_Title: String { return self._s[2504]! } - public var EditTheme_ThemeTemplateAlertText: String { return self._s[2505]! } - public var Passport_Language_fr: String { return self._s[2506]! } - public var TwoFactorSetup_EmailVerification_Action: String { return self._s[2507]! } - public var Notifications_ResetAllNotifications: String { return self._s[2508]! } - public var IntentsSettings_SuggestedChats: String { return self._s[2510]! } - public var PrivacySettings_SecurityTitle: String { return self._s[2512]! } - public var Checkout_NewCard_Title: String { return self._s[2513]! } - public var Login_HaveNotReceivedCodeInternal: String { return self._s[2514]! } - public var Conversation_ForwardChats: String { return self._s[2515]! } - public var Wallet_SecureStorageReset_PasscodeText: String { return self._s[2517]! } - public var PasscodeSettings_4DigitCode: String { return self._s[2518]! } - public var Settings_FAQ: String { return self._s[2520]! } - public var AutoDownloadSettings_DocumentsTitle: String { return self._s[2521]! } - public var Conversation_ContextMenuForward: String { return self._s[2522]! } - public var VoiceOver_Chat_YourPhoto: String { return self._s[2525]! } - public var PrivacyPolicy_Title: String { return self._s[2528]! } - public var Notifications_TextTone: String { return self._s[2529]! } - public var Profile_CreateNewContact: String { return self._s[2530]! } - public var PrivacyPhoneNumberSettings_WhoCanSeeMyPhoneNumber: String { return self._s[2531]! } - public var TwoFactorSetup_EmailVerification_Title: String { return self._s[2533]! } - public var Call_Speaker: String { return self._s[2534]! } - public var AutoNightTheme_AutomaticSection: String { return self._s[2535]! } - public var Channel_OwnershipTransfer_EnterPassword: String { return self._s[2537]! } - public var Channel_Username_InvalidCharacters: String { return self._s[2538]! } + public var Channel_Management_LabelAdministrator: String { return self._s[2482]! } + public var EditTheme_FileReadError: String { return self._s[2483]! } + public var OwnershipTransfer_ComeBackLater: String { return self._s[2484]! } + public var PrivacyLastSeenSettings_NeverShareWith_Placeholder: String { return self._s[2485]! } + public var AutoDownloadSettings_Photos: String { return self._s[2487]! } + public var Appearance_PreviewIncomingText: String { return self._s[2488]! } + public var ChatList_Context_MarkAllAsRead: String { return self._s[2489]! } + public var ChannelInfo_ConfirmLeave: String { return self._s[2490]! } + public var MediaPicker_MomentsDateRangeSameMonthYearFormat: String { return self._s[2491]! } + public var Passport_Identity_DocumentNumberPlaceholder: String { return self._s[2492]! } + public var Channel_AdminLogFilter_EventsNewMembers: String { return self._s[2493]! } + public var PasscodeSettings_AutoLock_IfAwayFor_5minutes: String { return self._s[2494]! } + public var GroupInfo_SetGroupPhotoStop: String { return self._s[2495]! } + public var Notification_SecretChatScreenshot: String { return self._s[2496]! } + public var AccessDenied_Wallpapers: String { return self._s[2497]! } + public var ChatList_Context_Mute: String { return self._s[2499]! } + public var Passport_Address_City: String { return self._s[2500]! } + public var InfoPlist_NSPhotoLibraryAddUsageDescription: String { return self._s[2501]! } + public var Appearance_ThemeCarouselClassic: String { return self._s[2502]! } + public var SocksProxySetup_SecretPlaceholder: String { return self._s[2503]! } + public var AccessDenied_LocationDisabled: String { return self._s[2504]! } + public var Group_Location_Title: String { return self._s[2505]! } + public var SocksProxySetup_HostnamePlaceholder: String { return self._s[2507]! } + public var GroupInfo_Sound: String { return self._s[2508]! } + public var SettingsSearch_Synonyms_ChatSettings_OpenLinksIn: String { return self._s[2509]! } + public var ChannelInfo_ScamChannelWarning: String { return self._s[2510]! } + public var Stickers_RemoveFromFavorites: String { return self._s[2511]! } + public var Contacts_Title: String { return self._s[2512]! } + public var EditTheme_ThemeTemplateAlertText: String { return self._s[2513]! } + public var Passport_Language_fr: String { return self._s[2514]! } + public var TwoFactorSetup_EmailVerification_Action: String { return self._s[2515]! } + public var Notifications_ResetAllNotifications: String { return self._s[2516]! } + public var IntentsSettings_SuggestedChats: String { return self._s[2518]! } + public var PrivacySettings_SecurityTitle: String { return self._s[2520]! } + public var Checkout_NewCard_Title: String { return self._s[2521]! } + public var Login_HaveNotReceivedCodeInternal: String { return self._s[2522]! } + public var Conversation_ForwardChats: String { return self._s[2523]! } + public var Wallet_SecureStorageReset_PasscodeText: String { return self._s[2525]! } + public var PasscodeSettings_4DigitCode: String { return self._s[2526]! } + public var Settings_FAQ: String { return self._s[2528]! } + public var AutoDownloadSettings_DocumentsTitle: String { return self._s[2529]! } + public var Conversation_ContextMenuForward: String { return self._s[2530]! } + public var VoiceOver_Chat_YourPhoto: String { return self._s[2533]! } + public var PrivacyPolicy_Title: String { return self._s[2536]! } + public var Notifications_TextTone: String { return self._s[2537]! } + public var Profile_CreateNewContact: String { return self._s[2538]! } + public var PrivacyPhoneNumberSettings_WhoCanSeeMyPhoneNumber: String { return self._s[2539]! } + public var TwoFactorSetup_EmailVerification_Title: String { return self._s[2541]! } + public var Call_Speaker: String { return self._s[2542]! } + public var AutoNightTheme_AutomaticSection: String { return self._s[2543]! } + public var Channel_OwnershipTransfer_EnterPassword: String { return self._s[2545]! } + public var Channel_Username_InvalidCharacters: String { return self._s[2546]! } public func Channel_AdminLog_MessageChangedChannelUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2539]!, self._r[2539]!, [_0]) + return formatWithArgumentRanges(self._s[2547]!, self._r[2547]!, [_0]) } - public var AutoDownloadSettings_AutodownloadFiles: String { return self._s[2540]! } - public var PrivacySettings_LastSeenTitle: String { return self._s[2541]! } - public var Channel_AdminLog_CanInviteUsers: String { return self._s[2542]! } - public var SettingsSearch_Synonyms_Privacy_Data_ClearPaymentsInfo: String { return self._s[2543]! } - public var OwnershipTransfer_SecurityCheck: String { return self._s[2544]! } - public var Conversation_MessageDeliveryFailed: String { return self._s[2545]! } - public var Watch_ChatList_NoConversationsText: String { return self._s[2546]! } - public var Bot_Unblock: String { return self._s[2547]! } - public var TextFormat_Italic: String { return self._s[2548]! } - public var WallpaperSearch_ColorPink: String { return self._s[2549]! } - public var Settings_About_Help: String { return self._s[2551]! } - public var SearchImages_Title: String { return self._s[2552]! } - public var Weekday_Wednesday: String { return self._s[2553]! } - public var Conversation_ClousStorageInfo_Description1: String { return self._s[2554]! } - public var ExplicitContent_AlertTitle: String { return self._s[2555]! } + public var AutoDownloadSettings_AutodownloadFiles: String { return self._s[2548]! } + public var PrivacySettings_LastSeenTitle: String { return self._s[2549]! } + public var Channel_AdminLog_CanInviteUsers: String { return self._s[2550]! } + public var SettingsSearch_Synonyms_Privacy_Data_ClearPaymentsInfo: String { return self._s[2551]! } + public var OwnershipTransfer_SecurityCheck: String { return self._s[2552]! } + public var Conversation_MessageDeliveryFailed: String { return self._s[2553]! } + public var Watch_ChatList_NoConversationsText: String { return self._s[2554]! } + public var Bot_Unblock: String { return self._s[2555]! } + public var TextFormat_Italic: String { return self._s[2556]! } + public var WallpaperSearch_ColorPink: String { return self._s[2557]! } + public var Settings_About_Help: String { return self._s[2559]! } + public var SearchImages_Title: String { return self._s[2560]! } + public var Weekday_Wednesday: String { return self._s[2561]! } + public var Conversation_ClousStorageInfo_Description1: String { return self._s[2562]! } + public var ExplicitContent_AlertTitle: String { return self._s[2563]! } public func Time_PreciseDate_m5(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2556]!, self._r[2556]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2564]!, self._r[2564]!, [_1, _2, _3]) } - public var Channel_DiscussionGroup_Create: String { return self._s[2557]! } - public var Weekday_Thursday: String { return self._s[2558]! } - public var Channel_BanUser_PermissionChangeGroupInfo: String { return self._s[2559]! } - public var Channel_Members_AddMembersHelp: String { return self._s[2560]! } + public var Channel_DiscussionGroup_Create: String { return self._s[2565]! } + public var Weekday_Thursday: String { return self._s[2566]! } + public var Channel_BanUser_PermissionChangeGroupInfo: String { return self._s[2567]! } + public var Channel_Members_AddMembersHelp: String { return self._s[2568]! } public func Checkout_SavePasswordTimeout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2561]!, self._r[2561]!, [_0]) + return formatWithArgumentRanges(self._s[2569]!, self._r[2569]!, [_0]) } - public var Channel_DiscussionGroup_LinkGroup: String { return self._s[2562]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsVibrate: String { return self._s[2563]! } - public var Passport_RequestedInformation: String { return self._s[2564]! } - public var Login_PhoneAndCountryHelp: String { return self._s[2565]! } - public var Conversation_EncryptionProcessing: String { return self._s[2567]! } - public var Notifications_PermissionsSuppressWarningTitle: String { return self._s[2568]! } - public var PhotoEditor_EnhanceTool: String { return self._s[2570]! } - public var Channel_Setup_Title: String { return self._s[2571]! } - public var Conversation_SearchPlaceholder: String { return self._s[2572]! } - public var OldChannels_GroupEmptyFormat: String { return self._s[2573]! } - public var AccessDenied_LocationAlwaysDenied: String { return self._s[2574]! } - public var Checkout_ErrorGeneric: String { return self._s[2575]! } - public var Passport_Language_hu: String { return self._s[2576]! } - public var GroupPermission_EditingDisabled: String { return self._s[2577]! } - public var Wallet_Month_ShortSeptember: String { return self._s[2579]! } + public var Channel_DiscussionGroup_LinkGroup: String { return self._s[2570]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsVibrate: String { return self._s[2571]! } + public var Passport_RequestedInformation: String { return self._s[2572]! } + public var Login_PhoneAndCountryHelp: String { return self._s[2573]! } + public var Conversation_EncryptionProcessing: String { return self._s[2575]! } + public var Notifications_PermissionsSuppressWarningTitle: String { return self._s[2576]! } + public var PhotoEditor_EnhanceTool: String { return self._s[2578]! } + public var Channel_Setup_Title: String { return self._s[2579]! } + public var Conversation_SearchPlaceholder: String { return self._s[2580]! } + public var OldChannels_GroupEmptyFormat: String { return self._s[2581]! } + public var AccessDenied_LocationAlwaysDenied: String { return self._s[2582]! } + public var Checkout_ErrorGeneric: String { return self._s[2583]! } + public var Passport_Language_hu: String { return self._s[2584]! } + public var GroupPermission_EditingDisabled: String { return self._s[2585]! } + public var Wallet_Month_ShortSeptember: String { return self._s[2587]! } public func Passport_Identity_UploadOneOfScan(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2580]!, self._r[2580]!, [_0]) + return formatWithArgumentRanges(self._s[2588]!, self._r[2588]!, [_0]) } public func PUSH_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2583]!, self._r[2583]!, [_1]) + return formatWithArgumentRanges(self._s[2591]!, self._r[2591]!, [_1]) } - public var ChatList_DeleteSavedMessagesConfirmationTitle: String { return self._s[2584]! } + public var ChatList_DeleteSavedMessagesConfirmationTitle: String { return self._s[2592]! } public func UserInfo_BlockConfirmationTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2585]!, self._r[2585]!, [_0]) + return formatWithArgumentRanges(self._s[2593]!, self._r[2593]!, [_0]) } - public var Conversation_CloudStorageInfo_Title: String { return self._s[2586]! } - public var Group_Location_Info: String { return self._s[2587]! } - public var PhotoEditor_CropAspectRatioSquare: String { return self._s[2588]! } - public var Permissions_PeopleNearbyAllow_v0: String { return self._s[2589]! } + public var Conversation_CloudStorageInfo_Title: String { return self._s[2594]! } + public var Group_Location_Info: String { return self._s[2595]! } + public var PhotoEditor_CropAspectRatioSquare: String { return self._s[2596]! } + public var Permissions_PeopleNearbyAllow_v0: String { return self._s[2597]! } public func Notification_Exceptions_MutedUntil(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2590]!, self._r[2590]!, [_0]) + return formatWithArgumentRanges(self._s[2598]!, self._r[2598]!, [_0]) } - public var Conversation_ClearPrivateHistory: String { return self._s[2591]! } - public var ContactInfo_PhoneLabelHome: String { return self._s[2592]! } - public var Appearance_RemoveThemeConfirmation: String { return self._s[2593]! } - public var PrivacySettings_LastSeenContacts: String { return self._s[2594]! } + public var Conversation_ClearPrivateHistory: String { return self._s[2599]! } + public var ContactInfo_PhoneLabelHome: String { return self._s[2600]! } + public var Appearance_RemoveThemeConfirmation: String { return self._s[2601]! } + public var PrivacySettings_LastSeenContacts: String { return self._s[2602]! } public func ChangePhone_ErrorOccupied(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2595]!, self._r[2595]!, [_0]) + return formatWithArgumentRanges(self._s[2603]!, self._r[2603]!, [_0]) } - public var Passport_Language_cs: String { return self._s[2596]! } - public var Message_PinnedAnimationMessage: String { return self._s[2598]! } - public var Passport_Identity_ReverseSideHelp: String { return self._s[2600]! } - public var SettingsSearch_Synonyms_Data_Storage_Title: String { return self._s[2601]! } - public var Wallet_Info_TransactionTo: String { return self._s[2603]! } - public var ChatList_DeleteForEveryoneConfirmationText: String { return self._s[2604]! } - public var SettingsSearch_Synonyms_Privacy_PasscodeAndTouchId: String { return self._s[2605]! } - public var Embed_PlayingInPIP: String { return self._s[2606]! } - public var Appearance_ThemePreview_Chat_3_TextWithLink: String { return self._s[2607]! } - public var AutoNightTheme_ScheduleSection: String { return self._s[2608]! } + public var Passport_Language_cs: String { return self._s[2604]! } + public var Message_PinnedAnimationMessage: String { return self._s[2606]! } + public var Passport_Identity_ReverseSideHelp: String { return self._s[2608]! } + public var SettingsSearch_Synonyms_Data_Storage_Title: String { return self._s[2609]! } + public var Wallet_Info_TransactionTo: String { return self._s[2611]! } + public var ChatList_DeleteForEveryoneConfirmationText: String { return self._s[2612]! } + public var SettingsSearch_Synonyms_Privacy_PasscodeAndTouchId: String { return self._s[2613]! } + public var Embed_PlayingInPIP: String { return self._s[2614]! } + public var Appearance_ThemePreview_Chat_3_TextWithLink: String { return self._s[2615]! } + public var AutoNightTheme_ScheduleSection: String { return self._s[2616]! } public func Call_EmojiDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2609]!, self._r[2609]!, [_0]) + return formatWithArgumentRanges(self._s[2617]!, self._r[2617]!, [_0]) } - public var MediaPicker_LivePhotoDescription: String { return self._s[2610]! } + public var MediaPicker_LivePhotoDescription: String { return self._s[2618]! } public func Channel_AdminLog_MessageRestrictedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2611]!, self._r[2611]!, [_1]) + return formatWithArgumentRanges(self._s[2619]!, self._r[2619]!, [_1]) } - public var Notification_PaymentSent: String { return self._s[2612]! } - public var PhotoEditor_CurvesGreen: String { return self._s[2613]! } - public var Notification_Exceptions_PreviewAlwaysOff: String { return self._s[2614]! } - public var AutoNightTheme_System: String { return self._s[2615]! } - public var SaveIncomingPhotosSettings_Title: String { return self._s[2616]! } - public var CreatePoll_QuizTitle: String { return self._s[2617]! } - public var NotificationSettings_ShowNotificationsAllAccounts: String { return self._s[2618]! } - public var VoiceOver_Chat_PagePreview: String { return self._s[2619]! } + public var Notification_PaymentSent: String { return self._s[2620]! } + public var PhotoEditor_CurvesGreen: String { return self._s[2621]! } + public var Notification_Exceptions_PreviewAlwaysOff: String { return self._s[2622]! } + public var AutoNightTheme_System: String { return self._s[2623]! } + public var SaveIncomingPhotosSettings_Title: String { return self._s[2624]! } + public var CreatePoll_QuizTitle: String { return self._s[2625]! } + public var NotificationSettings_ShowNotificationsAllAccounts: String { return self._s[2626]! } + public var VoiceOver_Chat_PagePreview: String { return self._s[2627]! } public func PUSH_MESSAGE_SCREENSHOT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2622]!, self._r[2622]!, [_1]) + return formatWithArgumentRanges(self._s[2630]!, self._r[2630]!, [_1]) } public func PUSH_MESSAGE_PHOTO_SECRET(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2623]!, self._r[2623]!, [_1]) + return formatWithArgumentRanges(self._s[2631]!, self._r[2631]!, [_1]) } public func ApplyLanguage_UnsufficientDataText(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2624]!, self._r[2624]!, [_1]) + return formatWithArgumentRanges(self._s[2632]!, self._r[2632]!, [_1]) } - public var NetworkUsageSettings_CallDataSection: String { return self._s[2626]! } - public var PasscodeSettings_HelpTop: String { return self._s[2627]! } - public var Conversation_WalletRequiredTitle: String { return self._s[2628]! } - public var Group_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[2629]! } - public var Passport_Address_TypeRentalAgreement: String { return self._s[2630]! } - public var EditTheme_ShortLink: String { return self._s[2631]! } - public var Theme_Colors_ColorWallpaperWarning: String { return self._s[2632]! } - public var ProxyServer_VoiceOver_Active: String { return self._s[2633]! } - public var ReportPeer_ReasonOther_Placeholder: String { return self._s[2634]! } - public var CheckoutInfo_ErrorPhoneInvalid: String { return self._s[2635]! } - public var Call_Accept: String { return self._s[2637]! } - public var GroupRemoved_RemoveInfo: String { return self._s[2638]! } - public var Month_GenMarch: String { return self._s[2640]! } - public var PhotoEditor_ShadowsTool: String { return self._s[2641]! } - public var LoginPassword_Title: String { return self._s[2642]! } - public var Call_End: String { return self._s[2643]! } - public var Watch_Conversation_GroupInfo: String { return self._s[2644]! } - public var VoiceOver_Chat_Contact: String { return self._s[2645]! } - public var EditTheme_Create_Preview_IncomingText: String { return self._s[2646]! } - public var CallSettings_Always: String { return self._s[2647]! } - public var CallFeedback_Success: String { return self._s[2648]! } - public var TwoStepAuth_SetupHint: String { return self._s[2649]! } + public var NetworkUsageSettings_CallDataSection: String { return self._s[2634]! } + public var PasscodeSettings_HelpTop: String { return self._s[2635]! } + public var Conversation_WalletRequiredTitle: String { return self._s[2636]! } + public var Group_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[2637]! } + public var Passport_Address_TypeRentalAgreement: String { return self._s[2638]! } + public var EditTheme_ShortLink: String { return self._s[2639]! } + public var Theme_Colors_ColorWallpaperWarning: String { return self._s[2640]! } + public var ProxyServer_VoiceOver_Active: String { return self._s[2641]! } + public var ReportPeer_ReasonOther_Placeholder: String { return self._s[2642]! } + public var CheckoutInfo_ErrorPhoneInvalid: String { return self._s[2643]! } + public var Call_Accept: String { return self._s[2645]! } + public var GroupRemoved_RemoveInfo: String { return self._s[2646]! } + public var Month_GenMarch: String { return self._s[2648]! } + public var PhotoEditor_ShadowsTool: String { return self._s[2649]! } + public var LoginPassword_Title: String { return self._s[2650]! } + public var Call_End: String { return self._s[2651]! } + public var Watch_Conversation_GroupInfo: String { return self._s[2652]! } + public var VoiceOver_Chat_Contact: String { return self._s[2653]! } + public var EditTheme_Create_Preview_IncomingText: String { return self._s[2654]! } + public var CallSettings_Always: String { return self._s[2655]! } + public var CallFeedback_Success: String { return self._s[2656]! } + public var TwoStepAuth_SetupHint: String { return self._s[2657]! } public func AddContact_ContactWillBeSharedAfterMutual(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2650]!, self._r[2650]!, [_1]) + return formatWithArgumentRanges(self._s[2658]!, self._r[2658]!, [_1]) } - public var ConversationProfile_UsersTooMuchError: String { return self._s[2651]! } - public var Login_PhoneTitle: String { return self._s[2652]! } - public var Passport_FieldPhoneHelp: String { return self._s[2653]! } - public var Weekday_ShortSunday: String { return self._s[2654]! } - public var Passport_InfoFAQ_URL: String { return self._s[2655]! } - public var ContactInfo_Job: String { return self._s[2657]! } - public var UserInfo_InviteBotToGroup: String { return self._s[2658]! } - public var Appearance_ThemeCarouselNightBlue: String { return self._s[2659]! } - public var CreatePoll_QuizTip: String { return self._s[2660]! } - public var TwoFactorSetup_Email_Text: String { return self._s[2661]! } - public var TwoStepAuth_PasswordRemovePassportConfirmation: String { return self._s[2662]! } - public var Invite_ChannelsTooMuch: String { return self._s[2663]! } - public var Wallet_Send_ConfirmationConfirm: String { return self._s[2664]! } - public var Wallet_TransactionInfo_OtherFeeInfo: String { return self._s[2665]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsPreview: String { return self._s[2666]! } - public var Wallet_Receive_AmountText: String { return self._s[2667]! } - public var Passport_DeletePersonalDetailsConfirmation: String { return self._s[2668]! } - public var CallFeedback_ReasonNoise: String { return self._s[2669]! } - public var Appearance_AppIconDefault: String { return self._s[2671]! } - public var Passport_Identity_AddInternalPassport: String { return self._s[2672]! } - public var MediaPicker_AddCaption: String { return self._s[2673]! } - public var CallSettings_TabIconDescription: String { return self._s[2674]! } + public var ConversationProfile_UsersTooMuchError: String { return self._s[2659]! } + public var Login_PhoneTitle: String { return self._s[2660]! } + public var Passport_FieldPhoneHelp: String { return self._s[2661]! } + public var Weekday_ShortSunday: String { return self._s[2662]! } + public var Passport_InfoFAQ_URL: String { return self._s[2663]! } + public var ContactInfo_Job: String { return self._s[2665]! } + public var UserInfo_InviteBotToGroup: String { return self._s[2666]! } + public var Appearance_ThemeCarouselNightBlue: String { return self._s[2667]! } + public var CreatePoll_QuizTip: String { return self._s[2668]! } + public var TwoFactorSetup_Email_Text: String { return self._s[2669]! } + public var TwoStepAuth_PasswordRemovePassportConfirmation: String { return self._s[2670]! } + public var Invite_ChannelsTooMuch: String { return self._s[2671]! } + public var Wallet_Send_ConfirmationConfirm: String { return self._s[2672]! } + public var Wallet_TransactionInfo_OtherFeeInfo: String { return self._s[2673]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsPreview: String { return self._s[2674]! } + public var Wallet_Receive_AmountText: String { return self._s[2675]! } + public var Passport_DeletePersonalDetailsConfirmation: String { return self._s[2676]! } + public var CallFeedback_ReasonNoise: String { return self._s[2677]! } + public var Appearance_AppIconDefault: String { return self._s[2679]! } + public var Passport_Identity_AddInternalPassport: String { return self._s[2680]! } + public var MediaPicker_AddCaption: String { return self._s[2681]! } + public var CallSettings_TabIconDescription: String { return self._s[2682]! } public func VoiceOver_Chat_Caption(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2675]!, self._r[2675]!, [_0]) + return formatWithArgumentRanges(self._s[2683]!, self._r[2683]!, [_0]) } - public var IntentsSettings_SuggestedChatsGroups: String { return self._s[2676]! } + public var IntentsSettings_SuggestedChatsGroups: String { return self._s[2684]! } public func Map_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2677]!, self._r[2677]!, [_0]) + return formatWithArgumentRanges(self._s[2685]!, self._r[2685]!, [_0]) } - public var ChatList_UndoArchiveHiddenTitle: String { return self._s[2678]! } - public var Privacy_GroupsAndChannels_AlwaysAllow: String { return self._s[2679]! } - public var Passport_Identity_TypePersonalDetails: String { return self._s[2680]! } - public var DialogList_SearchSectionRecent: String { return self._s[2681]! } - public var PrivacyPolicy_DeclineMessage: String { return self._s[2682]! } - public var CreatePoll_Anonymous: String { return self._s[2683]! } - public var LogoutOptions_ClearCacheText: String { return self._s[2686]! } - public var LastSeen_WithinAWeek: String { return self._s[2687]! } - public var ChannelMembers_GroupAdminsTitle: String { return self._s[2688]! } - public var Conversation_CloudStorage_ChatStatus: String { return self._s[2690]! } - public var VoiceOver_Media_PlaybackRateNormal: String { return self._s[2691]! } + public var ChatList_UndoArchiveHiddenTitle: String { return self._s[2686]! } + public var Privacy_GroupsAndChannels_AlwaysAllow: String { return self._s[2687]! } + public var Passport_Identity_TypePersonalDetails: String { return self._s[2688]! } + public var DialogList_SearchSectionRecent: String { return self._s[2689]! } + public var PrivacyPolicy_DeclineMessage: String { return self._s[2690]! } + public var CreatePoll_Anonymous: String { return self._s[2691]! } + public var LogoutOptions_ClearCacheText: String { return self._s[2694]! } + public var LastSeen_WithinAWeek: String { return self._s[2695]! } + public var ChannelMembers_GroupAdminsTitle: String { return self._s[2696]! } + public var Conversation_CloudStorage_ChatStatus: String { return self._s[2698]! } + public var VoiceOver_Media_PlaybackRateNormal: String { return self._s[2699]! } public func AddContact_SharedContactExceptionInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2692]!, self._r[2692]!, [_0]) + return formatWithArgumentRanges(self._s[2700]!, self._r[2700]!, [_0]) } - public var Passport_Address_TypeResidentialAddress: String { return self._s[2693]! } - public var Conversation_StatusLeftGroup: String { return self._s[2694]! } - public var SocksProxySetup_ProxyDetailsTitle: String { return self._s[2695]! } - public var SettingsSearch_Synonyms_Calls_Title: String { return self._s[2697]! } - public var GroupPermission_AddSuccess: String { return self._s[2698]! } - public var PhotoEditor_BlurToolRadial: String { return self._s[2700]! } - public var Conversation_ContextMenuCopy: String { return self._s[2701]! } - public var AccessDenied_CallMicrophone: String { return self._s[2702]! } + public var Passport_Address_TypeResidentialAddress: String { return self._s[2701]! } + public var Conversation_StatusLeftGroup: String { return self._s[2702]! } + public var SocksProxySetup_ProxyDetailsTitle: String { return self._s[2703]! } + public var SettingsSearch_Synonyms_Calls_Title: String { return self._s[2705]! } + public var GroupPermission_AddSuccess: String { return self._s[2706]! } + public var PhotoEditor_BlurToolRadial: String { return self._s[2708]! } + public var Conversation_ContextMenuCopy: String { return self._s[2709]! } + public var AccessDenied_CallMicrophone: String { return self._s[2710]! } public func Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2703]!, self._r[2703]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2711]!, self._r[2711]!, [_1, _2, _3]) } - public var Login_InvalidFirstNameError: String { return self._s[2704]! } - public var Notifications_Badge_CountUnreadMessages_InfoOn: String { return self._s[2705]! } - public var Checkout_PaymentMethod_New: String { return self._s[2706]! } - public var ShareMenu_CopyShareLinkGame: String { return self._s[2707]! } - public var PhotoEditor_QualityTool: String { return self._s[2708]! } - public var Login_SendCodeViaSms: String { return self._s[2709]! } - public var SettingsSearch_Synonyms_Privacy_DeleteAccountIfAwayFor: String { return self._s[2710]! } - public var Chat_SlowmodeAttachmentLimitReached: String { return self._s[2711]! } - public var Wallet_Receive_CopyAddress: String { return self._s[2712]! } - public var Login_EmailNotConfiguredError: String { return self._s[2713]! } - public var SocksProxySetup_Status: String { return self._s[2714]! } - public var Conversation_ScheduleMessage_SendWhenOnline: String { return self._s[2715]! } - public var PrivacyPolicy_Accept: String { return self._s[2716]! } - public var Notifications_ExceptionsMessagePlaceholder: String { return self._s[2717]! } - public var Appearance_AppIconClassicX: String { return self._s[2718]! } + public var Login_InvalidFirstNameError: String { return self._s[2712]! } + public var Notifications_Badge_CountUnreadMessages_InfoOn: String { return self._s[2713]! } + public var Checkout_PaymentMethod_New: String { return self._s[2714]! } + public var ShareMenu_CopyShareLinkGame: String { return self._s[2715]! } + public var PhotoEditor_QualityTool: String { return self._s[2716]! } + public var Login_SendCodeViaSms: String { return self._s[2717]! } + public var SettingsSearch_Synonyms_Privacy_DeleteAccountIfAwayFor: String { return self._s[2718]! } + public var Chat_SlowmodeAttachmentLimitReached: String { return self._s[2719]! } + public var Wallet_Receive_CopyAddress: String { return self._s[2720]! } + public var Login_EmailNotConfiguredError: String { return self._s[2721]! } + public var SocksProxySetup_Status: String { return self._s[2722]! } + public var Conversation_ScheduleMessage_SendWhenOnline: String { return self._s[2723]! } + public var PrivacyPolicy_Accept: String { return self._s[2724]! } + public var Notifications_ExceptionsMessagePlaceholder: String { return self._s[2725]! } + public var Appearance_AppIconClassicX: String { return self._s[2726]! } public func PUSH_CHAT_MESSAGE_TEXT(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2719]!, self._r[2719]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2727]!, self._r[2727]!, [_1, _2, _3]) } - public var OwnershipTransfer_SecurityRequirements: String { return self._s[2720]! } - public var InfoPlist_NSLocationAlwaysUsageDescription: String { return self._s[2722]! } - public var AutoNightTheme_Automatic: String { return self._s[2723]! } - public var Channel_Username_InvalidStartsWithNumber: String { return self._s[2724]! } - public var Privacy_ContactsSyncHelp: String { return self._s[2725]! } - public var Cache_Help: String { return self._s[2726]! } - public var Group_ErrorAccessDenied: String { return self._s[2727]! } - public var Passport_Language_fa: String { return self._s[2728]! } - public var Wallet_Intro_Text: String { return self._s[2729]! } - public var Login_ResetAccountProtected_TimerTitle: String { return self._s[2730]! } - public var VoiceOver_Chat_YourVideoMessage: String { return self._s[2731]! } - public var PrivacySettings_LastSeen: String { return self._s[2732]! } + public var OwnershipTransfer_SecurityRequirements: String { return self._s[2728]! } + public var InfoPlist_NSLocationAlwaysUsageDescription: String { return self._s[2730]! } + public var AutoNightTheme_Automatic: String { return self._s[2731]! } + public var Channel_Username_InvalidStartsWithNumber: String { return self._s[2732]! } + public var Privacy_ContactsSyncHelp: String { return self._s[2733]! } + public var Cache_Help: String { return self._s[2734]! } + public var Group_ErrorAccessDenied: String { return self._s[2735]! } + public var Passport_Language_fa: String { return self._s[2736]! } + public var Wallet_Intro_Text: String { return self._s[2737]! } + public var Login_ResetAccountProtected_TimerTitle: String { return self._s[2738]! } + public var VoiceOver_Chat_YourVideoMessage: String { return self._s[2739]! } + public var PrivacySettings_LastSeen: String { return self._s[2740]! } public func DialogList_MultipleTyping(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2733]!, self._r[2733]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2741]!, self._r[2741]!, [_0, _1]) } - public var Wallet_Configuration_Apply: String { return self._s[2737]! } - public var Preview_SaveGif: String { return self._s[2738]! } - public var SettingsSearch_Synonyms_Privacy_TwoStepAuth: String { return self._s[2739]! } - public var Profile_About: String { return self._s[2740]! } - public var Channel_About_Placeholder: String { return self._s[2741]! } - public var Login_InfoTitle: String { return self._s[2742]! } + public var Wallet_Configuration_Apply: String { return self._s[2745]! } + public var Preview_SaveGif: String { return self._s[2746]! } + public var SettingsSearch_Synonyms_Privacy_TwoStepAuth: String { return self._s[2747]! } + public var Profile_About: String { return self._s[2748]! } + public var Channel_About_Placeholder: String { return self._s[2749]! } + public var Login_InfoTitle: String { return self._s[2750]! } public func TwoStepAuth_SetupPendingEmail(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2743]!, self._r[2743]!, [_0]) + return formatWithArgumentRanges(self._s[2751]!, self._r[2751]!, [_0]) } - public var EditTheme_Expand_Preview_IncomingReplyText: String { return self._s[2744]! } - public var Watch_Suggestion_CantTalk: String { return self._s[2746]! } - public var ContactInfo_Title: String { return self._s[2747]! } - public var Media_ShareThisVideo: String { return self._s[2748]! } - public var Weekday_ShortFriday: String { return self._s[2749]! } - public var AccessDenied_Contacts: String { return self._s[2751]! } - public var Notification_CallIncomingShort: String { return self._s[2752]! } - public var Group_Setup_TypePublic: String { return self._s[2753]! } - public var Notifications_MessageNotificationsExceptions: String { return self._s[2754]! } - public var Notifications_Badge_IncludeChannels: String { return self._s[2755]! } - public var Notifications_MessageNotificationsPreview: String { return self._s[2758]! } - public var ConversationProfile_ErrorCreatingConversation: String { return self._s[2759]! } - public var Group_ErrorAddTooMuchBots: String { return self._s[2760]! } - public var Privacy_GroupsAndChannels_CustomShareHelp: String { return self._s[2761]! } - public var Permissions_CellularDataAllowInSettings_v0: String { return self._s[2762]! } + public var EditTheme_Expand_Preview_IncomingReplyText: String { return self._s[2752]! } + public var Watch_Suggestion_CantTalk: String { return self._s[2754]! } + public var ContactInfo_Title: String { return self._s[2755]! } + public var Media_ShareThisVideo: String { return self._s[2756]! } + public var Weekday_ShortFriday: String { return self._s[2757]! } + public var AccessDenied_Contacts: String { return self._s[2759]! } + public var Notification_CallIncomingShort: String { return self._s[2760]! } + public var Group_Setup_TypePublic: String { return self._s[2761]! } + public var Notifications_MessageNotificationsExceptions: String { return self._s[2762]! } + public var Notifications_Badge_IncludeChannels: String { return self._s[2763]! } + public var Notifications_MessageNotificationsPreview: String { return self._s[2766]! } + public var ConversationProfile_ErrorCreatingConversation: String { return self._s[2767]! } + public var Group_ErrorAddTooMuchBots: String { return self._s[2768]! } + public var Privacy_GroupsAndChannels_CustomShareHelp: String { return self._s[2769]! } + public var Permissions_CellularDataAllowInSettings_v0: String { return self._s[2770]! } public func Wallet_SecureStorageChanged_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2763]!, self._r[2763]!, [_0]) + return formatWithArgumentRanges(self._s[2771]!, self._r[2771]!, [_0]) } - public var DialogList_Typing: String { return self._s[2764]! } - public var CallFeedback_IncludeLogs: String { return self._s[2766]! } - public var Checkout_Phone: String { return self._s[2768]! } - public var Login_InfoFirstNamePlaceholder: String { return self._s[2771]! } - public var Privacy_Calls_Integration: String { return self._s[2772]! } - public var Notifications_PermissionsAllow: String { return self._s[2773]! } - public var TwoStepAuth_AddHintDescription: String { return self._s[2777]! } - public var Settings_ChatSettings: String { return self._s[2778]! } - public var Conversation_SendingOptionsTooltip: String { return self._s[2779]! } + public var DialogList_Typing: String { return self._s[2772]! } + public var CallFeedback_IncludeLogs: String { return self._s[2774]! } + public var Checkout_Phone: String { return self._s[2776]! } + public var Login_InfoFirstNamePlaceholder: String { return self._s[2779]! } + public var Privacy_Calls_Integration: String { return self._s[2780]! } + public var Notifications_PermissionsAllow: String { return self._s[2781]! } + public var TwoStepAuth_AddHintDescription: String { return self._s[2786]! } + public var Settings_ChatSettings: String { return self._s[2787]! } + public var Conversation_SendingOptionsTooltip: String { return self._s[2788]! } public func UserInfo_StartSecretChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2781]!, self._r[2781]!, [_0]) + return formatWithArgumentRanges(self._s[2790]!, self._r[2790]!, [_0]) } public func Channel_AdminLog_MessageInvitedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2782]!, self._r[2782]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2791]!, self._r[2791]!, [_1, _2]) } - public var GroupRemoved_DeleteUser: String { return self._s[2784]! } + public var GroupRemoved_DeleteUser: String { return self._s[2793]! } public func Channel_AdminLog_PollStopped(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2785]!, self._r[2785]!, [_0]) + return formatWithArgumentRanges(self._s[2794]!, self._r[2794]!, [_0]) } public func PUSH_MESSAGE_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2786]!, self._r[2786]!, [_1]) + return formatWithArgumentRanges(self._s[2795]!, self._r[2795]!, [_1]) } - public var Login_ContinueWithLocalization: String { return self._s[2787]! } - public var Watch_Message_ForwardedFrom: String { return self._s[2788]! } - public var TwoStepAuth_EnterEmailCode: String { return self._s[2790]! } - public var Conversation_Unblock: String { return self._s[2791]! } - public var PrivacySettings_DataSettings: String { return self._s[2792]! } - public var WallpaperPreview_PatternPaternApply: String { return self._s[2793]! } - public var Group_PublicLink_Info: String { return self._s[2794]! } + public var Login_ContinueWithLocalization: String { return self._s[2796]! } + public var Watch_Message_ForwardedFrom: String { return self._s[2797]! } + public var TwoStepAuth_EnterEmailCode: String { return self._s[2799]! } + public var Conversation_Unblock: String { return self._s[2800]! } + public var PrivacySettings_DataSettings: String { return self._s[2801]! } + public var WallpaperPreview_PatternPaternApply: String { return self._s[2802]! } + public var Group_PublicLink_Info: String { return self._s[2803]! } public func Wallet_Time_PreciseDate_m1(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2795]!, self._r[2795]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2804]!, self._r[2804]!, [_1, _2, _3]) } - public var Notifications_InAppNotificationsVibrate: String { return self._s[2796]! } + public var Notifications_InAppNotificationsVibrate: String { return self._s[2805]! } public func Privacy_GroupsAndChannels_InviteToChannelError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2797]!, self._r[2797]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2806]!, self._r[2806]!, [_0, _1]) } - public var OldChannels_ChannelsHeader: String { return self._s[2799]! } - public var Wallet_RestoreFailed_CreateWallet: String { return self._s[2800]! } - public var PrivacySettings_Passcode: String { return self._s[2802]! } - public var Call_Mute: String { return self._s[2803]! } - public var Wallet_Weekday_Yesterday: String { return self._s[2804]! } - public var Passport_Language_dz: String { return self._s[2805]! } - public var Wallet_Receive_AmountHeader: String { return self._s[2806]! } - public var Wallet_TransactionInfo_OtherFeeInfoUrl: String { return self._s[2807]! } - public var Passport_Language_tk: String { return self._s[2808]! } + public var OldChannels_ChannelsHeader: String { return self._s[2808]! } + public var Wallet_RestoreFailed_CreateWallet: String { return self._s[2809]! } + public var PrivacySettings_Passcode: String { return self._s[2811]! } + public var Call_Mute: String { return self._s[2812]! } + public var Wallet_Weekday_Yesterday: String { return self._s[2813]! } + public var Passport_Language_dz: String { return self._s[2814]! } + public var Wallet_Receive_AmountHeader: String { return self._s[2815]! } + public var Wallet_TransactionInfo_OtherFeeInfoUrl: String { return self._s[2816]! } + public var Passport_Language_tk: String { return self._s[2817]! } public func Login_EmailCodeSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2809]!, self._r[2809]!, [_0]) + return formatWithArgumentRanges(self._s[2818]!, self._r[2818]!, [_0]) } - public var Settings_Search: String { return self._s[2810]! } - public var Wallet_Month_ShortFebruary: String { return self._s[2811]! } - public var InfoPlist_NSPhotoLibraryUsageDescription: String { return self._s[2812]! } - public var Wallet_Configuration_SourceJSON: String { return self._s[2813]! } - public var Conversation_ContextMenuReply: String { return self._s[2814]! } - public var WallpaperSearch_ColorBrown: String { return self._s[2815]! } - public var Chat_AttachmentMultipleForwardDisabled: String { return self._s[2816]! } - public var Tour_Title1: String { return self._s[2817]! } - public var Wallet_Alert_Cancel: String { return self._s[2818]! } - public var Conversation_ClearGroupHistory: String { return self._s[2820]! } - public var Wallet_TransactionInfo_RecipientHeader: String { return self._s[2821]! } - public var WallpaperPreview_Motion: String { return self._s[2822]! } + public var Settings_Search: String { return self._s[2819]! } + public var Wallet_Month_ShortFebruary: String { return self._s[2820]! } + public var InfoPlist_NSPhotoLibraryUsageDescription: String { return self._s[2821]! } + public var Wallet_Configuration_SourceJSON: String { return self._s[2822]! } + public var Conversation_ContextMenuReply: String { return self._s[2823]! } + public var WallpaperSearch_ColorBrown: String { return self._s[2824]! } + public var Chat_AttachmentMultipleForwardDisabled: String { return self._s[2825]! } + public var Tour_Title1: String { return self._s[2826]! } + public var Wallet_Alert_Cancel: String { return self._s[2827]! } + public var Conversation_ClearGroupHistory: String { return self._s[2829]! } + public var Wallet_TransactionInfo_RecipientHeader: String { return self._s[2830]! } + public var WallpaperPreview_Motion: String { return self._s[2831]! } public func Checkout_PasswordEntry_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2823]!, self._r[2823]!, [_0]) - } - public var Wallet_Configuration_ApplyErrorTextJSONInvalidData: String { return self._s[2824]! } - public var Call_RateCall: String { return self._s[2825]! } - public var Channel_AdminLog_BanSendStickersAndGifs: String { return self._s[2826]! } - public var Passport_PasswordCompleteSetup: String { return self._s[2827]! } - public var Conversation_InputTextSilentBroadcastPlaceholder: String { return self._s[2828]! } - public var UserInfo_LastNamePlaceholder: String { return self._s[2830]! } - public func Login_WillCallYou(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2832]!, self._r[2832]!, [_0]) } - public var Compose_Create: String { return self._s[2833]! } - public var Contacts_InviteToTelegram: String { return self._s[2834]! } - public var GroupInfo_Notifications: String { return self._s[2835]! } - public var ChatList_DeleteSavedMessagesConfirmationAction: String { return self._s[2837]! } - public var Message_PinnedLiveLocationMessage: String { return self._s[2838]! } - public var Month_GenApril: String { return self._s[2839]! } - public var Appearance_AutoNightTheme: String { return self._s[2840]! } - public var ChatSettings_AutomaticAudioDownload: String { return self._s[2842]! } - public var Login_CodeSentSms: String { return self._s[2844]! } + public var Wallet_Configuration_ApplyErrorTextJSONInvalidData: String { return self._s[2833]! } + public var Call_RateCall: String { return self._s[2834]! } + public var Channel_AdminLog_BanSendStickersAndGifs: String { return self._s[2835]! } + public var Passport_PasswordCompleteSetup: String { return self._s[2836]! } + public var Conversation_InputTextSilentBroadcastPlaceholder: String { return self._s[2837]! } + public var UserInfo_LastNamePlaceholder: String { return self._s[2839]! } + public func Login_WillCallYou(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2841]!, self._r[2841]!, [_0]) + } + public var Compose_Create: String { return self._s[2842]! } + public var Contacts_InviteToTelegram: String { return self._s[2843]! } + public var GroupInfo_Notifications: String { return self._s[2844]! } + public var ChatList_DeleteSavedMessagesConfirmationAction: String { return self._s[2846]! } + public var Message_PinnedLiveLocationMessage: String { return self._s[2847]! } + public var Month_GenApril: String { return self._s[2848]! } + public var Appearance_AutoNightTheme: String { return self._s[2849]! } + public var ChatSettings_AutomaticAudioDownload: String { return self._s[2851]! } + public var Login_CodeSentSms: String { return self._s[2853]! } public func UserInfo_UnblockConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2845]!, self._r[2845]!, [_0]) + return formatWithArgumentRanges(self._s[2854]!, self._r[2854]!, [_0]) } - public var EmptyGroupInfo_Line3: String { return self._s[2846]! } - public var LogoutOptions_ContactSupportText: String { return self._s[2847]! } - public var Passport_Language_hr: String { return self._s[2848]! } - public var Common_ActionNotAllowedError: String { return self._s[2849]! } + public var EmptyGroupInfo_Line3: String { return self._s[2855]! } + public var LogoutOptions_ContactSupportText: String { return self._s[2856]! } + public var Passport_Language_hr: String { return self._s[2857]! } + public var Common_ActionNotAllowedError: String { return self._s[2858]! } public func Channel_AdminLog_MessageRestrictedNewSetting(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2850]!, self._r[2850]!, [_0]) + return formatWithArgumentRanges(self._s[2859]!, self._r[2859]!, [_0]) } - public var GroupInfo_InviteLink_CopyLink: String { return self._s[2851]! } - public var Wallet_Info_TransactionFrom: String { return self._s[2852]! } - public var Wallet_Send_ErrorDecryptionFailed: String { return self._s[2853]! } - public var Conversation_InputTextBroadcastPlaceholder: String { return self._s[2854]! } - public var Privacy_SecretChatsTitle: String { return self._s[2855]! } - public var Notification_SecretChatMessageScreenshotSelf: String { return self._s[2857]! } - public var GroupInfo_AddUserLeftError: String { return self._s[2858]! } - public var AutoDownloadSettings_TypePrivateChats: String { return self._s[2859]! } - public var LogoutOptions_ContactSupportTitle: String { return self._s[2860]! } - public var Appearance_ThemePreview_Chat_7_Text: String { return self._s[2861]! } - public var Channel_AddBotErrorHaveRights: String { return self._s[2862]! } - public var Preview_DeleteGif: String { return self._s[2863]! } - public var GroupInfo_Permissions_Exceptions: String { return self._s[2864]! } - public var Group_ErrorNotMutualContact: String { return self._s[2865]! } - public var Notification_MessageLifetime5s: String { return self._s[2866]! } - public var Wallet_Send_OwnAddressAlertText: String { return self._s[2867]! } - public var OldChannels_ChannelFormat: String { return self._s[2868]! } + public var GroupInfo_InviteLink_CopyLink: String { return self._s[2860]! } + public var Wallet_Info_TransactionFrom: String { return self._s[2861]! } + public var Wallet_Send_ErrorDecryptionFailed: String { return self._s[2862]! } + public var Conversation_InputTextBroadcastPlaceholder: String { return self._s[2863]! } + public var Privacy_SecretChatsTitle: String { return self._s[2864]! } + public var Notification_SecretChatMessageScreenshotSelf: String { return self._s[2866]! } + public var GroupInfo_AddUserLeftError: String { return self._s[2867]! } + public var AutoDownloadSettings_TypePrivateChats: String { return self._s[2868]! } + public var LogoutOptions_ContactSupportTitle: String { return self._s[2869]! } + public var Appearance_ThemePreview_Chat_7_Text: String { return self._s[2870]! } + public var Channel_AddBotErrorHaveRights: String { return self._s[2871]! } + public var Preview_DeleteGif: String { return self._s[2872]! } + public var GroupInfo_Permissions_Exceptions: String { return self._s[2873]! } + public var Group_ErrorNotMutualContact: String { return self._s[2874]! } + public var Notification_MessageLifetime5s: String { return self._s[2875]! } + public var Wallet_Send_OwnAddressAlertText: String { return self._s[2876]! } + public var OldChannels_ChannelFormat: String { return self._s[2877]! } public func Watch_LastSeen_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2869]!, self._r[2869]!, [_0]) + return formatWithArgumentRanges(self._s[2878]!, self._r[2878]!, [_0]) } - public var VoiceOver_Chat_Video: String { return self._s[2870]! } - public var Channel_OwnershipTransfer_ErrorPublicChannelsTooMuch: String { return self._s[2872]! } - public var ReportSpam_DeleteThisChat: String { return self._s[2873]! } - public var Passport_Address_AddBankStatement: String { return self._s[2874]! } - public var Notification_CallIncoming: String { return self._s[2875]! } - public var Wallet_Words_NotDoneTitle: String { return self._s[2876]! } - public var Compose_NewGroupTitle: String { return self._s[2877]! } - public var TwoStepAuth_RecoveryCodeHelp: String { return self._s[2879]! } - public var Passport_Address_Postcode: String { return self._s[2881]! } + public var VoiceOver_Chat_Video: String { return self._s[2879]! } + public var Channel_OwnershipTransfer_ErrorPublicChannelsTooMuch: String { return self._s[2881]! } + public var ReportSpam_DeleteThisChat: String { return self._s[2882]! } + public var Passport_Address_AddBankStatement: String { return self._s[2883]! } + public var Notification_CallIncoming: String { return self._s[2884]! } + public var Wallet_Words_NotDoneTitle: String { return self._s[2885]! } + public var Compose_NewGroupTitle: String { return self._s[2886]! } + public var TwoStepAuth_RecoveryCodeHelp: String { return self._s[2888]! } + public var Passport_Address_Postcode: String { return self._s[2890]! } public func LastSeen_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2882]!, self._r[2882]!, [_0]) + return formatWithArgumentRanges(self._s[2891]!, self._r[2891]!, [_0]) } - public var Checkout_NewCard_SaveInfoHelp: String { return self._s[2883]! } - public var Wallet_Month_ShortOctober: String { return self._s[2884]! } - public var VoiceOver_Chat_YourMusic: String { return self._s[2885]! } - public var WallpaperColors_Title: String { return self._s[2886]! } - public var SocksProxySetup_ShareQRCodeInfo: String { return self._s[2887]! } - public var VoiceOver_MessageContextForward: String { return self._s[2888]! } - public var GroupPermission_Duration: String { return self._s[2889]! } + public var Checkout_NewCard_SaveInfoHelp: String { return self._s[2892]! } + public var Wallet_Month_ShortOctober: String { return self._s[2893]! } + public var VoiceOver_Chat_YourMusic: String { return self._s[2894]! } + public var WallpaperColors_Title: String { return self._s[2895]! } + public var SocksProxySetup_ShareQRCodeInfo: String { return self._s[2896]! } + public var VoiceOver_MessageContextForward: String { return self._s[2897]! } + public var GroupPermission_Duration: String { return self._s[2898]! } public func Cache_Clear(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2890]!, self._r[2890]!, [_0]) + return formatWithArgumentRanges(self._s[2899]!, self._r[2899]!, [_0]) } - public var Bot_GroupStatusDoesNotReadHistory: String { return self._s[2891]! } - public var Username_Placeholder: String { return self._s[2892]! } - public var CallFeedback_WhatWentWrong: String { return self._s[2893]! } - public var Passport_FieldAddressUploadHelp: String { return self._s[2894]! } - public var Permissions_NotificationsAllowInSettings_v0: String { return self._s[2895]! } + public var Bot_GroupStatusDoesNotReadHistory: String { return self._s[2900]! } + public var Username_Placeholder: String { return self._s[2901]! } + public var CallFeedback_WhatWentWrong: String { return self._s[2902]! } + public var Passport_FieldAddressUploadHelp: String { return self._s[2903]! } + public var Permissions_NotificationsAllowInSettings_v0: String { return self._s[2904]! } public func Channel_AdminLog_MessageChangedUnlinkedChannel(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2897]!, self._r[2897]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2906]!, self._r[2906]!, [_1, _2]) } - public var Passport_PasswordDescription: String { return self._s[2898]! } - public var Channel_MessagePhotoUpdated: String { return self._s[2899]! } - public var MediaPicker_TapToUngroupDescription: String { return self._s[2900]! } - public var SettingsSearch_Synonyms_Notifications_BadgeCountUnreadMessages: String { return self._s[2901]! } - public var AttachmentMenu_PhotoOrVideo: String { return self._s[2902]! } - public var Conversation_ContextMenuMore: String { return self._s[2903]! } - public var Privacy_PaymentsClearInfo: String { return self._s[2904]! } - public var CallSettings_TabIcon: String { return self._s[2905]! } - public var KeyCommand_Find: String { return self._s[2906]! } - public var ClearCache_FreeSpaceDescription: String { return self._s[2907]! } - public var Appearance_ThemePreview_ChatList_7_Text: String { return self._s[2908]! } - public var EditTheme_Edit_Preview_IncomingText: String { return self._s[2909]! } - public var Message_PinnedGame: String { return self._s[2910]! } - public var VoiceOver_Chat_ForwardedFromYou: String { return self._s[2911]! } - public var Notifications_Badge_CountUnreadMessages_InfoOff: String { return self._s[2913]! } - public var Login_CallRequestState2: String { return self._s[2915]! } - public var CheckoutInfo_ReceiverInfoNamePlaceholder: String { return self._s[2917]! } + public var Passport_PasswordDescription: String { return self._s[2907]! } + public var Channel_MessagePhotoUpdated: String { return self._s[2908]! } + public var MediaPicker_TapToUngroupDescription: String { return self._s[2909]! } + public var SettingsSearch_Synonyms_Notifications_BadgeCountUnreadMessages: String { return self._s[2910]! } + public var AttachmentMenu_PhotoOrVideo: String { return self._s[2911]! } + public var Conversation_ContextMenuMore: String { return self._s[2912]! } + public var Privacy_PaymentsClearInfo: String { return self._s[2913]! } + public var CallSettings_TabIcon: String { return self._s[2914]! } + public var KeyCommand_Find: String { return self._s[2915]! } + public var ClearCache_FreeSpaceDescription: String { return self._s[2916]! } + public var Appearance_ThemePreview_ChatList_7_Text: String { return self._s[2917]! } + public var EditTheme_Edit_Preview_IncomingText: String { return self._s[2918]! } + public var Message_PinnedGame: String { return self._s[2919]! } + public var VoiceOver_Chat_ForwardedFromYou: String { return self._s[2920]! } + public var Notifications_Badge_CountUnreadMessages_InfoOff: String { return self._s[2922]! } + public var Login_CallRequestState2: String { return self._s[2924]! } + public var CheckoutInfo_ReceiverInfoNamePlaceholder: String { return self._s[2926]! } public func VoiceOver_Chat_PhotoFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2918]!, self._r[2918]!, [_0]) + return formatWithArgumentRanges(self._s[2927]!, self._r[2927]!, [_0]) } public func Checkout_PayPrice(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2920]!, self._r[2920]!, [_0]) + return formatWithArgumentRanges(self._s[2929]!, self._r[2929]!, [_0]) } - public var AuthSessions_AddDevice: String { return self._s[2921]! } - public var WallpaperPreview_Blurred: String { return self._s[2922]! } - public var Conversation_InstantPagePreview: String { return self._s[2923]! } + public var AuthSessions_AddDevice: String { return self._s[2930]! } + public var WallpaperPreview_Blurred: String { return self._s[2931]! } + public var Conversation_InstantPagePreview: String { return self._s[2932]! } public func DialogList_SingleUploadingVideoSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2924]!, self._r[2924]!, [_0]) + return formatWithArgumentRanges(self._s[2933]!, self._r[2933]!, [_0]) } - public var SecretTimer_VideoDescription: String { return self._s[2927]! } - public var WallpaperSearch_ColorRed: String { return self._s[2928]! } - public var GroupPermission_NoPinMessages: String { return self._s[2929]! } - public var Passport_Language_es: String { return self._s[2930]! } - public var Permissions_ContactsAllow_v0: String { return self._s[2932]! } - public var Conversation_EditingMessageMediaEditCurrentVideo: String { return self._s[2933]! } + public var SecretTimer_VideoDescription: String { return self._s[2936]! } + public var WallpaperSearch_ColorRed: String { return self._s[2937]! } + public var GroupPermission_NoPinMessages: String { return self._s[2938]! } + public var Passport_Language_es: String { return self._s[2939]! } + public var Permissions_ContactsAllow_v0: String { return self._s[2941]! } + public var Conversation_EditingMessageMediaEditCurrentVideo: String { return self._s[2942]! } public func PUSH_CHAT_MESSAGE_CONTACT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2934]!, self._r[2934]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2943]!, self._r[2943]!, [_1, _2]) } - public var Privacy_Forwards_CustomHelp: String { return self._s[2935]! } - public var WebPreview_GettingLinkInfo: String { return self._s[2936]! } - public var Watch_UserInfo_Unmute: String { return self._s[2937]! } - public var GroupInfo_ChannelListNamePlaceholder: String { return self._s[2938]! } - public var AccessDenied_CameraRestricted: String { return self._s[2940]! } + public var Privacy_Forwards_CustomHelp: String { return self._s[2944]! } + public var WebPreview_GettingLinkInfo: String { return self._s[2945]! } + public var Watch_UserInfo_Unmute: String { return self._s[2946]! } + public var GroupInfo_ChannelListNamePlaceholder: String { return self._s[2947]! } + public var AccessDenied_CameraRestricted: String { return self._s[2949]! } public func Conversation_Kilobytes(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2941]!, self._r[2941]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[2950]!, self._r[2950]!, ["\(_0)"]) } - public var ChatList_ReadAll: String { return self._s[2943]! } - public var Settings_CopyUsername: String { return self._s[2944]! } - public var Contacts_SearchLabel: String { return self._s[2945]! } - public var Map_OpenInYandexNavigator: String { return self._s[2947]! } - public var PasscodeSettings_EncryptData: String { return self._s[2948]! } - public var Settings_Wallet: String { return self._s[2949]! } - public var Group_ErrorSupergroupConversionNotPossible: String { return self._s[2950]! } - public var WallpaperSearch_ColorPrefix: String { return self._s[2951]! } - public var Notifications_GroupNotificationsPreview: String { return self._s[2952]! } - public var DialogList_AdNoticeAlert: String { return self._s[2953]! } - public var Wallet_Month_GenMay: String { return self._s[2955]! } - public var CheckoutInfo_ShippingInfoAddress1: String { return self._s[2956]! } - public var CheckoutInfo_ShippingInfoAddress2: String { return self._s[2957]! } - public var Localization_LanguageCustom: String { return self._s[2958]! } - public var Passport_Identity_TypeDriversLicenseUploadScan: String { return self._s[2959]! } - public var CallFeedback_Title: String { return self._s[2960]! } - public var VoiceOver_Chat_RecordPreviewVoiceMessage: String { return self._s[2963]! } - public var Passport_Address_OneOfTypePassportRegistration: String { return self._s[2964]! } - public var Wallet_Intro_CreateErrorTitle: String { return self._s[2965]! } - public var Conversation_InfoGroup: String { return self._s[2966]! } - public var Compose_NewMessage: String { return self._s[2967]! } - public var FastTwoStepSetup_HintPlaceholder: String { return self._s[2968]! } - public var ChatSettings_AutoDownloadVideoMessages: String { return self._s[2969]! } - public var Wallet_SecureStorageReset_BiometryFaceId: String { return self._s[2970]! } - public var Channel_DiscussionGroup_UnlinkChannel: String { return self._s[2971]! } + public var ChatList_ReadAll: String { return self._s[2952]! } + public var Settings_CopyUsername: String { return self._s[2953]! } + public var Contacts_SearchLabel: String { return self._s[2954]! } + public var Map_OpenInYandexNavigator: String { return self._s[2956]! } + public var PasscodeSettings_EncryptData: String { return self._s[2957]! } + public var Settings_Wallet: String { return self._s[2958]! } + public var Group_ErrorSupergroupConversionNotPossible: String { return self._s[2959]! } + public var WallpaperSearch_ColorPrefix: String { return self._s[2960]! } + public var Notifications_GroupNotificationsPreview: String { return self._s[2961]! } + public var DialogList_AdNoticeAlert: String { return self._s[2962]! } + public var Wallet_Month_GenMay: String { return self._s[2964]! } + public var CheckoutInfo_ShippingInfoAddress1: String { return self._s[2965]! } + public var CheckoutInfo_ShippingInfoAddress2: String { return self._s[2966]! } + public var Localization_LanguageCustom: String { return self._s[2967]! } + public var Passport_Identity_TypeDriversLicenseUploadScan: String { return self._s[2968]! } + public var CallFeedback_Title: String { return self._s[2969]! } + public var VoiceOver_Chat_RecordPreviewVoiceMessage: String { return self._s[2972]! } + public var Passport_Address_OneOfTypePassportRegistration: String { return self._s[2973]! } + public var Wallet_Intro_CreateErrorTitle: String { return self._s[2974]! } + public var Conversation_InfoGroup: String { return self._s[2975]! } + public var Compose_NewMessage: String { return self._s[2976]! } + public var FastTwoStepSetup_HintPlaceholder: String { return self._s[2977]! } + public var ChatSettings_AutoDownloadVideoMessages: String { return self._s[2978]! } + public var Wallet_SecureStorageReset_BiometryFaceId: String { return self._s[2979]! } + public var Channel_DiscussionGroup_UnlinkChannel: String { return self._s[2980]! } public func Passport_Scans_ScanIndex(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2972]!, self._r[2972]!, [_0]) + return formatWithArgumentRanges(self._s[2981]!, self._r[2981]!, [_0]) } - public var Channel_AdminLog_CanDeleteMessages: String { return self._s[2973]! } - public var Login_CancelSignUpConfirmation: String { return self._s[2974]! } - public var ChangePhoneNumberCode_Help: String { return self._s[2975]! } - public var PrivacySettings_DeleteAccountHelp: String { return self._s[2976]! } - public var Channel_BlackList_Title: String { return self._s[2977]! } - public var UserInfo_PhoneCall: String { return self._s[2978]! } - public var Passport_Address_OneOfTypeBankStatement: String { return self._s[2980]! } - public var Wallet_Month_ShortJanuary: String { return self._s[2981]! } - public var State_connecting: String { return self._s[2982]! } - public var Appearance_ThemePreview_ChatList_6_Text: String { return self._s[2983]! } - public var Wallet_Month_GenMarch: String { return self._s[2984]! } - public var EditTheme_Expand_BottomInfo: String { return self._s[2985]! } - public var AuthSessions_AddedDeviceTerminate: String { return self._s[2986]! } + public var Channel_AdminLog_CanDeleteMessages: String { return self._s[2982]! } + public var Login_CancelSignUpConfirmation: String { return self._s[2983]! } + public var ChangePhoneNumberCode_Help: String { return self._s[2984]! } + public var PrivacySettings_DeleteAccountHelp: String { return self._s[2985]! } + public var Channel_BlackList_Title: String { return self._s[2986]! } + public var UserInfo_PhoneCall: String { return self._s[2987]! } + public var Passport_Address_OneOfTypeBankStatement: String { return self._s[2989]! } + public var Wallet_Month_ShortJanuary: String { return self._s[2990]! } + public var State_connecting: String { return self._s[2991]! } + public var Appearance_ThemePreview_ChatList_6_Text: String { return self._s[2992]! } + public var Wallet_Month_GenMarch: String { return self._s[2993]! } + public var EditTheme_Expand_BottomInfo: String { return self._s[2994]! } + public var AuthSessions_AddedDeviceTerminate: String { return self._s[2995]! } public func LastSeen_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2987]!, self._r[2987]!, [_0]) + return formatWithArgumentRanges(self._s[2996]!, self._r[2996]!, [_0]) } public func DialogList_SingleRecordingAudioSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2988]!, self._r[2988]!, [_0]) + return formatWithArgumentRanges(self._s[2997]!, self._r[2997]!, [_0]) } - public var Notifications_GroupNotifications: String { return self._s[2989]! } - public var Conversation_SendMessageErrorTooMuchScheduled: String { return self._s[2990]! } - public var Passport_Identity_EditPassport: String { return self._s[2991]! } - public var EnterPasscode_RepeatNewPasscode: String { return self._s[2993]! } - public var Localization_EnglishLanguageName: String { return self._s[2994]! } - public var Share_AuthDescription: String { return self._s[2995]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsAlert: String { return self._s[2996]! } - public var Passport_Identity_Surname: String { return self._s[2997]! } - public var Compose_TokenListPlaceholder: String { return self._s[2998]! } - public var Wallet_AccessDenied_Camera: String { return self._s[2999]! } - public var Passport_Identity_OneOfTypePassport: String { return self._s[3000]! } - public var Settings_AboutEmpty: String { return self._s[3001]! } - public var Conversation_Unmute: String { return self._s[3002]! } - public var CreateGroup_ChannelsTooMuch: String { return self._s[3004]! } - public var Wallet_Sending_Text: String { return self._s[3005]! } + public var Notifications_GroupNotifications: String { return self._s[2998]! } + public var Conversation_SendMessageErrorTooMuchScheduled: String { return self._s[2999]! } + public var Passport_Identity_EditPassport: String { return self._s[3000]! } + public var EnterPasscode_RepeatNewPasscode: String { return self._s[3002]! } + public var Localization_EnglishLanguageName: String { return self._s[3003]! } + public var Share_AuthDescription: String { return self._s[3004]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsAlert: String { return self._s[3005]! } + public var Passport_Identity_Surname: String { return self._s[3006]! } + public var Compose_TokenListPlaceholder: String { return self._s[3007]! } + public var Wallet_AccessDenied_Camera: String { return self._s[3008]! } + public var Passport_Identity_OneOfTypePassport: String { return self._s[3009]! } + public var Settings_AboutEmpty: String { return self._s[3010]! } + public var Conversation_Unmute: String { return self._s[3011]! } + public var CreateGroup_ChannelsTooMuch: String { return self._s[3013]! } + public var Wallet_Sending_Text: String { return self._s[3014]! } public func PUSH_CONTACT_JOINED(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3006]!, self._r[3006]!, [_1]) + return formatWithArgumentRanges(self._s[3015]!, self._r[3015]!, [_1]) } - public var Login_CodeSentCall: String { return self._s[3007]! } - public var ContactInfo_PhoneLabelHomeFax: String { return self._s[3009]! } - public var ChatSettings_Appearance: String { return self._s[3010]! } - public var ClearCache_StorageUsage: String { return self._s[3011]! } - public var Appearance_PickAccentColor: String { return self._s[3012]! } + public var Login_CodeSentCall: String { return self._s[3016]! } + public var ContactInfo_PhoneLabelHomeFax: String { return self._s[3018]! } + public var ChatSettings_Appearance: String { return self._s[3019]! } + public var ClearCache_StorageUsage: String { return self._s[3020]! } + public var Appearance_PickAccentColor: String { return self._s[3021]! } public func PUSH_CHAT_MESSAGE_NOTEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3013]!, self._r[3013]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3022]!, self._r[3022]!, [_1, _2]) } public func PUSH_MESSAGE_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3014]!, self._r[3014]!, [_1]) + return formatWithArgumentRanges(self._s[3023]!, self._r[3023]!, [_1]) } - public var Notification_CallMissed: String { return self._s[3015]! } - public var SettingsSearch_Synonyms_Appearance_ChatBackground_Custom: String { return self._s[3016]! } - public var Channel_AdminLogFilter_EventsInfo: String { return self._s[3017]! } - public var Wallet_Month_GenOctober: String { return self._s[3019]! } - public var ChatAdmins_AdminLabel: String { return self._s[3020]! } - public var KeyCommand_JumpToNextChat: String { return self._s[3021]! } - public var Conversation_StopPollConfirmationTitle: String { return self._s[3023]! } - public var ChangePhoneNumberCode_CodePlaceholder: String { return self._s[3024]! } - public var Month_GenJune: String { return self._s[3025]! } - public var IntentsSettings_MainAccountInfo: String { return self._s[3026]! } - public var Watch_Location_Current: String { return self._s[3027]! } - public var Wallet_Receive_CopyInvoiceUrl: String { return self._s[3028]! } - public var Conversation_TitleMute: String { return self._s[3029]! } - public var Map_PlacesInThisArea: String { return self._s[3030]! } + public var Notification_CallMissed: String { return self._s[3024]! } + public var SettingsSearch_Synonyms_Appearance_ChatBackground_Custom: String { return self._s[3025]! } + public var Channel_AdminLogFilter_EventsInfo: String { return self._s[3026]! } + public var Wallet_Month_GenOctober: String { return self._s[3028]! } + public var ChatAdmins_AdminLabel: String { return self._s[3029]! } + public var KeyCommand_JumpToNextChat: String { return self._s[3030]! } + public var Conversation_StopPollConfirmationTitle: String { return self._s[3032]! } + public var ChangePhoneNumberCode_CodePlaceholder: String { return self._s[3033]! } + public var Month_GenJune: String { return self._s[3034]! } + public var IntentsSettings_MainAccountInfo: String { return self._s[3035]! } + public var Watch_Location_Current: String { return self._s[3036]! } + public var Wallet_Receive_CopyInvoiceUrl: String { return self._s[3037]! } + public var Conversation_TitleMute: String { return self._s[3038]! } + public var Map_PlacesInThisArea: String { return self._s[3039]! } public func PUSH_CHANNEL_MESSAGE_ROUND(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3031]!, self._r[3031]!, [_1]) + return formatWithArgumentRanges(self._s[3040]!, self._r[3040]!, [_1]) } - public var GroupInfo_DeleteAndExit: String { return self._s[3032]! } + public var GroupInfo_DeleteAndExit: String { return self._s[3041]! } public func Conversation_Moderate_DeleteAllMessages(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3033]!, self._r[3033]!, [_0]) + return formatWithArgumentRanges(self._s[3042]!, self._r[3042]!, [_0]) } - public var Call_ReportPlaceholder: String { return self._s[3034]! } - public var Chat_SlowmodeSendError: String { return self._s[3035]! } - public var MaskStickerSettings_Info: String { return self._s[3036]! } - public var EditTheme_Expand_TopInfo: String { return self._s[3037]! } + public var Call_ReportPlaceholder: String { return self._s[3043]! } + public var Chat_SlowmodeSendError: String { return self._s[3044]! } + public var MaskStickerSettings_Info: String { return self._s[3045]! } + public var EditTheme_Expand_TopInfo: String { return self._s[3046]! } public func GroupInfo_AddParticipantConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3038]!, self._r[3038]!, [_0]) + return formatWithArgumentRanges(self._s[3047]!, self._r[3047]!, [_0]) } - public var Checkout_NewCard_PostcodeTitle: String { return self._s[3039]! } - public var Passport_Address_RegionPlaceholder: String { return self._s[3041]! } - public var Contacts_ShareTelegram: String { return self._s[3042]! } - public var EnterPasscode_EnterNewPasscodeNew: String { return self._s[3043]! } - public var Map_AddressOnMap: String { return self._s[3044]! } - public var Channel_ErrorAccessDenied: String { return self._s[3045]! } - public var UserInfo_ScamBotWarning: String { return self._s[3047]! } - public var Stickers_GroupChooseStickerPack: String { return self._s[3048]! } - public var Call_ConnectionErrorTitle: String { return self._s[3049]! } - public var UserInfo_NotificationsEnable: String { return self._s[3050]! } - public var ArchivedChats_IntroText1: String { return self._s[3051]! } - public var Tour_Text4: String { return self._s[3054]! } - public var WallpaperSearch_Recent: String { return self._s[3055]! } - public var GroupInfo_ScamGroupWarning: String { return self._s[3056]! } - public var Profile_MessageLifetime2s: String { return self._s[3058]! } - public var Appearance_ThemePreview_ChatList_5_Text: String { return self._s[3059]! } - public var Notification_MessageLifetime2s: String { return self._s[3060]! } + public var Checkout_NewCard_PostcodeTitle: String { return self._s[3048]! } + public var Passport_Address_RegionPlaceholder: String { return self._s[3050]! } + public var Contacts_ShareTelegram: String { return self._s[3051]! } + public var EnterPasscode_EnterNewPasscodeNew: String { return self._s[3052]! } + public var Map_AddressOnMap: String { return self._s[3053]! } + public var Channel_ErrorAccessDenied: String { return self._s[3054]! } + public var UserInfo_ScamBotWarning: String { return self._s[3056]! } + public var Stickers_GroupChooseStickerPack: String { return self._s[3057]! } + public var Call_ConnectionErrorTitle: String { return self._s[3058]! } + public var UserInfo_NotificationsEnable: String { return self._s[3059]! } + public var ArchivedChats_IntroText1: String { return self._s[3060]! } + public var Tour_Text4: String { return self._s[3063]! } + public var WallpaperSearch_Recent: String { return self._s[3064]! } + public var GroupInfo_ScamGroupWarning: String { return self._s[3065]! } + public var PeopleNearby_MakeVisibleTitle: String { return self._s[3066]! } + public var Profile_MessageLifetime2s: String { return self._s[3068]! } + public var Appearance_ThemePreview_ChatList_5_Text: String { return self._s[3069]! } + public var Notification_MessageLifetime2s: String { return self._s[3070]! } public func Time_PreciseDate_m10(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3061]!, self._r[3061]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3071]!, self._r[3071]!, [_1, _2, _3]) } - public var Cache_ClearCache: String { return self._s[3062]! } - public var AutoNightTheme_UpdateLocation: String { return self._s[3063]! } - public var Permissions_NotificationsUnreachableText_v0: String { return self._s[3064]! } + public var Cache_ClearCache: String { return self._s[3072]! } + public var AutoNightTheme_UpdateLocation: String { return self._s[3073]! } + public var Permissions_NotificationsUnreachableText_v0: String { return self._s[3074]! } public func Channel_AdminLog_MessageChangedGroupUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3068]!, self._r[3068]!, [_0]) + return formatWithArgumentRanges(self._s[3078]!, self._r[3078]!, [_0]) } public func Conversation_ShareMyPhoneNumber_StatusSuccess(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3070]!, self._r[3070]!, [_0]) + return formatWithArgumentRanges(self._s[3080]!, self._r[3080]!, [_0]) } - public var LocalGroup_Text: String { return self._s[3071]! } - public var Channel_AdminLog_EmptyFilterTitle: String { return self._s[3072]! } - public var SocksProxySetup_TypeSocks: String { return self._s[3073]! } - public var ChatList_UnarchiveAction: String { return self._s[3074]! } - public var AutoNightTheme_Title: String { return self._s[3075]! } - public var InstantPage_FeedbackButton: String { return self._s[3076]! } - public var Passport_FieldAddress: String { return self._s[3077]! } + public var LocalGroup_Text: String { return self._s[3081]! } + public var Channel_AdminLog_EmptyFilterTitle: String { return self._s[3082]! } + public var SocksProxySetup_TypeSocks: String { return self._s[3083]! } + public var ChatList_UnarchiveAction: String { return self._s[3084]! } + public var AutoNightTheme_Title: String { return self._s[3085]! } + public var InstantPage_FeedbackButton: String { return self._s[3086]! } + public var Passport_FieldAddress: String { return self._s[3087]! } public func Channel_AdminLog_SetSlowmode(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3078]!, self._r[3078]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3088]!, self._r[3088]!, [_1, _2]) } - public var Month_ShortMarch: String { return self._s[3079]! } + public var Month_ShortMarch: String { return self._s[3089]! } public func PUSH_MESSAGE_INVOICE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3080]!, self._r[3080]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3090]!, self._r[3090]!, [_1, _2]) } - public var SocksProxySetup_UsernamePlaceholder: String { return self._s[3081]! } - public var Conversation_ShareInlineBotLocationConfirmation: String { return self._s[3082]! } - public var Passport_FloodError: String { return self._s[3083]! } - public var SecretGif_Title: String { return self._s[3084]! } - public var NotificationSettings_ShowNotificationsAllAccountsInfoOn: String { return self._s[3085]! } - public var ChatList_Context_UnhideArchive: String { return self._s[3086]! } - public var Passport_Language_th: String { return self._s[3088]! } - public var Passport_Address_Address: String { return self._s[3089]! } - public var Login_InvalidLastNameError: String { return self._s[3090]! } - public var Notifications_InAppNotificationsPreview: String { return self._s[3091]! } - public var Notifications_PermissionsUnreachableTitle: String { return self._s[3092]! } - public var ChatList_Context_Archive: String { return self._s[3093]! } - public var SettingsSearch_FAQ: String { return self._s[3094]! } - public var ShareMenu_Send: String { return self._s[3095]! } - public var WallpaperSearch_ColorYellow: String { return self._s[3097]! } - public var Month_GenNovember: String { return self._s[3099]! } - public var SettingsSearch_Synonyms_Appearance_LargeEmoji: String { return self._s[3101]! } + public var SocksProxySetup_UsernamePlaceholder: String { return self._s[3091]! } + public var Conversation_ShareInlineBotLocationConfirmation: String { return self._s[3092]! } + public var Passport_FloodError: String { return self._s[3093]! } + public var SecretGif_Title: String { return self._s[3094]! } + public var NotificationSettings_ShowNotificationsAllAccountsInfoOn: String { return self._s[3095]! } + public var ChatList_Context_UnhideArchive: String { return self._s[3096]! } + public var Passport_Language_th: String { return self._s[3098]! } + public var Passport_Address_Address: String { return self._s[3099]! } + public var Login_InvalidLastNameError: String { return self._s[3100]! } + public var Notifications_InAppNotificationsPreview: String { return self._s[3101]! } + public var Notifications_PermissionsUnreachableTitle: String { return self._s[3102]! } + public var ChatList_Context_Archive: String { return self._s[3103]! } + public var SettingsSearch_FAQ: String { return self._s[3104]! } + public var ShareMenu_Send: String { return self._s[3105]! } + public var WallpaperSearch_ColorYellow: String { return self._s[3107]! } + public var Month_GenNovember: String { return self._s[3109]! } + public var SettingsSearch_Synonyms_Appearance_LargeEmoji: String { return self._s[3111]! } public func Conversation_ShareMyPhoneNumberConfirmation(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3102]!, self._r[3102]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3112]!, self._r[3112]!, [_1, _2]) } - public var Conversation_SwipeToReplyHintText: String { return self._s[3103]! } - public var Checkout_Email: String { return self._s[3104]! } - public var NotificationsSound_Tritone: String { return self._s[3105]! } - public var StickerPacksSettings_ManagingHelp: String { return self._s[3107]! } - public var Wallet_ContextMenuCopy: String { return self._s[3109]! } + public var Conversation_SwipeToReplyHintText: String { return self._s[3113]! } + public var Checkout_Email: String { return self._s[3114]! } + public var NotificationsSound_Tritone: String { return self._s[3115]! } + public var StickerPacksSettings_ManagingHelp: String { return self._s[3117]! } + public var Wallet_ContextMenuCopy: String { return self._s[3119]! } public func Wallet_Time_PreciseDate_m6(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3111]!, self._r[3111]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3121]!, self._r[3121]!, [_1, _2, _3]) } - public var Appearance_TextSize_Automatic: String { return self._s[3112]! } + public var Appearance_TextSize_Automatic: String { return self._s[3122]! } public func PUSH_PINNED_ROUND(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3113]!, self._r[3113]!, [_1]) + return formatWithArgumentRanges(self._s[3123]!, self._r[3123]!, [_1]) } public func StickerPackActionInfo_AddedText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3114]!, self._r[3114]!, [_0]) + return formatWithArgumentRanges(self._s[3124]!, self._r[3124]!, [_0]) } - public var ChangePhoneNumberNumber_Help: String { return self._s[3115]! } + public var ChangePhoneNumberNumber_Help: String { return self._s[3125]! } public func Checkout_LiabilityAlert(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3116]!, self._r[3116]!, [_1, _1, _1, _2]) + return formatWithArgumentRanges(self._s[3126]!, self._r[3126]!, [_1, _1, _1, _2]) } - public var ChatList_UndoArchiveTitle: String { return self._s[3117]! } - public var Notification_Exceptions_Add: String { return self._s[3118]! } - public var DialogList_You: String { return self._s[3119]! } - public var MediaPicker_Send: String { return self._s[3122]! } - public var SettingsSearch_Synonyms_Stickers_Title: String { return self._s[3123]! } - public var Appearance_ThemePreview_ChatList_4_Text: String { return self._s[3124]! } - public var Call_AudioRouteSpeaker: String { return self._s[3125]! } - public var Watch_UserInfo_Title: String { return self._s[3126]! } - public var VoiceOver_Chat_PollFinalResults: String { return self._s[3127]! } - public var Appearance_AccentColor: String { return self._s[3129]! } + public var ChatList_UndoArchiveTitle: String { return self._s[3127]! } + public var Notification_Exceptions_Add: String { return self._s[3128]! } + public var DialogList_You: String { return self._s[3129]! } + public var MediaPicker_Send: String { return self._s[3132]! } + public var SettingsSearch_Synonyms_Stickers_Title: String { return self._s[3133]! } + public var Appearance_ThemePreview_ChatList_4_Text: String { return self._s[3134]! } + public var Call_AudioRouteSpeaker: String { return self._s[3135]! } + public var Watch_UserInfo_Title: String { return self._s[3136]! } + public var VoiceOver_Chat_PollFinalResults: String { return self._s[3137]! } + public var Appearance_AccentColor: String { return self._s[3139]! } public func Login_EmailPhoneSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3130]!, self._r[3130]!, [_0]) + return formatWithArgumentRanges(self._s[3140]!, self._r[3140]!, [_0]) } - public var Permissions_ContactsAllowInSettings_v0: String { return self._s[3131]! } + public var Permissions_ContactsAllowInSettings_v0: String { return self._s[3141]! } public func PUSH_CHANNEL_MESSAGE_GAME(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3132]!, self._r[3132]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3142]!, self._r[3142]!, [_1, _2]) } - public var Conversation_ClousStorageInfo_Description2: String { return self._s[3133]! } - public var WebSearch_RecentClearConfirmation: String { return self._s[3134]! } - public var Notification_CallOutgoing: String { return self._s[3135]! } - public var PrivacySettings_PasscodeAndFaceId: String { return self._s[3136]! } - public var Channel_DiscussionGroup_MakeHistoryPublic: String { return self._s[3137]! } - public var Call_RecordingDisabledMessage: String { return self._s[3138]! } - public var Message_Game: String { return self._s[3139]! } - public var Conversation_PressVolumeButtonForSound: String { return self._s[3140]! } - public var PrivacyLastSeenSettings_CustomHelp: String { return self._s[3141]! } - public var Channel_DiscussionGroup_PrivateGroup: String { return self._s[3142]! } - public var Channel_EditAdmin_PermissionAddAdmins: String { return self._s[3143]! } - public var Date_DialogDateFormat: String { return self._s[3145]! } - public var WallpaperColors_SetCustomColor: String { return self._s[3146]! } - public var Notifications_InAppNotifications: String { return self._s[3147]! } + public var Conversation_ClousStorageInfo_Description2: String { return self._s[3143]! } + public var WebSearch_RecentClearConfirmation: String { return self._s[3144]! } + public var Notification_CallOutgoing: String { return self._s[3145]! } + public var PrivacySettings_PasscodeAndFaceId: String { return self._s[3146]! } + public var Channel_DiscussionGroup_MakeHistoryPublic: String { return self._s[3147]! } + public var Call_RecordingDisabledMessage: String { return self._s[3148]! } + public var Message_Game: String { return self._s[3149]! } + public var Conversation_PressVolumeButtonForSound: String { return self._s[3150]! } + public var PrivacyLastSeenSettings_CustomHelp: String { return self._s[3151]! } + public var Channel_DiscussionGroup_PrivateGroup: String { return self._s[3152]! } + public var Channel_EditAdmin_PermissionAddAdmins: String { return self._s[3153]! } + public var Date_DialogDateFormat: String { return self._s[3155]! } + public var WallpaperColors_SetCustomColor: String { return self._s[3156]! } + public var Notifications_InAppNotifications: String { return self._s[3157]! } public func Channel_Management_RemovedBy(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3148]!, self._r[3148]!, [_0]) + return formatWithArgumentRanges(self._s[3158]!, self._r[3158]!, [_0]) } public func Settings_ApplyProxyAlert(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3149]!, self._r[3149]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3159]!, self._r[3159]!, [_1, _2]) } - public var NewContact_Title: String { return self._s[3150]! } + public var NewContact_Title: String { return self._s[3160]! } public func AutoDownloadSettings_UpToForAll(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3151]!, self._r[3151]!, [_0]) + return formatWithArgumentRanges(self._s[3161]!, self._r[3161]!, [_0]) } - public var Conversation_ViewContactDetails: String { return self._s[3152]! } + public var Conversation_ViewContactDetails: String { return self._s[3162]! } public func PUSH_CHANNEL_MESSAGE_CONTACT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3154]!, self._r[3154]!, [_1]) + return formatWithArgumentRanges(self._s[3164]!, self._r[3164]!, [_1]) } - public var Checkout_NewCard_CardholderNameTitle: String { return self._s[3155]! } - public var Passport_Identity_ExpiryDateNone: String { return self._s[3156]! } - public var PrivacySettings_Title: String { return self._s[3157]! } - public var Conversation_SilentBroadcastTooltipOff: String { return self._s[3160]! } - public var GroupRemoved_UsersSectionTitle: String { return self._s[3161]! } - public var VoiceOver_Chat_ContactEmail: String { return self._s[3162]! } - public var Contacts_PhoneNumber: String { return self._s[3163]! } - public var TwoFactorSetup_Password_PlaceholderConfirmPassword: String { return self._s[3165]! } - public var Map_ShowPlaces: String { return self._s[3166]! } - public var ChatAdmins_Title: String { return self._s[3167]! } - public var InstantPage_Reference: String { return self._s[3169]! } - public var Wallet_Info_Updating: String { return self._s[3170]! } - public var ReportGroupLocation_Text: String { return self._s[3171]! } + public var Checkout_NewCard_CardholderNameTitle: String { return self._s[3165]! } + public var Passport_Identity_ExpiryDateNone: String { return self._s[3166]! } + public var PrivacySettings_Title: String { return self._s[3167]! } + public var Conversation_SilentBroadcastTooltipOff: String { return self._s[3170]! } + public var GroupRemoved_UsersSectionTitle: String { return self._s[3171]! } + public var VoiceOver_Chat_ContactEmail: String { return self._s[3172]! } + public var Contacts_PhoneNumber: String { return self._s[3173]! } + public var TwoFactorSetup_Password_PlaceholderConfirmPassword: String { return self._s[3175]! } + public var Map_ShowPlaces: String { return self._s[3176]! } + public var ChatAdmins_Title: String { return self._s[3177]! } + public var InstantPage_Reference: String { return self._s[3179]! } + public var Wallet_Info_Updating: String { return self._s[3180]! } + public var ReportGroupLocation_Text: String { return self._s[3181]! } public func PUSH_CHAT_MESSAGE_FWD(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3172]!, self._r[3172]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3182]!, self._r[3182]!, [_1, _2]) } - public var Camera_FlashOff: String { return self._s[3173]! } - public var Watch_UserInfo_Block: String { return self._s[3174]! } - public var ChatSettings_Stickers: String { return self._s[3175]! } - public var ChatSettings_DownloadInBackground: String { return self._s[3176]! } - public var Appearance_ThemeCarouselTintedNight: String { return self._s[3177]! } + public var Camera_FlashOff: String { return self._s[3183]! } + public var Watch_UserInfo_Block: String { return self._s[3184]! } + public var ChatSettings_Stickers: String { return self._s[3185]! } + public var ChatSettings_DownloadInBackground: String { return self._s[3186]! } + public var Appearance_ThemeCarouselTintedNight: String { return self._s[3187]! } public func UserInfo_BlockConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3178]!, self._r[3178]!, [_0]) + return formatWithArgumentRanges(self._s[3188]!, self._r[3188]!, [_0]) } - public var Settings_ViewPhoto: String { return self._s[3179]! } - public var Login_CheckOtherSessionMessages: String { return self._s[3180]! } - public var AutoDownloadSettings_Cellular: String { return self._s[3181]! } - public var Wallet_Created_ExportErrorTitle: String { return self._s[3182]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsExceptions: String { return self._s[3183]! } - public var VoiceOver_MessageContextShare: String { return self._s[3184]! } + public var Settings_ViewPhoto: String { return self._s[3189]! } + public var Login_CheckOtherSessionMessages: String { return self._s[3190]! } + public var AutoDownloadSettings_Cellular: String { return self._s[3191]! } + public var Wallet_Created_ExportErrorTitle: String { return self._s[3192]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsExceptions: String { return self._s[3193]! } + public var VoiceOver_MessageContextShare: String { return self._s[3194]! } public func Target_InviteToGroupConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3186]!, self._r[3186]!, [_0]) + return formatWithArgumentRanges(self._s[3196]!, self._r[3196]!, [_0]) } - public var Privacy_DeleteDrafts: String { return self._s[3187]! } - public var Wallpaper_SetCustomBackgroundInfo: String { return self._s[3188]! } + public var Privacy_DeleteDrafts: String { return self._s[3197]! } + public var Wallpaper_SetCustomBackgroundInfo: String { return self._s[3198]! } public func LastSeen_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3189]!, self._r[3189]!, [_0]) + return formatWithArgumentRanges(self._s[3199]!, self._r[3199]!, [_0]) } - public var DialogList_SavedMessagesHelp: String { return self._s[3190]! } - public var Wallet_SecureStorageNotAvailable_Title: String { return self._s[3191]! } - public var DialogList_SavedMessages: String { return self._s[3192]! } - public var GroupInfo_UpgradeButton: String { return self._s[3193]! } - public var Appearance_ThemePreview_ChatList_3_Text: String { return self._s[3195]! } - public var DialogList_Pin: String { return self._s[3196]! } + public var DialogList_SavedMessagesHelp: String { return self._s[3200]! } + public var Wallet_SecureStorageNotAvailable_Title: String { return self._s[3201]! } + public var DialogList_SavedMessages: String { return self._s[3202]! } + public var GroupInfo_UpgradeButton: String { return self._s[3203]! } + public var Appearance_ThemePreview_ChatList_3_Text: String { return self._s[3205]! } + public var DialogList_Pin: String { return self._s[3206]! } public func ForwardedAuthors2(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3197]!, self._r[3197]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3207]!, self._r[3207]!, [_0, _1]) } public func Login_PhoneGenericEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3198]!, self._r[3198]!, [_0]) + return formatWithArgumentRanges(self._s[3208]!, self._r[3208]!, [_0]) } - public var Notification_Exceptions_AlwaysOn: String { return self._s[3199]! } - public var UserInfo_NotificationsDisable: String { return self._s[3200]! } - public var Conversation_ContextMenuCancelEditing: String { return self._s[3201]! } - public var Paint_Outlined: String { return self._s[3202]! } - public var Activity_PlayingGame: String { return self._s[3203]! } - public var SearchImages_NoImagesFound: String { return self._s[3204]! } - public var SocksProxySetup_ProxyType: String { return self._s[3205]! } - public var AppleWatch_ReplyPresetsHelp: String { return self._s[3207]! } - public var Conversation_ContextMenuCancelSending: String { return self._s[3208]! } - public var Settings_AppLanguage: String { return self._s[3209]! } - public var TwoStepAuth_ResetAccountHelp: String { return self._s[3210]! } - public var Common_ChoosePhoto: String { return self._s[3211]! } - public var AuthSessions_AddDevice_InvalidQRCode: String { return self._s[3212]! } - public var CallFeedback_ReasonEcho: String { return self._s[3213]! } + public var Notification_Exceptions_AlwaysOn: String { return self._s[3209]! } + public var UserInfo_NotificationsDisable: String { return self._s[3210]! } + public var Conversation_ContextMenuCancelEditing: String { return self._s[3211]! } + public var Paint_Outlined: String { return self._s[3212]! } + public var Activity_PlayingGame: String { return self._s[3213]! } + public var SearchImages_NoImagesFound: String { return self._s[3214]! } + public var SocksProxySetup_ProxyType: String { return self._s[3215]! } + public var AppleWatch_ReplyPresetsHelp: String { return self._s[3217]! } + public var Conversation_ContextMenuCancelSending: String { return self._s[3218]! } + public var Settings_AppLanguage: String { return self._s[3219]! } + public var TwoStepAuth_ResetAccountHelp: String { return self._s[3220]! } + public var Common_ChoosePhoto: String { return self._s[3221]! } + public var AuthSessions_AddDevice_InvalidQRCode: String { return self._s[3222]! } + public var CallFeedback_ReasonEcho: String { return self._s[3223]! } public func PUSH_PINNED_AUDIO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3214]!, self._r[3214]!, [_1]) + return formatWithArgumentRanges(self._s[3224]!, self._r[3224]!, [_1]) } - public var Privacy_Calls_AlwaysAllow: String { return self._s[3215]! } - public var PollResults_Collapse: String { return self._s[3216]! } - public var Activity_UploadingVideo: String { return self._s[3217]! } - public var Conversation_WalletRequiredNotNow: String { return self._s[3218]! } - public var ChannelInfo_DeleteChannelConfirmation: String { return self._s[3219]! } - public var NetworkUsageSettings_Wifi: String { return self._s[3220]! } - public var VoiceOver_Editing_ClearText: String { return self._s[3221]! } - public var PUSH_SENDER_YOU: String { return self._s[3222]! } - public var Channel_BanUser_PermissionReadMessages: String { return self._s[3223]! } - public var Checkout_PayWithTouchId: String { return self._s[3224]! } - public var Wallpaper_ResetWallpapersConfirmation: String { return self._s[3225]! } + public var Privacy_Calls_AlwaysAllow: String { return self._s[3225]! } + public var PollResults_Collapse: String { return self._s[3226]! } + public var Activity_UploadingVideo: String { return self._s[3227]! } + public var Conversation_WalletRequiredNotNow: String { return self._s[3228]! } + public var ChannelInfo_DeleteChannelConfirmation: String { return self._s[3229]! } + public var NetworkUsageSettings_Wifi: String { return self._s[3230]! } + public var VoiceOver_Editing_ClearText: String { return self._s[3231]! } + public var PUSH_SENDER_YOU: String { return self._s[3232]! } + public var Channel_BanUser_PermissionReadMessages: String { return self._s[3233]! } + public var Checkout_PayWithTouchId: String { return self._s[3234]! } + public var Wallpaper_ResetWallpapersConfirmation: String { return self._s[3235]! } public func PUSH_LOCKED_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3227]!, self._r[3227]!, [_1]) + return formatWithArgumentRanges(self._s[3237]!, self._r[3237]!, [_1]) } - public var Notifications_ExceptionsNone: String { return self._s[3228]! } + public var Notifications_ExceptionsNone: String { return self._s[3238]! } public func Message_ForwardedMessageShort(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3229]!, self._r[3229]!, [_0]) + return formatWithArgumentRanges(self._s[3239]!, self._r[3239]!, [_0]) } public func PUSH_PINNED_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3230]!, self._r[3230]!, [_1]) + return formatWithArgumentRanges(self._s[3240]!, self._r[3240]!, [_1]) } - public var AuthSessions_IncompleteAttempts: String { return self._s[3232]! } - public var Passport_Address_Region: String { return self._s[3235]! } - public var ChatList_DeleteChat: String { return self._s[3236]! } - public var LogoutOptions_ClearCacheTitle: String { return self._s[3237]! } - public var PhotoEditor_TiltShift: String { return self._s[3238]! } - public var Settings_FAQ_URL: String { return self._s[3239]! } - public var TwoFactorSetup_EmailVerification_ChangeAction: String { return self._s[3240]! } - public var Passport_Language_sl: String { return self._s[3241]! } - public var Settings_PrivacySettings: String { return self._s[3243]! } - public var SharedMedia_TitleLink: String { return self._s[3244]! } - public var Passport_Identity_TypePassportUploadScan: String { return self._s[3245]! } - public var Settings_SetProfilePhoto: String { return self._s[3246]! } - public var Channel_About_Help: String { return self._s[3247]! } - public var Contacts_PermissionsEnable: String { return self._s[3248]! } - public var Wallet_Sending_Title: String { return self._s[3249]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsAlert: String { return self._s[3250]! } - public var AttachmentMenu_SendAsFiles: String { return self._s[3251]! } - public var CallFeedback_ReasonInterruption: String { return self._s[3253]! } - public var Passport_Address_AddTemporaryRegistration: String { return self._s[3254]! } - public var AutoDownloadSettings_AutodownloadVideos: String { return self._s[3255]! } - public var ChatSettings_AutoDownloadSettings_Delimeter: String { return self._s[3256]! } - public var OldChannels_Title: String { return self._s[3257]! } - public var PrivacySettings_DeleteAccountTitle: String { return self._s[3258]! } - public var AccessDenied_VideoMessageCamera: String { return self._s[3260]! } - public var Map_OpenInYandexMaps: String { return self._s[3262]! } - public var CreateGroup_ErrorLocatedGroupsTooMuch: String { return self._s[3263]! } - public var VoiceOver_MessageContextReply: String { return self._s[3264]! } - public var PhotoEditor_SaturationTool: String { return self._s[3266]! } + public var AuthSessions_IncompleteAttempts: String { return self._s[3242]! } + public var Passport_Address_Region: String { return self._s[3245]! } + public var ChatList_DeleteChat: String { return self._s[3246]! } + public var LogoutOptions_ClearCacheTitle: String { return self._s[3247]! } + public var PhotoEditor_TiltShift: String { return self._s[3248]! } + public var Settings_FAQ_URL: String { return self._s[3249]! } + public var TwoFactorSetup_EmailVerification_ChangeAction: String { return self._s[3250]! } + public var Passport_Language_sl: String { return self._s[3251]! } + public var Settings_PrivacySettings: String { return self._s[3253]! } + public var SharedMedia_TitleLink: String { return self._s[3254]! } + public var Passport_Identity_TypePassportUploadScan: String { return self._s[3255]! } + public var Settings_SetProfilePhoto: String { return self._s[3256]! } + public var Channel_About_Help: String { return self._s[3257]! } + public var Contacts_PermissionsEnable: String { return self._s[3258]! } + public var Wallet_Sending_Title: String { return self._s[3259]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsAlert: String { return self._s[3260]! } + public var AttachmentMenu_SendAsFiles: String { return self._s[3261]! } + public var CallFeedback_ReasonInterruption: String { return self._s[3263]! } + public var Passport_Address_AddTemporaryRegistration: String { return self._s[3264]! } + public var AutoDownloadSettings_AutodownloadVideos: String { return self._s[3265]! } + public var ChatSettings_AutoDownloadSettings_Delimeter: String { return self._s[3266]! } + public var OldChannels_Title: String { return self._s[3267]! } + public var PrivacySettings_DeleteAccountTitle: String { return self._s[3268]! } + public var AccessDenied_VideoMessageCamera: String { return self._s[3270]! } + public var Map_OpenInYandexMaps: String { return self._s[3272]! } + public var CreateGroup_ErrorLocatedGroupsTooMuch: String { return self._s[3273]! } + public var VoiceOver_MessageContextReply: String { return self._s[3274]! } + public var PhotoEditor_SaturationTool: String { return self._s[3276]! } public func PUSH_MESSAGE_STICKER(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3267]!, self._r[3267]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3277]!, self._r[3277]!, [_1, _2]) } - public var PrivacyPhoneNumberSettings_CustomHelp: String { return self._s[3268]! } - public var Notification_Exceptions_NewException_NotificationHeader: String { return self._s[3269]! } - public var Group_OwnershipTransfer_ErrorLocatedGroupsTooMuch: String { return self._s[3270]! } + public var PrivacyPhoneNumberSettings_CustomHelp: String { return self._s[3278]! } + public var Notification_Exceptions_NewException_NotificationHeader: String { return self._s[3279]! } + public var Group_OwnershipTransfer_ErrorLocatedGroupsTooMuch: String { return self._s[3280]! } public func LOCAL_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3271]!, self._r[3271]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[3281]!, self._r[3281]!, [_1, "\(_2)"]) } - public var Appearance_ThemePreview_ChatList_2_Text: String { return self._s[3272]! } - public var Channel_Username_InvalidTooShort: String { return self._s[3274]! } - public var SettingsSearch_Synonyms_Wallet: String { return self._s[3275]! } + public var Appearance_ThemePreview_ChatList_2_Text: String { return self._s[3282]! } + public var Channel_Username_InvalidTooShort: String { return self._s[3284]! } + public var SettingsSearch_Synonyms_Wallet: String { return self._s[3285]! } public func Group_OwnershipTransfer_DescriptionInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3276]!, self._r[3276]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3286]!, self._r[3286]!, [_1, _2]) } - public var Forward_ErrorPublicPollDisabledInChannels: String { return self._s[3277]! } + public var Forward_ErrorPublicPollDisabledInChannels: String { return self._s[3287]! } public func PUSH_CHAT_MESSAGE_GAME(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3278]!, self._r[3278]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3288]!, self._r[3288]!, [_1, _2, _3]) } - public var WallpaperPreview_PatternTitle: String { return self._s[3279]! } - public var GroupInfo_PublicLinkAdd: String { return self._s[3280]! } - public var Passport_PassportInformation: String { return self._s[3283]! } - public var Theme_Unsupported: String { return self._s[3284]! } - public var WatchRemote_AlertTitle: String { return self._s[3285]! } - public var Privacy_GroupsAndChannels_NeverAllow: String { return self._s[3286]! } - public var ConvertToSupergroup_HelpText: String { return self._s[3288]! } + public var WallpaperPreview_PatternTitle: String { return self._s[3289]! } + public var GroupInfo_PublicLinkAdd: String { return self._s[3290]! } + public var Passport_PassportInformation: String { return self._s[3293]! } + public var Theme_Unsupported: String { return self._s[3294]! } + public var WatchRemote_AlertTitle: String { return self._s[3295]! } + public var Privacy_GroupsAndChannels_NeverAllow: String { return self._s[3296]! } + public var ConvertToSupergroup_HelpText: String { return self._s[3298]! } public func Time_MonthOfYear_m7(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3289]!, self._r[3289]!, [_0]) + return formatWithArgumentRanges(self._s[3299]!, self._r[3299]!, [_0]) } public func PUSH_PHONE_CALL_REQUEST(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3290]!, self._r[3290]!, [_1]) + return formatWithArgumentRanges(self._s[3300]!, self._r[3300]!, [_1]) } - public var Privacy_GroupsAndChannels_CustomHelp: String { return self._s[3291]! } - public var Wallet_Navigation_Done: String { return self._s[3293]! } - public var TwoStepAuth_RecoveryCodeInvalid: String { return self._s[3294]! } - public var AccessDenied_CameraDisabled: String { return self._s[3295]! } + public var Privacy_GroupsAndChannels_CustomHelp: String { return self._s[3301]! } + public var Wallet_Navigation_Done: String { return self._s[3303]! } + public var TwoStepAuth_RecoveryCodeInvalid: String { return self._s[3304]! } + public var AccessDenied_CameraDisabled: String { return self._s[3305]! } public func Channel_Username_UsernameIsAvailable(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3296]!, self._r[3296]!, [_0]) + return formatWithArgumentRanges(self._s[3306]!, self._r[3306]!, [_0]) } - public var ClearCache_Forever: String { return self._s[3297]! } - public var AuthSessions_AddDeviceIntro_Title: String { return self._s[3298]! } - public var CreatePoll_Quiz: String { return self._s[3299]! } - public var PhotoEditor_ContrastTool: String { return self._s[3302]! } + public var ClearCache_Forever: String { return self._s[3307]! } + public var AuthSessions_AddDeviceIntro_Title: String { return self._s[3308]! } + public var CreatePoll_Quiz: String { return self._s[3309]! } + public var PhotoEditor_ContrastTool: String { return self._s[3312]! } public func PUSH_PINNED_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3303]!, self._r[3303]!, [_1]) + return formatWithArgumentRanges(self._s[3313]!, self._r[3313]!, [_1]) } - public var DialogList_Draft: String { return self._s[3304]! } - public var Wallet_Configuration_BlockchainIdInfo: String { return self._s[3305]! } - public var Privacy_TopPeersDelete: String { return self._s[3307]! } - public var LoginPassword_PasswordPlaceholder: String { return self._s[3308]! } - public var Passport_Identity_TypeIdentityCardUploadScan: String { return self._s[3309]! } - public var WebSearch_RecentSectionClear: String { return self._s[3310]! } - public var EditTheme_ErrorInvalidCharacters: String { return self._s[3311]! } - public var Watch_ChatList_NoConversationsTitle: String { return self._s[3313]! } - public var Common_Done: String { return self._s[3315]! } - public var Shortcut_SwitchAccount: String { return self._s[3316]! } - public var AuthSessions_EmptyText: String { return self._s[3317]! } - public var Wallet_Configuration_BlockchainNameChangedTitle: String { return self._s[3318]! } - public var Conversation_ShareBotContactConfirmation: String { return self._s[3319]! } - public var Tour_Title5: String { return self._s[3320]! } - public var Wallet_Settings_Title: String { return self._s[3321]! } + public var DialogList_Draft: String { return self._s[3314]! } + public var Wallet_Configuration_BlockchainIdInfo: String { return self._s[3315]! } + public func PeopleNearby_VisibleUntil(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3316]!, self._r[3316]!, [_0]) + } + public var Privacy_TopPeersDelete: String { return self._s[3318]! } + public var LoginPassword_PasswordPlaceholder: String { return self._s[3319]! } + public var Passport_Identity_TypeIdentityCardUploadScan: String { return self._s[3320]! } + public var WebSearch_RecentSectionClear: String { return self._s[3321]! } + public var EditTheme_ErrorInvalidCharacters: String { return self._s[3322]! } + public var Watch_ChatList_NoConversationsTitle: String { return self._s[3324]! } + public var Common_Done: String { return self._s[3326]! } + public var Shortcut_SwitchAccount: String { return self._s[3327]! } + public var AuthSessions_EmptyText: String { return self._s[3328]! } + public var Wallet_Configuration_BlockchainNameChangedTitle: String { return self._s[3329]! } + public var Conversation_ShareBotContactConfirmation: String { return self._s[3330]! } + public var Tour_Title5: String { return self._s[3331]! } + public var Wallet_Settings_Title: String { return self._s[3332]! } public func Map_DirectionsDriveEta(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3322]!, self._r[3322]!, [_0]) + return formatWithArgumentRanges(self._s[3333]!, self._r[3333]!, [_0]) } - public var ApplyLanguage_UnsufficientDataTitle: String { return self._s[3323]! } - public var Conversation_LinkDialogSave: String { return self._s[3324]! } - public var GroupInfo_ActionRestrict: String { return self._s[3325]! } - public var Checkout_Title: String { return self._s[3326]! } - public var Channel_DiscussionGroup_HeaderLabel: String { return self._s[3328]! } - public var Channel_AdminLog_CanChangeInfo: String { return self._s[3330]! } - public var Notification_RenamedGroup: String { return self._s[3331]! } - public var PeopleNearby_Groups: String { return self._s[3332]! } - public var Checkout_PayWithFaceId: String { return self._s[3333]! } - public var Channel_BanList_BlockedTitle: String { return self._s[3334]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsSound: String { return self._s[3336]! } - public var Checkout_WebConfirmation_Title: String { return self._s[3337]! } - public var Notifications_MessageNotificationsAlert: String { return self._s[3338]! } + public var ApplyLanguage_UnsufficientDataTitle: String { return self._s[3334]! } + public var Conversation_LinkDialogSave: String { return self._s[3335]! } + public var GroupInfo_ActionRestrict: String { return self._s[3336]! } + public var Checkout_Title: String { return self._s[3337]! } + public var Channel_DiscussionGroup_HeaderLabel: String { return self._s[3339]! } + public var Channel_AdminLog_CanChangeInfo: String { return self._s[3341]! } + public var Notification_RenamedGroup: String { return self._s[3342]! } + public var PeopleNearby_Groups: String { return self._s[3343]! } + public var Checkout_PayWithFaceId: String { return self._s[3344]! } + public var Channel_BanList_BlockedTitle: String { return self._s[3345]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsSound: String { return self._s[3347]! } + public var Checkout_WebConfirmation_Title: String { return self._s[3348]! } + public var Notifications_MessageNotificationsAlert: String { return self._s[3349]! } public func Activity_RemindAboutGroup(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3339]!, self._r[3339]!, [_0]) + return formatWithArgumentRanges(self._s[3350]!, self._r[3350]!, [_0]) } - public var Profile_AddToExisting: String { return self._s[3341]! } + public var Profile_AddToExisting: String { return self._s[3352]! } public func Profile_CreateEncryptedChatOutdatedError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3342]!, self._r[3342]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3353]!, self._r[3353]!, [_0, _1]) } - public var Cache_Files: String { return self._s[3344]! } - public var Permissions_PrivacyPolicy: String { return self._s[3345]! } - public var SocksProxySetup_ConnectAndSave: String { return self._s[3346]! } - public var UserInfo_NotificationsDefaultDisabled: String { return self._s[3347]! } - public var AutoDownloadSettings_TypeContacts: String { return self._s[3349]! } - public var Appearance_ThemePreview_ChatList_1_Text: String { return self._s[3351]! } - public var Calls_NoCallsPlaceholder: String { return self._s[3352]! } + public var Cache_Files: String { return self._s[3355]! } + public var Permissions_PrivacyPolicy: String { return self._s[3356]! } + public var SocksProxySetup_ConnectAndSave: String { return self._s[3357]! } + public var UserInfo_NotificationsDefaultDisabled: String { return self._s[3358]! } + public var AutoDownloadSettings_TypeContacts: String { return self._s[3360]! } + public var Appearance_ThemePreview_ChatList_1_Text: String { return self._s[3362]! } + public var Calls_NoCallsPlaceholder: String { return self._s[3363]! } public func Wallet_Receive_ShareInvoiceUrlInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3353]!, self._r[3353]!, [_0]) + return formatWithArgumentRanges(self._s[3364]!, self._r[3364]!, [_0]) } - public var Channel_Username_RevokeExistingUsernamesInfo: String { return self._s[3354]! } - public var VoiceOver_AttachMedia: String { return self._s[3357]! } - public var Notifications_ExceptionsGroupPlaceholder: String { return self._s[3358]! } + public var Channel_Username_RevokeExistingUsernamesInfo: String { return self._s[3365]! } + public var VoiceOver_AttachMedia: String { return self._s[3368]! } + public var Notifications_ExceptionsGroupPlaceholder: String { return self._s[3369]! } public func PUSH_CHAT_MESSAGE_INVOICE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3359]!, self._r[3359]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3370]!, self._r[3370]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsSound: String { return self._s[3360]! } - public var Conversation_SetReminder_Title: String { return self._s[3361]! } - public var Passport_FieldAddressHelp: String { return self._s[3362]! } - public var Privacy_GroupsAndChannels_InviteToChannelMultipleError: String { return self._s[3363]! } - public var PUSH_REMINDER_TITLE: String { return self._s[3364]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsSound: String { return self._s[3371]! } + public var Conversation_SetReminder_Title: String { return self._s[3372]! } + public var Passport_FieldAddressHelp: String { return self._s[3373]! } + public var Privacy_GroupsAndChannels_InviteToChannelMultipleError: String { return self._s[3374]! } + public var PUSH_REMINDER_TITLE: String { return self._s[3375]! } public func Login_TermsOfService_ProceedBot(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3365]!, self._r[3365]!, [_0]) + return formatWithArgumentRanges(self._s[3376]!, self._r[3376]!, [_0]) } - public var Channel_AdminLog_EmptyTitle: String { return self._s[3366]! } - public var Privacy_Calls_NeverAllow_Title: String { return self._s[3367]! } - public var Login_UnknownError: String { return self._s[3368]! } - public var Group_UpgradeNoticeText2: String { return self._s[3371]! } - public var Watch_Compose_AddContact: String { return self._s[3372]! } - public var ClearCache_StorageServiceFiles: String { return self._s[3373]! } - public var Web_Error: String { return self._s[3374]! } - public var Gif_Search: String { return self._s[3375]! } - public var Profile_MessageLifetime1h: String { return self._s[3376]! } - public var CheckoutInfo_ReceiverInfoEmailPlaceholder: String { return self._s[3377]! } - public var Channel_Username_CheckingUsername: String { return self._s[3378]! } - public var CallFeedback_ReasonSilentRemote: String { return self._s[3379]! } - public var AutoDownloadSettings_TypeChannels: String { return self._s[3380]! } - public var Channel_AboutItem: String { return self._s[3381]! } - public var Privacy_GroupsAndChannels_AlwaysAllow_Placeholder: String { return self._s[3383]! } - public var VoiceOver_Chat_VoiceMessage: String { return self._s[3384]! } - public var GroupInfo_SharedMedia: String { return self._s[3385]! } + public var Channel_AdminLog_EmptyTitle: String { return self._s[3377]! } + public var Privacy_Calls_NeverAllow_Title: String { return self._s[3378]! } + public var Login_UnknownError: String { return self._s[3379]! } + public var Group_UpgradeNoticeText2: String { return self._s[3382]! } + public var Watch_Compose_AddContact: String { return self._s[3383]! } + public var ClearCache_StorageServiceFiles: String { return self._s[3384]! } + public var Web_Error: String { return self._s[3385]! } + public var Gif_Search: String { return self._s[3386]! } + public var Profile_MessageLifetime1h: String { return self._s[3387]! } + public var CheckoutInfo_ReceiverInfoEmailPlaceholder: String { return self._s[3388]! } + public var Channel_Username_CheckingUsername: String { return self._s[3389]! } + public var CallFeedback_ReasonSilentRemote: String { return self._s[3390]! } + public var AutoDownloadSettings_TypeChannels: String { return self._s[3391]! } + public var Channel_AboutItem: String { return self._s[3392]! } + public var Privacy_GroupsAndChannels_AlwaysAllow_Placeholder: String { return self._s[3394]! } + public var VoiceOver_Chat_VoiceMessage: String { return self._s[3395]! } + public var GroupInfo_SharedMedia: String { return self._s[3396]! } public func Channel_AdminLog_MessagePromotedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3386]!, self._r[3386]!, [_1]) + return formatWithArgumentRanges(self._s[3397]!, self._r[3397]!, [_1]) } - public var Call_PhoneCallInProgressMessage: String { return self._s[3387]! } + public var Call_PhoneCallInProgressMessage: String { return self._s[3398]! } public func PUSH_CHANNEL_ALBUM(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3388]!, self._r[3388]!, [_1]) + return formatWithArgumentRanges(self._s[3399]!, self._r[3399]!, [_1]) } - public var ChatList_UndoArchiveRevealedText: String { return self._s[3389]! } - public var GroupInfo_InviteLink_RevokeAlert_Text: String { return self._s[3390]! } - public var Conversation_SearchByName_Placeholder: String { return self._s[3391]! } - public var CreatePoll_AddOption: String { return self._s[3392]! } - public var GroupInfo_Permissions_SearchPlaceholder: String { return self._s[3393]! } - public var Group_UpgradeNoticeHeader: String { return self._s[3394]! } - public var Channel_Management_AddModerator: String { return self._s[3395]! } - public var AutoDownloadSettings_MaxFileSize: String { return self._s[3396]! } - public var StickerPacksSettings_ShowStickersButton: String { return self._s[3397]! } - public var Wallet_Info_RefreshErrorNetworkText: String { return self._s[3398]! } - public var Theme_Colors_Background: String { return self._s[3399]! } - public var NotificationsSound_Hello: String { return self._s[3401]! } - public var SocksProxySetup_SavedProxies: String { return self._s[3402]! } - public var Channel_Stickers_Placeholder: String { return self._s[3404]! } + public var ChatList_UndoArchiveRevealedText: String { return self._s[3400]! } + public var GroupInfo_InviteLink_RevokeAlert_Text: String { return self._s[3401]! } + public var Conversation_SearchByName_Placeholder: String { return self._s[3402]! } + public var CreatePoll_AddOption: String { return self._s[3403]! } + public var GroupInfo_Permissions_SearchPlaceholder: String { return self._s[3404]! } + public var Group_UpgradeNoticeHeader: String { return self._s[3405]! } + public var Channel_Management_AddModerator: String { return self._s[3406]! } + public var AutoDownloadSettings_MaxFileSize: String { return self._s[3407]! } + public var StickerPacksSettings_ShowStickersButton: String { return self._s[3408]! } + public var Wallet_Info_RefreshErrorNetworkText: String { return self._s[3409]! } + public var Theme_Colors_Background: String { return self._s[3410]! } + public var NotificationsSound_Hello: String { return self._s[3412]! } + public var SocksProxySetup_SavedProxies: String { return self._s[3413]! } + public var Channel_Stickers_Placeholder: String { return self._s[3415]! } public func Login_EmailCodeBody(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3405]!, self._r[3405]!, [_0]) + return formatWithArgumentRanges(self._s[3416]!, self._r[3416]!, [_0]) } - public var PrivacyPolicy_DeclineDeclineAndDelete: String { return self._s[3406]! } - public var Channel_Management_AddModeratorHelp: String { return self._s[3407]! } - public var ContactInfo_BirthdayLabel: String { return self._s[3408]! } - public var ChangePhoneNumberCode_RequestingACall: String { return self._s[3409]! } - public var AutoDownloadSettings_Channels: String { return self._s[3410]! } - public var Passport_Language_mn: String { return self._s[3411]! } - public var Notifications_ResetAllNotificationsHelp: String { return self._s[3414]! } - public var GroupInfo_Permissions_SlowmodeValue_Off: String { return self._s[3415]! } - public var Passport_Language_ja: String { return self._s[3417]! } - public var Settings_About_Title: String { return self._s[3418]! } - public var Settings_NotificationsAndSounds: String { return self._s[3419]! } - public var ChannelInfo_DeleteGroup: String { return self._s[3420]! } - public var Settings_BlockedUsers: String { return self._s[3421]! } + public var PrivacyPolicy_DeclineDeclineAndDelete: String { return self._s[3417]! } + public var Channel_Management_AddModeratorHelp: String { return self._s[3418]! } + public var ContactInfo_BirthdayLabel: String { return self._s[3419]! } + public var ChangePhoneNumberCode_RequestingACall: String { return self._s[3420]! } + public var AutoDownloadSettings_Channels: String { return self._s[3421]! } + public var Passport_Language_mn: String { return self._s[3422]! } + public var Notifications_ResetAllNotificationsHelp: String { return self._s[3425]! } + public var GroupInfo_Permissions_SlowmodeValue_Off: String { return self._s[3426]! } + public var Passport_Language_ja: String { return self._s[3428]! } + public var Settings_About_Title: String { return self._s[3429]! } + public var Settings_NotificationsAndSounds: String { return self._s[3430]! } + public var ChannelInfo_DeleteGroup: String { return self._s[3431]! } + public var Settings_BlockedUsers: String { return self._s[3432]! } public func Time_MonthOfYear_m4(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3422]!, self._r[3422]!, [_0]) + return formatWithArgumentRanges(self._s[3433]!, self._r[3433]!, [_0]) } - public var EditTheme_Create_Preview_OutgoingText: String { return self._s[3423]! } - public var Wallet_Weekday_Today: String { return self._s[3424]! } - public var AutoDownloadSettings_PreloadVideo: String { return self._s[3425]! } - public var Widget_ApplicationLocked: String { return self._s[3426]! } - public var Passport_Address_AddResidentialAddress: String { return self._s[3427]! } - public var Channel_Username_Title: String { return self._s[3428]! } + public var EditTheme_Create_Preview_OutgoingText: String { return self._s[3434]! } + public var Wallet_Weekday_Today: String { return self._s[3435]! } + public var AutoDownloadSettings_PreloadVideo: String { return self._s[3436]! } + public var Widget_ApplicationLocked: String { return self._s[3437]! } + public var Passport_Address_AddResidentialAddress: String { return self._s[3438]! } + public var Channel_Username_Title: String { return self._s[3439]! } public func Notification_RemovedGroupPhoto(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3429]!, self._r[3429]!, [_0]) + return formatWithArgumentRanges(self._s[3440]!, self._r[3440]!, [_0]) } - public var AttachmentMenu_File: String { return self._s[3431]! } - public var AppleWatch_Title: String { return self._s[3432]! } - public var Activity_RecordingVideoMessage: String { return self._s[3433]! } + public var AttachmentMenu_File: String { return self._s[3442]! } + public var AppleWatch_Title: String { return self._s[3443]! } + public var Activity_RecordingVideoMessage: String { return self._s[3444]! } public func Channel_DiscussionGroup_PublicChannelLink(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3434]!, self._r[3434]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3445]!, self._r[3445]!, [_1, _2]) } - public var Theme_Colors_Messages: String { return self._s[3435]! } - public var Weekday_Saturday: String { return self._s[3436]! } - public var WallpaperPreview_SwipeColorsTopText: String { return self._s[3437]! } - public var Profile_CreateEncryptedChatError: String { return self._s[3438]! } - public var Common_Next: String { return self._s[3440]! } - public var Channel_Stickers_YourStickers: String { return self._s[3442]! } - public var Message_Theme: String { return self._s[3443]! } - public var Call_AudioRouteHeadphones: String { return self._s[3444]! } - public var TwoStepAuth_EnterPasswordForgot: String { return self._s[3446]! } - public var Watch_Contacts_NoResults: String { return self._s[3448]! } - public var PhotoEditor_TintTool: String { return self._s[3451]! } - public var LoginPassword_ResetAccount: String { return self._s[3453]! } - public var Settings_SavedMessages: String { return self._s[3454]! } - public var SettingsSearch_Synonyms_Appearance_Animations: String { return self._s[3455]! } - public var Bot_GenericSupportStatus: String { return self._s[3456]! } - public var StickerPack_Add: String { return self._s[3457]! } - public var Checkout_TotalAmount: String { return self._s[3458]! } - public var Your_cards_number_is_invalid: String { return self._s[3459]! } - public var SettingsSearch_Synonyms_Appearance_AutoNightTheme: String { return self._s[3460]! } - public var VoiceOver_Chat_VideoMessage: String { return self._s[3461]! } + public var Theme_Colors_Messages: String { return self._s[3446]! } + public var Weekday_Saturday: String { return self._s[3447]! } + public var WallpaperPreview_SwipeColorsTopText: String { return self._s[3448]! } + public var Profile_CreateEncryptedChatError: String { return self._s[3449]! } + public var Common_Next: String { return self._s[3451]! } + public var Channel_Stickers_YourStickers: String { return self._s[3453]! } + public var Message_Theme: String { return self._s[3454]! } + public var Call_AudioRouteHeadphones: String { return self._s[3455]! } + public var TwoStepAuth_EnterPasswordForgot: String { return self._s[3457]! } + public var Watch_Contacts_NoResults: String { return self._s[3459]! } + public var PhotoEditor_TintTool: String { return self._s[3462]! } + public var LoginPassword_ResetAccount: String { return self._s[3464]! } + public var Settings_SavedMessages: String { return self._s[3465]! } + public var SettingsSearch_Synonyms_Appearance_Animations: String { return self._s[3466]! } + public var Bot_GenericSupportStatus: String { return self._s[3467]! } + public var StickerPack_Add: String { return self._s[3468]! } + public var Checkout_TotalAmount: String { return self._s[3469]! } + public var Your_cards_number_is_invalid: String { return self._s[3470]! } + public var SettingsSearch_Synonyms_Appearance_AutoNightTheme: String { return self._s[3471]! } + public var VoiceOver_Chat_VideoMessage: String { return self._s[3472]! } public func ChangePhoneNumberCode_CallTimer(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3462]!, self._r[3462]!, [_0]) + return formatWithArgumentRanges(self._s[3473]!, self._r[3473]!, [_0]) } public func GroupPermission_AddedInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3463]!, self._r[3463]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3474]!, self._r[3474]!, [_1, _2]) } - public var ChatSettings_ConnectionType_UseSocks5: String { return self._s[3464]! } + public var ChatSettings_ConnectionType_UseSocks5: String { return self._s[3475]! } public func PUSH_CHAT_PHOTO_EDITED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3466]!, self._r[3466]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3477]!, self._r[3477]!, [_1, _2]) } public func Conversation_RestrictedTextTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3467]!, self._r[3467]!, [_0]) + return formatWithArgumentRanges(self._s[3478]!, self._r[3478]!, [_0]) } - public var GroupInfo_InviteLink_ShareLink: String { return self._s[3468]! } - public var StickerPack_Share: String { return self._s[3469]! } - public var Passport_DeleteAddress: String { return self._s[3470]! } - public var Settings_Passport: String { return self._s[3471]! } - public var SharedMedia_EmptyFilesText: String { return self._s[3472]! } - public var Conversation_DeleteMessagesForMe: String { return self._s[3473]! } - public var PasscodeSettings_AutoLock_IfAwayFor_1hour: String { return self._s[3474]! } - public var Contacts_PermissionsText: String { return self._s[3475]! } - public var Group_Setup_HistoryVisible: String { return self._s[3476]! } - public var Wallet_Month_ShortDecember: String { return self._s[3478]! } - public var Channel_EditAdmin_PermissionEnabledByDefault: String { return self._s[3479]! } - public var Passport_Address_AddRentalAgreement: String { return self._s[3480]! } - public var SocksProxySetup_Title: String { return self._s[3481]! } - public var Notification_Mute1h: String { return self._s[3482]! } + public var GroupInfo_InviteLink_ShareLink: String { return self._s[3479]! } + public var StickerPack_Share: String { return self._s[3480]! } + public var Passport_DeleteAddress: String { return self._s[3481]! } + public var Settings_Passport: String { return self._s[3482]! } + public var SharedMedia_EmptyFilesText: String { return self._s[3483]! } + public var Conversation_DeleteMessagesForMe: String { return self._s[3484]! } + public var PasscodeSettings_AutoLock_IfAwayFor_1hour: String { return self._s[3485]! } + public var Contacts_PermissionsText: String { return self._s[3486]! } + public var Group_Setup_HistoryVisible: String { return self._s[3487]! } + public var Wallet_Month_ShortDecember: String { return self._s[3489]! } + public var Channel_EditAdmin_PermissionEnabledByDefault: String { return self._s[3490]! } + public var Passport_Address_AddRentalAgreement: String { return self._s[3491]! } + public var SocksProxySetup_Title: String { return self._s[3492]! } + public var Notification_Mute1h: String { return self._s[3493]! } public func Passport_Email_CodeHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3483]!, self._r[3483]!, [_0]) + return formatWithArgumentRanges(self._s[3494]!, self._r[3494]!, [_0]) } - public var NotificationSettings_ShowNotificationsAllAccountsInfoOff: String { return self._s[3484]! } + public var NotificationSettings_ShowNotificationsAllAccountsInfoOff: String { return self._s[3495]! } public func PUSH_PINNED_GEOLIVE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3485]!, self._r[3485]!, [_1]) + return formatWithArgumentRanges(self._s[3496]!, self._r[3496]!, [_1]) } - public var FastTwoStepSetup_PasswordSection: String { return self._s[3486]! } - public var NetworkUsageSettings_ResetStatsConfirmation: String { return self._s[3489]! } - public var InfoPlist_NSFaceIDUsageDescription: String { return self._s[3491]! } - public var DialogList_NoMessagesText: String { return self._s[3492]! } - public var Privacy_ContactsResetConfirmation: String { return self._s[3493]! } - public var Privacy_Calls_P2PHelp: String { return self._s[3494]! } - public var Channel_DiscussionGroup_SearchPlaceholder: String { return self._s[3496]! } - public var Your_cards_expiration_year_is_invalid: String { return self._s[3497]! } - public var Common_TakePhotoOrVideo: String { return self._s[3498]! } - public var Wallet_Words_Text: String { return self._s[3499]! } - public var Call_StatusBusy: String { return self._s[3500]! } - public var Conversation_PinnedMessage: String { return self._s[3501]! } - public var AutoDownloadSettings_VoiceMessagesTitle: String { return self._s[3502]! } - public var Wallet_Configuration_BlockchainNameChangedProceed: String { return self._s[3503]! } - public var TwoStepAuth_SetupPasswordConfirmFailed: String { return self._s[3504]! } - public var Undo_ChatCleared: String { return self._s[3505]! } - public var AppleWatch_ReplyPresets: String { return self._s[3506]! } - public var Passport_DiscardMessageDescription: String { return self._s[3508]! } - public var Login_NetworkError: String { return self._s[3509]! } + public var FastTwoStepSetup_PasswordSection: String { return self._s[3497]! } + public var NetworkUsageSettings_ResetStatsConfirmation: String { return self._s[3500]! } + public var InfoPlist_NSFaceIDUsageDescription: String { return self._s[3502]! } + public var DialogList_NoMessagesText: String { return self._s[3503]! } + public var Privacy_ContactsResetConfirmation: String { return self._s[3504]! } + public var Privacy_Calls_P2PHelp: String { return self._s[3505]! } + public var Channel_DiscussionGroup_SearchPlaceholder: String { return self._s[3507]! } + public var Your_cards_expiration_year_is_invalid: String { return self._s[3508]! } + public var Common_TakePhotoOrVideo: String { return self._s[3509]! } + public var Wallet_Words_Text: String { return self._s[3510]! } + public var Call_StatusBusy: String { return self._s[3511]! } + public var Conversation_PinnedMessage: String { return self._s[3512]! } + public var AutoDownloadSettings_VoiceMessagesTitle: String { return self._s[3513]! } + public var Wallet_Configuration_BlockchainNameChangedProceed: String { return self._s[3514]! } + public var TwoStepAuth_SetupPasswordConfirmFailed: String { return self._s[3515]! } + public var Undo_ChatCleared: String { return self._s[3516]! } + public var AppleWatch_ReplyPresets: String { return self._s[3517]! } + public var Passport_DiscardMessageDescription: String { return self._s[3519]! } + public var Login_NetworkError: String { return self._s[3520]! } public func Notification_PinnedRoundMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3510]!, self._r[3510]!, [_0]) + return formatWithArgumentRanges(self._s[3521]!, self._r[3521]!, [_0]) } public func Channel_AdminLog_MessageRemovedChannelUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3511]!, self._r[3511]!, [_0]) + return formatWithArgumentRanges(self._s[3522]!, self._r[3522]!, [_0]) } - public var SocksProxySetup_PasswordPlaceholder: String { return self._s[3512]! } - public var Wallet_WordCheck_ViewWords: String { return self._s[3514]! } - public var Login_ResetAccountProtected_LimitExceeded: String { return self._s[3515]! } + public var SocksProxySetup_PasswordPlaceholder: String { return self._s[3523]! } + public var Wallet_WordCheck_ViewWords: String { return self._s[3525]! } + public var Login_ResetAccountProtected_LimitExceeded: String { return self._s[3526]! } public func Watch_LastSeen_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3517]!, self._r[3517]!, [_0]) + return formatWithArgumentRanges(self._s[3528]!, self._r[3528]!, [_0]) } - public var Call_ConnectionErrorMessage: String { return self._s[3518]! } - public var VoiceOver_Chat_Music: String { return self._s[3519]! } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsSound: String { return self._s[3520]! } - public var Compose_GroupTokenListPlaceholder: String { return self._s[3522]! } - public var ConversationMedia_Title: String { return self._s[3523]! } - public var EncryptionKey_Title: String { return self._s[3525]! } - public var TwoStepAuth_EnterPasswordTitle: String { return self._s[3526]! } - public var Notification_Exceptions_AddException: String { return self._s[3527]! } - public var PrivacySettings_BlockedPeersEmpty: String { return self._s[3528]! } - public var Profile_MessageLifetime1m: String { return self._s[3529]! } + public var Call_ConnectionErrorMessage: String { return self._s[3529]! } + public var VoiceOver_Chat_Music: String { return self._s[3530]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsSound: String { return self._s[3531]! } + public var Compose_GroupTokenListPlaceholder: String { return self._s[3533]! } + public var ConversationMedia_Title: String { return self._s[3534]! } + public var EncryptionKey_Title: String { return self._s[3536]! } + public var TwoStepAuth_EnterPasswordTitle: String { return self._s[3537]! } + public var Notification_Exceptions_AddException: String { return self._s[3538]! } + public var PrivacySettings_BlockedPeersEmpty: String { return self._s[3539]! } + public var Profile_MessageLifetime1m: String { return self._s[3540]! } public func Channel_AdminLog_MessageUnkickedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3530]!, self._r[3530]!, [_1]) + return formatWithArgumentRanges(self._s[3541]!, self._r[3541]!, [_1]) } - public var Month_GenMay: String { return self._s[3531]! } + public var Month_GenMay: String { return self._s[3542]! } public func LiveLocationUpdated_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3532]!, self._r[3532]!, [_0]) + return formatWithArgumentRanges(self._s[3543]!, self._r[3543]!, [_0]) } - public var PeopleNearby_Users: String { return self._s[3533]! } - public var Wallet_Send_AddressInfo: String { return self._s[3534]! } - public var ChannelMembers_WhoCanAddMembersAllHelp: String { return self._s[3535]! } - public var AutoDownloadSettings_ResetSettings: String { return self._s[3536]! } + public var PeopleNearby_Users: String { return self._s[3544]! } + public var Wallet_Send_AddressInfo: String { return self._s[3545]! } + public var ChannelMembers_WhoCanAddMembersAllHelp: String { return self._s[3546]! } + public var AutoDownloadSettings_ResetSettings: String { return self._s[3547]! } public func Wallet_Updated_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3538]!, self._r[3538]!, [_0]) + return formatWithArgumentRanges(self._s[3549]!, self._r[3549]!, [_0]) } - public var Conversation_EmptyPlaceholder: String { return self._s[3539]! } - public var Passport_Address_AddPassportRegistration: String { return self._s[3540]! } - public var Notifications_ChannelNotificationsAlert: String { return self._s[3541]! } - public var ChatSettings_AutoDownloadUsingCellular: String { return self._s[3542]! } - public var Camera_TapAndHoldForVideo: String { return self._s[3543]! } - public var Channel_JoinChannel: String { return self._s[3545]! } - public var Appearance_Animations: String { return self._s[3548]! } + public var Conversation_EmptyPlaceholder: String { return self._s[3550]! } + public var Passport_Address_AddPassportRegistration: String { return self._s[3551]! } + public var Notifications_ChannelNotificationsAlert: String { return self._s[3552]! } + public var ChatSettings_AutoDownloadUsingCellular: String { return self._s[3553]! } + public var Camera_TapAndHoldForVideo: String { return self._s[3554]! } + public var Channel_JoinChannel: String { return self._s[3556]! } + public var Appearance_Animations: String { return self._s[3559]! } public func Notification_MessageLifetimeChanged(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3549]!, self._r[3549]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3560]!, self._r[3560]!, [_1, _2]) } - public var Stickers_GroupStickers: String { return self._s[3551]! } - public var Appearance_ShareTheme: String { return self._s[3552]! } - public var TwoFactorSetup_Hint_Placeholder: String { return self._s[3553]! } - public var ConvertToSupergroup_HelpTitle: String { return self._s[3555]! } - public var StickerPackActionInfo_RemovedTitle: String { return self._s[3556]! } - public var Passport_Address_Street: String { return self._s[3557]! } - public var Conversation_AddContact: String { return self._s[3558]! } - public var Login_PhonePlaceholder: String { return self._s[3559]! } - public var Channel_Members_InviteLink: String { return self._s[3561]! } - public var Bot_Stop: String { return self._s[3562]! } - public var SettingsSearch_Synonyms_Proxy_UseForCalls: String { return self._s[3564]! } - public var Notification_PassportValueAddress: String { return self._s[3565]! } - public var Month_ShortJuly: String { return self._s[3566]! } - public var Passport_Address_TypeTemporaryRegistrationUploadScan: String { return self._s[3567]! } - public var Channel_AdminLog_BanSendMedia: String { return self._s[3568]! } - public var Passport_Identity_ReverseSide: String { return self._s[3569]! } - public var Watch_Stickers_Recents: String { return self._s[3572]! } - public var PrivacyLastSeenSettings_EmpryUsersPlaceholder: String { return self._s[3574]! } - public var Map_SendThisLocation: String { return self._s[3575]! } + public var Stickers_GroupStickers: String { return self._s[3562]! } + public var Appearance_ShareTheme: String { return self._s[3563]! } + public var TwoFactorSetup_Hint_Placeholder: String { return self._s[3564]! } + public var ConvertToSupergroup_HelpTitle: String { return self._s[3566]! } + public var StickerPackActionInfo_RemovedTitle: String { return self._s[3567]! } + public var Passport_Address_Street: String { return self._s[3568]! } + public var Conversation_AddContact: String { return self._s[3569]! } + public var Login_PhonePlaceholder: String { return self._s[3570]! } + public var Channel_Members_InviteLink: String { return self._s[3572]! } + public var Bot_Stop: String { return self._s[3573]! } + public var SettingsSearch_Synonyms_Proxy_UseForCalls: String { return self._s[3575]! } + public var Notification_PassportValueAddress: String { return self._s[3576]! } + public var Month_ShortJuly: String { return self._s[3577]! } + public var Passport_Address_TypeTemporaryRegistrationUploadScan: String { return self._s[3578]! } + public var Channel_AdminLog_BanSendMedia: String { return self._s[3579]! } + public var Passport_Identity_ReverseSide: String { return self._s[3580]! } + public var Watch_Stickers_Recents: String { return self._s[3583]! } + public var PrivacyLastSeenSettings_EmpryUsersPlaceholder: String { return self._s[3585]! } + public var Map_SendThisLocation: String { return self._s[3586]! } public func Time_MonthOfYear_m1(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3576]!, self._r[3576]!, [_0]) + return formatWithArgumentRanges(self._s[3587]!, self._r[3587]!, [_0]) } public func InviteText_SingleContact(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3577]!, self._r[3577]!, [_0]) + return formatWithArgumentRanges(self._s[3588]!, self._r[3588]!, [_0]) } - public var ConvertToSupergroup_Note: String { return self._s[3578]! } - public var Wallet_Intro_NotNow: String { return self._s[3579]! } + public var ConvertToSupergroup_Note: String { return self._s[3589]! } + public var Wallet_Intro_NotNow: String { return self._s[3590]! } public func FileSize_MB(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3580]!, self._r[3580]!, [_0]) + return formatWithArgumentRanges(self._s[3591]!, self._r[3591]!, [_0]) } - public var NetworkUsageSettings_GeneralDataSection: String { return self._s[3581]! } + public var NetworkUsageSettings_GeneralDataSection: String { return self._s[3592]! } public func Compatibility_SecretMediaVersionTooLow(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3582]!, self._r[3582]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3593]!, self._r[3593]!, [_0, _1]) } - public var Login_CallRequestState3: String { return self._s[3584]! } - public var Wallpaper_SearchShort: String { return self._s[3585]! } - public var SettingsSearch_Synonyms_Appearance_ColorTheme: String { return self._s[3587]! } - public var PasscodeSettings_UnlockWithFaceId: String { return self._s[3588]! } - public var Channel_BotDoesntSupportGroups: String { return self._s[3589]! } + public var Login_CallRequestState3: String { return self._s[3595]! } + public var Wallpaper_SearchShort: String { return self._s[3596]! } + public var SettingsSearch_Synonyms_Appearance_ColorTheme: String { return self._s[3598]! } + public var PasscodeSettings_UnlockWithFaceId: String { return self._s[3599]! } + public var Channel_BotDoesntSupportGroups: String { return self._s[3600]! } public func PUSH_CHAT_MESSAGE_GEOLIVE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3590]!, self._r[3590]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3601]!, self._r[3601]!, [_1, _2]) } - public var Channel_AdminLogFilter_Title: String { return self._s[3591]! } - public var Appearance_ThemePreview_Chat_4_Text: String { return self._s[3593]! } - public var Notifications_GroupNotificationsExceptions: String { return self._s[3596]! } + public var Channel_AdminLogFilter_Title: String { return self._s[3602]! } + public var Appearance_ThemePreview_Chat_4_Text: String { return self._s[3604]! } + public var Notifications_GroupNotificationsExceptions: String { return self._s[3607]! } public func FileSize_B(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3597]!, self._r[3597]!, [_0]) + return formatWithArgumentRanges(self._s[3608]!, self._r[3608]!, [_0]) } - public var Passport_CorrectErrors: String { return self._s[3598]! } - public var VoiceOver_Chat_YourAnonymousPoll: String { return self._s[3599]! } + public var Passport_CorrectErrors: String { return self._s[3609]! } + public var VoiceOver_Chat_YourAnonymousPoll: String { return self._s[3610]! } public func Channel_MessageTitleUpdated(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3600]!, self._r[3600]!, [_0]) + return formatWithArgumentRanges(self._s[3611]!, self._r[3611]!, [_0]) } - public var Map_SendMyCurrentLocation: String { return self._s[3601]! } - public var Channel_DiscussionGroup: String { return self._s[3602]! } - public var TwoFactorSetup_Email_SkipConfirmationSkip: String { return self._s[3603]! } + public var Map_SendMyCurrentLocation: String { return self._s[3612]! } + public var Channel_DiscussionGroup: String { return self._s[3613]! } + public var TwoFactorSetup_Email_SkipConfirmationSkip: String { return self._s[3614]! } public func PUSH_PINNED_CONTACT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3604]!, self._r[3604]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3615]!, self._r[3615]!, [_1, _2]) } - public var SharedMedia_SearchNoResults: String { return self._s[3605]! } - public var Permissions_NotificationsText_v0: String { return self._s[3606]! } - public var Channel_EditAdmin_PermissionDeleteMessagesOfOthers: String { return self._s[3607]! } - public var Appearance_AppIcon: String { return self._s[3608]! } - public var Appearance_ThemePreview_ChatList_3_AuthorName: String { return self._s[3609]! } - public var LoginPassword_FloodError: String { return self._s[3610]! } - public var Wallet_Send_OwnAddressAlertProceed: String { return self._s[3612]! } - public var Group_Setup_HistoryHiddenHelp: String { return self._s[3613]! } + public var SharedMedia_SearchNoResults: String { return self._s[3616]! } + public var Permissions_NotificationsText_v0: String { return self._s[3617]! } + public var Channel_EditAdmin_PermissionDeleteMessagesOfOthers: String { return self._s[3618]! } + public var Appearance_AppIcon: String { return self._s[3619]! } + public var Appearance_ThemePreview_ChatList_3_AuthorName: String { return self._s[3620]! } + public var LoginPassword_FloodError: String { return self._s[3621]! } + public var Wallet_Send_OwnAddressAlertProceed: String { return self._s[3623]! } + public var Group_Setup_HistoryHiddenHelp: String { return self._s[3624]! } public func TwoStepAuth_PendingEmailHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3614]!, self._r[3614]!, [_0]) + return formatWithArgumentRanges(self._s[3625]!, self._r[3625]!, [_0]) } - public var Passport_Language_bn: String { return self._s[3615]! } + public var Passport_Language_bn: String { return self._s[3626]! } public func DialogList_SingleUploadingPhotoSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3616]!, self._r[3616]!, [_0]) + return formatWithArgumentRanges(self._s[3627]!, self._r[3627]!, [_0]) } - public var ChatList_Context_Pin: String { return self._s[3617]! } + public var ChatList_Context_Pin: String { return self._s[3628]! } public func Notification_PinnedAudioMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3618]!, self._r[3618]!, [_0]) + return formatWithArgumentRanges(self._s[3629]!, self._r[3629]!, [_0]) } public func Channel_AdminLog_MessageChangedGroupStickerPack(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3619]!, self._r[3619]!, [_0]) + return formatWithArgumentRanges(self._s[3630]!, self._r[3630]!, [_0]) } - public var Wallet_Navigation_Close: String { return self._s[3620]! } - public var GroupInfo_InvitationLinkGroupFull: String { return self._s[3624]! } - public var Group_EditAdmin_PermissionChangeInfo: String { return self._s[3626]! } - public var Wallet_Month_GenDecember: String { return self._s[3627]! } - public var Contacts_PermissionsAllow: String { return self._s[3628]! } - public var ReportPeer_ReasonCopyright: String { return self._s[3629]! } - public var Channel_EditAdmin_PermissinAddAdminOn: String { return self._s[3630]! } - public var WallpaperPreview_Pattern: String { return self._s[3631]! } - public var Paint_Duplicate: String { return self._s[3632]! } - public var Passport_Address_Country: String { return self._s[3633]! } - public var Notification_RenamedChannel: String { return self._s[3635]! } - public var ChatList_Context_Unmute: String { return self._s[3636]! } - public var CheckoutInfo_ErrorPostcodeInvalid: String { return self._s[3637]! } - public var Group_MessagePhotoUpdated: String { return self._s[3638]! } - public var Channel_BanUser_PermissionSendMedia: String { return self._s[3639]! } - public var Conversation_ContextMenuBan: String { return self._s[3640]! } - public var TwoStepAuth_EmailSent: String { return self._s[3641]! } - public var MessagePoll_NoVotes: String { return self._s[3642]! } - public var Wallet_Send_ErrorNotEnoughFundsTitle: String { return self._s[3643]! } - public var Passport_Language_is: String { return self._s[3645]! } - public var PeopleNearby_UsersEmpty: String { return self._s[3647]! } - public var Tour_Text5: String { return self._s[3648]! } + public var Wallet_Navigation_Close: String { return self._s[3631]! } + public var GroupInfo_InvitationLinkGroupFull: String { return self._s[3635]! } + public var Group_EditAdmin_PermissionChangeInfo: String { return self._s[3637]! } + public var Wallet_Month_GenDecember: String { return self._s[3638]! } + public var Contacts_PermissionsAllow: String { return self._s[3639]! } + public var ReportPeer_ReasonCopyright: String { return self._s[3640]! } + public var Channel_EditAdmin_PermissinAddAdminOn: String { return self._s[3641]! } + public var WallpaperPreview_Pattern: String { return self._s[3642]! } + public var Paint_Duplicate: String { return self._s[3643]! } + public var Passport_Address_Country: String { return self._s[3644]! } + public var Notification_RenamedChannel: String { return self._s[3646]! } + public var ChatList_Context_Unmute: String { return self._s[3647]! } + public var CheckoutInfo_ErrorPostcodeInvalid: String { return self._s[3648]! } + public var Group_MessagePhotoUpdated: String { return self._s[3649]! } + public var Channel_BanUser_PermissionSendMedia: String { return self._s[3650]! } + public var Conversation_ContextMenuBan: String { return self._s[3651]! } + public var TwoStepAuth_EmailSent: String { return self._s[3652]! } + public var MessagePoll_NoVotes: String { return self._s[3653]! } + public var Wallet_Send_ErrorNotEnoughFundsTitle: String { return self._s[3654]! } + public var Passport_Language_is: String { return self._s[3656]! } + public var PeopleNearby_UsersEmpty: String { return self._s[3658]! } + public var Tour_Text5: String { return self._s[3659]! } public func Call_GroupFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3651]!, self._r[3651]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3662]!, self._r[3662]!, [_1, _2]) } - public var Undo_SecretChatDeleted: String { return self._s[3652]! } - public var SocksProxySetup_ShareQRCode: String { return self._s[3653]! } + public var Undo_SecretChatDeleted: String { return self._s[3663]! } + public var SocksProxySetup_ShareQRCode: String { return self._s[3664]! } public func VoiceOver_Chat_Size(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3654]!, self._r[3654]!, [_0]) + return formatWithArgumentRanges(self._s[3665]!, self._r[3665]!, [_0]) } - public var Forward_ErrorDisabledForChat: String { return self._s[3655]! } - public var LogoutOptions_ChangePhoneNumberText: String { return self._s[3656]! } - public var Paint_Edit: String { return self._s[3658]! } - public var ScheduledMessages_ReminderNotification: String { return self._s[3660]! } - public var Undo_DeletedGroup: String { return self._s[3662]! } - public var LoginPassword_ForgotPassword: String { return self._s[3663]! } - public var Wallet_WordImport_IncorrectTitle: String { return self._s[3664]! } - public var GroupInfo_GroupNamePlaceholder: String { return self._s[3665]! } + public var Forward_ErrorDisabledForChat: String { return self._s[3666]! } + public var LogoutOptions_ChangePhoneNumberText: String { return self._s[3667]! } + public var Paint_Edit: String { return self._s[3669]! } + public var ScheduledMessages_ReminderNotification: String { return self._s[3671]! } + public var Undo_DeletedGroup: String { return self._s[3673]! } + public var LoginPassword_ForgotPassword: String { return self._s[3674]! } + public var Wallet_WordImport_IncorrectTitle: String { return self._s[3675]! } + public var GroupInfo_GroupNamePlaceholder: String { return self._s[3676]! } public func Notification_Kicked(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3666]!, self._r[3666]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3677]!, self._r[3677]!, [_0, _1]) } - public var AppWallet_TransactionInfo_FeeInfoURL: String { return self._s[3667]! } - public var Conversation_InputTextCaptionPlaceholder: String { return self._s[3668]! } - public var AutoDownloadSettings_VideoMessagesTitle: String { return self._s[3669]! } - public var Passport_Language_uz: String { return self._s[3670]! } - public var Conversation_PinMessageAlertGroup: String { return self._s[3671]! } - public var SettingsSearch_Synonyms_Privacy_GroupsAndChannels: String { return self._s[3672]! } - public var Map_StopLiveLocation: String { return self._s[3674]! } - public var VoiceOver_MessageContextSend: String { return self._s[3676]! } - public var PasscodeSettings_Help: String { return self._s[3677]! } - public var NotificationsSound_Input: String { return self._s[3678]! } - public var Share_Title: String { return self._s[3681]! } - public var LogoutOptions_Title: String { return self._s[3682]! } - public var Wallet_Send_AddressText: String { return self._s[3683]! } - public var Login_TermsOfServiceAgree: String { return self._s[3684]! } - public var Compose_NewEncryptedChatTitle: String { return self._s[3685]! } - public var Channel_AdminLog_TitleSelectedEvents: String { return self._s[3686]! } - public var Channel_EditAdmin_PermissionEditMessages: String { return self._s[3687]! } - public var EnterPasscode_EnterTitle: String { return self._s[3688]! } + public var AppWallet_TransactionInfo_FeeInfoURL: String { return self._s[3678]! } + public var Conversation_InputTextCaptionPlaceholder: String { return self._s[3679]! } + public var AutoDownloadSettings_VideoMessagesTitle: String { return self._s[3680]! } + public var Passport_Language_uz: String { return self._s[3681]! } + public var Conversation_PinMessageAlertGroup: String { return self._s[3682]! } + public var SettingsSearch_Synonyms_Privacy_GroupsAndChannels: String { return self._s[3683]! } + public var Map_StopLiveLocation: String { return self._s[3685]! } + public var VoiceOver_MessageContextSend: String { return self._s[3687]! } + public var PasscodeSettings_Help: String { return self._s[3688]! } + public var NotificationsSound_Input: String { return self._s[3689]! } + public var Share_Title: String { return self._s[3692]! } + public var LogoutOptions_Title: String { return self._s[3693]! } + public var Wallet_Send_AddressText: String { return self._s[3694]! } + public var Login_TermsOfServiceAgree: String { return self._s[3695]! } + public var Compose_NewEncryptedChatTitle: String { return self._s[3696]! } + public var Channel_AdminLog_TitleSelectedEvents: String { return self._s[3697]! } + public var Channel_EditAdmin_PermissionEditMessages: String { return self._s[3698]! } + public var EnterPasscode_EnterTitle: String { return self._s[3699]! } public func Call_PrivacyErrorMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3689]!, self._r[3689]!, [_0]) + return formatWithArgumentRanges(self._s[3700]!, self._r[3700]!, [_0]) } - public var Settings_CopyPhoneNumber: String { return self._s[3690]! } - public var Conversation_AddToContacts: String { return self._s[3691]! } + public var Settings_CopyPhoneNumber: String { return self._s[3701]! } + public var Conversation_AddToContacts: String { return self._s[3702]! } public func VoiceOver_Chat_ReplyFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3692]!, self._r[3692]!, [_0]) - } - public var NotificationsSound_Keys: String { return self._s[3693]! } - public func Call_ParticipantVersionOutdatedError(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3694]!, self._r[3694]!, [_0]) - } - public var Notification_MessageLifetime1w: String { return self._s[3695]! } - public var Message_Video: String { return self._s[3696]! } - public var AutoDownloadSettings_CellularTitle: String { return self._s[3697]! } - public func PUSH_CHANNEL_MESSAGE_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3698]!, self._r[3698]!, [_1]) - } - public var Wallet_Receive_AmountInfo: String { return self._s[3701]! } - public func Notification_JoinedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3702]!, self._r[3702]!, [_0]) - } - public func PrivacySettings_LastSeenContactsPlus(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3703]!, self._r[3703]!, [_0]) } - public var Passport_Language_mk: String { return self._s[3704]! } - public func Wallet_Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3705]!, self._r[3705]!, [_1, _2, _3]) + public var NotificationsSound_Keys: String { return self._s[3704]! } + public func Call_ParticipantVersionOutdatedError(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3705]!, self._r[3705]!, [_0]) } - public var CreatePoll_CancelConfirmation: String { return self._s[3706]! } - public var MessagePoll_LabelAnonymousQuiz: String { return self._s[3707]! } - public var Conversation_SilentBroadcastTooltipOn: String { return self._s[3709]! } - public var PrivacyPolicy_Decline: String { return self._s[3710]! } - public var Passport_Identity_DoesNotExpire: String { return self._s[3711]! } - public var Channel_AdminLogFilter_EventsRestrictions: String { return self._s[3712]! } - public var AuthSessions_AddDeviceIntro_Action: String { return self._s[3713]! } - public var Permissions_SiriAllow_v0: String { return self._s[3715]! } - public var Wallet_Month_ShortAugust: String { return self._s[3716]! } - public var Appearance_ThemeCarouselNight: String { return self._s[3717]! } + public var Notification_MessageLifetime1w: String { return self._s[3706]! } + public var Message_Video: String { return self._s[3707]! } + public var AutoDownloadSettings_CellularTitle: String { return self._s[3708]! } + public func PUSH_CHANNEL_MESSAGE_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3709]!, self._r[3709]!, [_1]) + } + public var Wallet_Receive_AmountInfo: String { return self._s[3712]! } + public func Notification_JoinedChat(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3713]!, self._r[3713]!, [_0]) + } + public func PrivacySettings_LastSeenContactsPlus(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3714]!, self._r[3714]!, [_0]) + } + public var Passport_Language_mk: String { return self._s[3715]! } + public func Wallet_Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3716]!, self._r[3716]!, [_1, _2, _3]) + } + public var CreatePoll_CancelConfirmation: String { return self._s[3717]! } + public var MessagePoll_LabelAnonymousQuiz: String { return self._s[3718]! } + public var Conversation_SilentBroadcastTooltipOn: String { return self._s[3720]! } + public var PrivacyPolicy_Decline: String { return self._s[3721]! } + public var Passport_Identity_DoesNotExpire: String { return self._s[3722]! } + public var Channel_AdminLogFilter_EventsRestrictions: String { return self._s[3723]! } + public var AuthSessions_AddDeviceIntro_Action: String { return self._s[3724]! } + public var Permissions_SiriAllow_v0: String { return self._s[3726]! } + public var Wallet_Month_ShortAugust: String { return self._s[3727]! } + public var Appearance_ThemeCarouselNight: String { return self._s[3728]! } public func LOCAL_CHAT_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3718]!, self._r[3718]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[3729]!, self._r[3729]!, [_1, "\(_2)"]) } public func Notification_RenamedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3719]!, self._r[3719]!, [_0]) + return formatWithArgumentRanges(self._s[3730]!, self._r[3730]!, [_0]) } - public var Paint_Regular: String { return self._s[3720]! } - public var ChatSettings_AutoDownloadReset: String { return self._s[3721]! } - public var SocksProxySetup_ShareLink: String { return self._s[3722]! } - public var Wallet_Qr_Title: String { return self._s[3723]! } - public var BlockedUsers_SelectUserTitle: String { return self._s[3724]! } - public var VoiceOver_Chat_RecordModeVoiceMessage: String { return self._s[3726]! } - public var Wallet_Settings_Configuration: String { return self._s[3727]! } - public var GroupInfo_InviteByLink: String { return self._s[3728]! } - public var MessageTimer_Custom: String { return self._s[3729]! } - public var UserInfo_NotificationsDefaultEnabled: String { return self._s[3730]! } - public var Conversation_StopQuizConfirmationTitle: String { return self._s[3731]! } - public var Passport_Address_TypeTemporaryRegistration: String { return self._s[3733]! } - public var Conversation_SendMessage_SetReminder: String { return self._s[3734]! } - public var VoiceOver_Chat_Selected: String { return self._s[3735]! } - public var ChatSettings_AutoDownloadUsingWiFi: String { return self._s[3736]! } - public var Channel_Username_InvalidTaken: String { return self._s[3737]! } - public var Conversation_ClousStorageInfo_Description3: String { return self._s[3738]! } - public var Wallet_WordCheck_TryAgain: String { return self._s[3739]! } - public var Wallet_Info_TransactionPendingHeader: String { return self._s[3740]! } - public var Settings_ChatBackground: String { return self._s[3741]! } - public var Channel_Subscribers_Title: String { return self._s[3742]! } - public var Wallet_Receive_InvoiceUrlHeader: String { return self._s[3743]! } - public var ApplyLanguage_ChangeLanguageTitle: String { return self._s[3744]! } - public var Watch_ConnectionDescription: String { return self._s[3745]! } - public var OldChannels_NoticeText: String { return self._s[3748]! } - public var Wallet_Configuration_ApplyErrorTitle: String { return self._s[3749]! } - public var IntentsSettings_SuggestBy: String { return self._s[3751]! } - public var Theme_ThemeChangedText: String { return self._s[3752]! } - public var ChatList_ArchivedChatsTitle: String { return self._s[3753]! } - public var Wallpaper_ResetWallpapers: String { return self._s[3754]! } - public var Wallet_Send_TransactionInProgress: String { return self._s[3755]! } - public var EditProfile_Title: String { return self._s[3756]! } - public var NotificationsSound_Bamboo: String { return self._s[3758]! } - public var Channel_AdminLog_MessagePreviousMessage: String { return self._s[3760]! } - public var Login_SmsRequestState2: String { return self._s[3761]! } - public var Passport_Language_ar: String { return self._s[3762]! } + public var Paint_Regular: String { return self._s[3731]! } + public var ChatSettings_AutoDownloadReset: String { return self._s[3732]! } + public var SocksProxySetup_ShareLink: String { return self._s[3733]! } + public var Wallet_Qr_Title: String { return self._s[3734]! } + public var BlockedUsers_SelectUserTitle: String { return self._s[3735]! } + public var VoiceOver_Chat_RecordModeVoiceMessage: String { return self._s[3737]! } + public var Wallet_Settings_Configuration: String { return self._s[3738]! } + public var GroupInfo_InviteByLink: String { return self._s[3739]! } + public var MessageTimer_Custom: String { return self._s[3740]! } + public var UserInfo_NotificationsDefaultEnabled: String { return self._s[3741]! } + public var Conversation_StopQuizConfirmationTitle: String { return self._s[3742]! } + public var Passport_Address_TypeTemporaryRegistration: String { return self._s[3744]! } + public var Conversation_SendMessage_SetReminder: String { return self._s[3745]! } + public var VoiceOver_Chat_Selected: String { return self._s[3746]! } + public var ChatSettings_AutoDownloadUsingWiFi: String { return self._s[3747]! } + public var Channel_Username_InvalidTaken: String { return self._s[3748]! } + public var Conversation_ClousStorageInfo_Description3: String { return self._s[3749]! } + public var Wallet_WordCheck_TryAgain: String { return self._s[3750]! } + public var Wallet_Info_TransactionPendingHeader: String { return self._s[3751]! } + public var Settings_ChatBackground: String { return self._s[3752]! } + public var Channel_Subscribers_Title: String { return self._s[3753]! } + public var Wallet_Receive_InvoiceUrlHeader: String { return self._s[3754]! } + public var ApplyLanguage_ChangeLanguageTitle: String { return self._s[3755]! } + public var Watch_ConnectionDescription: String { return self._s[3756]! } + public var OldChannels_NoticeText: String { return self._s[3759]! } + public var Wallet_Configuration_ApplyErrorTitle: String { return self._s[3760]! } + public var IntentsSettings_SuggestBy: String { return self._s[3762]! } + public var Theme_ThemeChangedText: String { return self._s[3763]! } + public var ChatList_ArchivedChatsTitle: String { return self._s[3764]! } + public var Wallpaper_ResetWallpapers: String { return self._s[3765]! } + public var Wallet_Send_TransactionInProgress: String { return self._s[3766]! } + public var EditProfile_Title: String { return self._s[3767]! } + public var NotificationsSound_Bamboo: String { return self._s[3769]! } + public var Channel_AdminLog_MessagePreviousMessage: String { return self._s[3771]! } + public var Login_SmsRequestState2: String { return self._s[3772]! } + public var Passport_Language_ar: String { return self._s[3773]! } public func Message_AuthorPinnedGame(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3763]!, self._r[3763]!, [_0]) + return formatWithArgumentRanges(self._s[3774]!, self._r[3774]!, [_0]) } - public var SettingsSearch_Synonyms_EditProfile_Title: String { return self._s[3764]! } - public var Wallet_Created_Text: String { return self._s[3765]! } - public var Conversation_MessageDialogEdit: String { return self._s[3767]! } - public var Wallet_Created_Proceed: String { return self._s[3768]! } - public var Wallet_Words_Done: String { return self._s[3769]! } - public var VoiceOver_Media_PlaybackPause: String { return self._s[3770]! } + public var SettingsSearch_Synonyms_EditProfile_Title: String { return self._s[3775]! } + public var Wallet_Created_Text: String { return self._s[3776]! } + public var Conversation_MessageDialogEdit: String { return self._s[3778]! } + public var Wallet_Created_Proceed: String { return self._s[3779]! } + public var Wallet_Words_Done: String { return self._s[3780]! } + public var VoiceOver_Media_PlaybackPause: String { return self._s[3781]! } public func PUSH_AUTH_UNKNOWN(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3771]!, self._r[3771]!, [_1]) + return formatWithArgumentRanges(self._s[3782]!, self._r[3782]!, [_1]) } - public var Common_Close: String { return self._s[3772]! } - public var GroupInfo_PublicLink: String { return self._s[3773]! } - public var Channel_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[3774]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsPreview: String { return self._s[3775]! } + public var Common_Close: String { return self._s[3783]! } + public var GroupInfo_PublicLink: String { return self._s[3784]! } + public var Channel_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[3785]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsPreview: String { return self._s[3786]! } public func Channel_AdminLog_MessageToggleInvitesOff(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3779]!, self._r[3779]!, [_0]) + return formatWithArgumentRanges(self._s[3790]!, self._r[3790]!, [_0]) } - public var UserInfo_About_Placeholder: String { return self._s[3780]! } + public var UserInfo_About_Placeholder: String { return self._s[3791]! } public func Conversation_FileHowToText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3781]!, self._r[3781]!, [_0]) + return formatWithArgumentRanges(self._s[3792]!, self._r[3792]!, [_0]) } - public var GroupInfo_Permissions_SectionTitle: String { return self._s[3782]! } - public var Channel_Info_Banned: String { return self._s[3784]! } + public var GroupInfo_Permissions_SectionTitle: String { return self._s[3793]! } + public var Channel_Info_Banned: String { return self._s[3795]! } public func Time_MonthOfYear_m11(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3785]!, self._r[3785]!, [_0]) + return formatWithArgumentRanges(self._s[3796]!, self._r[3796]!, [_0]) } - public var Appearance_Other: String { return self._s[3786]! } - public var Passport_Language_my: String { return self._s[3787]! } - public var Group_Setup_BasicHistoryHiddenHelp: String { return self._s[3788]! } + public var Appearance_Other: String { return self._s[3797]! } + public var Passport_Language_my: String { return self._s[3798]! } + public var Group_Setup_BasicHistoryHiddenHelp: String { return self._s[3799]! } public func Time_PreciseDate_m9(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3789]!, self._r[3789]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3800]!, self._r[3800]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Privacy_PasscodeAndFaceId: String { return self._s[3790]! } - public var IntentsSettings_SuggestedAndSpotlightChatsInfo: String { return self._s[3791]! } - public var Preview_CopyAddress: String { return self._s[3792]! } + public var SettingsSearch_Synonyms_Privacy_PasscodeAndFaceId: String { return self._s[3801]! } + public var IntentsSettings_SuggestedAndSpotlightChatsInfo: String { return self._s[3802]! } + public var Preview_CopyAddress: String { return self._s[3803]! } public func DialogList_SinglePlayingGameSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3793]!, self._r[3793]!, [_0]) + return formatWithArgumentRanges(self._s[3804]!, self._r[3804]!, [_0]) } - public var KeyCommand_JumpToPreviousChat: String { return self._s[3794]! } - public var UserInfo_BotSettings: String { return self._s[3795]! } - public var LiveLocation_MenuStopAll: String { return self._s[3797]! } - public var Passport_PasswordCreate: String { return self._s[3798]! } - public var StickerSettings_MaskContextInfo: String { return self._s[3799]! } - public var Message_PinnedLocationMessage: String { return self._s[3800]! } - public var Map_Satellite: String { return self._s[3801]! } - public var Watch_Message_Unsupported: String { return self._s[3802]! } - public var Username_TooManyPublicUsernamesError: String { return self._s[3803]! } - public var TwoStepAuth_EnterPasswordInvalid: String { return self._s[3804]! } + public var KeyCommand_JumpToPreviousChat: String { return self._s[3805]! } + public var UserInfo_BotSettings: String { return self._s[3806]! } + public var LiveLocation_MenuStopAll: String { return self._s[3808]! } + public var Passport_PasswordCreate: String { return self._s[3809]! } + public var StickerSettings_MaskContextInfo: String { return self._s[3810]! } + public var Message_PinnedLocationMessage: String { return self._s[3811]! } + public var Map_Satellite: String { return self._s[3812]! } + public var Watch_Message_Unsupported: String { return self._s[3813]! } + public var Username_TooManyPublicUsernamesError: String { return self._s[3814]! } + public var TwoStepAuth_EnterPasswordInvalid: String { return self._s[3815]! } public func Notification_PinnedTextMessage(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3805]!, self._r[3805]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3816]!, self._r[3816]!, [_0, _1]) } public func Conversation_OpenBotLinkText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3806]!, self._r[3806]!, [_0]) + return formatWithArgumentRanges(self._s[3817]!, self._r[3817]!, [_0]) } - public var Wallet_WordImport_Continue: String { return self._s[3807]! } + public var Wallet_WordImport_Continue: String { return self._s[3818]! } public func TwoFactorSetup_EmailVerification_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3808]!, self._r[3808]!, [_0]) + return formatWithArgumentRanges(self._s[3819]!, self._r[3819]!, [_0]) } - public var Notifications_ChannelNotificationsHelp: String { return self._s[3809]! } - public var Privacy_Calls_P2PContacts: String { return self._s[3810]! } - public var NotificationsSound_None: String { return self._s[3811]! } - public var Wallet_TransactionInfo_StorageFeeHeader: String { return self._s[3812]! } - public var Channel_DiscussionGroup_UnlinkGroup: String { return self._s[3814]! } - public var AccessDenied_VoiceMicrophone: String { return self._s[3815]! } + public var Notifications_ChannelNotificationsHelp: String { return self._s[3820]! } + public var Privacy_Calls_P2PContacts: String { return self._s[3821]! } + public var NotificationsSound_None: String { return self._s[3822]! } + public var Wallet_TransactionInfo_StorageFeeHeader: String { return self._s[3823]! } + public var Channel_DiscussionGroup_UnlinkGroup: String { return self._s[3825]! } + public var AccessDenied_VoiceMicrophone: String { return self._s[3826]! } public func ApplyLanguage_ChangeLanguageAlreadyActive(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3816]!, self._r[3816]!, [_1]) + return formatWithArgumentRanges(self._s[3827]!, self._r[3827]!, [_1]) } - public var Cache_Indexing: String { return self._s[3817]! } - public var DialogList_RecentTitlePeople: String { return self._s[3819]! } - public var DialogList_EncryptionRejected: String { return self._s[3820]! } - public var GroupInfo_Administrators: String { return self._s[3821]! } - public var Passport_ScanPassportHelp: String { return self._s[3822]! } - public var Application_Name: String { return self._s[3823]! } - public var Channel_AdminLogFilter_ChannelEventsInfo: String { return self._s[3824]! } - public var Appearance_ThemeCarouselDay: String { return self._s[3826]! } - public var Passport_Identity_TranslationHelp: String { return self._s[3827]! } + public var Cache_Indexing: String { return self._s[3828]! } + public var DialogList_RecentTitlePeople: String { return self._s[3830]! } + public var DialogList_EncryptionRejected: String { return self._s[3831]! } + public var GroupInfo_Administrators: String { return self._s[3832]! } + public var Passport_ScanPassportHelp: String { return self._s[3833]! } + public var Application_Name: String { return self._s[3834]! } + public var Channel_AdminLogFilter_ChannelEventsInfo: String { return self._s[3835]! } + public var PeopleNearby_MakeVisible: String { return self._s[3837]! } + public var Appearance_ThemeCarouselDay: String { return self._s[3838]! } + public var Passport_Identity_TranslationHelp: String { return self._s[3839]! } public func VoiceOver_Chat_VideoMessageFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3828]!, self._r[3828]!, [_0]) + return formatWithArgumentRanges(self._s[3840]!, self._r[3840]!, [_0]) } public func Notification_JoinedGroupByLink(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3829]!, self._r[3829]!, [_0]) + return formatWithArgumentRanges(self._s[3841]!, self._r[3841]!, [_0]) } public func DialogList_EncryptedChatStartedOutgoing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3830]!, self._r[3830]!, [_0]) + return formatWithArgumentRanges(self._s[3842]!, self._r[3842]!, [_0]) } - public var Channel_EditAdmin_PermissionDeleteMessages: String { return self._s[3831]! } - public var Privacy_ChatsTitle: String { return self._s[3832]! } - public var DialogList_ClearHistoryConfirmation: String { return self._s[3833]! } - public var SettingsSearch_Synonyms_Data_Storage_ClearCache: String { return self._s[3834]! } - public var Watch_Suggestion_HoldOn: String { return self._s[3835]! } - public var Group_EditAdmin_TransferOwnership: String { return self._s[3836]! } - public var WebBrowser_Title: String { return self._s[3837]! } - public var Group_LinkedChannel: String { return self._s[3838]! } - public var VoiceOver_Chat_SeenByRecipient: String { return self._s[3839]! } - public var SocksProxySetup_RequiredCredentials: String { return self._s[3840]! } - public var Passport_Address_TypeRentalAgreementUploadScan: String { return self._s[3841]! } - public var Appearance_TextSize_UseSystem: String { return self._s[3842]! } - public var TwoStepAuth_EmailSkipAlert: String { return self._s[3843]! } - public var ScheduledMessages_RemindersTitle: String { return self._s[3845]! } - public var Channel_Setup_TypePublic: String { return self._s[3847]! } + public var Channel_EditAdmin_PermissionDeleteMessages: String { return self._s[3843]! } + public var Privacy_ChatsTitle: String { return self._s[3844]! } + public var DialogList_ClearHistoryConfirmation: String { return self._s[3845]! } + public var SettingsSearch_Synonyms_Data_Storage_ClearCache: String { return self._s[3846]! } + public var Watch_Suggestion_HoldOn: String { return self._s[3847]! } + public var Group_EditAdmin_TransferOwnership: String { return self._s[3848]! } + public var WebBrowser_Title: String { return self._s[3849]! } + public var Group_LinkedChannel: String { return self._s[3850]! } + public var VoiceOver_Chat_SeenByRecipient: String { return self._s[3851]! } + public var SocksProxySetup_RequiredCredentials: String { return self._s[3852]! } + public var Passport_Address_TypeRentalAgreementUploadScan: String { return self._s[3853]! } + public var Appearance_TextSize_UseSystem: String { return self._s[3854]! } + public var TwoStepAuth_EmailSkipAlert: String { return self._s[3855]! } + public var ScheduledMessages_RemindersTitle: String { return self._s[3857]! } + public var Channel_Setup_TypePublic: String { return self._s[3859]! } public func Channel_AdminLog_MessageToggleInvitesOn(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3848]!, self._r[3848]!, [_0]) + return formatWithArgumentRanges(self._s[3860]!, self._r[3860]!, [_0]) } - public var Channel_TypeSetup_Title: String { return self._s[3850]! } - public var MessagePoll_ViewResults: String { return self._s[3851]! } - public var Map_OpenInMaps: String { return self._s[3853]! } + public var Channel_TypeSetup_Title: String { return self._s[3862]! } + public var MessagePoll_ViewResults: String { return self._s[3863]! } + public var Map_OpenInMaps: String { return self._s[3865]! } public func PUSH_PINNED_NOTEXT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3854]!, self._r[3854]!, [_1]) + return formatWithArgumentRanges(self._s[3866]!, self._r[3866]!, [_1]) } - public var NotificationsSound_Tremolo: String { return self._s[3856]! } + public var NotificationsSound_Tremolo: String { return self._s[3868]! } public func Date_ChatDateHeaderYear(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3857]!, self._r[3857]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3869]!, self._r[3869]!, [_1, _2, _3]) } - public var ConversationProfile_UnknownAddMemberError: String { return self._s[3858]! } - public var Channel_OwnershipTransfer_PasswordPlaceholder: String { return self._s[3859]! } - public var Passport_PasswordHelp: String { return self._s[3860]! } - public var Login_CodeExpiredError: String { return self._s[3861]! } - public var Channel_EditAdmin_PermissionChangeInfo: String { return self._s[3862]! } - public var Conversation_TitleUnmute: String { return self._s[3863]! } - public var Passport_Identity_ScansHelp: String { return self._s[3864]! } - public var Passport_Language_lo: String { return self._s[3865]! } - public var Camera_FlashAuto: String { return self._s[3866]! } - public var Conversation_OpenBotLinkOpen: String { return self._s[3867]! } - public var Common_Cancel: String { return self._s[3868]! } - public var DialogList_SavedMessagesTooltip: String { return self._s[3869]! } - public var TwoStepAuth_SetupPasswordTitle: String { return self._s[3870]! } - public var Appearance_TintAllColors: String { return self._s[3871]! } + public var ConversationProfile_UnknownAddMemberError: String { return self._s[3870]! } + public var Channel_OwnershipTransfer_PasswordPlaceholder: String { return self._s[3871]! } + public var Passport_PasswordHelp: String { return self._s[3872]! } + public var Login_CodeExpiredError: String { return self._s[3873]! } + public var Channel_EditAdmin_PermissionChangeInfo: String { return self._s[3874]! } + public var Conversation_TitleUnmute: String { return self._s[3875]! } + public var Passport_Identity_ScansHelp: String { return self._s[3876]! } + public var Passport_Language_lo: String { return self._s[3877]! } + public var Camera_FlashAuto: String { return self._s[3878]! } + public var Conversation_OpenBotLinkOpen: String { return self._s[3879]! } + public var Common_Cancel: String { return self._s[3880]! } + public var DialogList_SavedMessagesTooltip: String { return self._s[3881]! } + public var TwoStepAuth_SetupPasswordTitle: String { return self._s[3882]! } + public var Appearance_TintAllColors: String { return self._s[3883]! } public func PUSH_MESSAGE_FWD(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3872]!, self._r[3872]!, [_1]) + return formatWithArgumentRanges(self._s[3884]!, self._r[3884]!, [_1]) } - public var Conversation_ReportSpamConfirmation: String { return self._s[3873]! } - public var ChatSettings_Title: String { return self._s[3875]! } - public var Passport_PasswordReset: String { return self._s[3876]! } - public var SocksProxySetup_TypeNone: String { return self._s[3877]! } - public var EditTheme_Title: String { return self._s[3880]! } - public var PhoneNumberHelp_Help: String { return self._s[3881]! } - public var Checkout_EnterPassword: String { return self._s[3882]! } - public var Share_AuthTitle: String { return self._s[3884]! } - public var Activity_UploadingDocument: String { return self._s[3885]! } - public var State_Connecting: String { return self._s[3886]! } - public var Profile_MessageLifetime1w: String { return self._s[3887]! } - public var Conversation_ContextMenuReport: String { return self._s[3888]! } - public var CheckoutInfo_ReceiverInfoPhone: String { return self._s[3889]! } - public var AutoNightTheme_ScheduledTo: String { return self._s[3890]! } + public var Conversation_ReportSpamConfirmation: String { return self._s[3885]! } + public var ChatSettings_Title: String { return self._s[3887]! } + public var Passport_PasswordReset: String { return self._s[3888]! } + public var SocksProxySetup_TypeNone: String { return self._s[3889]! } + public var EditTheme_Title: String { return self._s[3892]! } + public var PhoneNumberHelp_Help: String { return self._s[3893]! } + public var Checkout_EnterPassword: String { return self._s[3894]! } + public var Share_AuthTitle: String { return self._s[3896]! } + public var Activity_UploadingDocument: String { return self._s[3897]! } + public var State_Connecting: String { return self._s[3898]! } + public var Profile_MessageLifetime1w: String { return self._s[3899]! } + public var Conversation_ContextMenuReport: String { return self._s[3900]! } + public var CheckoutInfo_ReceiverInfoPhone: String { return self._s[3901]! } + public var AutoNightTheme_ScheduledTo: String { return self._s[3902]! } public func VoiceOver_Chat_AnonymousPollFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3891]!, self._r[3891]!, [_0]) + return formatWithArgumentRanges(self._s[3903]!, self._r[3903]!, [_0]) } - public var AuthSessions_Terminate: String { return self._s[3892]! } - public var Wallet_WordImport_CanNotRemember: String { return self._s[3893]! } - public var Checkout_NewCard_CardholderNamePlaceholder: String { return self._s[3895]! } - public var KeyCommand_JumpToPreviousUnreadChat: String { return self._s[3896]! } - public var PhotoEditor_Set: String { return self._s[3897]! } - public var EmptyGroupInfo_Title: String { return self._s[3898]! } - public var Login_PadPhoneHelp: String { return self._s[3899]! } - public var AutoDownloadSettings_TypeGroupChats: String { return self._s[3901]! } - public var PrivacyPolicy_DeclineLastWarning: String { return self._s[3903]! } - public var NotificationsSound_Complete: String { return self._s[3904]! } - public var SettingsSearch_Synonyms_Privacy_Data_Title: String { return self._s[3905]! } - public var Group_Info_AdminLog: String { return self._s[3906]! } - public var GroupPermission_NotAvailableInPublicGroups: String { return self._s[3907]! } + public var AuthSessions_Terminate: String { return self._s[3904]! } + public var Wallet_WordImport_CanNotRemember: String { return self._s[3905]! } + public var Checkout_NewCard_CardholderNamePlaceholder: String { return self._s[3907]! } + public var KeyCommand_JumpToPreviousUnreadChat: String { return self._s[3908]! } + public var PhotoEditor_Set: String { return self._s[3909]! } + public var EmptyGroupInfo_Title: String { return self._s[3910]! } + public var Login_PadPhoneHelp: String { return self._s[3911]! } + public var AutoDownloadSettings_TypeGroupChats: String { return self._s[3913]! } + public var PrivacyPolicy_DeclineLastWarning: String { return self._s[3915]! } + public var NotificationsSound_Complete: String { return self._s[3916]! } + public var SettingsSearch_Synonyms_Privacy_Data_Title: String { return self._s[3917]! } + public var Group_Info_AdminLog: String { return self._s[3918]! } + public var GroupPermission_NotAvailableInPublicGroups: String { return self._s[3919]! } public func Wallet_Time_PreciseDate_m11(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3908]!, self._r[3908]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3920]!, self._r[3920]!, [_1, _2, _3]) } - public var Channel_AdminLog_InfoPanelAlertText: String { return self._s[3909]! } - public var Group_Location_CreateInThisPlace: String { return self._s[3911]! } - public var Conversation_Admin: String { return self._s[3912]! } - public var Conversation_GifTooltip: String { return self._s[3913]! } - public var Passport_NotLoggedInMessage: String { return self._s[3914]! } + public var Channel_AdminLog_InfoPanelAlertText: String { return self._s[3921]! } + public var Group_Location_CreateInThisPlace: String { return self._s[3923]! } + public var Conversation_Admin: String { return self._s[3924]! } + public var Conversation_GifTooltip: String { return self._s[3925]! } + public var Passport_NotLoggedInMessage: String { return self._s[3926]! } public func AutoDownloadSettings_OnFor(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3916]!, self._r[3916]!, [_0]) + return formatWithArgumentRanges(self._s[3928]!, self._r[3928]!, [_0]) } - public var Profile_MessageLifetimeForever: String { return self._s[3917]! } - public var SharedMedia_EmptyTitle: String { return self._s[3919]! } - public var Channel_Edit_PrivatePublicLinkAlert: String { return self._s[3921]! } - public var Username_Help: String { return self._s[3922]! } - public var DialogList_LanguageTooltip: String { return self._s[3924]! } - public var Map_LoadError: String { return self._s[3925]! } - public var Login_PhoneNumberAlreadyAuthorized: String { return self._s[3926]! } - public var Channel_AdminLog_AddMembers: String { return self._s[3927]! } - public var ArchivedChats_IntroTitle2: String { return self._s[3928]! } - public var Notification_Exceptions_NewException: String { return self._s[3929]! } - public var TwoStepAuth_EmailTitle: String { return self._s[3930]! } - public var WatchRemote_AlertText: String { return self._s[3931]! } + public var Profile_MessageLifetimeForever: String { return self._s[3929]! } + public var SharedMedia_EmptyTitle: String { return self._s[3931]! } + public var Channel_Edit_PrivatePublicLinkAlert: String { return self._s[3933]! } + public var Username_Help: String { return self._s[3934]! } + public var DialogList_LanguageTooltip: String { return self._s[3936]! } + public var Map_LoadError: String { return self._s[3937]! } + public var Login_PhoneNumberAlreadyAuthorized: String { return self._s[3938]! } + public var Channel_AdminLog_AddMembers: String { return self._s[3939]! } + public var ArchivedChats_IntroTitle2: String { return self._s[3940]! } + public var Notification_Exceptions_NewException: String { return self._s[3941]! } + public var TwoStepAuth_EmailTitle: String { return self._s[3942]! } + public var WatchRemote_AlertText: String { return self._s[3943]! } public func Wallet_Send_ConfirmationText(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3932]!, self._r[3932]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3944]!, self._r[3944]!, [_1, _2, _3]) } - public var ChatSettings_ConnectionType_Title: String { return self._s[3936]! } - public var WebBrowser_DefaultBrowser: String { return self._s[3937]! } + public var ChatSettings_ConnectionType_Title: String { return self._s[3948]! } + public var WebBrowser_DefaultBrowser: String { return self._s[3949]! } public func Settings_CheckPhoneNumberTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3938]!, self._r[3938]!, [_0]) + return formatWithArgumentRanges(self._s[3950]!, self._r[3950]!, [_0]) } - public var SettingsSearch_Synonyms_Calls_CallTab: String { return self._s[3939]! } - public var Passport_Address_CountryPlaceholder: String { return self._s[3940]! } + public var SettingsSearch_Synonyms_Calls_CallTab: String { return self._s[3951]! } + public var Passport_Address_CountryPlaceholder: String { return self._s[3952]! } public func DialogList_AwaitingEncryption(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3941]!, self._r[3941]!, [_0]) + return formatWithArgumentRanges(self._s[3953]!, self._r[3953]!, [_0]) } public func Time_PreciseDate_m6(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3942]!, self._r[3942]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3954]!, self._r[3954]!, [_1, _2, _3]) } - public var Group_AdminLog_EmptyText: String { return self._s[3943]! } - public var SettingsSearch_Synonyms_Appearance_Title: String { return self._s[3944]! } - public var Conversation_PrivateChannelTooltip: String { return self._s[3946]! } - public var Wallet_Created_ExportErrorText: String { return self._s[3947]! } - public var ChatList_UndoArchiveText1: String { return self._s[3948]! } - public var AccessDenied_VideoMicrophone: String { return self._s[3949]! } - public var Conversation_ContextMenuStickerPackAdd: String { return self._s[3950]! } - public var Cache_ClearNone: String { return self._s[3951]! } - public var SocksProxySetup_FailedToConnect: String { return self._s[3952]! } - public var Permissions_NotificationsTitle_v0: String { return self._s[3953]! } + public var Group_AdminLog_EmptyText: String { return self._s[3955]! } + public var SettingsSearch_Synonyms_Appearance_Title: String { return self._s[3956]! } + public var Conversation_PrivateChannelTooltip: String { return self._s[3958]! } + public var Wallet_Created_ExportErrorText: String { return self._s[3959]! } + public var ChatList_UndoArchiveText1: String { return self._s[3960]! } + public var AccessDenied_VideoMicrophone: String { return self._s[3961]! } + public var Conversation_ContextMenuStickerPackAdd: String { return self._s[3962]! } + public var Cache_ClearNone: String { return self._s[3963]! } + public var SocksProxySetup_FailedToConnect: String { return self._s[3964]! } + public var Permissions_NotificationsTitle_v0: String { return self._s[3965]! } public func Channel_AdminLog_MessageEdited(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3954]!, self._r[3954]!, [_0]) + return formatWithArgumentRanges(self._s[3966]!, self._r[3966]!, [_0]) } - public var Passport_Identity_Country: String { return self._s[3955]! } + public var Passport_Identity_Country: String { return self._s[3967]! } public func ChatSettings_AutoDownloadSettings_TypeFile(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3956]!, self._r[3956]!, [_0]) + return formatWithArgumentRanges(self._s[3968]!, self._r[3968]!, [_0]) } public func Notification_CreatedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3957]!, self._r[3957]!, [_0]) + return formatWithArgumentRanges(self._s[3969]!, self._r[3969]!, [_0]) } - public var Exceptions_AddToExceptions: String { return self._s[3958]! } - public var AccessDenied_Settings: String { return self._s[3959]! } - public var Passport_Address_TypeUtilityBillUploadScan: String { return self._s[3960]! } - public var Month_ShortMay: String { return self._s[3961]! } - public var Compose_NewGroup: String { return self._s[3963]! } - public var Group_Setup_TypePrivate: String { return self._s[3965]! } - public var Login_PadPhoneHelpTitle: String { return self._s[3967]! } - public var Appearance_ThemeDayClassic: String { return self._s[3968]! } - public var Channel_AdminLog_MessagePreviousCaption: String { return self._s[3969]! } - public var AutoDownloadSettings_OffForAll: String { return self._s[3970]! } - public var Privacy_GroupsAndChannels_WhoCanAddMe: String { return self._s[3971]! } - public var Conversation_typing: String { return self._s[3973]! } - public var Undo_ScheduledMessagesCleared: String { return self._s[3974]! } - public var Paint_Masks: String { return self._s[3975]! } - public var Contacts_DeselectAll: String { return self._s[3976]! } + public var Exceptions_AddToExceptions: String { return self._s[3970]! } + public var AccessDenied_Settings: String { return self._s[3971]! } + public var Passport_Address_TypeUtilityBillUploadScan: String { return self._s[3972]! } + public var Month_ShortMay: String { return self._s[3973]! } + public var Compose_NewGroup: String { return self._s[3975]! } + public var Group_Setup_TypePrivate: String { return self._s[3977]! } + public var Login_PadPhoneHelpTitle: String { return self._s[3979]! } + public var Appearance_ThemeDayClassic: String { return self._s[3980]! } + public var Channel_AdminLog_MessagePreviousCaption: String { return self._s[3981]! } + public var AutoDownloadSettings_OffForAll: String { return self._s[3982]! } + public var Privacy_GroupsAndChannels_WhoCanAddMe: String { return self._s[3983]! } + public var Conversation_typing: String { return self._s[3985]! } + public var Undo_ScheduledMessagesCleared: String { return self._s[3986]! } + public var Paint_Masks: String { return self._s[3987]! } + public var Contacts_DeselectAll: String { return self._s[3988]! } public func Wallet_Updated_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3977]!, self._r[3977]!, [_0]) + return formatWithArgumentRanges(self._s[3989]!, self._r[3989]!, [_0]) } - public var CreatePoll_MultipleChoiceQuizAlert: String { return self._s[3978]! } - public var Username_InvalidTaken: String { return self._s[3979]! } - public var Call_StatusNoAnswer: String { return self._s[3980]! } - public var TwoStepAuth_EmailAddSuccess: String { return self._s[3981]! } - public var SettingsSearch_Synonyms_Privacy_BlockedUsers: String { return self._s[3982]! } - public var Passport_Identity_Selfie: String { return self._s[3983]! } - public var Login_InfoLastNamePlaceholder: String { return self._s[3984]! } - public var Privacy_SecretChatsLinkPreviewsHelp: String { return self._s[3985]! } - public var Conversation_ClearSecretHistory: String { return self._s[3986]! } - public var PeopleNearby_Description: String { return self._s[3988]! } - public var NetworkUsageSettings_Title: String { return self._s[3989]! } - public var Your_cards_security_code_is_invalid: String { return self._s[3991]! } + public var CreatePoll_MultipleChoiceQuizAlert: String { return self._s[3990]! } + public var Username_InvalidTaken: String { return self._s[3991]! } + public var Call_StatusNoAnswer: String { return self._s[3992]! } + public var TwoStepAuth_EmailAddSuccess: String { return self._s[3993]! } + public var SettingsSearch_Synonyms_Privacy_BlockedUsers: String { return self._s[3994]! } + public var Passport_Identity_Selfie: String { return self._s[3995]! } + public var Login_InfoLastNamePlaceholder: String { return self._s[3996]! } + public var Privacy_SecretChatsLinkPreviewsHelp: String { return self._s[3997]! } + public var Conversation_ClearSecretHistory: String { return self._s[3998]! } + public var PeopleNearby_Description: String { return self._s[4000]! } + public var NetworkUsageSettings_Title: String { return self._s[4001]! } + public var Your_cards_security_code_is_invalid: String { return self._s[4003]! } public func Notification_LeftChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3993]!, self._r[3993]!, [_0]) - } - public func Call_CallInProgressMessage(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3994]!, self._r[3994]!, [_1, _2]) - } - public var SaveIncomingPhotosSettings_From: String { return self._s[3996]! } - public var VoiceOver_Navigation_Search: String { return self._s[3997]! } - public var Map_LiveLocationTitle: String { return self._s[3998]! } - public var Login_InfoAvatarAdd: String { return self._s[3999]! } - public var Passport_Identity_FilesView: String { return self._s[4000]! } - public var UserInfo_GenericPhoneLabel: String { return self._s[4001]! } - public var Privacy_Calls_NeverAllow: String { return self._s[4002]! } - public var VoiceOver_Chat_File: String { return self._s[4003]! } - public var Wallet_Settings_DeleteWalletInfo: String { return self._s[4004]! } - public func Contacts_AddPhoneNumber(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[4005]!, self._r[4005]!, [_0]) } - public var ContactInfo_PhoneNumberHidden: String { return self._s[4006]! } - public var TwoStepAuth_ConfirmationText: String { return self._s[4007]! } - public var ChatSettings_AutomaticVideoMessageDownload: String { return self._s[4008]! } + public func Call_CallInProgressMessage(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[4006]!, self._r[4006]!, [_1, _2]) + } + public var SaveIncomingPhotosSettings_From: String { return self._s[4008]! } + public var VoiceOver_Navigation_Search: String { return self._s[4009]! } + public var Map_LiveLocationTitle: String { return self._s[4010]! } + public var Login_InfoAvatarAdd: String { return self._s[4011]! } + public var Passport_Identity_FilesView: String { return self._s[4012]! } + public var UserInfo_GenericPhoneLabel: String { return self._s[4013]! } + public var Privacy_Calls_NeverAllow: String { return self._s[4014]! } + public var VoiceOver_Chat_File: String { return self._s[4015]! } + public var Wallet_Settings_DeleteWalletInfo: String { return self._s[4016]! } + public func Contacts_AddPhoneNumber(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[4017]!, self._r[4017]!, [_0]) + } + public var ContactInfo_PhoneNumberHidden: String { return self._s[4018]! } + public var TwoStepAuth_ConfirmationText: String { return self._s[4019]! } + public var ChatSettings_AutomaticVideoMessageDownload: String { return self._s[4020]! } public func PUSH_CHAT_MESSAGE_VIDEOS(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4009]!, self._r[4009]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4021]!, self._r[4021]!, [_1, _2, _3]) } - public var Channel_AdminLogFilter_AdminsAll: String { return self._s[4010]! } - public var Wallet_Intro_CreateErrorText: String { return self._s[4011]! } - public var Tour_Title2: String { return self._s[4012]! } - public var Wallet_Sent_ViewWallet: String { return self._s[4013]! } - public var Conversation_FileOpenIn: String { return self._s[4014]! } - public var Checkout_ErrorPrecheckoutFailed: String { return self._s[4015]! } - public var Wallet_Send_ErrorInvalidAddress: String { return self._s[4016]! } - public var Wallpaper_Set: String { return self._s[4017]! } - public var Passport_Identity_Translations: String { return self._s[4019]! } + public var Channel_AdminLogFilter_AdminsAll: String { return self._s[4022]! } + public var Wallet_Intro_CreateErrorText: String { return self._s[4023]! } + public var Tour_Title2: String { return self._s[4024]! } + public var Wallet_Sent_ViewWallet: String { return self._s[4025]! } + public var Conversation_FileOpenIn: String { return self._s[4026]! } + public var Checkout_ErrorPrecheckoutFailed: String { return self._s[4027]! } + public var Wallet_Send_ErrorInvalidAddress: String { return self._s[4028]! } + public var Wallpaper_Set: String { return self._s[4029]! } + public var Passport_Identity_Translations: String { return self._s[4031]! } public func Channel_AdminLog_MessageChangedChannelAbout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4020]!, self._r[4020]!, [_0]) + return formatWithArgumentRanges(self._s[4032]!, self._r[4032]!, [_0]) } - public var Channel_LeaveChannel: String { return self._s[4021]! } + public var Channel_LeaveChannel: String { return self._s[4033]! } public func PINNED_INVOICE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4022]!, self._r[4022]!, [_1]) + return formatWithArgumentRanges(self._s[4034]!, self._r[4034]!, [_1]) } - public var SettingsSearch_Synonyms_Proxy_AddProxy: String { return self._s[4024]! } - public var PhotoEditor_HighlightsTint: String { return self._s[4025]! } - public var MessagePoll_LabelPoll: String { return self._s[4026]! } - public var Passport_Email_Delete: String { return self._s[4027]! } - public var Conversation_Mute: String { return self._s[4029]! } - public var Channel_AddBotAsAdmin: String { return self._s[4030]! } - public var Channel_AdminLog_CanSendMessages: String { return self._s[4032]! } - public var Wallet_Configuration_BlockchainNameChangedText: String { return self._s[4033]! } - public var ChatSettings_IntentsSettings: String { return self._s[4035]! } - public var Channel_Management_LabelOwner: String { return self._s[4036]! } + public var SettingsSearch_Synonyms_Proxy_AddProxy: String { return self._s[4036]! } + public var PhotoEditor_HighlightsTint: String { return self._s[4037]! } + public var MessagePoll_LabelPoll: String { return self._s[4038]! } + public var Passport_Email_Delete: String { return self._s[4039]! } + public var Conversation_Mute: String { return self._s[4041]! } + public var Channel_AddBotAsAdmin: String { return self._s[4042]! } + public var Channel_AdminLog_CanSendMessages: String { return self._s[4044]! } + public var Wallet_Configuration_BlockchainNameChangedText: String { return self._s[4045]! } + public var ChatSettings_IntentsSettings: String { return self._s[4047]! } + public var Channel_Management_LabelOwner: String { return self._s[4048]! } public func Notification_PassportValuesSentMessage(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4037]!, self._r[4037]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4049]!, self._r[4049]!, [_1, _2]) } - public var Calls_CallTabDescription: String { return self._s[4038]! } - public var Passport_Identity_NativeNameHelp: String { return self._s[4039]! } - public var Common_No: String { return self._s[4040]! } - public var Weekday_Sunday: String { return self._s[4041]! } - public var Notification_Reply: String { return self._s[4042]! } - public var Conversation_ViewMessage: String { return self._s[4043]! } + public var Calls_CallTabDescription: String { return self._s[4050]! } + public var Passport_Identity_NativeNameHelp: String { return self._s[4051]! } + public var Common_No: String { return self._s[4052]! } + public var Weekday_Sunday: String { return self._s[4053]! } + public var Notification_Reply: String { return self._s[4054]! } + public var Conversation_ViewMessage: String { return self._s[4055]! } public func Checkout_SavePasswordTimeoutAndFaceId(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4044]!, self._r[4044]!, [_0]) + return formatWithArgumentRanges(self._s[4056]!, self._r[4056]!, [_0]) } public func Map_LiveLocationPrivateDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4045]!, self._r[4045]!, [_0]) + return formatWithArgumentRanges(self._s[4057]!, self._r[4057]!, [_0]) } public func Wallet_Time_PreciseDate_m7(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4046]!, self._r[4046]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4058]!, self._r[4058]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_EditProfile_AddAccount: String { return self._s[4047]! } - public var Wallet_Send_Title: String { return self._s[4048]! } - public var Message_PinnedDocumentMessage: String { return self._s[4049]! } - public var Wallet_Info_RefreshErrorText: String { return self._s[4050]! } - public var DialogList_TabTitle: String { return self._s[4052]! } - public var ChatSettings_AutoPlayTitle: String { return self._s[4053]! } - public var Passport_FieldEmail: String { return self._s[4054]! } - public var Conversation_UnpinMessageAlert: String { return self._s[4055]! } - public var Passport_Address_TypeBankStatement: String { return self._s[4056]! } - public var Wallet_SecureStorageReset_Title: String { return self._s[4057]! } - public var Passport_Identity_ExpiryDate: String { return self._s[4058]! } - public var Privacy_Calls_P2P: String { return self._s[4059]! } + public var SettingsSearch_Synonyms_EditProfile_AddAccount: String { return self._s[4059]! } + public var Wallet_Send_Title: String { return self._s[4060]! } + public var Message_PinnedDocumentMessage: String { return self._s[4061]! } + public var Wallet_Info_RefreshErrorText: String { return self._s[4062]! } + public var DialogList_TabTitle: String { return self._s[4064]! } + public var ChatSettings_AutoPlayTitle: String { return self._s[4065]! } + public var Passport_FieldEmail: String { return self._s[4066]! } + public var Conversation_UnpinMessageAlert: String { return self._s[4067]! } + public var Passport_Address_TypeBankStatement: String { return self._s[4068]! } + public var Wallet_SecureStorageReset_Title: String { return self._s[4069]! } + public var Passport_Identity_ExpiryDate: String { return self._s[4070]! } + public var Privacy_Calls_P2P: String { return self._s[4071]! } public func CancelResetAccount_Success(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4061]!, self._r[4061]!, [_0]) + return formatWithArgumentRanges(self._s[4073]!, self._r[4073]!, [_0]) } - public var SocksProxySetup_UseForCallsHelp: String { return self._s[4062]! } + public var SocksProxySetup_UseForCallsHelp: String { return self._s[4074]! } public func PUSH_CHAT_ALBUM(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4063]!, self._r[4063]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4075]!, self._r[4075]!, [_1, _2]) } - public var Stickers_ClearRecent: String { return self._s[4064]! } - public var EnterPasscode_ChangeTitle: String { return self._s[4065]! } - public var TwoFactorSetup_Email_Title: String { return self._s[4066]! } - public var Passport_InfoText: String { return self._s[4067]! } - public var Checkout_NewCard_SaveInfoEnableHelp: String { return self._s[4068]! } + public var Stickers_ClearRecent: String { return self._s[4076]! } + public var EnterPasscode_ChangeTitle: String { return self._s[4077]! } + public var TwoFactorSetup_Email_Title: String { return self._s[4078]! } + public var Passport_InfoText: String { return self._s[4079]! } + public var Checkout_NewCard_SaveInfoEnableHelp: String { return self._s[4080]! } public func Login_InvalidPhoneEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4069]!, self._r[4069]!, [_0]) + return formatWithArgumentRanges(self._s[4081]!, self._r[4081]!, [_0]) } public func Time_PreciseDate_m3(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4070]!, self._r[4070]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4082]!, self._r[4082]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChannels: String { return self._s[4071]! } - public var ScheduledMessages_PollUnavailable: String { return self._s[4072]! } - public var VoiceOver_Navigation_Compose: String { return self._s[4073]! } - public var Passport_Identity_EditDriversLicense: String { return self._s[4074]! } - public var Conversation_TapAndHoldToRecord: String { return self._s[4076]! } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChats: String { return self._s[4077]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChannels: String { return self._s[4083]! } + public var ScheduledMessages_PollUnavailable: String { return self._s[4084]! } + public var VoiceOver_Navigation_Compose: String { return self._s[4085]! } + public var Passport_Identity_EditDriversLicense: String { return self._s[4086]! } + public var Conversation_TapAndHoldToRecord: String { return self._s[4088]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChats: String { return self._s[4089]! } public func Notification_CallTimeFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4078]!, self._r[4078]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4090]!, self._r[4090]!, [_1, _2]) } - public var Channel_EditAdmin_PermissionInviteViaLink: String { return self._s[4080]! } - public var ChatSettings_OpenLinksIn: String { return self._s[4081]! } - public var Map_HomeAndWorkTitle: String { return self._s[4082]! } + public var Channel_EditAdmin_PermissionInviteViaLink: String { return self._s[4093]! } + public var ChatSettings_OpenLinksIn: String { return self._s[4094]! } + public var Map_HomeAndWorkTitle: String { return self._s[4095]! } public func Generic_OpenHiddenLinkAlert(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4084]!, self._r[4084]!, [_0]) + return formatWithArgumentRanges(self._s[4097]!, self._r[4097]!, [_0]) } - public var DialogList_Unread: String { return self._s[4085]! } + public var DialogList_Unread: String { return self._s[4098]! } public func PUSH_CHAT_MESSAGE_GIF(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4086]!, self._r[4086]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4099]!, self._r[4099]!, [_1, _2]) } - public var User_DeletedAccount: String { return self._s[4087]! } - public var OwnershipTransfer_SetupTwoStepAuth: String { return self._s[4088]! } + public var User_DeletedAccount: String { return self._s[4100]! } + public var OwnershipTransfer_SetupTwoStepAuth: String { return self._s[4101]! } public func Watch_Time_ShortYesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4089]!, self._r[4089]!, [_0]) + return formatWithArgumentRanges(self._s[4102]!, self._r[4102]!, [_0]) } - public var UserInfo_NotificationsDefault: String { return self._s[4090]! } - public var SharedMedia_CategoryMedia: String { return self._s[4091]! } - public var SocksProxySetup_ProxyStatusUnavailable: String { return self._s[4092]! } - public var Channel_AdminLog_MessageRestrictedForever: String { return self._s[4093]! } - public var Watch_ChatList_Compose: String { return self._s[4094]! } - public var Notifications_MessageNotificationsExceptionsHelp: String { return self._s[4095]! } - public var AutoDownloadSettings_Delimeter: String { return self._s[4096]! } - public var Watch_Microphone_Access: String { return self._s[4097]! } - public var Group_Setup_HistoryHeader: String { return self._s[4098]! } - public var Map_SetThisLocation: String { return self._s[4099]! } - public var Appearance_ThemePreview_Chat_2_ReplyName: String { return self._s[4100]! } - public var Activity_UploadingPhoto: String { return self._s[4101]! } - public var Conversation_Edit: String { return self._s[4103]! } - public var Group_ErrorSendRestrictedMedia: String { return self._s[4104]! } - public var Login_TermsOfServiceDecline: String { return self._s[4105]! } - public var Message_PinnedContactMessage: String { return self._s[4106]! } + public var UserInfo_NotificationsDefault: String { return self._s[4103]! } + public var SharedMedia_CategoryMedia: String { return self._s[4104]! } + public var SocksProxySetup_ProxyStatusUnavailable: String { return self._s[4105]! } + public var Channel_AdminLog_MessageRestrictedForever: String { return self._s[4106]! } + public var Watch_ChatList_Compose: String { return self._s[4107]! } + public var Notifications_MessageNotificationsExceptionsHelp: String { return self._s[4108]! } + public var AutoDownloadSettings_Delimeter: String { return self._s[4109]! } + public var Watch_Microphone_Access: String { return self._s[4110]! } + public var Group_Setup_HistoryHeader: String { return self._s[4111]! } + public var Map_SetThisLocation: String { return self._s[4112]! } + public var Appearance_ThemePreview_Chat_2_ReplyName: String { return self._s[4113]! } + public var Activity_UploadingPhoto: String { return self._s[4114]! } + public var Conversation_Edit: String { return self._s[4116]! } + public var Group_ErrorSendRestrictedMedia: String { return self._s[4117]! } + public var Login_TermsOfServiceDecline: String { return self._s[4118]! } + public var Message_PinnedContactMessage: String { return self._s[4119]! } public func Channel_AdminLog_MessageRestrictedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4107]!, self._r[4107]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4120]!, self._r[4120]!, [_1, _2]) } public func Login_PhoneBannedEmailBody(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4108]!, self._r[4108]!, [_1, _2, _3, _4, _5]) + return formatWithArgumentRanges(self._s[4121]!, self._r[4121]!, [_1, _2, _3, _4, _5]) } - public var Appearance_LargeEmoji: String { return self._s[4109]! } - public var TwoStepAuth_AdditionalPassword: String { return self._s[4111]! } - public var EditTheme_Edit_Preview_IncomingReplyText: String { return self._s[4112]! } + public var Appearance_LargeEmoji: String { return self._s[4122]! } + public var TwoStepAuth_AdditionalPassword: String { return self._s[4124]! } + public var EditTheme_Edit_Preview_IncomingReplyText: String { return self._s[4125]! } public func PUSH_CHAT_DELETE_YOU(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4113]!, self._r[4113]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4126]!, self._r[4126]!, [_1, _2]) } - public var Passport_Phone_EnterOtherNumber: String { return self._s[4114]! } - public var Message_PinnedPhotoMessage: String { return self._s[4115]! } - public var Passport_FieldPhone: String { return self._s[4116]! } - public var TwoStepAuth_RecoveryEmailAddDescription: String { return self._s[4117]! } - public var ChatSettings_AutoPlayGifs: String { return self._s[4118]! } - public var InfoPlist_NSCameraUsageDescription: String { return self._s[4120]! } - public var Conversation_Call: String { return self._s[4121]! } - public var Common_TakePhoto: String { return self._s[4123]! } - public var Group_EditAdmin_RankTitle: String { return self._s[4124]! } - public var Wallet_Receive_CommentHeader: String { return self._s[4125]! } - public var Channel_NotificationLoading: String { return self._s[4126]! } + public var Passport_Phone_EnterOtherNumber: String { return self._s[4127]! } + public var Message_PinnedPhotoMessage: String { return self._s[4128]! } + public var Passport_FieldPhone: String { return self._s[4129]! } + public var TwoStepAuth_RecoveryEmailAddDescription: String { return self._s[4130]! } + public var ChatSettings_AutoPlayGifs: String { return self._s[4131]! } + public var InfoPlist_NSCameraUsageDescription: String { return self._s[4133]! } + public var Conversation_Call: String { return self._s[4134]! } + public var Common_TakePhoto: String { return self._s[4136]! } + public var Group_EditAdmin_RankTitle: String { return self._s[4137]! } + public var Wallet_Receive_CommentHeader: String { return self._s[4138]! } + public var Channel_NotificationLoading: String { return self._s[4139]! } public func Notification_Exceptions_Sound(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4127]!, self._r[4127]!, [_0]) + return formatWithArgumentRanges(self._s[4140]!, self._r[4140]!, [_0]) } public func ScheduledMessages_ScheduledDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4128]!, self._r[4128]!, [_0]) + return formatWithArgumentRanges(self._s[4141]!, self._r[4141]!, [_0]) } public func PUSH_CHANNEL_MESSAGE_VIDEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4129]!, self._r[4129]!, [_1]) + return formatWithArgumentRanges(self._s[4142]!, self._r[4142]!, [_1]) } - public var Permissions_SiriTitle_v0: String { return self._s[4130]! } + public var Permissions_SiriTitle_v0: String { return self._s[4143]! } public func VoiceOver_Chat_VoiceMessageFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4131]!, self._r[4131]!, [_0]) + return formatWithArgumentRanges(self._s[4144]!, self._r[4144]!, [_0]) } public func Login_ResetAccountProtected_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4132]!, self._r[4132]!, [_0]) + return formatWithArgumentRanges(self._s[4145]!, self._r[4145]!, [_0]) } - public var Channel_MessagePhotoRemoved: String { return self._s[4133]! } - public var Wallet_Info_ReceiveGrams: String { return self._s[4134]! } - public var ClearCache_FreeSpace: String { return self._s[4135]! } - public var Common_edit: String { return self._s[4136]! } - public var PrivacySettings_AuthSessions: String { return self._s[4137]! } - public var Month_ShortJune: String { return self._s[4138]! } - public var PrivacyLastSeenSettings_AlwaysShareWith_Placeholder: String { return self._s[4139]! } - public var Call_ReportSend: String { return self._s[4140]! } - public var Watch_LastSeen_JustNow: String { return self._s[4141]! } - public var Notifications_MessageNotifications: String { return self._s[4142]! } - public var WallpaperSearch_ColorGreen: String { return self._s[4143]! } - public var BroadcastListInfo_AddRecipient: String { return self._s[4145]! } - public var Group_Status: String { return self._s[4146]! } + public var Channel_MessagePhotoRemoved: String { return self._s[4146]! } + public var Wallet_Info_ReceiveGrams: String { return self._s[4147]! } + public var ClearCache_FreeSpace: String { return self._s[4148]! } + public var Common_edit: String { return self._s[4149]! } + public var PrivacySettings_AuthSessions: String { return self._s[4150]! } + public var Month_ShortJune: String { return self._s[4151]! } + public var PrivacyLastSeenSettings_AlwaysShareWith_Placeholder: String { return self._s[4152]! } + public var Call_ReportSend: String { return self._s[4153]! } + public var Watch_LastSeen_JustNow: String { return self._s[4154]! } + public var Notifications_MessageNotifications: String { return self._s[4155]! } + public var WallpaperSearch_ColorGreen: String { return self._s[4156]! } + public var BroadcastListInfo_AddRecipient: String { return self._s[4158]! } + public var Group_Status: String { return self._s[4159]! } public func AutoNightTheme_LocationHelp(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4147]!, self._r[4147]!, [_0, _1]) + return formatWithArgumentRanges(self._s[4160]!, self._r[4160]!, [_0, _1]) } - public var TextFormat_AddLinkTitle: String { return self._s[4148]! } - public var ShareMenu_ShareTo: String { return self._s[4149]! } - public var Conversation_Moderate_Ban: String { return self._s[4150]! } + public var TextFormat_AddLinkTitle: String { return self._s[4161]! } + public var ShareMenu_ShareTo: String { return self._s[4162]! } + public var Conversation_Moderate_Ban: String { return self._s[4163]! } public func Conversation_DeleteMessagesFor(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4151]!, self._r[4151]!, [_0]) + return formatWithArgumentRanges(self._s[4164]!, self._r[4164]!, [_0]) } - public var SharedMedia_ViewInChat: String { return self._s[4152]! } - public var Map_LiveLocationFor8Hours: String { return self._s[4153]! } + public var SharedMedia_ViewInChat: String { return self._s[4165]! } + public var Map_LiveLocationFor8Hours: String { return self._s[4166]! } public func PUSH_PINNED_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4154]!, self._r[4154]!, [_1]) + return formatWithArgumentRanges(self._s[4167]!, self._r[4167]!, [_1]) } public func PUSH_PINNED_POLL(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4155]!, self._r[4155]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4168]!, self._r[4168]!, [_1, _2]) } public func Map_AccurateTo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4157]!, self._r[4157]!, [_0]) + return formatWithArgumentRanges(self._s[4170]!, self._r[4170]!, [_0]) } - public var Map_OpenInHereMaps: String { return self._s[4158]! } - public var Appearance_ReduceMotion: String { return self._s[4159]! } + public var Map_OpenInHereMaps: String { return self._s[4171]! } + public var Appearance_ReduceMotion: String { return self._s[4172]! } public func PUSH_MESSAGE_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4160]!, self._r[4160]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4173]!, self._r[4173]!, [_1, _2]) } - public var Channel_Setup_TypePublicHelp: String { return self._s[4161]! } - public var Passport_Identity_EditInternalPassport: String { return self._s[4162]! } - public var PhotoEditor_Skip: String { return self._s[4163]! } - public func CreatePoll_AddMoreOptions(_ value: Int32) -> String { + public var Channel_Setup_TypePublicHelp: String { return self._s[4174]! } + public var Passport_Identity_EditInternalPassport: String { return self._s[4175]! } + public var PhotoEditor_Skip: String { return self._s[4176]! } + public func Notification_GameScoreSimple(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue) } - public func GroupInfo_ShowMoreMembers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_Minutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[2 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortWeeks(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[3 * 6 + Int(form.rawValue)]!, stringValue) - } - public func LastSeen_MinutesAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[4 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGE_VIDEOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[5 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[6 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedStickers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[7 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedPhotos(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[8 * 6 + Int(form.rawValue)]!, stringValue) - } - public func QuickSend_Photos(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[9 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Minutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[10 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_ExceptionMuteExpires_Days(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[11 * 6 + Int(form.rawValue)]!, stringValue) - } - public func LiveLocationUpdated_MinutesAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[12 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Map_ETAMinutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[13 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteFor_Days(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[14 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ChatList_DeleteConfirmation(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[15 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Forward_ConfirmMultipleFiles(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[16 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortHours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[17 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_Generic(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[18 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedMessages(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[19 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_DeleteItemsConfirmation(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[20 * 6 + Int(form.rawValue)]!, stringValue) - } public func PUSH_CHAT_MESSAGE_PHOTOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[21 * 6 + Int(form.rawValue)]!, _2, _1, _3) + return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, _2, _1, _3) } public func Wallpaper_DeleteConfirmation(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[22 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_RemoveStickerCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[23 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Contacts_InviteContacts(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[24 * 6 + Int(form.rawValue)]!, stringValue) - } - public func GroupInfo_ParticipantCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[25 * 6 + Int(form.rawValue)]!, stringValue) - } - public func DialogList_LiveLocationChatsCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[26 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Watch_LastSeen_MinutesAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[27 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PollResults_ShowMore(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[28 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreSelfSimple(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[29 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PasscodeSettings_FailedAttempts(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[30 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[31 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func MessageTimer_Months(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[32 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[33 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func InviteText_ContactsCountText(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[34 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_ShortMinutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[35 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Media_ShareVideo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[36 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Conversation_SelectedMessages(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[37 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Years(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[38 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Passport_Scans(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[39 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedAuthorsOthers(_ selector: Int32, _ _0: String, _ _1: String) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[40 * 6 + Int(form.rawValue)]!, _0, _1) - } - public func PUSH_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[41 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func AttachmentMenu_SendPhoto(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[42 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessagePoll_QuizCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[43 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[44 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func PUSH_CHANNEL_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[45 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func SharedMedia_Video(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[46 * 6 + Int(form.rawValue)]!, stringValue) - } - public func OldChannels_InactiveYear(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[47 * 6 + Int(form.rawValue)]!, stringValue) - } - public func OldChannels_InactiveWeek(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[48 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_PollVotes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[49 * 6 + Int(form.rawValue)]!, stringValue) - } - public func UserCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[50 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_ShortSeconds(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[51 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Weeks(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[52 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteExpires_Hours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[53 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Theme_UsersCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[54 * 6 + Int(form.rawValue)]!, stringValue) - } - public func AttachmentMenu_SendItem(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[55 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_Exceptions(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[56 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortDays(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[57 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedFiles(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[58 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Watch_LastSeen_HoursAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[59 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Contacts_ImportersCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[60 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedVideoMessages(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[61 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Wallet_Updated_HoursAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[62 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Chat_DeleteMessagesConfirmation(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[63 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ChatList_SelectedChats(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[64 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Media_SharePhoto(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[65 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedGifs(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[66 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedVideos(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[67 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_PollOptionCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[68 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PrivacyLastSeenSettings_AddUsers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[69 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_AddStickerCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[70 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ChatList_DeletedChats(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[71 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreSelfExtended(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[72 * 6 + Int(form.rawValue)]!, stringValue) - } - public func AttachmentMenu_SendGif(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[73 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_ExceptionMuteExpires_Minutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[74 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notification_GameScoreSelfSimple(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[75 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[2 * 6 + Int(form.rawValue)]!, stringValue) } public func Media_ShareItem(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[76 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[3 * 6 + Int(form.rawValue)]!, stringValue) } - public func Notifications_ExceptionMuteExpires_Hours(_ value: Int32) -> String { + public func Media_ShareVideo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[77 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[4 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessageTimer_Seconds(_ value: Int32) -> String { + public func GroupInfo_ParticipantCount(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[78 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[5 * 6 + Int(form.rawValue)]!, stringValue) } - public func MuteExpires_Days(_ value: Int32) -> String { + public func LiveLocationUpdated_MinutesAgo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[79 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[6 * 6 + Int(form.rawValue)]!, stringValue) } - public func OldChannels_InactiveMonth(_ value: Int32) -> String { + public func MuteExpires_Hours(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[80 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[7 * 6 + Int(form.rawValue)]!, stringValue) } - public func StickerPack_AddMaskCount(_ value: Int32) -> String { + public func LastSeen_MinutesAgo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[81 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[8 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessagePoll_VotedCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[82 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_ContactPhoneNumberCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[83 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_File(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[84 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Watch_UserInfo_Mute(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[85 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + public func PUSH_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[86 * 6 + Int(form.rawValue)]!, _1, _2) + return String(format: self._ps[9 * 6 + Int(form.rawValue)]!, _1, _2) } - public func Notification_GameScoreExtended(_ value: Int32) -> String { + public func Notifications_Exceptions(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[87 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[10 * 6 + Int(form.rawValue)]!, stringValue) } - public func StickerPack_StickerCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[88 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_RemoveMaskCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[89 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteExpires_Minutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[90 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_ContactEmailCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[91 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Conversation_StatusOnline(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[92 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_Seconds(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[93 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + public func PUSH_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[94 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func Notification_GameScoreSelfExtended(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[95 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Conversation_StatusMembers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[96 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedLocations(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[97 * 6 + Int(form.rawValue)]!, stringValue) - } - public func OldChannels_GroupFormat(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[98 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGE_ROUNDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[99 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func ForwardedAudios(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[100 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreExtended(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[101 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Days(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[102 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Hours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[103 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[11 * 6 + Int(form.rawValue)]!, _1, _2) } public func LastSeen_HoursAgo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[104 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[12 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notifications_ExceptionMuteExpires_Days(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[13 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Map_ETAHours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[14 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedPhotos(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[15 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[16 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func PUSH_CHANNEL_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[17 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func SharedMedia_File(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[18 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHAT_MESSAGE_ROUNDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[19 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func Contacts_InviteContacts(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[20 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Seconds(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[21 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortWeeks(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[22 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreSelfExtended(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[23 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Contacts_ImportersCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[24 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Chat_DeleteMessagesConfirmation(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[25 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Watch_LastSeen_MinutesAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[26 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_AddMaskCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[27 * 6 + Int(form.rawValue)]!, stringValue) + } + public func InviteText_ContactsCountText(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[28 * 6 + Int(form.rawValue)]!, stringValue) } public func MessageTimer_ShortSeconds(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[105 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[29 * 6 + Int(form.rawValue)]!, stringValue) } - public func LiveLocation_MenuChatsCount(_ value: Int32) -> String { + public func Conversation_LiveLocationMembersCount(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[106 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[30 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[107 * 6 + Int(form.rawValue)]!, _1, _2) + public func AttachmentMenu_SendVideo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[31 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Forward_ConfirmMultipleFiles(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[32 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Passport_Scans(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[33 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_Minutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[34 * 6 + Int(form.rawValue)]!, stringValue) } public func SharedMedia_Photo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[108 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[35 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_ShortMinutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[36 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[37 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func PrivacyLastSeenSettings_AddUsers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[38 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortMinutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[39 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Weeks(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[40 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_ContactEmailCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[41 * 6 + Int(form.rawValue)]!, stringValue) + } + public func UserCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[42 * 6 + Int(form.rawValue)]!, stringValue) + } + public func AttachmentMenu_SendItem(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[43 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ChatList_DeletedChats(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[44 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Invitation_Members(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[45 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_PollOptionCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[46 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notifications_ExceptionMuteExpires_Hours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[47 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[48 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedStickers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[49 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_SelectedMessages(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[50 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_RemoveMaskCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[51 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_StickerCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[52 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[53 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func MessageTimer_Hours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[54 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_RemoveStickerCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[55 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[56 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func ForwardedContacts(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[57 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Watch_UserInfo_Mute(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[58 * 6 + Int(form.rawValue)]!, stringValue) + } + public func AttachmentMenu_SendGif(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[59 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ChatList_SelectedChats(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[60 * 6 + Int(form.rawValue)]!, stringValue) + } + public func GroupInfo_ShowMoreMembers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[61 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_StatusOnline(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[62 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_Generic(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[63 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreSimple(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[64 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_Video(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[65 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[66 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func ForwardedFiles(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[67 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_DeleteItemsConfirmation(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[68 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_Seconds(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[69 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_ShortSeconds(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[70 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_ContactPhoneNumberCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[71 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteExpires_Days(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[72 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedAuthorsOthers(_ selector: Int32, _ _0: String, _ _1: String) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[73 * 6 + Int(form.rawValue)]!, _0, _1) + } + public func MessageTimer_ShortDays(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[74 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Watch_LastSeen_HoursAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[75 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_StatusMembers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[76 * 6 + Int(form.rawValue)]!, stringValue) } public func OldChannels_Leave(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[77 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Days(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[78 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreSelfExtended(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[79 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_AddStickerCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[80 * 6 + Int(form.rawValue)]!, stringValue) + } + public func OldChannels_InactiveYear(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[81 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedLocations(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[82 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Years(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[83 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PollResults_ShowMore(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[84 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Media_SharePhoto(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[85 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_StatusSubscribers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[86 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessagePoll_VotedCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[87 * 6 + Int(form.rawValue)]!, stringValue) + } + public func OldChannels_GroupFormat(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[88 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notifications_ExceptionMuteExpires_Minutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[89 * 6 + Int(form.rawValue)]!, stringValue) + } + public func OldChannels_InactiveWeek(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[90 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedMessages(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[91 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Theme_UsersCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[92 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreExtended(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[93 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[94 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func QuickSend_Photos(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[95 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Map_ETAMinutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[96 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Wallet_Updated_HoursAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[97 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreExtended(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[98 * 6 + Int(form.rawValue)]!, stringValue) + } + public func DialogList_LiveLocationChatsCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[99 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedVideos(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[100 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_PollVotes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[101 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHAT_MESSAGES(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[102 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func ChatList_DeleteConfirmation(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[103 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedPolls(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[104 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreSelfSimple(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[105 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedAudios(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[106 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreSelfSimple(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[107 * 6 + Int(form.rawValue)]!, stringValue) + } + public func LiveLocation_MenuChatsCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[108 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessagePoll_QuizCount(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[109 * 6 + Int(form.rawValue)]!, stringValue) } - public func AttachmentMenu_SendVideo(_ value: Int32) -> String { + public func SharedMedia_Link(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[110 * 6 + Int(form.rawValue)]!, stringValue) @@ -5235,30 +5245,30 @@ public final class PresentationStrings: Equatable { let form = getPluralizationForm(self.lc, selector) return String(format: self._ps[111 * 6 + Int(form.rawValue)]!, _2, _1, _3) } - public func MessageTimer_ShortMinutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[112 * 6 + Int(form.rawValue)]!, stringValue) + public func PUSH_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[112 * 6 + Int(form.rawValue)]!, _1, _2) } - public func Conversation_StatusSubscribers(_ value: Int32) -> String { + public func MuteFor_Days(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[113 * 6 + Int(form.rawValue)]!, stringValue) } - public func ForwardedPolls(_ value: Int32) -> String { + public func ForwardedVideoMessages(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[114 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_CHAT_MESSAGES(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[115 * 6 + Int(form.rawValue)]!, _2, _1, _3) + public func OldChannels_InactiveMonth(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[115 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + public func PUSH_CHAT_MESSAGE_VIDEOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[116 * 6 + Int(form.rawValue)]!, _1, _2) + return String(format: self._ps[116 * 6 + Int(form.rawValue)]!, _2, _1, _3) } - public func Map_ETAHours(_ value: Int32) -> String { + public func MessageTimer_Months(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[117 * 6 + Int(form.rawValue)]!, stringValue) @@ -5268,40 +5278,46 @@ public final class PresentationStrings: Equatable { let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[118 * 6 + Int(form.rawValue)]!, stringValue) } - public func Notification_GameScoreSimple(_ value: Int32) -> String { + public func CreatePoll_AddMoreOptions(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[119 * 6 + Int(form.rawValue)]!, stringValue) } - public func ForwardedContacts(_ value: Int32) -> String { + public func ForwardedGifs(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[120 * 6 + Int(form.rawValue)]!, stringValue) } - public func ServiceMessage_GameScoreSimple(_ value: Int32) -> String { + public func MessageTimer_Minutes(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[121 * 6 + Int(form.rawValue)]!, stringValue) } - public func Conversation_LiveLocationMembersCount(_ value: Int32) -> String { + public func PasscodeSettings_FailedAttempts(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[122 * 6 + Int(form.rawValue)]!, stringValue) } - public func SharedMedia_Link(_ value: Int32) -> String { + public func MessageTimer_ShortHours(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[123 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[124 * 6 + Int(form.rawValue)]!, _1, _2) + public func PeopleNearby_ShowMorePeople(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[124 * 6 + Int(form.rawValue)]!, stringValue) } - public func Invitation_Members(_ value: Int32) -> String { + public func AttachmentMenu_SendPhoto(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[125 * 6 + Int(form.rawValue)]!, stringValue) } + public func MuteExpires_Minutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[126 * 6 + Int(form.rawValue)]!, stringValue) + } public init(primaryComponent: PresentationStringsComponent, secondaryComponent: PresentationStringsComponent?, groupingSeparator: String) { self.primaryComponent = primaryComponent diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift index a1b0744fad..ff03ac0902 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift @@ -48,6 +48,8 @@ public enum PresentationResourceKey: Int32 { case itemListVerifiedPeerIcon case itemListCloudFetchIcon case itemListCloseIconImage + case itemListMakeVisibleIcon + case itemListMakeInvisibleIcon case itemListCornersTop case itemListCornersBottom case itemListCornersBoth diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesItemList.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesItemList.swift index 53b0efb48f..8a3e6fc808 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesItemList.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesItemList.swift @@ -152,6 +152,18 @@ public struct PresentationResourcesItemList { }) } + public static func makeVisibleIcon(_ theme: PresentationTheme) -> UIImage? { + return theme.image(PresentationResourceKey.itemListMakeVisibleIcon.rawValue, { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Contact List/MakeVisibleIcon"), color: theme.list.itemAccentColor) + }) + } + + public static func makeInvisibleIcon(_ theme: PresentationTheme) -> UIImage? { + return theme.image(PresentationResourceKey.itemListMakeInvisibleIcon.rawValue, { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Contact List/MakeInvisibleIcon"), color: theme.list.itemDestructiveColor) + }) + } + public static func cornersImage(_ theme: PresentationTheme, top: Bool, bottom: Bool) -> UIImage? { if !top && !bottom { return nil diff --git a/submodules/TelegramStringFormatting/Sources/PresenceStrings.swift b/submodules/TelegramStringFormatting/Sources/PresenceStrings.swift index b7bdd08a48..31893c0e27 100644 --- a/submodules/TelegramStringFormatting/Sources/PresenceStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/PresenceStrings.swift @@ -109,12 +109,13 @@ public func stringForMonth(strings: PresentationStrings, month: Int32, ofYear ye public enum RelativeTimestampFormatDay { case today case yesterday + case tomorrow } public func stringForUserPresence(strings: PresentationStrings, day: RelativeTimestampFormatDay, dateTimeFormat: PresentationDateTimeFormat, hours: Int32, minutes: Int32) -> String { let dayString: String switch day { - case .today: + case .today, .tomorrow: dayString = strings.LastSeen_TodayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0 case .yesterday: dayString = strings.LastSeen_YesterdayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0 @@ -125,10 +126,13 @@ public func stringForUserPresence(strings: PresentationStrings, day: RelativeTim private func humanReadableStringForTimestamp(strings: PresentationStrings, day: RelativeTimestampFormatDay, dateTimeFormat: PresentationDateTimeFormat, hours: Int32, minutes: Int32) -> String { let dayString: String switch day { - case .today: - dayString = strings.Time_TodayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0 - case .yesterday: - dayString = strings.Time_YesterdayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0 + case .today: + dayString = strings.Time_TodayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0 + case .yesterday: + dayString = strings.Time_YesterdayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0 + case .tomorrow: + dayString = strings.Time_TomorrowAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0 + } return dayString } @@ -148,12 +152,14 @@ public func humanReadableStringForTimestamp(strings: PresentationStrings, dateTi } let dayDifference = timeinfo.tm_yday - timeinfoNow.tm_yday - if dayDifference == 0 || dayDifference == -1 { + if dayDifference == 0 || dayDifference == -1 || dayDifference == 1 { let day: RelativeTimestampFormatDay if dayDifference == 0 { day = .today - } else { + } else if dayDifference == -1 { day = .yesterday + } else { + day = .tomorrow } return humanReadableStringForTimestamp(strings: strings, day: day, dateTimeFormat: dateTimeFormat, hours: timeinfo.tm_hour, minutes: timeinfo.tm_min) } else { diff --git a/submodules/TelegramUI/Images.xcassets/Chart/Contents.json b/submodules/TelegramUI/Images.xcassets/Chart/Contents.json new file mode 100644 index 0000000000..38f0c81fc2 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chart/Contents.json @@ -0,0 +1,9 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "provides-namespace" : true + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chart/arrow_left.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chart/arrow_left.imageset/Contents.json new file mode 100644 index 0000000000..78b05b5e2a --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chart/arrow_left.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "arrow_left.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chart/arrow_left.imageset/arrow_left.pdf b/submodules/TelegramUI/Images.xcassets/Chart/arrow_left.imageset/arrow_left.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7b20434672a16424c35740a555a96dd0fa6ae0d7 GIT binary patch literal 4081 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∇BcB0e~-anGPJ$_dkg}Rrv27GVsL4iWdDdEr2j{~ z|CNWNwN-zA7Y2j;s~!vvr}awz$b%#Q9Yg&79|U)_gEQX!dmnA=;7i*-S_5R{=0@|! zz6WR1 XZXN`hHNFc1laYY~!C(!2P2hh33O4!5 literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Images.xcassets/Chart/arrow_right.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chart/arrow_right.imageset/Contents.json new file mode 100644 index 0000000000..147027fa6d --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chart/arrow_right.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "arrow_right.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chart/arrow_right.imageset/arrow_right.pdf b/submodules/TelegramUI/Images.xcassets/Chart/arrow_right.imageset/arrow_right.pdf new file mode 100644 index 0000000000000000000000000000000000000000..baf05c2435b67cb6ed2e3c05f096faf0595e373c GIT binary patch literal 874 zcmY!laBDSrg$Nf-E~sEh zW`3SeW>QgNQKf=LaCT;*KF}0}Tr*2eJ3Fq_JfQL{E+d3VZkahHKy&onauQ2YT~d?t zQ&PF~eNyw%OEMG;Elup~6pBlVQWJBzD(2({81^w4^1S)Xb=^av`mx1H?iKy|Ygk0Q z8Nb(eZWQNySudwY_u$gnyA+GS+PQMma4t+JrS##fs zoM`R&EaQDNU~;M9RaH-$RXWcY(#5|^DaiSKeHNG#*wXxCB45(212H#M`TgJ6spU2N zF|=Cb7-#RC`!sG{`={W04U8_2LB5B21{w~=h;Rt0EJ#(*cTOxx%*js&hGk-UYO#U| zP(BC|Y#=T)0wBu4s<`x>^Gowe6b!lay)#pa6{1Z+x?&O9Kzs~sT>3$&#rdU0$v|r$ z5t)QS=Xea~E=Gn}BbGnDp><PQD8Ie)&bY zi8%=GR1~GAaTzF>a~Z&af|;qQv8h6u0$dDeFIZL~45S_H})!I@R5K-cL9<>!|ufMOWvUC+F> +endobj +2 0 obj +<> stream +xśŤ’MN1 …÷9…×HěŘůń ş.,8ŔĘbŠD{ 'ÓvBZ$&Ň(zvü9Î#@[ŮOĚG÷íŞ@$ŁÉmŕôîŢžŕËyć ž‹€—áer:¸çÂáěł×ú…kĘpti­­Ú©‹ >)ĺ Ô©SÝ JŚ˘) °zĆKşŹ´˘Hf7Ć.<ŁŚ± U lü5…(eĚz;níążŕ[µfsc×éwřNÜú5Â&oW\~É·™tÄm„ß`vźÖ{Ő *CK°ţŠ=N' Ő|ˇTŞžţ’[ŠRšü öbĐ35ĎLˇd‚Ővu™—ÖMłU ±˛ĎD-=°1‰X—¬ŮײÉTĽa«ß'Ű€˛°™zqŻnßcą¨M=Ä˙ŔŤ"Xîŕ+& đ-y€ďÝKSŞ˛ +endstream +endobj +3 0 obj +<> +endobj +4 0 obj +<> +endobj +5 0 obj +<>>> +/MediaBox [0 0 114 42] +/Contents 2 0 R +/Parent 4 0 R>> +endobj +6 0 obj +<> +endobj +7 0 obj +<> +endobj +xref +0 8 +0000000000 65535 f +0000000015 00000 n +0000000089 00000 n +0000000482 00000 n +0000000529 00000 n +0000000584 00000 n +0000000765 00000 n +0000000802 00000 n +trailer +<> +startxref +880 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chart/selection_frame_light.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chart/selection_frame_light.imageset/Contents.json new file mode 100644 index 0000000000..8cc38ca79c --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chart/selection_frame_light.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "selection_frame_light.pdf", + "resizing" : { + "mode" : "3-part-horizontal", + "center" : { + "mode" : "stretch", + "width" : 1 + }, + "cap-insets" : { + "right" : 11, + "left" : 11 + } + } + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chart/selection_frame_light.imageset/selection_frame_light.pdf b/submodules/TelegramUI/Images.xcassets/Chart/selection_frame_light.imageset/selection_frame_light.pdf new file mode 100644 index 0000000000..c426c5d695 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chart/selection_frame_light.imageset/selection_frame_light.pdf @@ -0,0 +1,62 @@ +%PDF-1.4 +%Óëéá +1 0 obj +<> +endobj +2 0 obj +<> stream +xśŤ’ĎNĂ0 Ćď~ +ź‘ěÄůă'Řypŕ*‡‰ńţNş­Y6$5ŠľĎőĎuĚH¶&¶M<ÎGř†*0‹#˘@Ńävňxz‡·'ü—c@WĽ˝¶˝ěđV8ŕyGxř¦ě´>ţ’„3!­™U;uď’röÂť:Ő‘Ä(š’`P¨Ä’îť–”8â Łwć±eôÎT-¸ń×ć”)ëős+w0ćţofnĹć2z—Ţrčđť¸Ők„MŢ~qą‘Ż=é[ ŢÁ źV{Ő ©]]ő­ľb—ÓÉÂ5^8U ůŞ'ćżä–„Ł”&?Č˝ôĂĆ‹ŰÄ1NľdôBučë˛QZm„¸ŽPĐŕ2{Q ÷ÁůD¬Ę ŮŐ†“ą8-,l Ęl¤x…}Ź E­ë>ţnˇr_1i€oÁ|żBŞV +endstream +endobj +3 0 obj +<> +endobj +4 0 obj +<> +endobj +5 0 obj +<>>> +/MediaBox [0 0 114 42] +/Contents 2 0 R +/Parent 4 0 R>> +endobj +6 0 obj +<> +endobj +7 0 obj +<> +endobj +xref +0 8 +0000000000 65535 f +0000000015 00000 n +0000000089 00000 n +0000000482 00000 n +0000000529 00000 n +0000000584 00000 n +0000000765 00000 n +0000000802 00000 n +trailer +<> +startxref +880 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/Contents.json new file mode 100644 index 0000000000..38f0c81fc2 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/Contents.json @@ -0,0 +1,9 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "provides-namespace" : true + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconCalls.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconCalls.imageset/Contents.json new file mode 100644 index 0000000000..9afc9c4e5d --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconCalls.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_calls.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconCalls.imageset/ic_calls.pdf b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconCalls.imageset/ic_calls.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f42e5fe81bb09773660cdedf91df9372a3f2c78e GIT binary patch literal 4945 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 E0`ayBbN~PV literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconContacts.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconContacts.imageset/Contents.json new file mode 100644 index 0000000000..006f82fb71 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconContacts.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_contacts.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconContacts.imageset/ic_contacts.pdf b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconContacts.imageset/ic_contacts.pdf new file mode 100644 index 0000000000000000000000000000000000000000..41f48e4e2d2d3aec55b300ee4f9c4c328540980a GIT binary patch literal 5894 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 ZpFfa~FD;fo7a9RopdH(YX`!`2{|6^f> literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Images.xcassets/Contact List/MakeInvisibleIcon.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Contact List/MakeInvisibleIcon.imageset/Contents.json new file mode 100644 index 0000000000..7abcd976aa --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Contact List/MakeInvisibleIcon.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_stopshowme.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Contact List/MakeInvisibleIcon.imageset/ic_stopshowme.pdf b/submodules/TelegramUI/Images.xcassets/Contact List/MakeInvisibleIcon.imageset/ic_stopshowme.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9cc4c3d65a220b5662bd6ba52981ae5758b1a737 GIT binary patch literal 4829 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 literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Images.xcassets/Contact List/MakeVisibleIcon.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Contact List/MakeVisibleIcon.imageset/Contents.json new file mode 100644 index 0000000000..97cc9be019 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Contact List/MakeVisibleIcon.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_showme.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Contact List/MakeVisibleIcon.imageset/ic_showme.pdf b/submodules/TelegramUI/Images.xcassets/Contact List/MakeVisibleIcon.imageset/ic_showme.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0c5a6e2133974427e947de70a8c8215173804043 GIT binary patch literal 4748 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 Fe*hY-?{feE literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOn.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOn.imageset/Contents.json new file mode 100644 index 0000000000..1d93d33a26 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOn.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "soundon (2).pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOn.imageset/soundon (2).pdf b/submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOn.imageset/soundon (2).pdf new file mode 100644 index 0000000000000000000000000000000000000000..20236a226bca22ffe396422910dea8eff031865f GIT binary patch literal 4774 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 rU?^*dm@QPo8isn|g9rD)? deliverOnMainQueue).start(next: { [weak self] info in + if let strongSelf = self, let info = info { + let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData) + var items: [ActionSheetItem] = [] + items.append(ActionSheetTextItem(title: info.title)) + if let url = info.url, let actionTitle = info.actionTitle { + items.append(ActionSheetButtonItem(title: actionTitle, color: .accent, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + if let strongSelf = self { + strongSelf.controllerInteraction?.openUrl(url, false, false, message) + } + })) + } + actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [ + ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + }) + ])]) + strongSelf.present(actionSheet, in: .window(.root)) + } + }) + strongSelf.chatDisplayNode.dismissInput() } } }, openCheckoutOrReceipt: { [weak self] messageId in diff --git a/submodules/TelegramUI/TelegramUI/ChatControllerInteraction.swift b/submodules/TelegramUI/TelegramUI/ChatControllerInteraction.swift index fdae414c0a..e9b15f43af 100644 --- a/submodules/TelegramUI/TelegramUI/ChatControllerInteraction.swift +++ b/submodules/TelegramUI/TelegramUI/ChatControllerInteraction.swift @@ -42,6 +42,7 @@ public enum ChatControllerInteractionLongTapAction { case command(String) case hashtag(String) case timecode(Double, String) + case bankCard(String) } struct ChatInterfacePollActionState: Equatable { @@ -119,6 +120,7 @@ public final class ChatControllerInteraction { var stickerSettings: ChatInterfaceStickerSettings var searchTextHighightState: (String, [MessageIndex])? var seenOneTimeAnimatedMedia = Set() + var seenDicePointsValue = [MessageId: Int]() init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, TapLongTapOrDoubleTapGestureRecognizer?) -> Void, openMessageContextActions: @escaping (Message, ASDisplayNode, CGRect, ContextGesture?) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, tapMessage: ((Message) -> Void)?, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendCurrentMessage: @escaping (Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool, ASDisplayNode, CGRect) -> Bool, sendGif: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?, Message?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openTheme: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, chatControllerNode: @escaping () -> ASDisplayNode?, reactionContainerNode: @escaping () -> ReactionSelectionParentNode?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOptions: @escaping (MessageId, [Data]) -> Void, requestOpenMessagePollResults: @escaping (MessageId, MediaId) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, scheduleCurrentMessage: @escaping () -> Void, sendScheduledMessagesNow: @escaping ([MessageId]) -> Void, editScheduledMessagesTime: @escaping ([MessageId]) -> Void, performTextSelectionAction: @escaping (UInt32, String, TextSelectionAction) -> Void, updateMessageReaction: @escaping (MessageId, String?) -> Void, openMessageReactions: @escaping (MessageId) -> Void, displaySwipeToReplyHint: @escaping () -> Void, dismissReplyMarkupMessage: @escaping (Message) -> Void, openMessagePollResults: @escaping (MessageId, Data) -> Void, openPollCreation: @escaping (Bool?) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings) { self.openMessage = openMessage diff --git a/submodules/TelegramUI/TelegramUI/ChatHistoryListNode.swift b/submodules/TelegramUI/TelegramUI/ChatHistoryListNode.swift index ab032691e6..6fb53ab372 100644 --- a/submodules/TelegramUI/TelegramUI/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatHistoryListNode.swift @@ -13,6 +13,7 @@ import AccountContext import TemporaryCachedPeerDataManager import ChatListSearchItemNode import Emoji +import AppBundle private class ChatHistoryListSelectionRecognizer: UIPanGestureRecognizer { private let selectionGestureActivationThreshold: CGFloat = 5.0 @@ -308,7 +309,7 @@ private final class ChatHistoryTransactionOpaqueState { } } -private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHistoryView, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, animatedEmojiStickers: [String: StickerPackItem], isScheduledMessages: Bool) -> ChatMessageItemAssociatedData { +private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHistoryView, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, animatedEmojiStickers: [String: [StickerPackItem]], isScheduledMessages: Bool) -> ChatMessageItemAssociatedData { var automaticMediaDownloadPeerType: MediaAutoDownloadPeerType = .channel var contactsPeerIds: Set = Set() if case let .peer(peerId) = chatLocation { @@ -605,19 +606,31 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { |> distinctUntilChanged let animatedEmojiStickers = loadedStickerPack(postbox: context.account.postbox, network: context.account.network, reference: .animatedEmoji, forceActualized: false) - |> map { result -> [String: StickerPackItem] in + |> map { result -> [String: [StickerPackItem]] in switch result { case let .result(_, items, _): - var animatedEmojiStickers: [String: StickerPackItem] = [:] + var animatedEmojiStickers: [String: [StickerPackItem]] = [:] for case let item as StickerPackItem in items { if let emoji = item.getStringRepresentationsOfIndexKeys().first { - animatedEmojiStickers[emoji.basicEmoji.0] = item + animatedEmojiStickers[emoji.basicEmoji.0] = [item] let strippedEmoji = emoji.basicEmoji.0.strippedEmoji if animatedEmojiStickers[strippedEmoji] == nil { - animatedEmojiStickers[strippedEmoji] = item + animatedEmojiStickers[strippedEmoji] = [item] } } } + + if let path = getAppBundle().path(forResource: "Dice_1", ofType: "tgs") { + var dices: [StickerPackItem] = [] + for i in 1...6 { + let path = path.replacingOccurrences(of: "_1", with: "_\(i)") + let id = arc4random64() + let resource = LocalFileReferenceMediaResource(localFilePath: path, randomId: id) + dices.append(StickerPackItem(index: ItemCollectionItemIndex(index: Int32(i), id: Int64(i)), file: TelegramMediaFile(fileId: MediaId(namespace: 10, id: Int64(i)), partialReference: nil, resource: resource, previewRepresentations: [], immediateThumbnailData: nil, mimeType: "application/x-tgsticker", size: nil, attributes: []), indexKeys: [])) + } + animatedEmojiStickers["🎲".strippedEmoji] = dices + } + return animatedEmojiStickers default: return [:] diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageAnimatedStickerItemNode.swift index 0cbef84d24..0098397abf 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageAnimatedStickerItemNode.swift @@ -255,9 +255,24 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { let (emoji, fitz) = item.message.text.basicEmoji if self.telegramFile == nil { - var emojiFile = item.associatedData.animatedEmojiStickers[emoji]?.file - if emojiFile == nil { - emojiFile = item.associatedData.animatedEmojiStickers[emoji.strippedEmoji]?.file + var emojiFile: TelegramMediaFile? + + if emoji == "🎲" { + var pointsValue: Int + if let value = item.controllerInteraction.seenDicePointsValue[item.message.id] { + pointsValue = value + } else { + pointsValue = Int(arc4random_uniform(6)) + item.controllerInteraction.seenDicePointsValue[item.message.id] = pointsValue + } + if let diceEmojis = item.associatedData.animatedEmojiStickers[emoji] { + emojiFile = diceEmojis[pointsValue].file + } + } else { + emojiFile = item.associatedData.animatedEmojiStickers[emoji]?.first?.file + if emojiFile == nil { + emojiFile = item.associatedData.animatedEmojiStickers[emoji.strippedEmoji]?.first?.file + } } if self.emojiFile?.id != emojiFile?.id { @@ -293,8 +308,12 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } self.animationNode.visibility = isPlaying && !alreadySeen + if self.didSetUpAnimationNode && alreadySeen { - self.animationNode.seekToStart() + if let emojiFile = self.emojiFile, emojiFile.resource is LocalFileReferenceMediaResource { + } else { + self.animationNode.seekTo(.start) + } } if self.isPlaying && !self.didSetUpAnimationNode { @@ -313,7 +332,11 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } else if let emojiFile = self.emojiFile { isEmoji = true file = emojiFile - playbackMode = .once + if alreadySeen && emojiFile.resource is LocalFileReferenceMediaResource { + playbackMode = .still(.end) + } else { + playbackMode = .once + } let (_, fitz) = item.message.text.basicEmoji if let fitz = fitz { fitzModifier = EmojiFitzModifier(emoji: fitz) @@ -323,7 +346,13 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if let file = file { let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512) let fittedSize = isEmoji ? dimensions.cgSize.aspectFilled(CGSize(width: 384.0, height: 384.0)) : dimensions.cgSize.aspectFitted(CGSize(width: 384.0, height: 384.0)) - self.animationNode.setup(source: AnimatedStickerResourceSource(account: item.context.account, resource: file.resource, fitzModifier: fitzModifier), width: Int(fittedSize.width), height: Int(fittedSize.height), playbackMode: playbackMode, mode: .cached) + let mode: AnimatedStickerMode + if file.resource is LocalFileReferenceMediaResource { + mode = .direct + } else { + mode = .cached + } + self.animationNode.setup(source: AnimatedStickerResourceSource(account: item.context.account, resource: file.resource, fitzModifier: fitzModifier), width: Int(fittedSize.width), height: Int(fittedSize.height), playbackMode: playbackMode, mode: mode) } } } @@ -870,34 +899,59 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if self.telegramFile != nil { let _ = item.controllerInteraction.openMessage(item.message, .default) } else if let _ = self.emojiFile { - var startTime: Signal - if self.animationNode.playIfNeeded() { - startTime = .single(0.0) + let (emoji, fitz) = item.message.text.basicEmoji + if emoji == "🎲" { + if !self.animationNode.isPlaying { + var pointsValue = Int(arc4random_uniform(6)) + item.controllerInteraction.seenDicePointsValue[item.message.id] = pointsValue + item.controllerInteraction.seenOneTimeAnimatedMedia.remove(item.message.id) + + var emojiFile: TelegramMediaFile? + if let diceEmojis = item.associatedData.animatedEmojiStickers[emoji] { + emojiFile = diceEmojis[pointsValue].file + } + + self.emojiFile = emojiFile + if let emojiFile = emojiFile { + let dimensions = emojiFile.dimensions ?? PixelDimensions(width: 512, height: 512) + self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: item.context.account.postbox, file: emojiFile, small: false, size: dimensions.cgSize.aspectFilled(CGSize(width: 384.0, height: 384.0)), fitzModifier: nil, thumbnail: false)) + self.disposable.set(freeMediaFileInteractiveFetched(account: item.context.account, fileReference: .standalone(media: emojiFile)).start()) + } + self.isPlaying = false + self.didSetUpAnimationNode = false + self.updateVisibility() + self.animationNode.playIfNeeded() + } } else { - startTime = self.animationNode.status + var startTime: Signal + if self.animationNode.playIfNeeded() { + startTime = .single(0.0) + } else { + startTime = self.animationNode.status |> map { $0.timestamp } |> take(1) |> deliverOnMainQueue - } - - if let text = self.item?.message.text, let firstScalar = text.unicodeScalars.first, firstScalar.value == 0x2764 { - let _ = startTime.start(next: { [weak self] time in - guard let strongSelf = self else { - return - } - - let heartbeatHaptic: ChatMessageHeartbeatHaptic - if let current = strongSelf.heartbeatHaptic { - heartbeatHaptic = current - } else { - heartbeatHaptic = ChatMessageHeartbeatHaptic() - heartbeatHaptic.enabled = true - strongSelf.heartbeatHaptic = heartbeatHaptic - } - if !heartbeatHaptic.active { - heartbeatHaptic.start(time: time) - } - }) + } + + if let text = self.item?.message.text, let firstScalar = text.unicodeScalars.first, firstScalar.value == 0x2764 { + let _ = startTime.start(next: { [weak self] time in + guard let strongSelf = self else { + return + } + + let heartbeatHaptic: ChatMessageHeartbeatHaptic + if let current = strongSelf.heartbeatHaptic { + heartbeatHaptic = current + } else { + heartbeatHaptic = ChatMessageHeartbeatHaptic() + heartbeatHaptic.enabled = true + strongSelf.heartbeatHaptic = heartbeatHaptic + } + if !heartbeatHaptic.active { + heartbeatHaptic.start(time: time) + } + }) + } } } return true diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageAttachedContentNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageAttachedContentNode.swift index 0e565d40fb..bfb409db6b 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageAttachedContentNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageAttachedContentNode.swift @@ -1019,7 +1019,8 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { TelegramTextAttributes.PeerMention, TelegramTextAttributes.PeerTextMention, TelegramTextAttributes.BotCommand, - TelegramTextAttributes.Hashtag + TelegramTextAttributes.Hashtag, + TelegramTextAttributes.BankCard ] for name in possibleNames { if let _ = attributes[NSAttributedString.Key(rawValue: name)] { diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageBubbleContentNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageBubbleContentNode.swift index 4c10c8609a..0e2b2d8b2f 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageBubbleContentNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageBubbleContentNode.swift @@ -80,6 +80,7 @@ enum ChatMessageBubbleContentTapAction { case openMessage case timecode(Double, String) case tooltip(String, ASDisplayNode?, CGRect?) + case bankCard(String) case ignore } diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageBubbleItemNode.swift index a507081fd5..93f968a020 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageBubbleItemNode.swift @@ -355,7 +355,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode break case .ignore: return .fail - case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .tooltip: + case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip: return .waitForSingleTap } } @@ -2381,6 +2381,11 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode item.controllerInteraction.seekToTimecode(mediaMessage, timecode, forceOpen) } break loop + case let .bankCard(number): + foundTapAction = true + if let item = self.item { + item.controllerInteraction.longTap(.bankCard(number), item.message) + } case let .tooltip(text, node, rect): foundTapAction = true if let item = self.item { @@ -2447,6 +2452,9 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode item.controllerInteraction.longTap(.timecode(timecode, text), mediaMessage) } break loop + case let .bankCard(number): + foundTapAction = true + item.controllerInteraction.longTap(.bankCard(number), message) case .tooltip: break } diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageItem.swift b/submodules/TelegramUI/TelegramUI/ChatMessageItem.swift index 26af9b2098..fe50b15654 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageItem.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageItem.swift @@ -226,10 +226,10 @@ public final class ChatMessageItemAssociatedData: Equatable { let isRecentActions: Bool let isScheduledMessages: Bool let contactsPeerIds: Set - let animatedEmojiStickers: [String: StickerPackItem] + let animatedEmojiStickers: [String: [StickerPackItem]] let forcedResourceStatus: FileMediaResourceStatus? - init(automaticDownloadPeerType: MediaAutoDownloadPeerType, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, isRecentActions: Bool = false, isScheduledMessages: Bool = false, contactsPeerIds: Set = Set(), animatedEmojiStickers: [String: StickerPackItem] = [:], forcedResourceStatus: FileMediaResourceStatus? = nil) { + init(automaticDownloadPeerType: MediaAutoDownloadPeerType, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, isRecentActions: Bool = false, isScheduledMessages: Bool = false, contactsPeerIds: Set = Set(), animatedEmojiStickers: [String: [StickerPackItem]] = [:], forcedResourceStatus: FileMediaResourceStatus? = nil) { self.automaticDownloadPeerType = automaticDownloadPeerType self.automaticDownloadNetworkType = automaticDownloadNetworkType self.isRecentActions = isRecentActions diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageTextBubbleContentNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageTextBubbleContentNode.swift index 31b1d33df8..5df3808ac2 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageTextBubbleContentNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageTextBubbleContentNode.swift @@ -428,6 +428,8 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { return .hashtag(hashtag.peerName, hashtag.hashtag) } else if let timecode = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Timecode)] as? TelegramTimecode { return .timecode(timecode.time, timecode.text) + } else if let bankCard = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.BankCard)] as? String { + return .bankCard(bankCard) } else { return .none } @@ -451,7 +453,8 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { TelegramTextAttributes.PeerTextMention, TelegramTextAttributes.BotCommand, TelegramTextAttributes.Hashtag, - TelegramTextAttributes.Timecode + TelegramTextAttributes.Timecode, + TelegramTextAttributes.BankCard ] for name in possibleNames { if let _ = attributes[NSAttributedString.Key(rawValue: name)] { diff --git a/submodules/TelegramUI/TelegramUI/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/TelegramUI/ChatRecentActionsControllerNode.swift index cf5344ad57..b4de87c21a 100644 --- a/submodules/TelegramUI/TelegramUI/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatRecentActionsControllerNode.swift @@ -392,6 +392,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { }) ])]) strongSelf.presentController(actionSheet, nil) + case .bankCard: + break } } }, openCheckoutOrReceipt: { _ in diff --git a/submodules/TelegramUI/TelegramUI/ChatScheduleTimeControllerNode.swift b/submodules/TelegramUI/TelegramUI/ChatScheduleTimeControllerNode.swift index 4b77d486aa..e69a824772 100644 --- a/submodules/TelegramUI/TelegramUI/ChatScheduleTimeControllerNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatScheduleTimeControllerNode.swift @@ -352,7 +352,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, UIScrollViewDel transition.updateFrame(node: self.doneButton, frame: CGRect(x: buttonInset, y: contentHeight - buttonHeight - insets.bottom - 10.0 - buttonOffset, width: contentFrame.width, height: buttonHeight)) let onlineSize = self.onlineButton.measure(CGSize(width: width, height: titleHeight)) - let onlineFrame = CGRect(origin: CGPoint(x: ceil((layout.size.width - onlineSize.width) / 2.0), y: contentHeight - 45.0 - insets.bottom), size: onlineSize) + let onlineFrame = CGRect(origin: CGPoint(x: ceil((contentFrame.width - onlineSize.width) / 2.0), y: contentHeight - 45.0 - insets.bottom), size: onlineSize) transition.updateFrame(node: self.onlineButton, frame: onlineFrame) self.pickerView?.frame = CGRect(origin: CGPoint(x: 0.0, y: 54.0), size: CGSize(width: contentFrame.width, height: pickerHeight)) diff --git a/submodules/TelegramUI/TelegramUI/GifPaneSearchContentNode.swift b/submodules/TelegramUI/TelegramUI/GifPaneSearchContentNode.swift index 48c50b6f43..606f2431d9 100644 --- a/submodules/TelegramUI/TelegramUI/GifPaneSearchContentNode.swift +++ b/submodules/TelegramUI/TelegramUI/GifPaneSearchContentNode.swift @@ -28,7 +28,7 @@ func paneGifSearchForQuery(account: Account, query: String, updateActivity: ((Bo } |> mapToSignal { peer -> Signal<(ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?, NoError> in if let user = peer as? TelegramUser, let botInfo = user.botInfo, let _ = botInfo.inlinePlaceholder { - let results = requestContextResults(account: account, botId: user.id, query: query, peerId: account.peerId, limit: 64) + let results = requestContextResults(account: account, botId: user.id, query: query, peerId: account.peerId, limit: 15) |> map { results -> (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult? in return { _ in return .contextRequestResult(user, results) diff --git a/submodules/TelegramUI/TelegramUI/ListMessageDateHeader.swift b/submodules/TelegramUI/TelegramUI/ListMessageDateHeader.swift index 5a3d511455..0e6f49d611 100644 --- a/submodules/TelegramUI/TelegramUI/ListMessageDateHeader.swift +++ b/submodules/TelegramUI/TelegramUI/ListMessageDateHeader.swift @@ -105,4 +105,3 @@ final class ListMessageDateHeaderNode: ListViewItemHeaderNode { self.backgroundNode.frame = CGRect(origin: CGPoint(), size: size) } } - diff --git a/submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping b/submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping index 0e740b4a155b225542e28dac2235e57e003820bf..97d55f8f57a492fb7368c27f9abfc86eca4f5ac6 100644 GIT binary patch delta 43152 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 delta 42239 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 HIqd%fUw-+g diff --git a/submodules/TextFormat/Sources/StringWithAppliedEntities.swift b/submodules/TextFormat/Sources/StringWithAppliedEntities.swift index 615d605e19..e3cad1726e 100644 --- a/submodules/TextFormat/Sources/StringWithAppliedEntities.swift +++ b/submodules/TextFormat/Sources/StringWithAppliedEntities.swift @@ -209,6 +209,15 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti string.insert(NSAttributedString(string: paragraphBreak), at: paragraphRange.upperBound) rangeOffset += paragraphBreak.count + case .BankCard: + string.addAttribute(NSAttributedString.Key.foregroundColor, value: linkColor, range: range) + if underlineLinks && underlineAllLinks { + string.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue as NSNumber, range: range) + } + if nsString == nil { + nsString = text as NSString + } + string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.BankCard), value: nsString!.substring(with: range), range: range) case let .Custom(type): if type == ApplicationSpecificEntityType.Timecode { string.addAttribute(NSAttributedString.Key.foregroundColor, value: linkColor, range: range) diff --git a/submodules/TextFormat/Sources/TelegramAttributes.swift b/submodules/TextFormat/Sources/TelegramAttributes.swift index b05f982d82..ab276a41e3 100644 --- a/submodules/TextFormat/Sources/TelegramAttributes.swift +++ b/submodules/TextFormat/Sources/TelegramAttributes.swift @@ -37,6 +37,7 @@ public struct TelegramTextAttributes { public static let PeerTextMention = "TelegramPeerTextMention" public static let BotCommand = "TelegramBotCommand" public static let Hashtag = "TelegramHashtag" + public static let BankCard = "TelegramBankCard" public static let Timecode = "TelegramTimecode" public static let BlockQuote = "TelegramBlockQuote" } diff --git a/submodules/UrlHandling/Sources/UrlHandling.swift b/submodules/UrlHandling/Sources/UrlHandling.swift index bd53d7861c..051053b059 100644 --- a/submodules/UrlHandling/Sources/UrlHandling.swift +++ b/submodules/UrlHandling/Sources/UrlHandling.swift @@ -14,6 +14,8 @@ import TelegramUIPreferences import AccountContext import WalletUrl +private let baseTelegramMePaths = ["telegram.me", "t.me", "telegram.dog"] + public enum ParsedInternalPeerUrlParameter { case botStart(String) case groupBotStart(String) @@ -346,7 +348,6 @@ private func resolveInternalUrl(account: Account, url: ParsedInternalUrl) -> Sig public func isTelegramMeLink(_ url: String) -> Bool { let schemes = ["http://", "https://", ""] - let baseTelegramMePaths = ["telegram.me", "t.me"] for basePath in baseTelegramMePaths { for scheme in schemes { let basePrefix = scheme + basePath + "/" @@ -360,7 +361,6 @@ public func isTelegramMeLink(_ url: String) -> Bool { public 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 + "/" @@ -382,7 +382,6 @@ public func parseProxyUrl(_ url: String) -> (host: String, port: Int32, username public func parseStickerPackUrl(_ url: String) -> String? { let schemes = ["http://", "https://", ""] - let baseTelegramMePaths = ["telegram.me", "t.me"] for basePath in baseTelegramMePaths { for scheme in schemes { let basePrefix = scheme + basePath + "/" @@ -404,7 +403,6 @@ public func parseStickerPackUrl(_ url: String) -> String? { public func parseWallpaperUrl(_ url: String) -> WallpaperUrlParameter? { let schemes = ["http://", "https://", ""] - let baseTelegramMePaths = ["telegram.me", "t.me"] for basePath in baseTelegramMePaths { for scheme in schemes { let basePrefix = scheme + basePath + "/" @@ -431,7 +429,6 @@ public func resolveUrlImpl(account: Account, url: String) -> Signal() private let centralItemTitleView = Promise() private let centralItemNavigationStyle = Promise() - private let centralItemFooterContentNode = Promise() + private let centralItemFooterContentNode = Promise<(GalleryFooterContentNode?, GalleryOverlayContentNode?)>() private let centralItemAttributesDisposable = DisposableSet(); private let checkedDisposable = MetaDisposable() @@ -156,7 +156,7 @@ class WebSearchGalleryController: ViewController { self?.navigationItem.titleView = titleView })) - self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode in + self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode, _ in self?.galleryNode.updatePresentationState({ $0.withUpdatedFooterContentNode(footerContentNode) }, transition: .immediate) diff --git a/submodules/WebSearchUI/Sources/WebSearchVideoGalleryItem.swift b/submodules/WebSearchUI/Sources/WebSearchVideoGalleryItem.swift index 498a758306..1f69d4ec7a 100644 --- a/submodules/WebSearchUI/Sources/WebSearchVideoGalleryItem.swift +++ b/submodules/WebSearchUI/Sources/WebSearchVideoGalleryItem.swift @@ -534,7 +534,7 @@ final class WebSearchVideoGalleryItemNode: ZoomableContentGalleryItemNode { } } - override func footerContent() -> Signal { - return .single(self.footerContentNode) + override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((self.footerContentNode, nil)) } } diff --git a/submodules/ffmpeg/gas-preprocessor.pl b/submodules/ffmpeg/gas-preprocessor.pl new file mode 100755 index 0000000000..6da37c1f0d --- /dev/null +++ b/submodules/ffmpeg/gas-preprocessor.pl @@ -0,0 +1,1210 @@ +#!/usr/bin/env perl +# by David Conrad +# This code is licensed under GPLv2 or later; go to gnu.org to read it +# (not that it much matters for an asm preprocessor) +# usage: set your assembler to be something like "perl gas-preprocessor.pl gcc" +use strict; + +# Apple's gas is ancient and doesn't support modern preprocessing features like +# .rept and has ugly macro syntax, among other things. Thus, this script +# implements the subset of the gas preprocessor used by x264 and ffmpeg +# that isn't supported by Apple's gas. + +my %canonical_arch = ("aarch64" => "aarch64", "arm64" => "aarch64", + "arm" => "arm", + "powerpc" => "powerpc", "ppc" => "powerpc"); + +my %comments = ("aarch64" => '//', + "arm" => '@', + "powerpc" => '#'); + +my @gcc_cmd; +my @preprocess_c_cmd; + +my $comm; +my $arch; +my $as_type = "apple-gas"; + +my $fix_unreq = $^O eq "darwin"; +my $force_thumb = 0; +my $verbose = 0; + +my $arm_cond_codes = "eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al|hs|lo"; + +my $usage_str = " +$0\n +Gas-preprocessor.pl converts assembler files using modern GNU as syntax for +Apple's ancient gas version or clang's incompatible integrated assembler. The +conversion is regularly tested for Libav, x264 and vlc. Other projects might +use different features which are not correctly handled. + +Options for this program needs to be separated with ' -- ' from the assembler +command. Following options are currently supported: + + -help - this usage text + -arch - target architecture + -as-type - one value out of {{,apple-}{gas,clang},armasm} + -fix-unreq + -no-fix-unreq + -force-thumb - assemble as thumb regardless of the input source + (note, this is incomplete and only works for sources + it explicitly was tested with) + -verbose - print executed commands +"; + +sub usage() { + print $usage_str; +} + +while (@ARGV) { + my $opt = shift; + + if ($opt =~ /^-(no-)?fix-unreq$/) { + $fix_unreq = $1 ne "no-"; + } elsif ($opt eq "-force-thumb") { + $force_thumb = 1; + } elsif ($opt eq "-verbose") { + $verbose = 1; + } elsif ($opt eq "-arch") { + $arch = shift; + die "unknown arch: '$arch'\n" if not exists $canonical_arch{$arch}; + } elsif ($opt eq "-as-type") { + $as_type = shift; + die "unknown as type: '$as_type'\n" if $as_type !~ /^((apple-)?(gas|clang)|armasm)$/; + } elsif ($opt eq "-help") { + usage(); + exit 0; + } elsif ($opt eq "--" ) { + @gcc_cmd = @ARGV; + } elsif ($opt =~ /^-/) { + die "option '$opt' is not known. See '$0 -help' for usage information\n"; + } else { + push @gcc_cmd, $opt, @ARGV; + } + last if (@gcc_cmd); +} + +if (grep /\.c$/, @gcc_cmd) { + # C file (inline asm?) - compile + @preprocess_c_cmd = (@gcc_cmd, "-S"); +} elsif (grep /\.[sS]$/, @gcc_cmd) { + # asm file, just do C preprocessor + @preprocess_c_cmd = (@gcc_cmd, "-E"); +} elsif (grep /-(v|h|-version|dumpversion)/, @gcc_cmd) { + # pass -v/--version along, used during probing. Matching '-v' might have + # uninteded results but it doesn't matter much if gas-preprocessor or + # the compiler fails. + print STDERR join(" ", @gcc_cmd)."\n" if $verbose; + exec(@gcc_cmd); +} else { + die "Unrecognized input filetype"; +} +if ($as_type eq "armasm") { + + $preprocess_c_cmd[0] = "cpp"; + push(@preprocess_c_cmd, "-undef"); + # Normally a preprocessor for windows would predefine _WIN32, + # but we're using any generic system-agnostic preprocessor "cpp" + # with -undef (to avoid getting predefined variables from the host + # system in cross compilation cases), so manually define it here. + push(@preprocess_c_cmd, "-D_WIN32"); + + @preprocess_c_cmd = grep ! /^-nologo$/, @preprocess_c_cmd; + # Remove -ignore XX parameter pairs from preprocess_c_cmd + my $index = 1; + while ($index < $#preprocess_c_cmd) { + if ($preprocess_c_cmd[$index] eq "-ignore" and $index + 1 < $#preprocess_c_cmd) { + splice(@preprocess_c_cmd, $index, 2); + next; + } + $index++; + } + if (grep /^-MM$/, @preprocess_c_cmd) { + print STDERR join(" ", @preprocess_c_cmd)."\n" if $verbose; + system(@preprocess_c_cmd) == 0 or die "Error running preprocessor"; + exit 0; + } +} + +# if compiling, avoid creating an output file named '-.o' +if ((grep /^-c$/, @gcc_cmd) && !(grep /^-o/, @gcc_cmd)) { + foreach my $i (@gcc_cmd) { + if ($i =~ /\.[csS]$/) { + my $outputfile = $i; + $outputfile =~ s/\.[csS]$/.o/; + push(@gcc_cmd, "-o"); + push(@gcc_cmd, $outputfile); + last; + } + } +} +# replace only the '-o' argument with '-', avoids rewriting the make dependency +# target specified with -MT to '-' +my $index = 1; +while ($index < $#preprocess_c_cmd) { + if ($preprocess_c_cmd[$index] eq "-o") { + $index++; + $preprocess_c_cmd[$index] = "-"; + } + $index++; +} + +my $tempfile; +if ($as_type ne "armasm") { + @gcc_cmd = map { /\.[csS]$/ ? qw(-x assembler -) : $_ } @gcc_cmd; +} else { + @preprocess_c_cmd = grep ! /^-c$/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-m/, @preprocess_c_cmd; + + @preprocess_c_cmd = grep ! /^-G/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-W/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-Z/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-fp/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-EHsc$/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-O/, @preprocess_c_cmd; + + @gcc_cmd = grep ! /^-G/, @gcc_cmd; + @gcc_cmd = grep ! /^-W/, @gcc_cmd; + @gcc_cmd = grep ! /^-Z/, @gcc_cmd; + @gcc_cmd = grep ! /^-fp/, @gcc_cmd; + @gcc_cmd = grep ! /^-EHsc$/, @gcc_cmd; + @gcc_cmd = grep ! /^-O/, @gcc_cmd; + + my @outfiles = grep /\.(o|obj)$/, @gcc_cmd; + $tempfile = $outfiles[0].".asm"; + + # Remove most parameters from gcc_cmd, which actually is the armasm command, + # which doesn't support any of the common compiler/preprocessor options. + @gcc_cmd = grep ! /^-D/, @gcc_cmd; + @gcc_cmd = grep ! /^-U/, @gcc_cmd; + @gcc_cmd = grep ! /^-m/, @gcc_cmd; + @gcc_cmd = grep ! /^-M/, @gcc_cmd; + @gcc_cmd = grep ! /^-c$/, @gcc_cmd; + @gcc_cmd = grep ! /^-I/, @gcc_cmd; + @gcc_cmd = map { /\.S$/ ? $tempfile : $_ } @gcc_cmd; +} + +# detect architecture from gcc binary name +if (!$arch) { + if ($gcc_cmd[0] =~ /(arm64|aarch64|arm|powerpc|ppc)/) { + $arch = $1; + } else { + # look for -arch flag + foreach my $i (1 .. $#gcc_cmd-1) { + if ($gcc_cmd[$i] eq "-arch" and + $gcc_cmd[$i+1] =~ /(arm64|aarch64|arm|powerpc|ppc)/) { + $arch = $1; + } + } + } +} + +# assume we're not cross-compiling if no -arch or the binary doesn't have the arch name +$arch = qx/arch/ if (!$arch); + +die "Unknown target architecture '$arch'" if not exists $canonical_arch{$arch}; + +$arch = $canonical_arch{$arch}; +$comm = $comments{$arch}; +my $inputcomm = $comm; +$comm = ";" if $as_type =~ /armasm/; + +my %ppc_spr = (ctr => 9, + vrsave => 256); + +print STDERR join(" ", @preprocess_c_cmd)."\n" if $verbose; +open(INPUT, "-|", @preprocess_c_cmd) || die "Error running preprocessor"; + +if ($ENV{GASPP_DEBUG}) { + open(ASMFILE, ">&STDOUT"); +} else { + if ($as_type ne "armasm") { + print STDERR join(" ", @gcc_cmd)."\n" if $verbose; + open(ASMFILE, "|-", @gcc_cmd) or die "Error running assembler"; + } else { + open(ASMFILE, ">", $tempfile); + } +} + +my $current_macro = ''; +my $macro_level = 0; +my $rept_level = 0; +my %macro_lines; +my %macro_args; +my %macro_args_default; +my $macro_count = 0; +my $altmacro = 0; +my $in_irp = 0; + +my $num_repts; +my @rept_lines; + +my @irp_args; +my $irp_param; + +my @ifstack; + +my %symbols; + +my @sections; + +my %literal_labels; # for ldr , = +my $literal_num = 0; +my $literal_expr = ".word"; +$literal_expr = ".quad" if $arch eq "aarch64"; + +my $thumb = 0; + +my %thumb_labels; +my %call_targets; +my %import_symbols; + +my %neon_alias_reg; +my %neon_alias_type; + +my $temp_label_next = 0; +my %last_temp_labels; +my %next_temp_labels; + +my %labels_seen; + +my %aarch64_req_alias; + +if ($force_thumb) { + parse_line(".thumb\n"); +} + +# pass 1: parse .macro +# note that the handling of arguments is probably overly permissive vs. gas +# but it should be the same for valid cases +while () { + # remove lines starting with '#', preprocessing is done, '#' at start of + # the line indicates a comment for all supported archs (aarch64, arm, ppc + # and x86). Also strips line number comments but since they are off anyway + # it is no loss. + s/^\s*#.*$//; + # remove all comments (to avoid interfering with evaluating directives) + s/(? 0) { + $ifstack[-1] = -$ifstack[-1]; + } + return 1; + } elsif ($line =~ /\.else/) { + $ifstack[-1] = !$ifstack[-1]; + return 1; + } elsif (handle_if($line)) { + return 1; + } + } + + # discard lines in false .if blocks + foreach my $i (0 .. $#ifstack) { + if ($ifstack[$i] <= 0) { + return 1; + } + } + } + return 0; +} + +sub parse_line { + my $line = $_[0]; + + return if (parse_if_line($line)); + + if (scalar(@rept_lines) == 0) { + if ($line =~ /\.macro/) { + $macro_level++; + if ($macro_level > 1 && !$current_macro) { + die "nested macros but we don't have master macro"; + } + } elsif ($line =~ /\.endm/) { + $macro_level--; + if ($macro_level < 0) { + die "unmatched .endm"; + } elsif ($macro_level == 0) { + $current_macro = ''; + return; + } + } + } + + if ($macro_level == 0) { + if ($line =~ /\.(rept|irp)/) { + $rept_level++; + } elsif ($line =~ /.endr/) { + $rept_level--; + } + } + + if ($macro_level > 1) { + push(@{$macro_lines{$current_macro}}, $line); + } elsif (scalar(@rept_lines) and $rept_level >= 1) { + push(@rept_lines, $line); + } elsif ($macro_level == 0) { + expand_macros($line); + } else { + if ($line =~ /\.macro\s+([\d\w\.]+)\s*,?\s*(.*)/) { + $current_macro = $1; + + # commas in the argument list are optional, so only use whitespace as the separator + my $arglist = $2; + $arglist =~ s/,/ /g; + + my @args = split(/\s+/, $arglist); + foreach my $i (0 .. $#args) { + my @argpair = split(/=/, $args[$i]); + $macro_args{$current_macro}[$i] = $argpair[0]; + $argpair[0] =~ s/:vararg$//; + $macro_args_default{$current_macro}{$argpair[0]} = $argpair[1]; + } + # ensure %macro_lines has the macro name added as a key + $macro_lines{$current_macro} = []; + + } elsif ($current_macro) { + push(@{$macro_lines{$current_macro}}, $line); + } else { + die "macro level without a macro name"; + } + } +} + +sub handle_set { + my $line = $_[0]; + if ($line =~ /\.(?:set|equ)\s+(\S*)\s*,\s*(.*)/) { + $symbols{$1} = eval_expr($2); + return 1; + } + return 0; +} + +sub expand_macros { + my $line = $_[0]; + + # handle .if directives; apple's assembler doesn't support important non-basic ones + # evaluating them is also needed to handle recursive macros + if (handle_if($line)) { + return; + } + + if (/\.purgem\s+([\d\w\.]+)/) { + delete $macro_lines{$1}; + delete $macro_args{$1}; + delete $macro_args_default{$1}; + return; + } + + if ($line =~ /\.altmacro/) { + $altmacro = 1; + return; + } + + if ($line =~ /\.noaltmacro/) { + $altmacro = 0; + return; + } + + $line =~ s/\%([^,]*)/eval_expr($1)/eg if $altmacro; + + # Strip out the .set lines from the armasm output + return if (handle_set($line) and $as_type eq "armasm"); + + if ($line =~ /\.rept\s+(.*)/) { + $num_repts = $1; + @rept_lines = ("\n"); + + # handle the possibility of repeating another directive on the same line + # .endr on the same line is not valid, I don't know if a non-directive is + if ($num_repts =~ s/(\.\w+.*)//) { + push(@rept_lines, "$1\n"); + } + $num_repts = eval_expr($num_repts); + } elsif ($line =~ /\.irp\s+([\d\w\.]+)\s*(.*)/) { + $in_irp = 1; + $num_repts = 1; + @rept_lines = ("\n"); + $irp_param = $1; + + # only use whitespace as the separator + my $irp_arglist = $2; + $irp_arglist =~ s/,/ /g; + $irp_arglist =~ s/^\s+//; + @irp_args = split(/\s+/, $irp_arglist); + } elsif ($line =~ /\.irpc\s+([\d\w\.]+)\s*(.*)/) { + $in_irp = 1; + $num_repts = 1; + @rept_lines = ("\n"); + $irp_param = $1; + + my $irp_arglist = $2; + $irp_arglist =~ s/,/ /g; + $irp_arglist =~ s/^\s+//; + @irp_args = split(//, $irp_arglist); + } elsif ($line =~ /\.endr/) { + my @prev_rept_lines = @rept_lines; + my $prev_in_irp = $in_irp; + my @prev_irp_args = @irp_args; + my $prev_irp_param = $irp_param; + my $prev_num_repts = $num_repts; + @rept_lines = (); + $in_irp = 0; + @irp_args = ''; + + if ($prev_in_irp != 0) { + foreach my $i (@prev_irp_args) { + foreach my $origline (@prev_rept_lines) { + my $line = $origline; + $line =~ s/\\$prev_irp_param/$i/g; + $line =~ s/\\\(\)//g; # remove \() + parse_line($line); + } + } + } else { + for (1 .. $prev_num_repts) { + foreach my $origline (@prev_rept_lines) { + my $line = $origline; + parse_line($line); + } + } + } + } elsif ($line =~ /(\S+:|)\s*([\w\d\.]+)\s*(.*)/ && exists $macro_lines{$2}) { + handle_serialized_line($1); + my $macro = $2; + + # commas are optional here too, but are syntactically important because + # parameters can be blank + my @arglist = split(/,/, $3); + my @args; + my @args_seperator; + + my $comma_sep_required = 0; + foreach (@arglist) { + # allow arithmetic/shift operators in macro arguments + $_ =~ s/\s*(\+|-|\*|\/|<<|>>|<|>)\s*/$1/g; + + my @whitespace_split = split(/\s+/, $_); + if (!@whitespace_split) { + push(@args, ''); + push(@args_seperator, ''); + } else { + foreach (@whitespace_split) { + #print ("arglist = \"$_\"\n"); + if (length($_)) { + push(@args, $_); + my $sep = $comma_sep_required ? "," : " "; + push(@args_seperator, $sep); + #print ("sep = \"$sep\", arg = \"$_\"\n"); + $comma_sep_required = 0; + } + } + } + + $comma_sep_required = 1; + } + + my %replacements; + if ($macro_args_default{$macro}){ + %replacements = %{$macro_args_default{$macro}}; + } + + # construct hashtable of text to replace + foreach my $i (0 .. $#args) { + my $argname = $macro_args{$macro}[$i]; + my @macro_args = @{ $macro_args{$macro} }; + if ($args[$i] =~ m/=/) { + # arg=val references the argument name + # XXX: I'm not sure what the expected behaviour if a lot of + # these are mixed with unnamed args + my @named_arg = split(/=/, $args[$i]); + $replacements{$named_arg[0]} = $named_arg[1]; + } elsif ($i > $#{$macro_args{$macro}}) { + # more args given than the macro has named args + # XXX: is vararg allowed on arguments before the last? + $argname = $macro_args{$macro}[-1]; + if ($argname =~ s/:vararg$//) { + #print "macro = $macro, args[$i] = $args[$i], args_seperator=@args_seperator, argname = $argname, arglist[$i] = $arglist[$i], arglist = @arglist, args=@args, macro_args=@macro_args\n"; + #$replacements{$argname} .= ", $args[$i]"; + $replacements{$argname} .= "$args_seperator[$i] $args[$i]"; + } else { + die "Too many arguments to macro $macro"; + } + } else { + $argname =~ s/:vararg$//; + $replacements{$argname} = $args[$i]; + } + } + + my $count = $macro_count++; + + # apply replacements as regex + foreach (@{$macro_lines{$macro}}) { + my $macro_line = $_; + # do replacements by longest first, this avoids wrong replacement + # when argument names are subsets of each other + foreach (reverse sort {length $a <=> length $b} keys %replacements) { + $macro_line =~ s/\\$_/$replacements{$_}/g; + } + if ($altmacro) { + foreach (reverse sort {length $a <=> length $b} keys %replacements) { + $macro_line =~ s/\b$_\b/$replacements{$_}/g; + } + } + $macro_line =~ s/\\\@/$count/g; + $macro_line =~ s/\\\(\)//g; # remove \() + parse_line($macro_line); + } + } else { + handle_serialized_line($line); + } +} + +sub is_arm_register { + my $name = $_[0]; + if ($name eq "lr" or + $name eq "ip" or + $name =~ /^[rav]\d+$/) { + return 1; + } + return 0; +} + +sub is_aarch64_register { + my $name = $_[0]; + if ($name =~ /^[xw]\d+$/) { + return 1; + } + return 0; +} + +sub handle_local_label { + my $line = $_[0]; + my $num = $_[1]; + my $dir = $_[2]; + my $target = "$num$dir"; + if ($dir eq "b") { + $line =~ s/\b$target\b/$last_temp_labels{$num}/g; + } else { + my $name = "temp_label_$temp_label_next"; + $temp_label_next++; + push(@{$next_temp_labels{$num}}, $name); + $line =~ s/\b$target\b/$name/g; + } + return $line; +} + +sub handle_serialized_line { + my $line = $_[0]; + + # handle .previous (only with regard to .section not .subsection) + if ($line =~ /\.(section|text|const_data)/) { + push(@sections, $line); + } elsif ($line =~ /\.previous/) { + if (!$sections[-2]) { + die ".previous without a previous section"; + } + $line = $sections[-2]; + push(@sections, $line); + } + + $thumb = 1 if $line =~ /\.code\s+16|\.thumb/; + $thumb = 0 if $line =~ /\.code\s+32|\.arm/; + + # handle ldr , = + if ($line =~ /(.*)\s*ldr([\w\s\d]+)\s*,\s*=(.*)/ and $as_type ne "armasm") { + my $label = $literal_labels{$3}; + if (!$label) { + $label = "Literal_$literal_num"; + $literal_num++; + $literal_labels{$3} = $label; + } + $line = "$1 ldr$2, $label\n"; + } elsif ($line =~ /\.ltorg/ and $as_type ne "armasm") { + $line .= ".align 2\n"; + foreach my $literal (keys %literal_labels) { + $line .= "$literal_labels{$literal}:\n $literal_expr $literal\n"; + } + %literal_labels = (); + } + + # handle GNU as pc-relative relocations for adrp/add + if ($line =~ /(.*)\s*adrp([\w\s\d]+)\s*,\s*#?:pg_hi21:([^\s]+)/ and $as_type =~ /^apple-/) { + $line = "$1 adrp$2, ${3}\@PAGE\n"; + } elsif ($line =~ /(.*)\s*add([\w\s\d]+)\s*,([\w\s\d]+)\s*,\s*#?:lo12:([^\s]+)/ and $as_type =~ /^apple-/) { + $line = "$1 add$2, $3, ${4}\@PAGEOFF\n"; + } + + # thumb add with large immediate needs explicit add.w + if ($thumb and $line =~ /add\s+.*#([^@]+)/) { + $line =~ s/add/add.w/ if eval_expr($1) > 255; + } + + # mach-o local symbol names start with L (no dot) + $line =~ s/(? with ic as conditional code + if ($cond =~ /^(|$arm_cond_codes)$/) { + if (exists $thumb_labels{$label}) { + print ASMFILE ".thumb_func $label\n"; + } else { + $call_targets{$label}++; + } + } + } + + # @l -> lo16() @ha -> ha16() + $line =~ s/,\s+([^,]+)\@l\b/, lo16($1)/g; + $line =~ s/,\s+([^,]+)\@ha\b/, ha16($1)/g; + + # move to/from SPR + if ($line =~ /(\s+)(m[ft])([a-z]+)\s+(\w+)/ and exists $ppc_spr{$3}) { + if ($2 eq 'mt') { + $line = "$1${2}spr $ppc_spr{$3}, $4\n"; + } else { + $line = "$1${2}spr $4, $ppc_spr{$3}\n"; + } + } + + if ($line =~ /\.unreq\s+(.*)/) { + if (defined $neon_alias_reg{$1}) { + delete $neon_alias_reg{$1}; + delete $neon_alias_type{$1}; + return; + } elsif (defined $aarch64_req_alias{$1}) { + delete $aarch64_req_alias{$1}; + return; + } + } + # old gas versions store upper and lower case names on .req, + # but they remove only one on .unreq + if ($fix_unreq) { + if ($line =~ /\.unreq\s+(.*)/) { + $line = ".unreq " . lc($1) . "\n"; + $line .= ".unreq " . uc($1) . "\n"; + } + } + + if ($line =~ /(\w+)\s+\.(dn|qn)\s+(\w+)(?:\.(\w+))?(\[\d+\])?/) { + $neon_alias_reg{$1} = "$3$5"; + $neon_alias_type{$1} = $4; + return; + } + if (scalar keys %neon_alias_reg > 0 && $line =~ /^\s+v\w+/) { + # This line seems to possibly have a neon instruction + foreach (keys %neon_alias_reg) { + my $alias = $_; + # Require the register alias to match as an invididual word, not as a substring + # of a larger word-token. + if ($line =~ /\b$alias\b/) { + $line =~ s/\b$alias\b/$neon_alias_reg{$alias}/g; + # Add the type suffix. If multiple aliases match on the same line, + # only do this replacement the first time (a vfoo.bar string won't match v\w+). + $line =~ s/^(\s+)(v\w+)(\s+)/$1$2.$neon_alias_type{$alias}$3/; + } + } + } + + if ($arch eq "aarch64" or $as_type eq "armasm") { + # clang's integrated aarch64 assembler in Xcode 5 does not support .req/.unreq + if ($line =~ /\b(\w+)\s+\.req\s+(\w+)\b/) { + $aarch64_req_alias{$1} = $2; + return; + } + foreach (keys %aarch64_req_alias) { + my $alias = $_; + # recursively resolve aliases + my $resolved = $aarch64_req_alias{$alias}; + while (defined $aarch64_req_alias{$resolved}) { + $resolved = $aarch64_req_alias{$resolved}; + } + $line =~ s/\b$alias\b/$resolved/g; + } + } + if ($arch eq "aarch64") { + # fix missing aarch64 instructions in Xcode 5.1 (beta3) + # mov with vector arguments is not supported, use alias orr instead + if ($line =~ /^(\d+:)?\s*mov\s+(v\d[\.{}\[\]\w]+),\s*(v\d[\.{}\[\]\w]+)\b\s*$/) { + $line = "$1 orr $2, $3, $3\n"; + } + # movi 16, 32 bit shifted variant, shift is optional + if ($line =~ /^(\d+:)?\s*movi\s+(v[0-3]?\d\.(?:2|4|8)[hsHS])\s*,\s*(#\w+)\b\s*$/) { + $line = "$1 movi $2, $3, lsl #0\n"; + } + # Xcode 5 misses the alias uxtl. Replace it with the more general ushll. + # Clang 3.4 misses the alias sxtl too. Replace it with the more general sshll. + # armasm64 also misses these instructions. + if ($line =~ /^(\d+:)?\s*(s|u)xtl(2)?\s+(v[0-3]?\d\.[248][hsdHSD])\s*,\s*(v[0-3]?\d\.(?:2|4|8|16)[bhsBHS])\b\s*$/) { + $line = "$1 $2shll$3 $4, $5, #0\n"; + } + # clang 3.4 and armasm64 do not automatically use shifted immediates in add/sub + if (($as_type eq "clang" or $as_type eq "armasm") and + $line =~ /^(\d+:)?(\s*(?:add|sub)s?) ([^#l]+)#([\d\+\-\*\/ <>]+)\s*$/) { + my $imm = eval $4; + if ($imm > 4095 and not ($imm & 4095)) { + $line = "$1 $2 $3#" . ($imm >> 12) . ", lsl #12\n"; + } + } + if ($ENV{GASPP_FIX_XCODE5}) { + if ($line =~ /^\s*bsl\b/) { + $line =~ s/\b(bsl)(\s+v[0-3]?\d\.(\w+))\b/$1.$3$2/; + $line =~ s/\b(v[0-3]?\d)\.$3\b/$1/g; + } + if ($line =~ /^\s*saddl2?\b/) { + $line =~ s/\b(saddl2?)(\s+v[0-3]?\d\.(\w+))\b/$1.$3$2/; + $line =~ s/\b(v[0-3]?\d)\.\w+\b/$1/g; + } + if ($line =~ /^\s*dup\b.*\]$/) { + $line =~ s/\bdup(\s+v[0-3]?\d)\.(\w+)\b/dup.$2$1/g; + $line =~ s/\b(v[0-3]?\d)\.[bhsdBHSD](\[\d\])$/$1$2/g; + } + } + } + + if ($as_type eq "armasm") { + # Also replace variables set by .set + foreach (keys %symbols) { + my $sym = $_; + $line =~ s/\b$sym\b/$symbols{$sym}/g; + } + + # Handle function declarations and keep track of the declared labels + if ($line =~ s/^\s*\.func\s+(\w+)/$1 PROC/) { + $labels_seen{$1} = 1; + } + + if ($line =~ s/^\s*(\d+)://) { + # Convert local labels into unique labels. armasm (at least in + # RVCT) has something similar, but still different enough. + # By converting to unique labels we avoid any possible + # incompatibilities. + + my $num = $1; + foreach (@{$next_temp_labels{$num}}) { + $line = "$_\n" . $line; + } + @next_temp_labels{$num} = (); + my $name = "temp_label_$temp_label_next"; + $temp_label_next++; + # The matching regexp above removes the label from the start of + # the line (which might contain an instruction as well), readd + # it on a separate line above it. + $line = "$name:\n" . $line; + $last_temp_labels{$num} = $name; + } + + if ($line =~ s/^\s*(\w+):/$1/) { + # Skip labels that have already been declared with a PROC, + # labels must not be declared multiple times. + return if (defined $labels_seen{$1}); + $labels_seen{$1} = 1; + } elsif ($line !~ /(\w+) PROC/) { + # If not a label, make sure the line starts with whitespace, + # otherwise ms armasm interprets it incorrectly. + $line =~ s/^[\.\w]/\t$&/; + } + + + # Check branch instructions + if ($line =~ /(?:^|\n)\s*(\w+\s*:\s*)?(bl?x?\.?([^\s]{2})?(\.w)?)\s+(\w+)/) { + my $instr = $2; + my $cond = $3; + my $width = $4; + my $target = $5; + # Don't interpret e.g. bic as b with ic as conditional code + if ($cond !~ /^(|$arm_cond_codes)$/) { + # Not actually a branch + } elsif ($target =~ /^(\d+)([bf])$/) { + # The target is a local label + $line = handle_local_label($line, $1, $2); + $line =~ s/\b$instr\b/$&.w/ if $width eq "" and $arch eq "arm"; + } elsif (($arch eq "arm" and !is_arm_register($target)) or + ($arch eq "aarch64" and !is_aarch64_register($target))) { + $call_targets{$target}++; + } + } elsif ($line =~ /(?:^|\n)\s*(\w+\s*:\s*)?(cbn?z|adr|tbz)\s+(\w+)\s*,(\s*#\d+\s*,)?\s*(\w+)/) { + my $instr = $2; + my $reg = $3; + my $bit = $4; + my $target = $5; + if ($target =~ /^(\d+)([bf])$/) { + # The target is a local label + $line = handle_local_label($line, $1, $2); + } else { + $call_targets{$target}++; + } + # Convert tbz with a wX register into an xX register, + # due to armasm64 bugs/limitations. + if ($instr eq "tbz" and $reg =~ /w\d+/) { + my $xreg = $reg; + $xreg =~ s/w/x/; + $line =~ s/\b$reg\b/$xreg/; + } + } elsif ($line =~ /^\s*.h?word.*\b\d+[bf]\b/) { + while ($line =~ /\b(\d+)([bf])\b/g) { + $line = handle_local_label($line, $1, $2); + } + } + + # ALIGN in armasm syntax is the actual number of bytes + if ($line =~ /\.(?:p2)?align\s+(\d+)/) { + my $align = 1 << $1; + $line =~ s/\.(?:p2)?align\s+(\d+)/ALIGN $align/; + } + # Convert gas style [r0, :128] into armasm [r0@128] alignment specification + $line =~ s/\[([^\[,]+),?\s*:(\d+)\]/[$1\@$2]/g; + + # armasm treats logical values {TRUE} and {FALSE} separately from + # numeric values - logical operators and values can't be intermixed + # with numerical values. Evaluate ! and (a <> b) into numbers, + # let the assembler evaluate the rest of the expressions. This current + # only works for cases when ! and <> are used with actual constant numbers, + # we don't evaluate subexpressions here. + + # Evaluate ! + while ($line =~ /!\s*(\d+)/g) { + my $val = ($1 != 0) ? 0 : 1; + $line =~ s/!(\d+)/$val/; + } + # Evaluate (a > b) + while ($line =~ /\(\s*(\d+)\s*([<>])\s*(\d+)\s*\)/) { + my $val; + if ($2 eq "<") { + $val = ($1 < $3) ? 1 : 0; + } else { + $val = ($1 > $3) ? 1 : 0; + } + $line =~ s/\(\s*(\d+)\s*([<>])\s*(\d+)\s*\)/$val/; + } + + if ($arch eq "arm") { + # Change a movw... #:lower16: into a mov32 pseudoinstruction + $line =~ s/^(\s*)movw(\s+\w+\s*,\s*)\#:lower16:(.*)$/$1mov32$2$3/; + # and remove the following, matching movt completely + $line =~ s/^\s*movt\s+\w+\s*,\s*\#:upper16:.*$//; + + if ($line =~ /^\s*mov32\s+\w+,\s*([a-zA-Z]\w*)/) { + $import_symbols{$1}++; + } + + # Misc bugs/deficiencies: + # armasm seems unable to parse e.g. "vmov s0, s1" without a type + # qualifier, thus add .f32. + $line =~ s/^(\s+(?:vmov|vadd))(\s+s\d+\s*,\s*s\d+)/$1.f32$2/; + } elsif ($arch eq "aarch64") { + # Convert ext into ext8; armasm64 seems to require it named as ext8. + $line =~ s/^(\s+)ext(\s+)/$1ext8$2/; + + # Pick up targets from ldr x0, =sym+offset + if ($line =~ /^\s*ldr\s+(\w+)\s*,\s*=([a-zA-Z]\w*)(.*)$/) { + my $reg = $1; + my $sym = $2; + my $offset = eval_expr($3); + if ($offset < 0 and $ENV{GASPP_ARMASM64_SKIP_NEG_OFFSET}) { + # armasm64 in VS < 15.6 is buggy with ldr x0, =sym+offset where the + # offset is a negative value; it does write a negative + # offset into the literal pool as it should, but the + # negative offset only covers the lower 32 bit of the 64 + # bit literal/relocation. + # Thus remove the offset and apply it manually with a sub + # afterwards. + $offset = -$offset; + $line = "\tldr $reg, =$sym\n\tsub $reg, $reg, #$offset\n"; + } + $import_symbols{$sym}++; + } + + # armasm64 (currently) doesn't support offsets on adrp targets, + # even though the COFF format relocations (and the linker) + # supports it. Therefore strip out the offsets from adrp and + # add :lo12: (in case future armasm64 would start handling it) + # and add an extra explicit add instruction for the offset. + if ($line =~ s/(adrp\s+\w+\s*,\s*(\w+))([\d\+\-\*\/\(\) <>]+)?/\1/) { + $import_symbols{$2}++; + } + if ($line =~ s/(add\s+(\w+)\s*,\s*\w+\s*,\s*):lo12:(\w+)([\d\+\-\*\/\(\) <>]+)?/\1\3/) { + my $reg = $2; + my $sym = $3; + my $offset = eval_expr($4); + $line .= "\tadd $reg, $reg, #$offset\n" if $offset > 0; + $import_symbols{$sym}++; + } + + # Convert e.g. "add x0, x0, w0, uxtw" into "add x0, x0, w0, uxtw #0", + # or "ldr x0, [x0, w0, uxtw]" into "ldr x0, [x0, w0, uxtw #0]". + $line =~ s/(uxt[whb]|sxt[whb])(\s*\]?\s*)$/\1 #0\2/i; + + # Convert "mov x0, v0.d[0]" into "umov x0, v0.d[0]" + $line =~ s/\bmov\s+[xw]\d+\s*,\s*v\d+\.[ds]/u$&/i; + + # Convert "ccmp w0, #0, #0, ne" into "ccmpne w0, #0, #0", + # and "csel w0, w0, w0, ne" into "cselne w0, w0, w0". + $line =~ s/(ccmp|csel)\s+([xw]\w+)\s*,\s*([xw#]\w+)\s*,\s*([xw#]\w+)\s*,\s*($arm_cond_codes)/\1\5 \2, \3, \4/; + + # Convert "cinc w0, w0, ne" into "cincne w0, w0". + $line =~ s/(cinc)\s+([xw]\w+)\s*,\s*([xw]\w+)\s*,\s*($arm_cond_codes)/\1\4 \2, \3/; + + # Convert "cset w0, lo" into "csetlo w0" + $line =~ s/(cset)\s+([xw]\w+)\s*,\s*($arm_cond_codes)/\1\3 \2/; + + if ($ENV{GASPP_ARMASM64_SKIP_PRFUM}) { + # Strip out prfum; armasm64 (VS < 15.5) fails to assemble any + # variant/combination of prfum tested so far, but since it is + # a prefetch instruction it can be skipped without changing + # results. + $line =~ s/prfum.*\]//; + } + + # Convert "ldrb w0, [x0, #-1]" into "ldurb w0, [x0, #-1]". + # Don't do this for forms with writeback though. + if ($line =~ /(ld|st)(r[bh]?)\s+(\w+)\s*,\s*\[\s*(\w+)\s*,\s*#([^\]]+)\s*\][^!]/) { + my $instr = $1; + my $suffix = $2; + my $target = $3; + my $base = $4; + my $offset = eval_expr($5); + if ($offset < 0) { + $line =~ s/$instr$suffix/${instr}u$suffix/; + } + } + + if ($ENV{GASPP_ARMASM64_INVERT_SCALE}) { + # Instructions like fcvtzs and scvtf store the scale value + # inverted in the opcode (stored as 64 - scale), but armasm64 + # in VS < 15.5 stores it as-is. Thus convert from + # "fcvtzs w0, s0, #8" into "fcvtzs w0, s0, #56". + if ($line =~ /(?:fcvtzs|scvtf)\s+(\w+)\s*,\s*(\w+)\s*,\s*#(\d+)/) { + my $scale = $3; + my $inverted_scale = 64 - $3; + $line =~ s/#$scale/#$inverted_scale/; + } + } + + # Convert "ld1 {v0.4h-v3.4h}" into "ld1 {v0.4h,v1.4h,v2.4h,v3.4h}" + if ($line =~ /(?:ld|st)\d\s+({\s*v(\d+)\.(\d[bhsdBHSD])\s*-\s*v(\d+)\.(\d[bhsdBHSD])\s*})/) { + my $regspec = $1; + my $reg1 = $2; + my $layout1 = $3; + my $reg2 = $4; + my $layout2 = $5; + if ($layout1 eq $layout2) { + my $new_regspec = "{"; + foreach my $i ($reg1 .. $reg2) { + $new_regspec .= "," if ($i > $reg1); + $new_regspec .= "v$i.$layout1"; + } + $new_regspec .= "}"; + $line =~ s/$regspec/$new_regspec/; + } + } + } + # armasm is unable to parse &0x - add spacing + $line =~ s/&0x/& 0x/g; + } + + if ($force_thumb) { + # Convert register post indexing to a separate add instruction. + # This converts e.g. "ldr r0, [r1], r2" into "ldr r0, [r1]", + # "add r1, r1, r2". + $line =~ s/((?:ldr|str)[bh]?)\s+(\w+),\s*\[(\w+)\],\s*(\w+)/$1 $2, [$3]\n\tadd $3, $3, $4/g; + + # Convert "mov pc, lr" into "bx lr", since the former only works + # for switching from arm to thumb (and only in armv7), but not + # from thumb to arm. + $line =~ s/mov\s*pc\s*,\s*lr/bx lr/g; + + # Convert stmdb/ldmia/stmfd/ldmfd/ldm with only one register into a plain str/ldr with post-increment/decrement. + # Wide thumb2 encoding requires at least two registers in register list while all other encodings support one register too. + $line =~ s/stm(?:db|fd)\s+sp!\s*,\s*\{([^,-]+)\}/str $1, [sp, #-4]!/g; + $line =~ s/ldm(?:ia|fd)?\s+sp!\s*,\s*\{([^,-]+)\}/ldr $1, [sp], #4/g; + + # Convert muls into mul+cmp + $line =~ s/muls\s+(\w+),\s*(\w+)\,\s*(\w+)/mul $1, $2, $3\n\tcmp $1, #0/g; + + # Convert "and r0, sp, #xx" into "mov r0, sp", "and r0, r0, #xx" + $line =~ s/and\s+(\w+),\s*(sp|r13)\,\s*#(\w+)/mov $1, $2\n\tand $1, $1, #$3/g; + + # Convert "ldr r0, [r0, r1, lsl #6]" where the shift is >3 (which + # can't be handled in thumb) into "add r0, r0, r1, lsl #6", + # "ldr r0, [r0]", for the special case where the same address is + # used as base and target for the ldr. + if ($line =~ /(ldr[bh]?)\s+(\w+),\s*\[\2,\s*(\w+),\s*lsl\s*#(\w+)\]/ and $4 > 3) { + $line =~ s/(ldr[bh]?)\s+(\w+),\s*\[\2,\s*(\w+),\s*lsl\s*#(\w+)\]/add $2, $2, $3, lsl #$4\n\t$1 $2, [$2]/; + } + + $line =~ s/\.arm/.thumb/x; + } + + # comment out unsupported directives + $line =~ s/\.type/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/\.func/$comm$&/x if $as_type =~ /^(apple-|clang)/; + $line =~ s/\.endfunc/$comm$&/x if $as_type =~ /^(apple-|clang)/; + $line =~ s/\.endfunc/ENDP/x if $as_type =~ /armasm/; + $line =~ s/\.ltorg/$comm$&/x if $as_type =~ /^(apple-|clang)/; + $line =~ s/\.ltorg/LTORG/x if $as_type eq "armasm"; + $line =~ s/\.size/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/\.fpu/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/\.arch/$comm$&/x if $as_type =~ /^(apple-|clang|armasm)/; + $line =~ s/\.object_arch/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/.section\s+.note.GNU-stack.*/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + + $line =~ s/\.syntax/$comm$&/x if $as_type =~ /armasm/; + + $line =~ s/\.hword/.short/x; + + if ($as_type =~ /^apple-/) { + # the syntax for these is a little different + $line =~ s/\.global/.globl/x; + # also catch .section .rodata since the equivalent to .const_data is .section __DATA,__const + $line =~ s/(.*)\.rodata/.const_data/x; + $line =~ s/\.int/.long/x; + $line =~ s/\.float/.single/x; + } + if ($as_type eq "apple-gas") { + $line =~ s/vmrs\s+APSR_nzcv/fmrx r15/x; + } + if ($as_type eq "armasm") { + $line =~ s/\.global/EXPORT/x; + $line =~ s/\.extern/IMPORT/x; + $line =~ s/\.int/dcd/x; + $line =~ s/\.long/dcd/x; + $line =~ s/\.float/dcfs/x; + $line =~ s/\.word/dcd/x; + $line =~ s/\.short/dcw/x; + $line =~ s/\.byte/dcb/x; + $line =~ s/\.quad/dcq/x; + $line =~ s/\.ascii/dcb/x; + $line =~ s/\.asciz(.*)$/dcb\1,0/x; + $line =~ s/\.thumb/THUMB/x; + $line =~ s/\.arm/ARM/x; + # The alignment in AREA is the power of two, just as .align in gas + $line =~ s/\.text/AREA |.text|, CODE, READONLY, ALIGN=4, CODEALIGN/; + $line =~ s/(\s*)(.*)\.ro?data/$1AREA |.rdata|, DATA, READONLY, ALIGN=5/; + $line =~ s/\.data/AREA |.data|, DATA, ALIGN=5/; + } + if ($as_type eq "armasm" and $arch eq "arm") { + $line =~ s/fmxr/vmsr/; + $line =~ s/fmrx/vmrs/; + $line =~ s/fadds/vadd.f32/; + } + if ($as_type eq "armasm" and $arch eq "aarch64") { + # Convert "b.eq" into "beq" + $line =~ s/\bb\.($arm_cond_codes)\b/b\1/; + } + + # catch unknown section names that aren't mach-o style (with a comma) + if ($as_type =~ /apple-/ and $line =~ /.section ([^,]*)$/) { + die ".section $1 unsupported; figure out the mach-o section name and add it"; + } + + print ASMFILE $line; +} + +if ($as_type ne "armasm") { + print ASMFILE ".text\n"; + print ASMFILE ".align 2\n"; + foreach my $literal (keys %literal_labels) { + print ASMFILE "$literal_labels{$literal}:\n $literal_expr $literal\n"; + } + + map print(ASMFILE ".thumb_func $_\n"), + grep exists $thumb_labels{$_}, keys %call_targets; +} else { + map print(ASMFILE "\tIMPORT $_\n"), + grep ! exists $labels_seen{$_}, (keys %call_targets, keys %import_symbols); + + print ASMFILE "\tEND\n"; +} + +close(INPUT) or exit 1; +close(ASMFILE) or exit 1; +if ($as_type eq "armasm" and ! defined $ENV{GASPP_DEBUG}) { + print STDERR join(" ", @gcc_cmd)."\n" if $verbose; + system(@gcc_cmd) == 0 or die "Error running assembler"; +} + +END { + unlink($tempfile) if defined $tempfile; +} +#exit 1 From c46d628dd682e168f6e200be9c9034f21b40ee01 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 11 Feb 2020 11:08:35 +0400 Subject: [PATCH 15/30] Fix build --- submodules/PeersNearbyUI/BUCK | 1 + 1 file changed, 1 insertion(+) diff --git a/submodules/PeersNearbyUI/BUCK b/submodules/PeersNearbyUI/BUCK index a6c565b2b6..b8e216e8a7 100644 --- a/submodules/PeersNearbyUI/BUCK +++ b/submodules/PeersNearbyUI/BUCK @@ -28,6 +28,7 @@ static_library( "//submodules/AppBundle:AppBundle", "//submodules/AnimatedStickerNode:AnimatedStickerNode", "//submodules/TelegramStringFormatting:TelegramStringFormatting", + "//submodules/TelegramNotices:TelegramNotices", ], frameworks = [ "$SDKROOT/System/Library/Frameworks/Foundation.framework", From 97fd1d10f02d0972031500433becf4a6e1299833 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 11 Feb 2020 11:12:36 +0400 Subject: [PATCH 16/30] Fix build --- submodules/StatisticsUI/BUCK | 1 - submodules/StatisticsUI/Sources/StatsController.swift | 2 -- 2 files changed, 3 deletions(-) diff --git a/submodules/StatisticsUI/BUCK b/submodules/StatisticsUI/BUCK index 911a9fff4a..693dcc8cbc 100644 --- a/submodules/StatisticsUI/BUCK +++ b/submodules/StatisticsUI/BUCK @@ -20,7 +20,6 @@ static_library( "//submodules/TelegramStringFormatting:TelegramStringFormatting", "//submodules/AlertUI:AlertUI", "//submodules/PresentationDataUtils:PresentationDataUtils", - "//submodules/TelegramNotices:TelegramNotices", "//submodules/MergeLists:MergeLists", "//submodules/Charts:Charts", ], diff --git a/submodules/StatisticsUI/Sources/StatsController.swift b/submodules/StatisticsUI/Sources/StatsController.swift index 440d29cf02..e24f2dc32b 100644 --- a/submodules/StatisticsUI/Sources/StatsController.swift +++ b/submodules/StatisticsUI/Sources/StatsController.swift @@ -13,8 +13,6 @@ import PresentationDataUtils import AccountContext import PresentationDataUtils import AppBundle -import ContextUI -import TelegramNotices private final class StatsArguments { init() { From fcdb2831da80645cf746f73c2d8eab807b05d5d8 Mon Sep 17 00:00:00 2001 From: overtake <> Date: Tue, 11 Feb 2020 18:41:00 +0400 Subject: [PATCH 17/30] no message --- .../TelegramCore/Sources/AuthTransfer.swift | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/submodules/TelegramCore/Sources/AuthTransfer.swift b/submodules/TelegramCore/Sources/AuthTransfer.swift index 793079c53e..e661aa715d 100644 --- a/submodules/TelegramCore/Sources/AuthTransfer.swift +++ b/submodules/TelegramCore/Sources/AuthTransfer.swift @@ -18,7 +18,7 @@ public enum ExportAuthTransferTokenResult { case displayToken(AuthTransferExportedToken) case changeAccountAndRetry(UnauthorizedAccount) case loggedIn - case passwordRequested + case passwordRequested(UnauthorizedAccount) } public func exportAuthTransferToken(accountManager: AccountManager, account: UnauthorizedAccount, otherAccountUserIds: [Int32], syncContacts: Bool) -> Signal { @@ -42,8 +42,6 @@ public func exportAuthTransferToken(accountManager: AccountManager, account: Una return nil } |> castError(ExportAuthTransferTokenError.self) - - return .single(nil) } } } else { @@ -52,7 +50,7 @@ public func exportAuthTransferToken(accountManager: AccountManager, account: Una } |> mapToSignal { result -> Signal in guard let result = result else { - return .single(.passwordRequested) + return .single(.passwordRequested(account)) } switch result { case let .loginToken(expires, token): @@ -66,7 +64,7 @@ public func exportAuthTransferToken(accountManager: AccountManager, account: Una |> map(Optional.init) |> `catch` { error -> Signal in if error.errorDescription == "SESSION_PASSWORD_NEEDED" { - return account.network.request(Api.functions.account.getPassword(), automaticFloodWait: false) + return updatedAccount.network.request(Api.functions.account.getPassword(), automaticFloodWait: false) |> mapError { error -> ExportAuthTransferTokenError in if error.errorDescription.hasPrefix("FLOOD_WAIT") { return .limitExceeded @@ -77,13 +75,11 @@ public func exportAuthTransferToken(accountManager: AccountManager, account: Una |> mapToSignal { result -> Signal in switch result { case let .password(password): - return account.postbox.transaction { transaction -> Api.auth.LoginToken? in - transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .passwordEntry(hint: password.hint ?? "", number: nil, code: nil, suggestReset: false, syncContacts: syncContacts))) + return updatedAccount.postbox.transaction { transaction -> Api.auth.LoginToken? in + transaction.setState(UnauthorizedAccountState(isTestingEnvironment: updatedAccount.testingEnvironment, masterDatacenterId: updatedAccount.masterDatacenterId, contents: .passwordEntry(hint: password.hint ?? "", number: nil, code: nil, suggestReset: false, syncContacts: syncContacts))) return nil } |> castError(ExportAuthTransferTokenError.self) - - return .single(nil) } } } else { @@ -91,8 +87,11 @@ public func exportAuthTransferToken(accountManager: AccountManager, account: Una } } |> mapToSignal { result -> Signal in + guard let result = result else { + return .single(.passwordRequested(updatedAccount)) + } switch result { - case let .loginTokenSuccess(authorization)?: + case let .loginTokenSuccess(authorization): switch authorization { case let .authorization(_, _, user): return updatedAccount.postbox.transaction { transaction -> Signal in From 580e1cebc5025a75f3a1923e4bcc09d0db529d7f Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 11 Feb 2020 15:42:35 +0100 Subject: [PATCH 18/30] Bug fixes and performance improvements --- .../Sources/AccountContext.swift | 2 +- .../Sources/CallListController.swift | 2 +- .../Sources/ContactsController.swift | 2 +- .../Sources/InstantPageControllerNode.swift | 2 +- .../Sources/ItemListPeerItem.swift | 8 +- .../Sources/SecureIdAuthController.swift | 2 +- .../Sources/AvatarGalleryController.swift | 31 +- .../AvatarGalleryItemFooterContentNode.swift | 2 +- .../Sources/PeerAvatarImageGalleryItem.swift | 1 + .../ChannelBannedMemberController.swift | 1 + .../Sources/ChannelBlacklistController.swift | 2 +- .../Sources/ChannelMembersController.swift | 4 +- .../ChannelPermissionsController.swift | 2 +- .../Sources/GroupInfoController.swift | 4 +- .../BlockedPeersController.swift | 2 +- ...ectivePrivacySettingsPeersController.swift | 2 +- .../Sources/ManagedChatListHoles.swift | 2 +- .../TelegramUI/ChatController.swift | 13 +- .../ChatRecentActionsControllerNode.swift | 4 +- .../TelegramUI/OpenAddContact.swift | 2 +- .../TelegramUI/TelegramUI/OpenUrl.swift | 4 +- .../PeerInfoScreenLabeledValueItem.swift | 160 +++++- .../ListItems/PeerInfoScreenMemberItem.swift | 111 +++- ...erInfoScreenSelectableBackgroundNode.swift | 27 +- .../PeerInfo/Panes/PeerInfoMembersPane.swift | 81 ++- .../TelegramUI/PeerInfo/PeerInfoData.swift | 167 +++++- .../PeerInfo/PeerInfoHeaderNode.swift | 32 +- .../TelegramUI/PeerInfo/PeerInfoMembers.swift | 146 ++++- .../PeerInfo/PeerInfoPaneContainerNode.swift | 22 +- .../TelegramUI/PeerInfo/PeerInfoScreen.swift | 499 +++++++++++++++++- .../PeerMediaCollectionController.swift | 2 +- .../TelegramUI/PollResultsController.swift | 2 +- .../TelegramUI/SharedAccountContext.swift | 12 +- .../TelegramUI/TextLinkHandling.swift | 2 +- ...annelMemberCategoriesContextsManager.swift | 171 ++++++ 35 files changed, 1393 insertions(+), 135 deletions(-) diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 56df2567ab..297b64c48d 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -442,7 +442,7 @@ public protocol SharedAccountContext: class { func openChatMessage(_ params: OpenChatMessageParams) -> Bool func messageFromPreloadedChatHistoryViewForLocation(id: MessageId, location: ChatHistoryLocationInput, account: Account, chatLocation: ChatLocation, tagMask: MessageTags?) -> Signal<(MessageIndex?, Bool), NoError> func makeOverlayAudioPlayerController(context: AccountContext, peerId: PeerId, type: MediaManagerPlayerType, initialMessageId: MessageId, initialOrder: MusicPlaybackSettingsOrder, parentNavigationController: NavigationController?) -> ViewController & OverlayAudioPlayerController - func makePeerInfoController(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool) -> ViewController? + func makePeerInfoController(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool, fromChat: Bool) -> ViewController? func makeDeviceContactInfoController(context: AccountContext, subject: DeviceContactInfoSubject, completed: (() -> Void)?, cancelled: (() -> Void)?) -> ViewController func makePeersNearbyController(context: AccountContext) -> ViewController func makeComposeController(context: AccountContext) -> ViewController diff --git a/submodules/CallListUI/Sources/CallListController.swift b/submodules/CallListUI/Sources/CallListController.swift index 1b87df0834..58e452733f 100644 --- a/submodules/CallListUI/Sources/CallListController.swift +++ b/submodules/CallListUI/Sources/CallListController.swift @@ -149,7 +149,7 @@ public final class CallListController: ViewController { let _ = (strongSelf.context.account.postbox.loadedPeerWithId(peerId) |> take(1) |> deliverOnMainQueue).start(next: { peer in - if let strongSelf = self, let controller = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .calls(messages: messages), avatarInitiallyExpanded: false) { + if let strongSelf = self, let controller = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .calls(messages: messages), avatarInitiallyExpanded: false, fromChat: false) { (strongSelf.navigationController as? NavigationController)?.pushViewController(controller) } }) diff --git a/submodules/ContactListUI/Sources/ContactsController.swift b/submodules/ContactListUI/Sources/ContactsController.swift index 087fdfa678..f9f2b5f05e 100644 --- a/submodules/ContactListUI/Sources/ContactsController.swift +++ b/submodules/ContactListUI/Sources/ContactsController.swift @@ -530,7 +530,7 @@ public class ContactsController: ViewController { return } if let peer = peer { - if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { (strongSelf.navigationController as? NavigationController)?.pushViewController(infoController) } } else { diff --git a/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift b/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift index e15556a53a..1360bc8ac7 100644 --- a/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift @@ -1180,7 +1180,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate { let _ = (strongSelf.context.account.postbox.loadedPeerWithId(peerId) |> deliverOnMainQueue).start(next: { peer in if let strongSelf = self { - if let controller = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let controller = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { strongSelf.getNavigationController()?.pushViewController(controller) } } diff --git a/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift b/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift index ce2f1c397a..8c8fcf6b0f 100644 --- a/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift +++ b/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift @@ -208,9 +208,9 @@ private final class LoadingShimmerNode: ASDisplayNode { public struct ItemListPeerItemEditing: Equatable { public var editable: Bool public var editing: Bool - public var revealed: Bool + public var revealed: Bool? - public init(editable: Bool, editing: Bool, revealed: Bool) { + public init(editable: Bool, editing: Bool, revealed: Bool?) { self.editable = editable self.editing = editing self.revealed = revealed @@ -1095,7 +1095,9 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo strongSelf.updateLayout(size: layout.contentSize, leftInset: params.leftInset, rightInset: params.rightInset) strongSelf.setRevealOptions((left: [], right: peerRevealOptions)) - strongSelf.setRevealOptionsOpened(item.editing.revealed, animated: animated) + if let revealed = item.editing.revealed { + strongSelf.setRevealOptionsOpened(revealed, animated: animated) + } } }) } diff --git a/submodules/PassportUI/Sources/SecureIdAuthController.swift b/submodules/PassportUI/Sources/SecureIdAuthController.swift index 66ca2894ea..1df3ddb5a0 100644 --- a/submodules/PassportUI/Sources/SecureIdAuthController.swift +++ b/submodules/PassportUI/Sources/SecureIdAuthController.swift @@ -330,7 +330,7 @@ public final class SecureIdAuthController: ViewController, StandalonePresentable guard let strongSelf = self else { return } - if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { (strongSelf.navigationController as? NavigationController)?.pushViewController(infoController) } }) diff --git a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift index 0692fc4ad2..0d243280fb 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift @@ -13,7 +13,7 @@ import GalleryUI public enum AvatarGalleryEntry: Equatable { case topImage([ImageRepresentationWithReference], GalleryItemIndexData?) - case image(TelegramMediaImageReference?, [ImageRepresentationWithReference], Peer, Int32, GalleryItemIndexData?, MessageId?) + case image(TelegramMediaImageReference?, [ImageRepresentationWithReference], Peer?, Int32, GalleryItemIndexData?, MessageId?) public var representations: [ImageRepresentationWithReference] { switch self { @@ -61,7 +61,7 @@ public final class AvatarGalleryControllerPresentationArguments { } } -private func initialAvatarGalleryEntries(peer: Peer) -> [AvatarGalleryEntry] { +public func initialAvatarGalleryEntries(peer: Peer) -> [AvatarGalleryEntry] { var initialEntries: [AvatarGalleryEntry] = [] if !peer.profileImageRepresentations.isEmpty, let peerReference = PeerReference(peer) { initialEntries.append(.topImage(peer.profileImageRepresentations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.avatar(peer: peerReference, resource: $0.resource)) }), nil)) @@ -96,6 +96,33 @@ public func fetchedAvatarGalleryEntries(account: Account, peer: Peer) -> Signal< ) } +public func fetchedAvatarGalleryEntries(account: Account, peer: Peer, firstEntry: AvatarGalleryEntry) -> Signal<[AvatarGalleryEntry], NoError> { + let initialEntries = [firstEntry] + return Signal<[AvatarGalleryEntry], NoError>.single(initialEntries) + |> then( + requestPeerPhotos(account: account, peerId: peer.id) + |> map { photos -> [AvatarGalleryEntry] in + var result: [AvatarGalleryEntry] = [] + let initialEntries = [firstEntry] + if photos.isEmpty { + result = initialEntries + } else { + var index: Int32 = 0 + for photo in photos { + let indexData = GalleryItemIndexData(position: index, totalCount: Int32(photos.count)) + if result.isEmpty, let first = initialEntries.first { + result.append(.image(photo.image.reference, first.representations, peer, photo.date, indexData, photo.messageId)) + } else { + result.append(.image(photo.image.reference, photo.image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.standalone(resource: $0.resource)) }), peer, photo.date, indexData, photo.messageId)) + } + index += 1 + } + } + return result + } + ) +} + public class AvatarGalleryController: ViewController, StandalonePresentableController { private var galleryNode: GalleryControllerNode { return self.displayNode as! GalleryControllerNode diff --git a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift index 7132c6cfa2..01cc3e6394 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift @@ -85,7 +85,7 @@ final class AvatarGalleryItemFooterContentNode: GalleryFooterContentNode { var dateText: String? switch entry { case let .image(_, _, peer, date, _, _): - nameText = peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) + nameText = peer?.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) ?? "" dateText = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: date) default: break diff --git a/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift b/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift index 4789f0c18f..428dcefb09 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift @@ -127,6 +127,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode { self?._ready.set(.single(Void())) } + self.imageNode.contentAnimations = .subsequentUpdates self.imageNode.view.contentMode = .scaleAspectFill self.imageNode.clipsToBounds = true diff --git a/submodules/PeerInfoUI/Sources/ChannelBannedMemberController.swift b/submodules/PeerInfoUI/Sources/ChannelBannedMemberController.swift index 4f9e7b9035..6e32a759d5 100644 --- a/submodules/PeerInfoUI/Sources/ChannelBannedMemberController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelBannedMemberController.swift @@ -757,6 +757,7 @@ public func channelBannedMemberController(context: AccountContext, peerId: PeerI } let controller = ItemListController(context: context, state: signal) + controller.navigationPresentation = .modal dismissImpl = { [weak controller] in controller?.dismiss() } diff --git a/submodules/PeerInfoUI/Sources/ChannelBlacklistController.swift b/submodules/PeerInfoUI/Sources/ChannelBlacklistController.swift index 0750e10edc..f2751edd1b 100644 --- a/submodules/PeerInfoUI/Sources/ChannelBlacklistController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelBlacklistController.swift @@ -366,7 +366,7 @@ public func channelBlacklistController(context: AccountContext, peerId: PeerId) } items.append(ActionSheetButtonItem(title: presentationData.strings.GroupRemoved_ViewUserInfo, action: { [weak actionSheet] in actionSheet?.dismissAnimated() - if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: participant.peer, mode: .generic, avatarInitiallyExpanded: false) { + if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: participant.peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { pushControllerImpl?(infoController) } })) diff --git a/submodules/PeerInfoUI/Sources/ChannelMembersController.swift b/submodules/PeerInfoUI/Sources/ChannelMembersController.swift index dc6dc37ef0..cb1c05e765 100644 --- a/submodules/PeerInfoUI/Sources/ChannelMembersController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelMembersController.swift @@ -450,7 +450,7 @@ public func channelMembersController(context: AccountContext, peerId: PeerId) -> } })) }, openPeer: { peer in - if let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { pushControllerImpl?(controller) } }, inviteViaLink: { @@ -502,7 +502,7 @@ public func channelMembersController(context: AccountContext, peerId: PeerId) -> return state.withUpdatedSearchingMembers(false) } }, openPeer: { peer, _ in - if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { pushControllerImpl?(infoController) } }, pushController: { c in diff --git a/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift b/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift index 85d9837112..f1813127e9 100644 --- a/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift @@ -666,7 +666,7 @@ public func channelPermissionsController(context: AccountContext, peerId origina }), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) }) }, openPeerInfo: { peer in - if let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { pushControllerImpl?(controller) } }, openKicked: { diff --git a/submodules/PeerInfoUI/Sources/GroupInfoController.swift b/submodules/PeerInfoUI/Sources/GroupInfoController.swift index 8e3288a0aa..367096905c 100644 --- a/submodules/PeerInfoUI/Sources/GroupInfoController.swift +++ b/submodules/PeerInfoUI/Sources/GroupInfoController.swift @@ -599,7 +599,7 @@ private enum GroupInfoEntry: ItemListNodeEntry { })) } return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer, presence: presence, text: .presence, label: label == nil ? .none : .text(label!, .standard), editing: editing, revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: enabled, selectable: selectable, sectionId: self.section, action: { - if let infoController = arguments.context.sharedContext.makePeerInfoController(context: arguments.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false), selectable { + if let infoController = arguments.context.sharedContext.makePeerInfoController(context: arguments.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false), selectable { arguments.pushController(infoController) } }, setPeerIdWithRevealedOptions: { peerId, fromPeerId in @@ -2342,7 +2342,7 @@ public func groupInfoController(context: AccountContext, peerId originalPeerId: return state.withUpdatedSearchingMembers(false) } }, openPeer: { peer, _ in - if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { arguments.pushController(infoController) } }, pushController: { c in diff --git a/submodules/SettingsUI/Sources/Privacy and Security/BlockedPeersController.swift b/submodules/SettingsUI/Sources/Privacy and Security/BlockedPeersController.swift index b59ad0429d..8af1364bf1 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/BlockedPeersController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/BlockedPeersController.swift @@ -259,7 +259,7 @@ public func blockedPeersController(context: AccountContext, blockedPeersContext: } })) }, openPeer: { peer in - if let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { pushControllerImpl?(controller) } }) diff --git a/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsPeersController.swift b/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsPeersController.swift index 130a649729..47875e24b9 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsPeersController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsPeersController.swift @@ -341,7 +341,7 @@ public func selectivePrivacyPeersController(context: AccountContext, title: Stri return transaction.getPeer(peerId) } |> deliverOnMainQueue).start(next: { peer in - guard let peer = peer, let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) else { + guard let peer = peer, let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) else { return } pushControllerImpl?(controller) diff --git a/submodules/TelegramCore/Sources/ManagedChatListHoles.swift b/submodules/TelegramCore/Sources/ManagedChatListHoles.swift index 4783619e83..ce36e13ef9 100644 --- a/submodules/TelegramCore/Sources/ManagedChatListHoles.swift +++ b/submodules/TelegramCore/Sources/ManagedChatListHoles.swift @@ -59,7 +59,7 @@ func managedChatListHoles(network: Network, postbox: Postbox, accountPeerId: Pee let disposable = combineLatest(postbox.chatListHolesView(), topRootHole).start(next: { view, topRootHoleView in var additionalLatestHole: ChatListHole? if let topRootHole = topRootHoleView.views[topRootHoleKey] as? AllChatListHolesView { - additionalLatestHole = topRootHole.latestHole + //additionalLatestHole = topRootHole.latestHole } let (removed, added, addedAdditionalLatestHole) = state.with { state in diff --git a/submodules/TelegramUI/TelegramUI/ChatController.swift b/submodules/TelegramUI/TelegramUI/ChatController.swift index 531666bdfa..6883e15cab 100644 --- a/submodules/TelegramUI/TelegramUI/ChatController.swift +++ b/submodules/TelegramUI/TelegramUI/ChatController.swift @@ -309,6 +309,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G private var isDismissed = false private var focusOnSearchAfterAppearance: Bool = false + + private let keepPeerInfoScreenDataHotDisposable = MetaDisposable() public override var customData: Any? { return self.chatLocation @@ -2513,6 +2515,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.reportIrrelvantGeoDisposable?.dispose() self.reminderActivity?.invalidate() self.updateSlowmodeStatusDisposable.dispose() + self.keepPeerInfoScreenDataHotDisposable.dispose() } public func updatePresentationMode(_ mode: ChatControllerPresentationMode) { @@ -4731,6 +4734,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { })]), in: .window(.root)) })) + + if case let .peer(peerId) = self.chatLocation { + self.keepPeerInfoScreenDataHotDisposable.set(keepPeerInfoScreenDataHot(context: self.context, peerId: peerId).start()) + } } if self.focusOnSearchAfterAppearance { @@ -5356,7 +5363,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if peer.smallProfileImage == nil { expandAvatar = false } - if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: expandAvatar) { + if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: expandAvatar, fromChat: true) { strongSelf.effectiveNavigationController?.pushViewController(infoController) } } @@ -7113,7 +7120,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } self.navigationActionDisposable.set((peerSignal |> take(1) |> deliverOnMainQueue).start(next: { [weak self] peer in if let strongSelf = self, let peer = peer { - if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: expandAvatar) { + if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: expandAvatar, fromChat: true) { strongSelf.effectiveNavigationController?.pushViewController(infoController) } } @@ -7530,7 +7537,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G |> take(1) |> deliverOnMainQueue).start(next: { [weak self] peer in if let strongSelf = self, peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil { - if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { strongSelf.effectiveNavigationController?.pushViewController(infoController) } } diff --git a/submodules/TelegramUI/TelegramUI/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/TelegramUI/ChatRecentActionsControllerNode.swift index c3b087ae3b..521def128a 100644 --- a/submodules/TelegramUI/TelegramUI/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatRecentActionsControllerNode.swift @@ -659,7 +659,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { if peer is TelegramChannel, let navigationController = strongSelf.getNavigationController() { strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id), animated: true)) } else { - if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { strongSelf.pushController(infoController) } } @@ -681,7 +681,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { |> deliverOnMainQueue).start(next: { [weak self] peer in if let strongSelf = self { if let peer = peer { - if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { strongSelf.pushController(infoController) } } diff --git a/submodules/TelegramUI/TelegramUI/OpenAddContact.swift b/submodules/TelegramUI/TelegramUI/OpenAddContact.swift index 98c49ce1ba..dec7f34047 100644 --- a/submodules/TelegramUI/TelegramUI/OpenAddContact.swift +++ b/submodules/TelegramUI/TelegramUI/OpenAddContact.swift @@ -18,7 +18,7 @@ func openAddContactImpl(context: AccountContext, firstName: String = "", lastNam let contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: firstName, lastName: lastName, phoneNumbers: [DeviceContactPhoneNumberData(label: label, value: phoneNumber)]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "") present(deviceContactInfoController(context: context, subject: .create(peer: nil, contactData: contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in if let peer = peer { - if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { pushController(infoController) } } else { diff --git a/submodules/TelegramUI/TelegramUI/OpenUrl.swift b/submodules/TelegramUI/TelegramUI/OpenUrl.swift index 11f7c094e2..37e7801e90 100644 --- a/submodules/TelegramUI/TelegramUI/OpenUrl.swift +++ b/submodules/TelegramUI/TelegramUI/OpenUrl.swift @@ -209,7 +209,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur case .info: let _ = (context.account.postbox.loadedPeerWithId(peerId) |> deliverOnMainQueue).start(next: { peer in - if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { context.sharedContext.applicationBindings.dismissNativeController() navigationController?.pushViewController(infoController) } @@ -491,7 +491,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur return transaction.getPeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: idValue)) } |> deliverOnMainQueue).start(next: { peer in - if let peer = peer, let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let peer = peer, let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { navigationController?.pushViewController(controller) } }) diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenLabeledValueItem.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenLabeledValueItem.swift index d7f382389f..33a0ebfdac 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenLabeledValueItem.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenLabeledValueItem.swift @@ -1,6 +1,8 @@ import AsyncDisplayKit import Display import TelegramPresentationData +import AccountContext +import TextFormat enum PeerInfoScreenLabeledValueTextColor { case primary @@ -9,7 +11,7 @@ enum PeerInfoScreenLabeledValueTextColor { enum PeerInfoScreenLabeledValueTextBehavior: Equatable { case singleLine - case multiLine(maxLines: Int) + case multiLine(maxLines: Int, enabledEntities: EnabledEntityTypes) } final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem { @@ -19,14 +21,27 @@ final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem { let textColor: PeerInfoScreenLabeledValueTextColor let textBehavior: PeerInfoScreenLabeledValueTextBehavior let action: (() -> Void)? + let longTapAction: ((ASDisplayNode) -> Void)? + let linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)? - init(id: AnyHashable, label: String, text: String, textColor: PeerInfoScreenLabeledValueTextColor = .primary, textBehavior: PeerInfoScreenLabeledValueTextBehavior = .singleLine, action: (() -> Void)?) { + init( + id: AnyHashable, + label: String, + text: String, + textColor: PeerInfoScreenLabeledValueTextColor = .primary, + textBehavior: PeerInfoScreenLabeledValueTextBehavior = .singleLine, + action: (() -> Void)?, + longTapAction: ((ASDisplayNode) -> Void)? = nil, + linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)? = nil + ) { self.id = id self.label = label self.text = text self.textColor = textColor self.textBehavior = textBehavior self.action = action + self.longTapAction = longTapAction + self.linkItemAction = linkItemAction } func node() -> PeerInfoScreenItemNode { @@ -40,11 +55,15 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode { private let textNode: ImmediateTextNode private let bottomSeparatorNode: ASDisplayNode + private var linkHighlightingNode: LinkHighlightingNode? + private var item: PeerInfoScreenLabeledValueItem? + private var theme: PresentationTheme? override init() { var bringToFrontForHighlightImpl: (() -> Void)? self.selectionNode = PeerInfoScreenSelectableBackgroundNode(bringToFrontForHighlight: { bringToFrontForHighlightImpl?() }) + self.selectionNode.isUserInteractionEnabled = false self.labelNode = ImmediateTextNode() self.labelNode.displaysAsynchronously = false @@ -69,12 +88,65 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode { self.addSubnode(self.textNode) } + override func didLoad() { + super.didLoad() + + let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:))) + recognizer.tapActionAtPoint = { [weak self] point in + guard let strongSelf = self, let item = strongSelf.item else { + return .keepWithSingleTap + } + if let _ = strongSelf.linkItemAtPoint(point) { + return .waitForSingleTap + } + if item.longTapAction != nil { + return .waitForSingleTap + } + if item.action != nil { + return .keepWithSingleTap + } + return .fail + } + recognizer.highlight = { [weak self] point in + guard let strongSelf = self else { + return + } + strongSelf.updateTouchesAtPoint(point) + } + self.view.addGestureRecognizer(recognizer) + } + + @objc private func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { + switch recognizer.state { + case .ended: + if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation { + switch gesture { + case .tap, .longTap: + if let item = self.item { + if let linkItem = self.linkItemAtPoint(location) { + item.linkItemAction?(gesture == .tap ? .tap : .longTap, linkItem) + } else if case .longTap = gesture { + item.longTapAction?(self) + } else if case .tap = gesture { + item.action?() + } + } + default: + break + } + } + default: + break + } + } + override func update(width: CGFloat, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { guard let item = item as? PeerInfoScreenLabeledValueItem else { return 10.0 } self.item = item + self.theme = presentationData.theme self.selectionNode.pressed = item.action @@ -95,10 +167,25 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode { switch item.textBehavior { case .singleLine: self.textNode.maximumNumberOfLines = 1 - case let .multiLine(maxLines): + self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(17.0), textColor: textColorValue) + case let .multiLine(maxLines, enabledEntities): self.textNode.maximumNumberOfLines = maxLines + if enabledEntities.isEmpty { + self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(17.0), textColor: textColorValue) + } else { + let fontSize: CGFloat = 17.0 + + var baseFont = Font.regular(fontSize) + var linkFont = baseFont + var boldFont = Font.medium(fontSize) + var italicFont = Font.italic(fontSize) + var boldItalicFont = Font.semiboldItalic(fontSize) + let titleFixedFont = Font.monospace(fontSize) + + let entities = generateTextEntities(item.text, enabledTypes: enabledEntities) + self.textNode.attributedText = stringWithAppliedEntities(item.text, entities: entities, baseColor: textColorValue, linkColor: presentationData.theme.list.itemAccentColor, baseFont: baseFont, linkFont: linkFont, boldFont: boldFont, italicFont: italicFont, boldItalicFont: boldItalicFont, fixedFont: titleFixedFont, blockQuoteFont: baseFont) + } } - self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(17.0), textColor: textColorValue) let labelSize = self.labelNode.updateLayout(CGSize(width: width - sideInset * 2.0, height: .greatestFiniteMagnitude)) let textSize = self.textNode.updateLayout(CGSize(width: width - sideInset * 2.0, height: .greatestFiniteMagnitude)) @@ -120,4 +207,69 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode { return height } + + private func linkItemAtPoint(_ point: CGPoint) -> TextLinkItem? { + let textNodeFrame = self.textNode.frame + if let (_, attributes) = self.textNode.attributesAtPoint(CGPoint(x: point.x - textNodeFrame.minX, y: point.y - textNodeFrame.minY)) { + if let url = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String { + return .url(url) + } else if let peerName = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.PeerTextMention)] as? String { + return .mention(peerName) + } else if let hashtag = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Hashtag)] as? TelegramHashtag { + return .hashtag(hashtag.peerName, hashtag.hashtag) + } else { + return nil + } + } + return nil + } + + private func updateTouchesAtPoint(_ point: CGPoint?) { + guard let item = self.item, let theme = self.theme else { + return + } + var rects: [CGRect]? + if let point = point { + let textNodeFrame = self.textNode.frame + if let (index, attributes) = self.textNode.attributesAtPoint(CGPoint(x: point.x - textNodeFrame.minX, y: point.y - textNodeFrame.minY)) { + let possibleNames: [String] = [ + TelegramTextAttributes.URL, + TelegramTextAttributes.PeerMention, + TelegramTextAttributes.PeerTextMention, + TelegramTextAttributes.BotCommand, + TelegramTextAttributes.Hashtag + ] + for name in possibleNames { + if let _ = attributes[NSAttributedString.Key(rawValue: name)] { + rects = self.textNode.attributeRects(name: name, at: index) + break + } + } + } + } + + if let rects = rects { + let linkHighlightingNode: LinkHighlightingNode + if let current = self.linkHighlightingNode { + linkHighlightingNode = current + } else { + linkHighlightingNode = LinkHighlightingNode(color: theme.list.itemAccentColor.withAlphaComponent(0.5)) + self.linkHighlightingNode = linkHighlightingNode + self.insertSubnode(linkHighlightingNode, belowSubnode: self.textNode) + } + linkHighlightingNode.frame = self.textNode.frame + linkHighlightingNode.updateRects(rects) + } else if let linkHighlightingNode = self.linkHighlightingNode { + self.linkHighlightingNode = nil + linkHighlightingNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.18, removeOnCompletion: false, completion: { [weak linkHighlightingNode] _ in + linkHighlightingNode?.removeFromSupernode() + }) + } + + if point != nil && rects == nil && item.action != nil { + self.selectionNode.updateIsHighlighted(true) + } else { + self.selectionNode.updateIsHighlighted(false) + } + } } diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift index 246861f33d..e593df1e4e 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenMemberItem.swift @@ -11,24 +11,31 @@ import SyncCore import TelegramCore import ItemListUI +enum PeerInfoScreenMemberItemAction { + case open + case promote + case restrict + case remove +} + final class PeerInfoScreenMemberItem: PeerInfoScreenItem { let id: AnyHashable let context: AccountContext - let peer: Peer - let presence: TelegramUserPresence? - let action: (() -> Void)? + let enclosingPeer: Peer + let member: PeerInfoMember + let action: ((PeerInfoScreenMemberItemAction) -> Void)? init( id: AnyHashable, context: AccountContext, - peer: Peer, - presence: TelegramUserPresence?, - action: (() -> Void)? + enclosingPeer: Peer, + member: PeerInfoMember, + action: ((PeerInfoScreenMemberItemAction) -> Void)? ) { self.id = id self.context = context - self.peer = peer - self.presence = presence + self.enclosingPeer = enclosingPeer + self.member = member self.action = action } @@ -47,6 +54,7 @@ private final class PeerInfoScreenMemberItemNode: PeerInfoScreenItemNode { override init() { var bringToFrontForHighlightImpl: (() -> Void)? self.selectionNode = PeerInfoScreenSelectableBackgroundNode(bringToFrontForHighlight: { bringToFrontForHighlightImpl?() }) + self.selectionNode.isUserInteractionEnabled = false self.bottomSeparatorNode = ASDisplayNode() self.bottomSeparatorNode.isLayerBacked = true @@ -61,6 +69,40 @@ private final class PeerInfoScreenMemberItemNode: PeerInfoScreenItemNode { self.addSubnode(self.selectionNode) } + override func didLoad() { + super.didLoad() + + let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:))) + recognizer.tapActionAtPoint = { [weak self] point in + return .keepWithSingleTap + } + recognizer.highlight = { [weak self] point in + guard let strongSelf = self else { + return + } + strongSelf.updateTouchesAtPoint(point) + } + self.view.addGestureRecognizer(recognizer) + } + + @objc private func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { + switch recognizer.state { + case .ended: + if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation { + switch gesture { + case .tap: + if let item = self.item { + item.action?(.open) + } + default: + break + } + } + default: + break + } + } + override func update(width: CGFloat, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat { guard let item = item as? PeerInfoScreenMemberItem else { return 10.0 @@ -68,13 +110,50 @@ private final class PeerInfoScreenMemberItemNode: PeerInfoScreenItemNode { self.item = item - self.selectionNode.pressed = item.action + self.selectionNode.pressed = item.action.flatMap { action in + return { + action(.open) + } + } let sideInset: CGFloat = 16.0 self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor - let peerItem = ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: item.context, peer: item.peer, height: .peerList, presence: item.presence, text: .presence, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: false, sectionId: 0, action: nil, setPeerIdWithRevealedOptions: { lhs, rhs in + let label: String? + if let rank = item.member.rank { + label = rank + } else { + switch item.member.role { + case .creator: + label = presentationData.strings.GroupInfo_LabelOwner + case .admin: + label = presentationData.strings.GroupInfo_LabelAdmin + case .member: + label = nil + } + } + + let actions = availableActionsForMemberOfPeer(accountPeerId: item.context.account.peerId, peer: item.enclosingPeer, member: item.member) + + var options: [ItemListPeerItemRevealOption] = [] + if actions.contains(.promote) && item.enclosingPeer is TelegramChannel { + options.append(ItemListPeerItemRevealOption(type: .neutral, title: presentationData.strings.GroupInfo_ActionPromote, action: { + item.action?(.promote) + })) + } + if actions.contains(.restrict) { + if item.enclosingPeer is TelegramChannel { + options.append(ItemListPeerItemRevealOption(type: .warning, title: presentationData.strings.GroupInfo_ActionRestrict, action: { + item.action?(.restrict) + })) + } + options.append(ItemListPeerItemRevealOption(type: .destructive, title: presentationData.strings.Common_Delete, action: { + item.action?(.remove) + })) + } + + let peerItem = ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: item.context, peer: item.member.peer, height: .peerList, presence: item.member.presence, text: .presence, label: label == nil ? .none : .text(label!, .standard), editing: ItemListPeerItemEditing(editable: !options.isEmpty, editing: false, revealed: nil), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, selectable: false, sectionId: 0, action: nil, setPeerIdWithRevealedOptions: { lhs, rhs in }, removePeer: { _ in @@ -103,7 +182,6 @@ private final class PeerInfoScreenMemberItemNode: PeerInfoScreenItemNode { apply().1(ListViewItemApply(isOnScreen: true)) }) itemNode = itemNodeValue as! ItemListPeerItemNode - itemNode.isUserInteractionEnabled = false self.itemNode = itemNode self.addSubnode(itemNode) } @@ -121,4 +199,15 @@ private final class PeerInfoScreenMemberItemNode: PeerInfoScreenItemNode { return height } + + private func updateTouchesAtPoint(_ point: CGPoint?) { + guard let item = self.item else { + return + } + if point != nil && item.context.account.peerId != item.member.id { + self.selectionNode.updateIsHighlighted(true) + } else { + self.selectionNode.updateIsHighlighted(false) + } + } } diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenSelectableBackgroundNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenSelectableBackgroundNode.swift index 08b0c6e17a..a630c37287 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenSelectableBackgroundNode.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/ListItems/PeerInfoScreenSelectableBackgroundNode.swift @@ -8,6 +8,8 @@ final class PeerInfoScreenSelectableBackgroundNode: ASDisplayNode { let bringToFrontForHighlight: () -> Void + private var isHighlighted: Bool = false + var pressed: (() -> Void)? { didSet { self.buttonNode.isUserInteractionEnabled = self.pressed != nil @@ -30,16 +32,7 @@ final class PeerInfoScreenSelectableBackgroundNode: ASDisplayNode { self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside) self.buttonNode.highligthedChanged = { [weak self] highlighted in - if let strongSelf = self { - if highlighted { - strongSelf.bringToFrontForHighlight() - strongSelf.backgroundNode.layer.removeAnimation(forKey: "opacity") - strongSelf.backgroundNode.alpha = 1.0 - } else { - strongSelf.backgroundNode.alpha = 0.0 - strongSelf.backgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25) - } - } + self?.updateIsHighlighted(highlighted) } } @@ -47,6 +40,20 @@ final class PeerInfoScreenSelectableBackgroundNode: ASDisplayNode { self.pressed?() } + func updateIsHighlighted(_ isHighlighted: Bool) { + if self.isHighlighted != isHighlighted { + self.isHighlighted = isHighlighted + if isHighlighted { + self.bringToFrontForHighlight() + self.backgroundNode.layer.removeAnimation(forKey: "opacity") + self.backgroundNode.alpha = 1.0 + } else { + self.backgroundNode.alpha = 0.0 + self.backgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25) + } + } + } + func update(size: CGSize, theme: PresentationTheme, transition: ContainedViewLayoutTransition) { self.backgroundNode.backgroundColor = theme.list.itemHighlightedBackgroundColor transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size)) diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoMembersPane.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoMembersPane.swift index 243a95f6a9..d555c930a0 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoMembersPane.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoMembersPane.swift @@ -19,6 +19,13 @@ private struct PeerMembersListTransaction { let updates: [ListViewUpdateItem] } +enum PeerMembersListAction { + case open + case promote + case restrict + case remove +} + private struct PeerMembersListEntry: Comparable, Identifiable { var index: Int var member: PeerInfoMember @@ -35,10 +42,43 @@ private struct PeerMembersListEntry: Comparable, Identifiable { return lhs.index < rhs.index } - func item(context: AccountContext, presentationData: PresentationData, openPeer: @escaping (Peer) -> Void) -> ListViewItem { + func item(context: AccountContext, presentationData: PresentationData, enclosingPeer: Peer, action: @escaping (PeerInfoMember, PeerMembersListAction) -> Void) -> ListViewItem { let member = self.member - return ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: context, peer: member.peer, presence: nil, text: .none, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: nil, enabled: true, selectable: true, sectionId: 0, action: { - openPeer(member.peer) + let label: String? + if let rank = member.rank { + label = rank + } else { + switch member.role { + case .creator: + label = presentationData.strings.GroupInfo_LabelOwner + case .admin: + label = presentationData.strings.GroupInfo_LabelAdmin + case .member: + label = nil + } + } + + let actions = availableActionsForMemberOfPeer(accountPeerId: context.account.peerId, peer: enclosingPeer, member: member) + + var options: [ItemListPeerItemRevealOption] = [] + if actions.contains(.promote) && enclosingPeer is TelegramChannel{ + options.append(ItemListPeerItemRevealOption(type: .neutral, title: presentationData.strings.GroupInfo_ActionPromote, action: { + action(member, .promote) + })) + } + if actions.contains(.restrict) { + if enclosingPeer is TelegramChannel { + options.append(ItemListPeerItemRevealOption(type: .warning, title: presentationData.strings.GroupInfo_ActionRestrict, action: { + action(member, .restrict) + })) + } + options.append(ItemListPeerItemRevealOption(type: .destructive, title: presentationData.strings.Common_Delete, action: { + action(member, .remove) + })) + } + + return ItemListPeerItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, context: context, peer: member.peer, presence: member.presence, text: .presence, label: label == nil ? .none : .text(label!, .standard), editing: ItemListPeerItemEditing(editable: !options.isEmpty, editing: false, revealed: false), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, selectable: member.id != context.account.peerId, sectionId: 0, action: { + action(member, .open) }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, contextAction: nil/*{ node, gesture in @@ -47,12 +87,12 @@ private struct PeerMembersListEntry: Comparable, Identifiable { } } -private func preparedTransition(from fromEntries: [PeerMembersListEntry], to toEntries: [PeerMembersListEntry], context: AccountContext, presentationData: PresentationData, openPeer: @escaping (Peer) -> Void) -> PeerMembersListTransaction { +private func preparedTransition(from fromEntries: [PeerMembersListEntry], to toEntries: [PeerMembersListEntry], context: AccountContext, presentationData: PresentationData, enclosingPeer: Peer, action: @escaping (PeerInfoMember, PeerMembersListAction) -> Void) -> PeerMembersListTransaction { 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(context: context, presentationData: presentationData, openPeer: openPeer), directionHint: nil) } - let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, openPeer: openPeer), directionHint: nil) } + let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enclosingPeer: enclosingPeer, action: action), directionHint: nil) } + let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enclosingPeer: enclosingPeer, action: action), directionHint: nil) } return PeerMembersListTransaction(deletions: deletions, insertions: insertions, updates: updates) } @@ -60,9 +100,11 @@ private func preparedTransition(from fromEntries: [PeerMembersListEntry], to toE final class PeerInfoMembersPaneNode: ASDisplayNode, PeerInfoPaneNode { private let context: AccountContext private let membersContext: PeerInfoMembersContext + private let action: (PeerInfoMember, PeerMembersListAction) -> Void private let listNode: ListView private var currentEntries: [PeerMembersListEntry] = [] + private var enclosingPeer: Peer? private var currentState: PeerInfoMembersState? private var canLoadMore: Bool = false private var enqueuedTransactions: [PeerMembersListTransaction] = [] @@ -77,9 +119,10 @@ final class PeerInfoMembersPaneNode: ASDisplayNode, PeerInfoPaneNode { private var disposable: Disposable? - init(context: AccountContext, membersContext: PeerInfoMembersContext) { + init(context: AccountContext, peerId: PeerId, membersContext: PeerInfoMembersContext, action: @escaping (PeerInfoMember, PeerMembersListAction) -> Void) { self.context = context self.membersContext = membersContext + self.action = action self.listNode = ListView() @@ -88,14 +131,19 @@ final class PeerInfoMembersPaneNode: ASDisplayNode, PeerInfoPaneNode { self.listNode.preloadPages = true self.addSubnode(self.listNode) - self.disposable = (membersContext.state - |> deliverOnMainQueue).start(next: { [weak self] state in - guard let strongSelf = self else { + self.disposable = (combineLatest(queue: .mainQueue(), + membersContext.state, + context.account.postbox.combinedView(keys: [.basicPeer(peerId)]) + ) + |> deliverOnMainQueue).start(next: { [weak self] state, combinedView in + guard let strongSelf = self, let basicPeerView = combinedView.views[.basicPeer(peerId)] as? BasicPeerView, let enclosingPeer = basicPeerView.peer else { return } + + strongSelf.enclosingPeer = enclosingPeer strongSelf.currentState = state if let (_, _, presentationData) = strongSelf.currentParams { - strongSelf.updateState(state: state, presentationData: presentationData) + strongSelf.updateState(enclosingPeer: enclosingPeer, state: state, presentationData: presentationData) } }) @@ -132,19 +180,20 @@ final class PeerInfoMembersPaneNode: ASDisplayNode, PeerInfoPaneNode { self.listNode.scrollEnabled = !isScrollingLockedAtTop - if isFirstLayout, let state = self.currentState { - self.updateState(state: state, presentationData: presentationData) + if isFirstLayout, let enclosingPeer = self.enclosingPeer, let state = self.currentState { + self.updateState(enclosingPeer: enclosingPeer, state: state, presentationData: presentationData) } } - private func updateState(state: PeerInfoMembersState, presentationData: PresentationData) { + private func updateState(enclosingPeer: Peer, state: PeerInfoMembersState, presentationData: PresentationData) { var entries: [PeerMembersListEntry] = [] for member in state.members { entries.append(PeerMembersListEntry(index: entries.count, member: member)) } - let transaction = preparedTransition(from: self.currentEntries, to: entries, context: self.context, presentationData: presentationData, openPeer: { [weak self] peer in - + let transaction = preparedTransition(from: self.currentEntries, to: entries, context: self.context, presentationData: presentationData, enclosingPeer: enclosingPeer, action: { [weak self] member, action in + self?.action(member, action) }) + self.enclosingPeer = enclosingPeer self.currentEntries = entries self.enqueuedTransactions.append(transaction) self.dequeueTransaction() diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift index 09bbdafd90..a2a81d49fe 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift @@ -8,6 +8,7 @@ import AccountContext import PeerPresenceStatusManager import TelegramStringFormatting import TelegramPresentationData +import PeerAvatarGalleryUI enum PeerInfoUpdatingAvatar { case none @@ -91,17 +92,17 @@ final class PeerInfoScreenData { } } -enum PeerInfoScreenInputUserKind { +private enum PeerInfoScreenInputUserKind { case user case bot case support } -enum PeerInfoScreenInputData: Equatable { +private enum PeerInfoScreenInputData: Equatable { case none case user(userId: PeerId, secretChatId: PeerId?, kind: PeerInfoScreenInputUserKind) case channel - case group(isSupergroup: Bool, membersContext: PeerInfoMembersContext) + case group(groupId: PeerId) } func peerInfoAvailableMediaPanes(context: AccountContext, peerId: PeerId) -> Signal<[PeerInfoPaneKey], NoError> { @@ -148,11 +149,20 @@ struct PeerInfoStatusData: Equatable { } enum PeerInfoMembersData: Equatable { - case shortList([PeerInfoMember]) + case shortList(membersContext: PeerInfoMembersContext, members: [PeerInfoMember]) case longList(PeerInfoMembersContext) + + var membersContext: PeerInfoMembersContext { + switch self { + case let .shortList(shortList): + return shortList.membersContext + case let .longList(membersContext): + return membersContext + } + } } -func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) -> Signal { +private func peerInfoScreenInputData(context: AccountContext, peerId: PeerId) -> Signal { return context.account.postbox.combinedView(keys: [.basicPeer(peerId)]) |> map { view -> PeerInfoScreenInputData in guard let peer = (view.views[.basicPeer(peerId)] as? BasicPeerView)?.peer else { @@ -170,17 +180,68 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen return .user(userId: user.id, secretChatId: nil, kind: kind) } else if let channel = peer as? TelegramChannel { if case .group = channel.info { - return .group(isSupergroup: true, membersContext: PeerInfoMembersContext(context: context, peerId: channel.id)) + return .group(groupId: channel.id) } else { return .channel } } else if let group = peer as? TelegramGroup { - return .group(isSupergroup: false, membersContext: PeerInfoMembersContext(context: context, peerId: group.id)) + return .group(groupId: group.id) } else { return .none } } |> distinctUntilChanged +} + +private func peerInfoProfilePhotos(context: AccountContext, peerId: PeerId) -> Signal { + return context.account.postbox.combinedView(keys: [.basicPeer(peerId)]) + |> map { view -> AvatarGalleryEntry? in + guard let peer = (view.views[.basicPeer(peerId)] as? BasicPeerView)?.peer else { + return nil + } + return initialAvatarGalleryEntries(peer: peer).first + } + |> distinctUntilChanged + |> mapToSignal { firstEntry -> Signal<[AvatarGalleryEntry], NoError> in + if let firstEntry = firstEntry { + return context.account.postbox.loadedPeerWithId(peerId) + |> mapToSignal { peer -> Signal<[AvatarGalleryEntry], NoError>in + return fetchedAvatarGalleryEntries(account: context.account, peer: peer, firstEntry: firstEntry) + } + } else { + return .single([]) + } + } + |> map { items -> Any in + return items + } +} + +func peerInfoProfilePhotosWithCache(context: AccountContext, peerId: PeerId) -> Signal<[AvatarGalleryEntry], NoError> { + return context.peerChannelMemberCategoriesContextsManager.profilePhotos(postbox: context.account.postbox, network: context.account.network, peerId: peerId, fetch: peerInfoProfilePhotos(context: context, peerId: peerId)) + |> map { items -> [AvatarGalleryEntry] in + return items as? [AvatarGalleryEntry] ?? [] + } +} + +func keepPeerInfoScreenDataHot(context: AccountContext, peerId: PeerId) -> Signal { + return peerInfoScreenInputData(context: context, peerId: peerId) + |> mapToSignal { inputData -> Signal in + switch inputData { + case .none: + return .complete() + case .user, .channel, .group: + return combineLatest( + context.peerChannelMemberCategoriesContextsManager.profileData(postbox: context.account.postbox, network: context.account.network, peerId: peerId, customData: peerInfoAvailableMediaPanes(context: context, peerId: peerId) |> ignoreValues), + context.peerChannelMemberCategoriesContextsManager.profilePhotos(postbox: context.account.postbox, network: context.account.network, peerId: peerId, fetch: peerInfoProfilePhotos(context: context, peerId: peerId)) |> ignoreValues + ) + |> ignoreValues + } + } +} + +func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) -> Signal { + return peerInfoScreenInputData(context: context, peerId: peerId) |> mapToSignal { inputData -> Signal in switch inputData { case .none: @@ -382,10 +443,10 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen members: nil ) } - case let .group(_, membersContext): - let status = context.account.viewTracker.peerView(peerId, updateData: false) + case let .group(groupId): + let status = context.account.viewTracker.peerView(groupId, updateData: false) |> map { peerView -> PeerInfoStatusData? in - guard let channel = peerView.peers[peerId] as? TelegramChannel else { + guard let channel = peerView.peers[groupId] as? TelegramChannel else { return PeerInfoStatusData(text: strings.Channel_Status, isActivity: false) } if let cachedChannelData = peerView.cachedData as? CachedChannelData, let memberCount = cachedChannelData.participantsSummary.memberCount, memberCount != 0 { @@ -396,12 +457,14 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen } |> distinctUntilChanged + let membersContext = PeerInfoMembersContext(context: context, peerId: groupId) + let membersData: Signal = membersContext.state |> map { state -> PeerInfoMembersData? in if state.members.count > 5 { return .longList(membersContext) } else { - return .shortList(state.members) + return .shortList(membersContext: membersContext, members: state.members) } } |> distinctUntilChanged @@ -409,9 +472,9 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen let globalNotificationsKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.globalNotifications])) var combinedKeys: [PostboxViewKey] = [] combinedKeys.append(globalNotificationsKey) - return combineLatest( - context.account.viewTracker.peerView(peerId, updateData: true), - peerInfoAvailableMediaPanes(context: context, peerId: peerId), + return combineLatest(queue: .mainQueue(), + context.account.viewTracker.peerView(groupId, updateData: true), + peerInfoAvailableMediaPanes(context: context, peerId: groupId), context.account.postbox.combinedView(keys: combinedKeys), status, membersData @@ -435,7 +498,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen } return PeerInfoScreenData( - peer: peerView.peers[peerId], + peer: peerView.peers[groupId], cachedData: peerView.cachedData, status: status, notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings, @@ -470,6 +533,80 @@ func canEditPeerInfo(peer: Peer?) -> Bool { return false } +struct PeerInfoMemberActions: OptionSet { + var rawValue: Int32 + + init(rawValue: Int32) { + self.rawValue = rawValue + } + + static let restrict = PeerInfoMemberActions(rawValue: 1 << 0) + static let promote = PeerInfoMemberActions(rawValue: 1 << 1) +} + +func availableActionsForMemberOfPeer(accountPeerId: PeerId, peer: Peer, member: PeerInfoMember) -> PeerInfoMemberActions { + var result: PeerInfoMemberActions = [] + + if member.id != accountPeerId { + if let channel = peer as? TelegramChannel { + if channel.flags.contains(.isCreator) { + result.insert(.restrict) + result.insert(.promote) + } else { + switch member { + case let .channelMember(channelMember): + switch channelMember.participant { + case .creator: + break + case let .member(member): + if let adminInfo = member.adminInfo { + if adminInfo.promotedBy == accountPeerId { + result.insert(.restrict) + if channel.hasPermission(.addAdmins) { + result.insert(.promote) + } + } + } else { + if channel.hasPermission(.banMembers) { + result.insert(.restrict) + } + } + } + case .legacyGroupMember: + break + } + } + } else if let group = peer as? TelegramGroup { + switch group.role { + case .creator: + result.insert(.restrict) + result.insert(.promote) + case .admin: + switch member { + case let .legacyGroupMember(legacyGroupMember): + if legacyGroupMember.invitedBy == accountPeerId { + result.insert(.restrict) + result.insert(.promote) + } + case .channelMember: + break + } + case .member: + switch member { + case let .legacyGroupMember(legacyGroupMember): + if legacyGroupMember.invitedBy == accountPeerId { + result.insert(.restrict) + } + case .channelMember: + break + } + } + } + } + + return result +} + func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?) -> [PeerInfoHeaderButtonKey] { var result: [PeerInfoHeaderButtonKey] = [] if let user = peer as? TelegramUser { diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift index 606947df54..ff3b630069 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift @@ -168,6 +168,7 @@ final class PeerInfoAvatarListItemNode: ASDisplayNode { super.init() + self.imageNode.contentAnimations = .subsequentUpdates self.addSubnode(self.imageNode) self.imageNode.imageUpdated = { [weak self] _ in @@ -420,7 +421,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { self.updateItems(size: size, transition: .immediate) } else if self.items.count > 1 { self.currentIndex = self.items.count - 1 - self.updateItems(size: size, transition: .immediate) + self.updateItems(size: size, transition: .immediate, synchronous: true) } } else if location.x > size.width * 4.0 / 5.0 { if self.currentIndex < self.items.count - 1 { @@ -486,7 +487,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { if let peer = peer, !self.initializedList { self.initializedList = true - self.disposable.set((fetchedAvatarGalleryEntries(account: self.context.account, peer: peer) + self.disposable.set((peerInfoProfilePhotosWithCache(context: self.context, peerId: peer.id) |> deliverOnMainQueue).start(next: { [weak self] entries in guard let strongSelf = self else { return @@ -1225,6 +1226,8 @@ final class PeerInfoHeaderNode: ASDisplayNode { private var context: AccountContext private var presentationData: PresentationData? + private let keepExpandedButtons: PeerInfoScreenKeepExpandedButtons + private(set) var isAvatarExpanded: Bool let avatarListNode: PeerInfoAvatarListNode @@ -1250,9 +1253,10 @@ final class PeerInfoHeaderNode: ASDisplayNode { var navigationTransition: PeerInfoHeaderNavigationTransition? - init(context: AccountContext, avatarInitiallyExpanded: Bool) { + init(context: AccountContext, avatarInitiallyExpanded: Bool, keepExpandedButtons: PeerInfoScreenKeepExpandedButtons) { self.context = context self.isAvatarExpanded = avatarInitiallyExpanded + self.keepExpandedButtons = keepExpandedButtons self.avatarListNode = PeerInfoAvatarListNode(context: context, readyWhenGalleryLoads: avatarInitiallyExpanded) @@ -1528,7 +1532,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { transition.updateFrameAdditive(node: self.avatarListNode.listContainerNode.controlsContainerNode, frame: CGRect(origin: CGPoint(x: -controlsClippingFrame.minX, y: -controlsClippingFrame.minY), size: CGSize(width: expandedAvatarListSize.width, height: expandedAvatarListSize.height))) transition.updateFrame(node: self.avatarListNode.listContainerNode.shadowNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: expandedAvatarListSize.width, height: navigationHeight + 20.0))) - transition.updateFrame(node: self.avatarListNode.listContainerNode.stripContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: statusBarHeight + 2.0), size: CGSize(width: expandedAvatarListSize.width, height: 2.0))) + transition.updateFrame(node: self.avatarListNode.listContainerNode.stripContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: statusBarHeight < 25.0 ? (statusBarHeight + 2.0) : (statusBarHeight - 3.0)), size: CGSize(width: expandedAvatarListSize.width, height: 2.0))) transition.updateFrame(node: self.avatarListNode.listContainerNode.highlightContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: expandedAvatarListSize.width, height: expandedAvatarListSize.height))) transition.updateAlpha(node: self.avatarListNode.listContainerNode.controlsContainerNode, alpha: self.isAvatarExpanded ? (1.0 - transitionFraction) : 0.0) @@ -1690,7 +1694,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { buttonText = "Message" buttonIcon = .message case .discussion: - buttonText = "Discussion" + buttonText = "Discuss" buttonIcon = .message case .call: buttonText = "Call" @@ -1716,11 +1720,21 @@ final class PeerInfoHeaderNode: ASDisplayNode { transition.updateAlpha(node: buttonNode, alpha: buttonsAlpha) let hiddenWhileExpanded: Bool - switch buttonKey { + switch self.keepExpandedButtons { + case .message: + switch buttonKey { + case .mute, .addMember: + hiddenWhileExpanded = true + default: + hiddenWhileExpanded = false + } case .mute: - hiddenWhileExpanded = true - default: - hiddenWhileExpanded = false + switch buttonKey { + case .message, .addMember: + hiddenWhileExpanded = true + default: + hiddenWhileExpanded = false + } } if self.isAvatarExpanded, hiddenWhileExpanded { diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoMembers.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoMembers.swift index ecc921a2c0..cbfd8230b7 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoMembers.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoMembers.swift @@ -6,20 +6,31 @@ import TelegramCore import AccountContext import TemporaryCachedPeerDataManager +enum PeerInfoMemberRole { + case creator + case admin + case member +} + enum PeerInfoMember: Equatable { case channelMember(RenderedChannelParticipant) + case legacyGroupMember(peer: RenderedPeer, role: PeerInfoMemberRole, invitedBy: PeerId?, presence: TelegramUserPresence?) var id: PeerId { switch self { case let .channelMember(channelMember): return channelMember.peer.id + case let .legacyGroupMember(legacyGroupMember): + return legacyGroupMember.peer.peerId } } var peer: Peer { switch self { - case let .channelMember(channelMember): + case let .channelMember(channelMember): return channelMember.peer + case let .legacyGroupMember(legacyGroupMember): + return legacyGroupMember.peer.peers[legacyGroupMember.peer.peerId]! } } @@ -27,6 +38,40 @@ enum PeerInfoMember: Equatable { switch self { case let .channelMember(channelMember): return channelMember.presences[channelMember.peer.id] as? TelegramUserPresence + case let .legacyGroupMember(legacyGroupMember): + return legacyGroupMember.presence + } + } + + var role: PeerInfoMemberRole { + switch self { + case let .channelMember(channelMember): + switch channelMember.participant { + case .creator: + return .creator + case let .member(member): + if member.adminInfo != nil { + return .admin + } else { + return .member + } + } + case let .legacyGroupMember(legacyGroupMember): + return legacyGroupMember.role + } + } + + var rank: String? { + switch self { + case let .channelMember(channelMember): + switch channelMember.participant { + case let .creator(creator): + return creator.rank + case let .member(member): + return member.rank + } + case .legacyGroupMember: + return nil } } } @@ -41,6 +86,31 @@ struct PeerInfoMembersState: Equatable { var dataState: PeerInfoMembersDataState } +private func membersSortedByPresence(_ members: [PeerInfoMember], accountPeerId: PeerId) -> [PeerInfoMember] { + return members.sorted(by: { lhs, rhs in + if lhs.id == accountPeerId { + return true + } else if rhs.id == accountPeerId { + return false + } + + let lhsPresence = lhs.presence + let rhsPresence = rhs.presence + if let lhsPresence = lhsPresence, let rhsPresence = rhsPresence { + if lhsPresence.status < rhsPresence.status { + return false + } else if lhsPresence.status > rhsPresence.status { + return true + } + } else if let _ = lhsPresence { + return true + } else if let _ = rhsPresence { + return false + } + return lhs.id < rhs.id + }) +} + private final class PeerInfoMembersContextImpl { private let queue: Queue private let context: AccountContext @@ -48,6 +118,7 @@ private final class PeerInfoMembersContextImpl { private var members: [PeerInfoMember] = [] private var dataState: PeerInfoMembersDataState = .loading(isInitial: true) + private var removingMemberIds: [PeerId: Disposable] = [:] private let stateValue = Promise() var state: Signal { @@ -70,7 +141,14 @@ private final class PeerInfoMembersContextImpl { guard let strongSelf = self else { return } - strongSelf.members = state.list.map(PeerInfoMember.channelMember) + let unsortedMembers = state.list.map(PeerInfoMember.channelMember) + let members: [PeerInfoMember] + if unsortedMembers.count <= 50 { + members = membersSortedByPresence(unsortedMembers, accountPeerId: strongSelf.context.account.peerId) + } else { + members = unsortedMembers + } + strongSelf.members = members switch state.loadingState { case let .loading(initial): strongSelf.dataState = .loading(isInitial: initial) @@ -88,12 +166,26 @@ private final class PeerInfoMembersContextImpl { guard let strongSelf = self, let cachedData = view.cachedData as? CachedGroupData, let participantsData = cachedData.participants else { return } - var members: [PeerInfoMember] = [] + var unsortedMembers: [PeerInfoMember] = [] for participant in participantsData.participants { if let peer = view.peers[participant.peerId] { - + let role: PeerInfoMemberRole + let invitedBy: PeerId? + switch participant { + case .creator: + role = .creator + invitedBy = nil + case let .admin(admin): + role = .admin + invitedBy = admin.invitedBy + case let .member(member): + role = .member + invitedBy = member.invitedBy + } + unsortedMembers.append(.legacyGroupMember(peer: RenderedPeer(peer: peer), role: role, invitedBy: invitedBy, presence: view.peerPresences[participant.peerId] as? TelegramUserPresence)) } } + strongSelf.members = membersSortedByPresence(unsortedMembers, accountPeerId: strongSelf.context.account.peerId) strongSelf.dataState = .ready(canLoadMore: false) strongSelf.pushState() })) @@ -108,7 +200,13 @@ private final class PeerInfoMembersContextImpl { } private func pushState() { - self.stateValue.set(.single(PeerInfoMembersState(members: self.members, dataState: self.dataState))) + if self.removingMemberIds.isEmpty { + self.stateValue.set(.single(PeerInfoMembersState(members: self.members, dataState: self.dataState))) + } else { + self.stateValue.set(.single(PeerInfoMembersState(members: self.members.filter { member in + return self.removingMemberIds[member.id] == nil + }, dataState: self.dataState))) + } } func loadMore() { @@ -116,6 +214,38 @@ private final class PeerInfoMembersContextImpl { self.context.peerChannelMemberCategoriesContextsManager.loadMore(peerId: self.peerId, control: channelMembersControl) } } + + func removeMember(memberId: PeerId) { + if removingMemberIds[memberId] == nil { + let signal: Signal + if self.peerId.namespace == Namespaces.Peer.CloudChannel { + signal = context.peerChannelMemberCategoriesContextsManager.updateMemberBannedRights(account: self.context.account, peerId: self.peerId, memberId: memberId, bannedRights: TelegramChatBannedRights(flags: [.banReadMessages], untilDate: Int32.max)) + |> ignoreValues + } else { + signal = removePeerMember(account: self.context.account, peerId: self.peerId, memberId: memberId) + |> ignoreValues + } + let completed: () -> Void = { [weak self] in + guard let strongSelf = self else { + return + } + if let _ = strongSelf.removingMemberIds.removeValue(forKey: memberId) { + strongSelf.pushState() + } + } + let disposable = MetaDisposable() + self.removingMemberIds[memberId] = disposable + + self.pushState() + + disposable.set((signal + |> deliverOn(self.queue)).start(error: { _ in + completed() + }, completed: { + completed() + })) + } + } } final class PeerInfoMembersContext: Equatable { @@ -147,6 +277,12 @@ final class PeerInfoMembersContext: Equatable { } } + func removeMember(memberId: PeerId) { + self.impl.with { impl in + impl.removeMember(memberId: memberId) + } + } + static func ==(lhs: PeerInfoMembersContext, rhs: PeerInfoMembersContext) -> Bool { return lhs === rhs } diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift index 9eb080c548..97da970c3b 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift @@ -60,6 +60,8 @@ final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode { private let titleNode: ImmediateTextNode private let buttonNode: HighlightTrackingButtonNode + private var isSelected: Bool = false + init(pressed: @escaping () -> Void) { self.pressed = pressed @@ -74,9 +76,9 @@ final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode { self.addSubnode(self.buttonNode) self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside) - self.buttonNode.highligthedChanged = { [weak self] highlighted in + /*self.buttonNode.highligthedChanged = { [weak self] highlighted in if let strongSelf = self { - if highlighted { + if highlighted && !strongSelf.isSelected { strongSelf.titleNode.layer.removeAnimation(forKey: "opacity") strongSelf.titleNode.alpha = 0.4 } else { @@ -84,7 +86,7 @@ final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode { strongSelf.titleNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) } } - } + }*/ } @objc private func buttonPressed() { @@ -92,6 +94,7 @@ final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode { } func updateText(_ title: String, isSelected: Bool, presentationData: PresentationData) { + self.isSelected = isSelected self.titleNode.attributedText = NSAttributedString(string: title, font: Font.medium(14.0), textColor: isSelected ? presentationData.theme.list.itemAccentColor : presentationData.theme.list.itemSecondaryTextColor) } @@ -304,8 +307,10 @@ final class PeerInfoPaneContainerNode: ASDisplayNode { var chatControllerInteraction: ChatControllerInteraction? var openPeerContextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)? + var requestPerformPeerMemberAction: ((PeerInfoMember, PeerMembersListAction) -> Void)? var currentPaneUpdated: (() -> Void)? + var requestExpandTabs: (() -> Bool)? private var currentAvailablePanes: [PeerInfoPaneKey]? @@ -336,7 +341,10 @@ final class PeerInfoPaneContainerNode: ASDisplayNode { return } if strongSelf.currentPaneKey == key { - strongSelf.currentPane?.node.scrollToTop() + if let requestExpandTabs = strongSelf.requestExpandTabs, requestExpandTabs() { + } else { + strongSelf.currentPane?.node.scrollToTop() + } return } if strongSelf.currentCandidatePaneKey == key { @@ -449,10 +457,12 @@ final class PeerInfoPaneContainerNode: ASDisplayNode { case .music: paneNode = PeerInfoListPaneNode(context: self.context, chatControllerInteraction: self.chatControllerInteraction!, peerId: self.peerId, tagMask: .music) case .groupsInCommon: - paneNode = PeerInfoGroupsInCommonPaneNode(context: self.context, peerId: peerId, chatControllerInteraction: self.chatControllerInteraction!, openPeerContextAction: self.openPeerContextAction!, peers: data?.groupsInCommon ?? []) + paneNode = PeerInfoGroupsInCommonPaneNode(context: self.context, peerId: self.peerId, chatControllerInteraction: self.chatControllerInteraction!, openPeerContextAction: self.openPeerContextAction!, peers: data?.groupsInCommon ?? []) case .members: if case let .longList(membersContext) = data?.members { - paneNode = PeerInfoMembersPaneNode(context: self.context, membersContext: membersContext) + paneNode = PeerInfoMembersPaneNode(context: self.context, peerId: self.peerId, membersContext: membersContext, action: { [weak self] member, action in + self?.requestPerformPeerMemberAction?(member, action) + }) } else { preconditionFailure() } diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift index 346f706c01..aa8dec56dd 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift @@ -35,6 +35,7 @@ import WebSearchUI import LocationResources import LocationUI import Geocoding +import TextFormat protocol PeerInfoScreenItem: class { var id: AnyHashable { get } @@ -53,6 +54,7 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { private let backgroundNode: ASDisplayNode private let topSeparatorNode: ASDisplayNode private let bottomSeparatorNode: ASDisplayNode + private let itemContainerNode: ASDisplayNode private var currentItems: [PeerInfoScreenItem] = [] private var itemNodes: [AnyHashable: PeerInfoScreenItemNode] = [:] @@ -67,9 +69,13 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { self.bottomSeparatorNode = ASDisplayNode() self.bottomSeparatorNode.isLayerBacked = true + self.itemContainerNode = ASDisplayNode() + self.itemContainerNode.clipsToBounds = true + super.init() self.addSubnode(self.backgroundNode) + self.addSubnode(self.itemContainerNode) self.addSubnode(self.topSeparatorNode) self.addSubnode(self.bottomSeparatorNode) } @@ -94,7 +100,7 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { wasAdded = true itemNode = item.node() self.itemNodes[item.id] = itemNode - self.addSubnode(itemNode) + self.itemContainerNode.addSubnode(itemNode) itemNode.bringToFrontForHighlight = { [weak self, weak itemNode] in guard let strongSelf = self, let itemNode = itemNode else { return @@ -150,12 +156,14 @@ private final class PeerInfoScreenItemSectionContainerNode: ASDisplayNode { } for id in removeIds { if let itemNode = self.itemNodes.removeValue(forKey: id) { + itemNode.view.superview?.sendSubviewToBack(itemNode.view) transition.updateAlpha(node: itemNode, alpha: 0.0, completion: { [weak itemNode] _ in itemNode?.removeFromSupernode() }) } } + transition.updateFrame(node: self.itemContainerNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: contentHeight))) transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentWithBackgroundOffset), size: CGSize(width: width, height: max(0.0, contentWithBackgroundHeight - contentWithBackgroundOffset)))) transition.updateFrame(node: self.topSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentWithBackgroundOffset - UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel))) transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentWithBackgroundHeight), size: CGSize(width: width, height: UIScreenPixel))) @@ -445,6 +453,18 @@ private enum PeerInfoParticipantsSection { case banned } +private enum PeerInfoMemberAction { + case promote + case restrict + case remove +} + +private enum PeerInfoContextSubject { + case bio + case phone(String) + case link +} + private final class PeerInfoInteraction { let openUsername: (String) -> Void let openPhone: (String) -> Void @@ -468,6 +488,9 @@ private final class PeerInfoInteraction { let openLocation: () -> Void let editingOpenSetupLocation: () -> Void let openPeerInfo: (Peer) -> Void + let performMemberAction: (PeerInfoMember, PeerInfoMemberAction) -> Void + let openPeerInfoContextMenu: (PeerInfoContextSubject, ASDisplayNode) -> Void + let performBioLinkAction: (TextLinkItemActionType, TextLinkItem) -> Void init( openUsername: @escaping (String) -> Void, @@ -491,7 +514,10 @@ private final class PeerInfoInteraction { editingOpenStickerPackSetup: @escaping () -> Void, openLocation: @escaping () -> Void, editingOpenSetupLocation: @escaping () -> Void, - openPeerInfo: @escaping (Peer) -> Void + openPeerInfo: @escaping (Peer) -> Void, + performMemberAction: @escaping (PeerInfoMember, PeerInfoMemberAction) -> Void, + openPeerInfoContextMenu: @escaping (PeerInfoContextSubject, ASDisplayNode) -> Void, + performBioLinkAction: @escaping (TextLinkItemActionType, TextLinkItem) -> Void ) { self.openUsername = openUsername self.openPhone = openPhone @@ -515,9 +541,14 @@ private final class PeerInfoInteraction { self.openLocation = openLocation self.editingOpenSetupLocation = editingOpenSetupLocation self.openPeerInfo = openPeerInfo + self.performMemberAction = performMemberAction + self.openPeerInfoContextMenu = openPeerInfoContextMenu + self.performBioLinkAction = performBioLinkAction } } +private let enabledBioEntities: EnabledEntityTypes = [.url, .mention, .hashtag] + private func infoItems(data: PeerInfoScreenData?, context: AccountContext, presentationData: PresentationData, interaction: PeerInfoInteraction) -> [(AnyHashable, [PeerInfoScreenItem])] { guard let data = data else { return [] @@ -534,22 +565,34 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese items[section] = [] } + let bioContextAction: (ASDisplayNode) -> Void = { sourceNode in + interaction.openPeerInfoContextMenu(.bio, sourceNode) + } + let bioLinkAction: (TextLinkItemActionType, TextLinkItem) -> Void = { action, item in + interaction.performBioLinkAction(action, item) + } + if let user = data.peer as? TelegramUser { if let phone = user.phone { - items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 2, label: "mobile", text: "\(formatPhoneNumber(phone))", textColor: .accent, action: { + let formattedPhone = formatPhoneNumber(phone) + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 2, label: "mobile", text: formattedPhone, textColor: .accent, action: { interaction.openPhone(phone) + }, longTapAction: { sourceNode in + interaction.openPeerInfoContextMenu(.phone(formattedPhone), sourceNode) })) } if let username = user.username { items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 1, label: "username", text: "@\(username)", textColor: .accent, action: { interaction.openUsername(username) + }, longTapAction: { sourceNode in + interaction.openPeerInfoContextMenu(.link, sourceNode) })) } if let cachedData = data.cachedData as? CachedUserData { if user.isScam { - items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: user.botInfo != nil ? presentationData.strings.UserInfo_ScamBotWarning : presentationData.strings.UserInfo_ScamUserWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: user.botInfo != nil ? presentationData.strings.UserInfo_ScamBotWarning : presentationData.strings.UserInfo_ScamUserWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: user.botInfo != nil ? enabledBioEntities : []), action: nil)) } else if let about = cachedData.about, !about.isEmpty { - items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction)) } } if !data.isContact { @@ -606,13 +649,15 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese if let username = channel.username { items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemUsername, label: presentationData.strings.Channel_LinkItem, text: "https://t.me/\(username)", textColor: .accent, action: { interaction.openUsername(username) + }, longTapAction: { sourceNode in + interaction.openPeerInfoContextMenu(.link, sourceNode) })) } if let cachedData = data.cachedData as? CachedChannelData { if channel.isScam { - items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Profile_About, text: presentationData.strings.GroupInfo_ScamGroupWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Profile_About, text: presentationData.strings.GroupInfo_ScamGroupWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil)) } else if let about = cachedData.about, !about.isEmpty { - items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Profile_About, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Profile_About, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction)) } if case .broadcast = channel.info { @@ -642,21 +687,31 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese } else if let group = data.peer as? TelegramGroup { if let cachedData = data.cachedData as? CachedGroupData { if group.isScam { - items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: presentationData.strings.GroupInfo_ScamGroupWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: presentationData.strings.GroupInfo_ScamGroupWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil)) } else if let about = cachedData.about, !about.isEmpty { - items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 10), action: nil)) + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction)) } } } - if let members = data.members, case let .shortList(memberList) = members { + if let peer = data.peer, let members = data.members, case let .shortList(_, memberList) = members { for member in memberList { var presence = member.presence - if member.id == context.account.peerId { + let isAccountPeer = member.id == context.account.peerId + if isAccountPeer { presence = TelegramUserPresence(status: .present(until: Int32.max - 1), lastActivity: 0) } - items[.peerMembers]!.append(PeerInfoScreenMemberItem(id: member.id, context: context, peer: member.peer, presence: presence, action: { - interaction.openPeerInfo(member.peer) + items[.peerMembers]!.append(PeerInfoScreenMemberItem(id: member.id, context: context, enclosingPeer: peer, member: member, action: isAccountPeer ? nil : { action in + switch action { + case .open: + interaction.openPeerInfo(member.peer) + case .promote: + interaction.performMemberAction(member, .promote) + case .restrict: + interaction.performMemberAction(member, .restrict) + case .remove: + interaction.performMemberAction(member, .remove) + } })) } } @@ -967,6 +1022,8 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD private let activeActionDisposable = MetaDisposable() private let resolveUrlDisposable = MetaDisposable() private let toggleShouldChannelMessagesSignaturesDisposable = MetaDisposable() + private let selectAddMemberDisposable = MetaDisposable() + private let addMemberDisposable = MetaDisposable() private let updateAvatarDisposable = MetaDisposable() private let currentAvatarMixin = Atomic(value: nil) @@ -977,7 +1034,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } private var didSetReady = false - init(controller: PeerInfoScreen, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool) { + init(controller: PeerInfoScreen, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, keepExpandedButtons: PeerInfoScreenKeepExpandedButtons) { self.controller = controller self.context = context self.peerId = peerId @@ -986,7 +1043,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self.scrollNode = ASScrollNode() self.scrollNode.view.delaysContentTouches = false - self.headerNode = PeerInfoHeaderNode(context: context, avatarInitiallyExpanded: avatarInitiallyExpanded) + self.headerNode = PeerInfoHeaderNode(context: context, avatarInitiallyExpanded: avatarInitiallyExpanded, keepExpandedButtons: keepExpandedButtons) self.paneContainerNode = PeerInfoPaneContainerNode(context: context, peerId: peerId) super.init() @@ -1057,6 +1114,15 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }, openPeerInfo: { [weak self] peer in self?.openPeerInfo(peer: peer) + }, + performMemberAction: { [weak self] member, action in + self?.performMemberAction(member: member, action: action) + }, + openPeerInfoContextMenu: { [weak self] subject, sourceNode in + self?.openPeerInfoContextMenu(subject: subject, sourceNode: sourceNode) + }, + performBioLinkAction: { [weak self] action, item in + self?.performBioLinkAction(action: action, item: item) } ) @@ -1429,6 +1495,36 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } } + self.paneContainerNode.requestExpandTabs = { [weak self] in + guard let strongSelf = self, let (_, navigationHeight) = strongSelf.validLayout else { + return false + } + let contentOffset = strongSelf.scrollNode.view.contentOffset + let paneAreaExpansionFinalPoint: CGFloat = strongSelf.paneContainerNode.frame.minY - navigationHeight + if contentOffset.y < paneAreaExpansionFinalPoint - CGFloat.ulpOfOne { + strongSelf.scrollNode.view.setContentOffset(CGPoint(x: 0.0, y: paneAreaExpansionFinalPoint), animated: true) + return true + } else { + return false + } + } + + self.paneContainerNode.requestPerformPeerMemberAction = { [weak self] member, action in + guard let strongSelf = self else { + return + } + switch action { + case .open: + strongSelf.openPeerInfo(peer: member.peer) + case .promote: + strongSelf.performMemberAction(member: member, action: .promote) + case .restrict: + strongSelf.performMemberAction(member: member, action: .restrict) + case .remove: + strongSelf.performMemberAction(member: member, action: .remove) + } + } + self.headerNode.performButtonAction = { [weak self] key in self?.performButtonAction(key: key) } @@ -1612,6 +1708,8 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self.hiddenAvatarRepresentationDisposable.dispose() self.toggleShouldChannelMessagesSignaturesDisposable.dispose() self.updateAvatarDisposable.dispose() + self.selectAddMemberDisposable.dispose() + self.addMemberDisposable.dispose() } override func didLoad() { @@ -1621,7 +1719,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD private func updateData(_ data: PeerInfoScreenData) { self.data = data if let (layout, navigationHeight) = self.validLayout { - self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate) + self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: self.didSetReady ? .animated(duration: 0.3, curve: .spring) : .immediate) } } @@ -1725,7 +1823,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD |> take(1) |> deliverOnMainQueue).start(next: { [weak self] peer in if let strongSelf = self, peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil { - if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { (strongSelf.controller?.navigationController as? NavigationController)?.pushViewController(infoController) } } @@ -1911,7 +2009,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self.view.endEditing(true) controller.present(actionSheet, in: .window(.root)) case .addMember: - break + self.openAddMember() } } @@ -2482,11 +2580,91 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } private func openPeerInfo(peer: Peer) { - if let infoController = self.context.sharedContext.makePeerInfoController(context: self.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let infoController = self.context.sharedContext.makePeerInfoController(context: self.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { (self.controller?.navigationController as? NavigationController)?.pushViewController(infoController) } } + private func performMemberAction(member: PeerInfoMember, action: PeerInfoMemberAction) { + guard let data = self.data, let peer = data.peer else { + return + } + switch action { + case .promote: + if case let .channelMember(channelMember) = member { + self.controller?.push(channelAdminController(context: self.context, peerId: peer.id, adminId: member.id, initialParticipant: channelMember.participant, updated: { _ in + }, upgradedToSupergroup: { _, f in f() }, transferedOwnership: { _ in })) + } + case .restrict: + if case let .channelMember(channelMember) = member { + self.controller?.push(channelBannedMemberController(context: self.context, peerId: peer.id, memberId: member.id, initialParticipant: channelMember.participant, updated: { _ in + }, upgradedToSupergroup: { _, f in f() })) + } + case .remove: + data.members?.membersContext.removeMember(memberId: member.id) + } + } + + private func openPeerInfoContextMenu(subject: PeerInfoContextSubject, sourceNode: ASDisplayNode) { + guard let data = self.data, let peer = data.peer, let controller = self.controller else { + return + } + switch subject { + case .bio: + var text: String? + if let cachedData = data.cachedData as? CachedUserData { + text = cachedData.about + } else if let cachedData = data.cachedData as? CachedGroupData { + text = cachedData.about + } else if let cachedData = data.cachedData as? CachedChannelData { + text = cachedData.about + } + if let text = text, !text.isEmpty { + let contextMenuController = ContextMenuController(actions: [ContextMenuAction(content: .text(title: self.presentationData.strings.Conversation_ContextMenuCopy, accessibilityLabel: self.presentationData.strings.Conversation_ContextMenuCopy), action: { + UIPasteboard.general.string = text + })]) + controller.present(contextMenuController, in: .window(.root), with: ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self, weak sourceNode] in + if let controller = self?.controller, let sourceNode = sourceNode { + return (sourceNode, sourceNode.bounds.insetBy(dx: 0.0, dy: -2.0), controller.displayNode, controller.view.bounds) + } else { + return nil + } + })) + } + case let .phone(phone): + let contextMenuController = ContextMenuController(actions: [ContextMenuAction(content: .text(title: self.presentationData.strings.Conversation_ContextMenuCopy, accessibilityLabel: self.presentationData.strings.Conversation_ContextMenuCopy), action: { + UIPasteboard.general.string = phone + })]) + controller.present(contextMenuController, in: .window(.root), with: ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self, weak sourceNode] in + if let controller = self?.controller, let sourceNode = sourceNode { + return (sourceNode, sourceNode.bounds.insetBy(dx: 0.0, dy: -2.0), controller.displayNode, controller.view.bounds) + } else { + return nil + } + })) + case .link: + if let addressName = peer.addressName { + let contextMenuController = ContextMenuController(actions: [ContextMenuAction(content: .text(title: self.presentationData.strings.Conversation_ContextMenuCopy, accessibilityLabel: self.presentationData.strings.Conversation_ContextMenuCopy), action: { + UIPasteboard.general.string = addressName + })]) + controller.present(contextMenuController, in: .window(.root), with: ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self, weak sourceNode] in + if let controller = self?.controller, let sourceNode = sourceNode { + return (sourceNode, sourceNode.bounds.insetBy(dx: 0.0, dy: -2.0), controller.displayNode, controller.view.bounds) + } else { + return nil + } + })) + } + } + } + + private func performBioLinkAction(action: TextLinkItemActionType, item: TextLinkItem) { + guard let data = self.data, let peer = data.peer, let controller = self.controller else { + return + } + self.context.sharedContext.handleTextLinkAction(context: self.context, peerId: peer.id, navigateDisposable: self.resolveUrlDisposable, controller: controller, action: action, itemLink: item) + } + private func openDeletePeer() { let peerId = self.peerId let _ = (self.context.account.postbox.transaction { transaction -> Peer? in @@ -2712,7 +2890,269 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }) } - func deleteMessages(messageIds: Set?) { + private func openAddMember() { + guard let data = self.data, let groupPeer = data.peer else { + return + } + + let members: Promise<[PeerId]> = Promise() + if groupPeer.id.namespace == Namespaces.Peer.CloudChannel { + /*var membersDisposable: Disposable? + let (disposable, _) = context.peerChannelMemberCategoriesContextsManager.recent(postbox: context.account.postbox, network: context.account.network, accountPeerId: context.account.peerId, peerId: peerView.peerId, updated: { listState in + members.set(.single(listState.list.map {$0.peer.id})) + membersDisposable?.dispose() + }) + membersDisposable = disposable*/ + members.set(.single([])) + } else { + members.set(.single([])) + } + + let _ = (members.get() + |> take(1) + |> deliverOnMainQueue).start(next: { [weak self] recentIds in + guard let strongSelf = self else { + return + } + var createInviteLinkImpl: (() -> Void)? + var confirmationImpl: ((PeerId) -> Signal)? + var options: [ContactListAdditionalOption] = [] + let presentationData = strongSelf.presentationData + + var canCreateInviteLink = false + if let group = groupPeer as? TelegramGroup { + switch group.role { + case .creator, .admin: + canCreateInviteLink = true + default: + break + } + } else if let channel = groupPeer as? TelegramChannel { + if channel.hasPermission(.inviteMembers) { + if channel.flags.contains(.isCreator) || (channel.adminRights != nil && channel.username == nil) { + canCreateInviteLink = true + } + } + } + + if canCreateInviteLink { + options.append(ContactListAdditionalOption(title: presentationData.strings.GroupInfo_InviteByLink, icon: .generic(UIImage(bundleImageName: "Contact List/LinkActionIcon")!), action: { + createInviteLinkImpl?() + })) + } + + let contactsController: ViewController + if groupPeer.id.namespace == Namespaces.Peer.CloudGroup { + contactsController = strongSelf.context.sharedContext.makeContactSelectionController(ContactSelectionControllerParams(context: strongSelf.context, autoDismiss: false, title: { $0.GroupInfo_AddParticipantTitle }, options: options, confirmation: { peer in + if let confirmationImpl = confirmationImpl, case let .peer(peer, _, _) = peer { + return confirmationImpl(peer.id) + } else { + return .single(false) + } + })) + contactsController.navigationPresentation = .modal + } else { + contactsController = strongSelf.context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: strongSelf.context, mode: .peerSelection(searchChatList: false, searchGroups: false), options: options, filters: [.excludeSelf, .disable(recentIds)])) + contactsController.navigationPresentation = .modal + } + + let context = strongSelf.context + confirmationImpl = { [weak contactsController] peerId in + return context.account.postbox.loadedPeerWithId(peerId) + |> deliverOnMainQueue + |> mapToSignal { peer in + let result = ValuePromise() + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + if let contactsController = contactsController { + let alertController = textAlertController(context: context, title: nil, text: presentationData.strings.GroupInfo_AddParticipantConfirmation(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).0, actions: [ + TextAlertAction(type: .genericAction, title: presentationData.strings.Common_No, action: { + result.set(false) + }), + TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Yes, action: { + result.set(true) + }) + ]) + contactsController.present(alertController, in: .window(.root)) + } + + return result.get() + } + } + + let addMember: (ContactListPeer) -> Signal = { memberPeer -> Signal in + if case let .peer(selectedPeer, _, _) = memberPeer { + let memberId = selectedPeer.id + if groupPeer.id.namespace == Namespaces.Peer.CloudChannel { + return context.peerChannelMemberCategoriesContextsManager.addMember(account: context.account, peerId: groupPeer.id, memberId: memberId) + |> map { _ -> Void in + return Void() + } + |> `catch` { _ -> Signal in + return .complete() + } + } else { + return addGroupMember(account: context.account, peerId: groupPeer.id, memberId: memberId) + |> deliverOnMainQueue + |> `catch` { error -> Signal in + switch error { + case .generic: + return .complete() + case .privacy: + let _ = (context.account.postbox.loadedPeerWithId(memberId) + |> deliverOnMainQueue).start(next: { peer in + self?.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(peer.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + }) + return .complete() + case .tooManyChannels: + let _ = (context.account.postbox.loadedPeerWithId(memberId) + |> deliverOnMainQueue).start(next: { peer in + self?.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.Invite_ChannelsTooMuch, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + }) + return .complete() + case .groupFull: + let signal = convertGroupToSupergroup(account: context.account, peerId: groupPeer.id) + |> map(Optional.init) + |> `catch` { error -> Signal in + switch error { + case .tooManyChannels: + Queue.mainQueue().async { + self?.controller?.push(oldChannelsController(context: context, intent: .upgrade)) + } + default: + break + } + return .single(nil) + } + |> mapToSignal { upgradedPeerId -> Signal in + guard let upgradedPeerId = upgradedPeerId else { + return .single(nil) + } + return context.peerChannelMemberCategoriesContextsManager.addMember(account: context.account, peerId: upgradedPeerId, memberId: memberId) + |> `catch` { _ -> Signal in + return .complete() + } + |> mapToSignal { _ -> Signal in + return .complete() + } + |> then(.single(upgradedPeerId)) + } + |> deliverOnMainQueue + |> mapToSignal { _ -> Signal in + return .complete() + } + return signal + } + } + } + } else { + return .complete() + } + } + + let addMembers: ([ContactListPeerId]) -> Signal = { members -> Signal in + let memberIds = members.compactMap { contact -> PeerId? in + switch contact { + case let .peer(peerId): + return peerId + default: + return nil + } + } + return context.account.postbox.multiplePeersView(memberIds) + |> take(1) + |> deliverOnMainQueue + |> mapError { _ in return .generic} + |> mapToSignal { view -> Signal in + if memberIds.count == 1 { + return context.peerChannelMemberCategoriesContextsManager.addMember(account: context.account, peerId: groupPeer.id, memberId: memberIds[0]) + |> map { _ -> Void in + return Void() + } + } else { + return context.peerChannelMemberCategoriesContextsManager.addMembers(account: context.account, peerId: groupPeer.id, memberIds: memberIds) |> map { _ in + } + } + } + } + + createInviteLinkImpl = { [weak contactsController] in + guard let strongSelf = self else { + return + } + let mode: ChannelVisibilityControllerMode + if groupPeer.addressName != nil { + mode = .generic + } else { + mode = .privateLink + } + let visibilityController = channelVisibilityController(context: strongSelf.context, peerId: groupPeer.id, mode: mode, upgradedToSupergroup: { _, f in f() }) + visibilityController.navigationPresentation = .modal + + if let navigationController = strongSelf.controller?.navigationController as? NavigationController { + var controllers = navigationController.viewControllers + if let contactsController = contactsController { + controllers.removeAll(where: { $0 === contactsController }) + } + controllers.append(visibilityController) + navigationController.setViewControllers(controllers, animated: true) + } + } + + strongSelf.controller?.push(contactsController) + let selectAddMemberDisposable = strongSelf.selectAddMemberDisposable + let addMemberDisposable = strongSelf.addMemberDisposable + if let contactsController = contactsController as? ContactSelectionController { + selectAddMemberDisposable.set((contactsController.result + |> deliverOnMainQueue).start(next: { [weak contactsController] memberPeer in + guard let memberPeer = memberPeer else { + return + } + + contactsController?.displayProgress = true + addMemberDisposable.set((addMember(memberPeer) + |> deliverOnMainQueue).start(completed: { + contactsController?.dismiss() + })) + })) + contactsController.dismissed = { + selectAddMemberDisposable.set(nil) + addMemberDisposable.set(nil) + } + } + if let contactsController = contactsController as? ContactMultiselectionController { + selectAddMemberDisposable.set((contactsController.result + |> deliverOnMainQueue).start(next: { [weak contactsController] peers in + contactsController?.displayProgress = true + addMemberDisposable.set((addMembers(peers) + |> deliverOnMainQueue).start(error: { error in + if peers.count == 1, case .restricted = error { + switch peers[0] { + case let .peer(peerId): + let _ = (context.account.postbox.loadedPeerWithId(peerId) + |> deliverOnMainQueue).start(next: { peer in + self?.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(peer.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + }) + default: + break + } + } else if case .tooMuchJoined = error { + self?.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.Invite_ChannelsTooMuch, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + } + + contactsController?.dismiss() + },completed: { + contactsController?.dismiss() + })) + })) + contactsController.dismissed = { + selectAddMemberDisposable.set(nil) + addMemberDisposable.set(nil) + } + } + }) + } + + private func deleteMessages(messageIds: Set?) { if let messageIds = messageIds ?? self.state.selectedMessageIds, !messageIds.isEmpty { self.activeActionDisposable.set((self.context.sharedContext.chatAvailableMessageActions(postbox: self.context.account.postbox, accountPeerId: self.context.account.peerId, messageIds: messageIds) |> deliverOnMainQueue).start(next: { [weak self] actions in @@ -3351,10 +3791,16 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } } +public enum PeerInfoScreenKeepExpandedButtons { + case message + case mute +} + public final class PeerInfoScreen: ViewController { private let context: AccountContext private let peerId: PeerId private let avatarInitiallyExpanded: Bool + private let keepExpandedButtons: PeerInfoScreenKeepExpandedButtons private var presentationData: PresentationData private var presentationDataDisposable: Disposable? @@ -3368,10 +3814,13 @@ public final class PeerInfoScreen: ViewController { return self._ready } - public init(context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool = false) { + private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)? + + public init(context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool = false, keepExpandedButtons: PeerInfoScreenKeepExpandedButtons = .message) { self.context = context self.peerId = peerId self.avatarInitiallyExpanded = avatarInitiallyExpanded + self.keepExpandedButtons = keepExpandedButtons self.presentationData = context.sharedContext.currentPresentationData.with { $0 } @@ -3439,7 +3888,7 @@ public final class PeerInfoScreen: ViewController { } override public func loadDisplayNode() { - self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded) + self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, keepExpandedButtons: self.keepExpandedButtons) self._ready.set(self.controllerNode.ready.get()) @@ -3448,11 +3897,17 @@ public final class PeerInfoScreen: ViewController { override public func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) + + if let (layout, navigationHeight) = self.validLayout { + self.controllerNode.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate) + } } override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { super.containerLayoutUpdated(layout, transition: transition) + self.validLayout = (layout, navigationHeight) + self.controllerNode.containerLayoutUpdated(layout: layout, navigationHeight: self.navigationHeight, transition: transition) } } diff --git a/submodules/TelegramUI/TelegramUI/PeerMediaCollectionController.swift b/submodules/TelegramUI/TelegramUI/PeerMediaCollectionController.swift index 7374fc9577..d2ff44fa00 100644 --- a/submodules/TelegramUI/TelegramUI/PeerMediaCollectionController.swift +++ b/submodules/TelegramUI/TelegramUI/PeerMediaCollectionController.swift @@ -759,7 +759,7 @@ public class PeerMediaCollectionController: TelegramBaseController { |> take(1) |> deliverOnMainQueue).start(next: { [weak self] peer in if let strongSelf = self, peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil { - if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { (strongSelf.navigationController as? NavigationController)?.pushViewController(infoController) } } diff --git a/submodules/TelegramUI/TelegramUI/PollResultsController.swift b/submodules/TelegramUI/TelegramUI/PollResultsController.swift index a1a24b756a..4a7e627a71 100644 --- a/submodules/TelegramUI/TelegramUI/PollResultsController.swift +++ b/submodules/TelegramUI/TelegramUI/PollResultsController.swift @@ -303,7 +303,7 @@ public func pollResultsController(context: AccountContext, messageId: MessageId, }) }, openPeer: { peer in if let peer = peer.peers[peer.peerId] { - if let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { pushControllerImpl?(controller) } } diff --git a/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift b/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift index 8a475cb359..f32768d66b 100644 --- a/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift +++ b/submodules/TelegramUI/TelegramUI/SharedAccountContext.swift @@ -1004,8 +1004,8 @@ public final class SharedAccountContextImpl: SharedAccountContext { handleTextLinkActionImpl(context: context, peerId: peerId, navigateDisposable: navigateDisposable, controller: controller, action: action, itemLink: itemLink) } - public func makePeerInfoController(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool) -> ViewController? { - let controller = peerInfoControllerImpl(context: context, peer: peer, mode: mode, avatarInitiallyExpanded: avatarInitiallyExpanded) + public func makePeerInfoController(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool, fromChat: Bool) -> ViewController? { + let controller = peerInfoControllerImpl(context: context, peer: peer, mode: mode, avatarInitiallyExpanded: avatarInitiallyExpanded, keepExpandedButtons: fromChat ? .mute : .message) controller?.navigationPresentation = .modalInLargeLayout return controller } @@ -1245,13 +1245,13 @@ public final class SharedAccountContextImpl: SharedAccountContext { private let defaultChatControllerInteraction = ChatControllerInteraction.default -private func peerInfoControllerImpl(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool) -> ViewController? { +private func peerInfoControllerImpl(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool, keepExpandedButtons: PeerInfoScreenKeepExpandedButtons = .message) -> ViewController? { if let _ = peer as? TelegramGroup { - return PeerInfoScreen(context: context, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded) + return PeerInfoScreen(context: context, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, keepExpandedButtons: keepExpandedButtons) return groupInfoController(context: context, peerId: peer.id) } else if let channel = peer as? TelegramChannel { - return PeerInfoScreen(context: context, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded) + return PeerInfoScreen(context: context, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, keepExpandedButtons: keepExpandedButtons) if case .group = channel.info { return groupInfoController(context: context, peerId: peer.id) @@ -1259,7 +1259,7 @@ private func peerInfoControllerImpl(context: AccountContext, peer: Peer, mode: P return channelInfoController(context: context, peerId: peer.id) } } else if peer is TelegramUser { - return PeerInfoScreen(context: context, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded) + return PeerInfoScreen(context: context, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, keepExpandedButtons: keepExpandedButtons) } else if peer is TelegramSecretChat { return userInfoController(context: context, peerId: peer.id, mode: mode) } diff --git a/submodules/TelegramUI/TelegramUI/TextLinkHandling.swift b/submodules/TelegramUI/TelegramUI/TextLinkHandling.swift index d8d1fd0fb2..6579d898c6 100644 --- a/submodules/TelegramUI/TelegramUI/TextLinkHandling.swift +++ b/submodules/TelegramUI/TelegramUI/TextLinkHandling.swift @@ -32,7 +32,7 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: PeerId?, navigate peerSignal = context.account.postbox.loadedPeerWithId(peerId) |> map(Optional.init) navigateDisposable.set((peerSignal |> take(1) |> deliverOnMainQueue).start(next: { peer in if let controller = controller, let peer = peer { - if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { (controller.navigationController as? NavigationController)?.pushViewController(infoController) } } diff --git a/submodules/TemporaryCachedPeerDataManager/Sources/PeerChannelMemberCategoriesContextsManager.swift b/submodules/TemporaryCachedPeerDataManager/Sources/PeerChannelMemberCategoriesContextsManager.swift index a1e70f6726..b5e386a3a8 100644 --- a/submodules/TemporaryCachedPeerDataManager/Sources/PeerChannelMemberCategoriesContextsManager.swift +++ b/submodules/TemporaryCachedPeerDataManager/Sources/PeerChannelMemberCategoriesContextsManager.swift @@ -27,9 +27,34 @@ private final class PeerChannelMembersOnlineContext { } } +private final class ProfileDataPreloadContext { + let subscribers = Bag<() -> Void>() + + let disposable: Disposable + var emptyTimer: SwiftSignalKit.Timer? + + init(disposable: Disposable) { + self.disposable = disposable + } +} + +private final class ProfileDataPhotoPreloadContext { + let subscribers = Bag<(Any?) -> Void>() + + let disposable: Disposable + var value: Any? + var emptyTimer: SwiftSignalKit.Timer? + + init(disposable: Disposable) { + self.disposable = disposable + } +} + private final class PeerChannelMemberCategoriesContextsManagerImpl { fileprivate var contexts: [PeerId: PeerChannelMemberCategoriesContext] = [:] fileprivate var onlineContexts: [PeerId: PeerChannelMembersOnlineContext] = [:] + fileprivate var profileDataPreloadContexts: [PeerId: ProfileDataPreloadContext] = [:] + fileprivate var profileDataPhotoPreloadContexts: [PeerId: ProfileDataPhotoPreloadContext] = [:] func getContext(postbox: Postbox, network: Network, accountPeerId: PeerId, peerId: PeerId, key: PeerChannelMemberContextKey, requestUpdate: Bool, updated: @escaping (ChannelMemberListState) -> Void) -> (Disposable, PeerChannelMemberCategoryControl) { if let current = self.contexts[peerId] { @@ -121,6 +146,121 @@ private final class PeerChannelMemberCategoriesContextsManagerImpl { context.loadMore(control) } } + + func profileData(postbox: Postbox, network: Network, peerId: PeerId, customData: Signal?) -> Disposable { + let context: ProfileDataPreloadContext + if let current = self.profileDataPreloadContexts[peerId] { + context = current + } else { + let disposable = DisposableSet() + context = ProfileDataPreloadContext(disposable: disposable) + self.profileDataPreloadContexts[peerId] = context + + if let customData = customData { + disposable.add(customData.start()) + } + + /*disposable.set(signal.start(next: { [weak context] value in + guard let context = context else { + return + } + context.value = value + for f in context.subscribers.copyItems() { + f(value) + } + }))*/ + } + + if let emptyTimer = context.emptyTimer { + emptyTimer.invalidate() + context.emptyTimer = nil + } + + let index = context.subscribers.add({ + }) + //updated(context.value ?? 0) + + return ActionDisposable { [weak self, weak context] in + Queue.mainQueue().async { + guard let strongSelf = self else { + return + } + if let current = strongSelf.profileDataPreloadContexts[peerId], let context = context, current === context { + current.subscribers.remove(index) + if current.subscribers.isEmpty { + if current.emptyTimer == nil { + let timer = SwiftSignalKit.Timer(timeout: 60.0, repeat: false, completion: { [weak context] in + if let current = strongSelf.profileDataPreloadContexts[peerId], let context = context, current === context { + if current.subscribers.isEmpty { + strongSelf.profileDataPreloadContexts.removeValue(forKey: peerId) + current.disposable.dispose() + } + } + }, queue: Queue.mainQueue()) + current.emptyTimer = timer + timer.start() + } + } + } + } + } + } + + func profilePhotos(postbox: Postbox, network: Network, peerId: PeerId, fetch: Signal, updated: @escaping (Any?) -> Void) -> Disposable { + let context: ProfileDataPhotoPreloadContext + if let current = self.profileDataPhotoPreloadContexts[peerId] { + context = current + } else { + let disposable = MetaDisposable() + context = ProfileDataPhotoPreloadContext(disposable: disposable) + self.profileDataPhotoPreloadContexts[peerId] = context + + disposable.set(fetch.start(next: { [weak context] value in + guard let context = context else { + return + } + context.value = value + for f in context.subscribers.copyItems() { + f(value) + } + })) + } + + if let emptyTimer = context.emptyTimer { + emptyTimer.invalidate() + context.emptyTimer = nil + } + + let index = context.subscribers.add({ next in + updated(next) + }) + updated(context.value) + + return ActionDisposable { [weak self, weak context] in + Queue.mainQueue().async { + guard let strongSelf = self else { + return + } + if let current = strongSelf.profileDataPhotoPreloadContexts[peerId], let context = context, current === context { + current.subscribers.remove(index) + if current.subscribers.isEmpty { + if current.emptyTimer == nil { + let timer = SwiftSignalKit.Timer(timeout: 60.0, repeat: false, completion: { [weak context] in + if let current = strongSelf.profileDataPhotoPreloadContexts[peerId], let context = context, current === context { + if current.subscribers.isEmpty { + strongSelf.profileDataPhotoPreloadContexts.removeValue(forKey: peerId) + current.disposable.dispose() + } + } + }, queue: Queue.mainQueue()) + current.emptyTimer = timer + timer.start() + } + } + } + } + } + } } public final class PeerChannelMemberCategoriesContextsManager { @@ -394,4 +534,35 @@ public final class PeerChannelMemberCategoriesContextsManager { } |> runOn(Queue.mainQueue()) } + + public func profileData(postbox: Postbox, network: Network, peerId: PeerId, customData: Signal?) -> Signal { + return Signal { [weak self] subscriber in + guard let strongSelf = self else { + subscriber.putCompletion() + return EmptyDisposable + } + let disposable = strongSelf.impl.syncWith({ impl -> Disposable in + return impl.profileData(postbox: postbox, network: network, peerId: peerId, customData: customData) + }) + return disposable ?? EmptyDisposable + } + |> runOn(Queue.mainQueue()) + } + + public func profilePhotos(postbox: Postbox, network: Network, peerId: PeerId, fetch: Signal) -> Signal { + return Signal { [weak self] subscriber in + guard let strongSelf = self else { + subscriber.putNext(0) + subscriber.putCompletion() + return EmptyDisposable + } + let disposable = strongSelf.impl.syncWith({ impl -> Disposable in + return impl.profilePhotos(postbox: postbox, network: network, peerId: peerId, fetch: fetch, updated: { value in + subscriber.putNext(value) + }) + }) + return disposable ?? EmptyDisposable + } + |> runOn(Queue.mainQueue()) + } } From 6a9f0774b6dc1a4701f40ef378959ec000f4d614 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 11 Feb 2020 15:43:59 +0100 Subject: [PATCH 19/30] Revert lottie? --- submodules/rlottie/rlottie | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/rlottie/rlottie b/submodules/rlottie/rlottie index a09896b3e7..0ee2e9c584 160000 --- a/submodules/rlottie/rlottie +++ b/submodules/rlottie/rlottie @@ -1 +1 @@ -Subproject commit a09896b3e72e76681c12e80572a7d570108cf885 +Subproject commit 0ee2e9c5843257ccd11672611829b9bb5d02aa98 From 801b26f1579ecce07cf1537828e0d9bae521660a Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 11 Feb 2020 19:41:59 +0400 Subject: [PATCH 20/30] Fixes --- Telegram-iOS/Resources/Compass.tgs | Bin 11211 -> 11147 bytes .../ZoomableContentGalleryItemNode.swift | 28 ++++--- .../Sources/PeersNearbyController.swift | 77 +++++++++++++----- submodules/SyncCore/Sources/Namespaces.swift | 7 ++ submodules/TelegramApi/Sources/Api0.swift | 5 +- submodules/TelegramApi/Sources/Api1.swift | 38 +++++++++ submodules/TelegramApi/Sources/Api2.swift | 38 ++++----- submodules/TelegramApi/Sources/Api3.swift | 27 ++++++ .../TelegramCore/Sources/BankCards.swift | 49 ++++++++--- .../TelegramCore/Sources/PeersNearby.swift | 48 ++++++++++- .../TelegramUI/ChatController.swift | 7 +- 11 files changed, 253 insertions(+), 71 deletions(-) diff --git a/Telegram-iOS/Resources/Compass.tgs b/Telegram-iOS/Resources/Compass.tgs index d9ec83eb7741d23487187cafe49dc52d7109fca7..535e4362bf03eedfbfae82180281b993846e68db 100644 GIT binary patch delta 11007 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 delta 11067 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 B#3=v( diff --git a/submodules/GalleryUI/Sources/ZoomableContentGalleryItemNode.swift b/submodules/GalleryUI/Sources/ZoomableContentGalleryItemNode.swift index a0abf7e711..a420bcbf20 100644 --- a/submodules/GalleryUI/Sources/ZoomableContentGalleryItemNode.swift +++ b/submodules/GalleryUI/Sources/ZoomableContentGalleryItemNode.swift @@ -7,7 +7,7 @@ private let leftFadeImage = generateImage(CGSize(width: 64.0, height: 1.0), opaq let bounds = CGRect(origin: CGPoint(), size: size) context.clear(bounds) - let gradientColors = [UIColor.black.withAlphaComponent(0.5).cgColor, UIColor.black.withAlphaComponent(0.0).cgColor] as CFArray + let gradientColors = [UIColor.black.withAlphaComponent(0.35).cgColor, UIColor.black.withAlphaComponent(0.0).cgColor] as CFArray var locations: [CGFloat] = [0.0, 1.0] let colorSpace = CGColorSpaceCreateDeviceRGB() @@ -20,7 +20,7 @@ private let rightFadeImage = generateImage(CGSize(width: 64.0, height: 1.0), opa let bounds = CGRect(origin: CGPoint(), size: size) context.clear(bounds) - let gradientColors = [UIColor.black.withAlphaComponent(0.0).cgColor, UIColor.black.withAlphaComponent(0.5).cgColor] as CFArray + let gradientColors = [UIColor.black.withAlphaComponent(0.0).cgColor, UIColor.black.withAlphaComponent(0.35).cgColor] as CFArray var locations: [CGFloat] = [0.0, 1.0] let colorSpace = CGColorSpaceCreateDeviceRGB() @@ -63,12 +63,12 @@ open class ZoomableContentGalleryItemNode: GalleryItemNode, UIScrollViewDelegate self.leftFadeNode = ASImageNode() self.leftFadeNode.contentMode = .scaleToFill self.leftFadeNode.image = leftFadeImage - self.leftFadeNode.isHidden = true + self.leftFadeNode.alpha = 0.0 self.rightFadeNode = ASImageNode() self.rightFadeNode.contentMode = .scaleToFill self.rightFadeNode.image = rightFadeImage - self.rightFadeNode.isHidden = true + self.rightFadeNode.alpha = 0.0 super.init() @@ -90,21 +90,21 @@ open class ZoomableContentGalleryItemNode: GalleryItemNode, UIScrollViewDelegate } tapRecognizer.highlight = { [weak self] location in if let strongSelf = self { + let transition: ContainedViewLayoutTransition = .animated(duration: 0.07, curve: .easeInOut) if let location = location, location.x < 44.0 { - strongSelf.leftFadeNode.isHidden = false + transition.updateAlpha(node: strongSelf.leftFadeNode, alpha: 1.0) } else { - strongSelf.leftFadeNode.isHidden = true + transition.updateAlpha(node: strongSelf.leftFadeNode, alpha: 0.0) } if let location = location, location.x > strongSelf.frame.width - 44.0 { - strongSelf.rightFadeNode.isHidden = false + transition.updateAlpha(node: strongSelf.rightFadeNode, alpha: 1.0) } else { - strongSelf.rightFadeNode.isHidden = true + transition.updateAlpha(node: strongSelf.rightFadeNode, alpha: 0.0) } } } self.scrollNode.view.addGestureRecognizer(tapRecognizer) - self.addSubnode(self.scrollNode) self.addSubnode(self.leftFadeNode) @@ -114,9 +114,10 @@ open class ZoomableContentGalleryItemNode: GalleryItemNode, UIScrollViewDelegate @objc open func contentTap(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { if recognizer.state == .ended { if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation { - if location.x < 44.0 { + let pointInNode = self.scrollNode.view.convert(location, to: self.view) + if pointInNode.x < 44.0 { self.goToPreviousItem() - } else if location.x > self.frame.width - 44.0 { + } else if pointInNode.x > self.frame.width - 44.0 { self.goToNextItem() } else { switch gesture { @@ -159,8 +160,9 @@ open class ZoomableContentGalleryItemNode: GalleryItemNode, UIScrollViewDelegate } self.containerLayout = layout - self.leftFadeNode.frame = CGRect(x: 0.0, y: 0.0, width: layout.size.width * 0.2, height: layout.size.height) - self.rightFadeNode.frame = CGRect(x: layout.size.width - layout.size.width * 0.2, y: 0.0, width: layout.size.width * 0.2, height: layout.size.height) + let fadeWidth = min(72.0, layout.size.width * 0.2) + self.leftFadeNode.frame = CGRect(x: 0.0, y: 0.0, width: fadeWidth, height: layout.size.height) + self.rightFadeNode.frame = CGRect(x: layout.size.width - fadeWidth, y: 0.0, width: fadeWidth, height: layout.size.height) if shouldResetContents { var previousFrame: CGRect? diff --git a/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift b/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift index b6f056e465..2a38f9c55b 100644 --- a/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift +++ b/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift @@ -24,6 +24,8 @@ import ContextUI import TelegramNotices import TelegramStringFormatting +private let maxUsersDisplayedLimit: Int32 = 5 + private struct PeerNearbyEntry { let peer: (Peer, CachedPeerData?) let expires: Int32 @@ -57,14 +59,16 @@ private final class PeersNearbyControllerArguments { let openChat: (Peer) -> Void let openCreateGroup: (Double, Double, String?) -> Void let contextAction: (Peer, ASDisplayNode, ContextGesture?) -> Void + let expandUsers: () -> Void - init(context: AccountContext, toggleVisibility: @escaping (Bool) -> Void, openProfile: @escaping (Peer) -> Void, openChat: @escaping (Peer) -> Void, openCreateGroup: @escaping (Double, Double, String?) -> Void, contextAction: @escaping (Peer, ASDisplayNode, ContextGesture?) -> Void) { + init(context: AccountContext, toggleVisibility: @escaping (Bool) -> Void, openProfile: @escaping (Peer) -> Void, openChat: @escaping (Peer) -> Void, openCreateGroup: @escaping (Double, Double, String?) -> Void, contextAction: @escaping (Peer, ASDisplayNode, ContextGesture?) -> Void, expandUsers: @escaping () -> Void) { self.context = context self.toggleVisibility = toggleVisibility self.openProfile = openProfile self.openChat = openChat self.openCreateGroup = openCreateGroup self.contextAction = contextAction + self.expandUsers = expandUsers } } @@ -82,6 +86,7 @@ private enum PeersNearbyEntry: ItemListNodeEntry { case empty(PresentationTheme, String) case visibility(PresentationTheme, String, Bool) case user(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, PeerNearbyEntry) + case expand(PresentationTheme, String) case groupsHeader(PresentationTheme, String, Bool) case createGroup(PresentationTheme, String, Double?, Double?, String?) @@ -94,7 +99,7 @@ private enum PeersNearbyEntry: ItemListNodeEntry { switch self { case .header: return PeersNearbySection.header.rawValue - case .usersHeader, .empty, .visibility, .user: + case .usersHeader, .empty, .visibility, .user, .expand: return PeersNearbySection.users.rawValue case .groupsHeader, .createGroup, .group: return PeersNearbySection.groups.rawValue @@ -115,12 +120,14 @@ private enum PeersNearbyEntry: ItemListNodeEntry { return 3 case let .user(index, _, _, _, _, _): return 4 + index - case .groupsHeader: + case .expand: return 1000 - case .createGroup: + case .groupsHeader: return 1001 + case .createGroup: + return 1002 case let .group(index, _, _, _, _, _): - return 1002 + index + return 1003 + index case .channelsHeader: return 2000 case let .channel(index, _, _, _, _, _): @@ -161,6 +168,12 @@ private enum PeersNearbyEntry: ItemListNodeEntry { } else { return false } + case let .expand(lhsTheme, lhsText): + if case let .expand(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } case let .groupsHeader(lhsTheme, lhsText, lhsLoading): if case let .groupsHeader(rhsTheme, rhsText, rhsLoading) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsLoading == rhsLoading { return true @@ -224,14 +237,19 @@ private enum PeersNearbyEntry: ItemListNodeEntry { }) case let .user(_, theme, strings, dateTimeFormat, nameDisplayOrder, peer): var text = strings.Map_DistanceAway(stringForDistance(peer.distance)).0 - if peer.peer.0.id == arguments.context.account.peerId { + let isSelfPeer = peer.peer.0.id == arguments.context.account.peerId + if isSelfPeer { text = strings.PeopleNearby_VisibleUntil(humanReadableStringForTimestamp(strings: strings, dateTimeFormat: dateTimeFormat, timestamp: peer.expires)).0 } - return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer.peer.0, aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: .text(strings.Map_DistanceAway(stringForDistance(peer.distance)).0), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: true, sectionId: self.section, action: { - arguments.openProfile(peer.peer.0) - }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: { node, gesture in - arguments.contextAction(peer.peer.0, node, gesture) - }, hasTopGroupInset: false, tag: nil) + return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer.peer.0, aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: .text(text), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: !isSelfPeer, sectionId: self.section, action: { + if !isSelfPeer { + arguments.openProfile(peer.peer.0) + } + }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: nil, hasTopGroupInset: false, tag: nil) + case let .expand(theme, title): + return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.downArrowImage(theme), title: title, sectionId: self.section, editing: false, action: { + arguments.expandUsers() + }) case let .groupsHeader(theme, text, loading): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, activityIndicator: loading ? .left : .none, sectionId: self.section) case let .createGroup(theme, title, latitude, longitude, address): @@ -294,7 +312,7 @@ private struct PeersNearbyData: Equatable { } } -private func peersNearbyControllerEntries(data: PeersNearbyData?, presentationData: PresentationData, displayLoading: Bool) -> [PeersNearbyEntry] { +private func peersNearbyControllerEntries(data: PeersNearbyData?, presentationData: PresentationData, displayLoading: Bool, expanded: Bool) -> [PeersNearbyEntry] { var entries: [PeersNearbyEntry] = [] entries.append(.header(presentationData.theme, presentationData.strings.PeopleNearby_DiscoverDescription)) @@ -305,10 +323,22 @@ private func peersNearbyControllerEntries(data: PeersNearbyData?, presentationDa if let data = data, !data.users.isEmpty { var i: Int32 = 0 - for user in data.users { + var users = data.users + var effectiveExpanded = expanded + if users.count > maxUsersDisplayedLimit && !expanded { + users = Array(users.prefix(Int(maxUsersDisplayedLimit))) + } else { + effectiveExpanded = true + } + + for user in users { entries.append(.user(i, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, user)) i += 1 } + + if !effectiveExpanded { + entries.append(.expand(presentationData.theme, presentationData.strings.PeopleNearby_ShowMorePeople(Int32(data.users.count) - maxUsersDisplayedLimit))) + } } entries.append(.groupsHeader(presentationData.theme, presentationData.strings.PeopleNearby_Groups.uppercased(), displayLoading && data == nil)) @@ -429,6 +459,9 @@ public func peersNearbyController(context: AccountContext) -> ViewController { let dataPromise = Promise(nil) let addressPromise = Promise(nil) + let visibilityPromise = ValuePromise(true) + let expandedPromise = ValuePromise(false) + let coordinatePromise = Promise(nil) coordinatePromise.set(.single(nil) |> then(currentLocationManagerCoordinate(manager: context.sharedContext.locationManager!, timeout: 5.0))) @@ -440,12 +473,16 @@ public func peersNearbyController(context: AccountContext) -> ViewController { let _ = (coordinatePromise.get() |> deliverOnMainQueue).start(next: { coordinate in if let coordinate = coordinate { - let _ = peersNearbyUpdateVisibility(network: context.account.network, stateManager: context.account.stateManager, update: .visible(latitude: coordinate.latitude, longitude: coordinate.longitude), background: false).start() + let _ = peersNearbyUpdateVisibility(account: context.account, update: .visible(latitude: coordinate.latitude, longitude: coordinate.longitude), background: false).start() } }) })]), nil) + + visibilityPromise.set(true) } else { - let _ = peersNearbyUpdateVisibility(network: context.account.network, stateManager: context.account.stateManager, update: .invisible, background: false).start() + let _ = peersNearbyUpdateVisibility(account: context.account, update: .invisible, background: false).start() + + visibilityPromise.set(false) } }, openProfile: { peer in navigateToProfileImpl?(peer) @@ -498,6 +535,8 @@ public func peersNearbyController(context: AccountContext) -> ViewController { presentControllerImpl?(c, nil) }), reactionItems: [], gesture: gesture) presentInGlobalOverlayImpl?(contextController) + }, expandUsers: { + expandedPromise.set(true) }) let dataSignal: Signal = coordinatePromise.get() @@ -569,9 +608,9 @@ public func peersNearbyController(context: AccountContext) -> ViewController { |> delay(1.0, queue: Queue.mainQueue()) ) - let signal = combineLatest(context.sharedContext.presentationData, dataPromise.get(), displayLoading) + let signal = combineLatest(context.sharedContext.presentationData, dataPromise.get(), displayLoading, visibilityPromise.get(), expandedPromise.get()) |> deliverOnMainQueue - |> map { presentationData, data, displayLoading -> (ItemListControllerState, (ItemListNodeState, Any)) in + |> map { presentationData, data, displayLoading, visibility, expanded -> (ItemListControllerState, (ItemListNodeState, Any)) in let previous = previousData.swap(data) var crossfade = false @@ -583,7 +622,7 @@ public func peersNearbyController(context: AccountContext) -> ViewController { } let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.PeopleNearby_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true) - let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: peersNearbyControllerEntries(data: data, presentationData: presentationData, displayLoading: displayLoading), style: .blocks, emptyStateItem: nil, crossfadeState: crossfade, animateChanges: !crossfade) + let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: peersNearbyControllerEntries(data: data, presentationData: presentationData, displayLoading: displayLoading, expanded: expanded), style: .blocks, emptyStateItem: nil, crossfadeState: crossfade, animateChanges: !crossfade) return (controllerState, (listState, arguments)) } @@ -596,7 +635,7 @@ public func peersNearbyController(context: AccountContext) -> ViewController { controller?.clearItemNodesHighlight(animated: true) } navigateToProfileImpl = { [weak controller] peer in - if let navigationController = controller?.navigationController as? NavigationController, let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: true) { + if let navigationController = controller?.navigationController as? NavigationController, let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { (navigationController as? NavigationController)?.pushViewController(controller) } } diff --git a/submodules/SyncCore/Sources/Namespaces.swift b/submodules/SyncCore/Sources/Namespaces.swift index 76d058ee03..1af4170023 100644 --- a/submodules/SyncCore/Sources/Namespaces.swift +++ b/submodules/SyncCore/Sources/Namespaces.swift @@ -197,6 +197,7 @@ private enum PreferencesKeyValues: Int32 { case walletCollection = 18 case contentSettings = 19 case chatListFilters = 20 + case peersNearby = 21 } public func applicationSpecificPreferencesKey(_ value: Int32) -> ValueBoxKey { @@ -313,6 +314,12 @@ public struct PreferencesKeys { key.setInt32(0, value: PreferencesKeyValues.chatListFilters.rawValue) return key }() + + public static let peersNearby: ValueBoxKey = { + let key = ValueBoxKey(length: 4) + key.setInt32(0, value: PreferencesKeyValues.peersNearby.rawValue) + return key + }() } private enum SharedDataKeyValues: Int32 { diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index d5464fef60..532cd4172a 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -561,6 +561,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1739392570] = { return Api.DocumentAttribute.parse_documentAttributeAudio($0) } dict[358154344] = { return Api.DocumentAttribute.parse_documentAttributeFilename($0) } dict[-1744710921] = { return Api.DocumentAttribute.parse_documentAttributeHasStickers($0) } + dict[-177732982] = { return Api.BankCardOpenUrl.parse_bankCardOpenUrl($0) } dict[307276766] = { return Api.account.Authorizations.parse_authorizations($0) } dict[935395612] = { return Api.ChatPhoto.parse_chatPhotoEmpty($0) } dict[1197267925] = { return Api.ChatPhoto.parse_chatPhoto($0) } @@ -818,7 +819,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1707344487] = { return Api.messages.HighScores.parse_highScores($0) } dict[-892779534] = { return Api.WebAuthorization.parse_webAuthorization($0) } dict[-805141448] = { return Api.ImportedContact.parse_importedContact($0) } - dict[-419239361] = { return Api.payments.BankCardData.parse_bankCardData($0) } + dict[1042605427] = { return Api.payments.BankCardData.parse_bankCardData($0) } return dict }() @@ -1238,6 +1239,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.DocumentAttribute: _1.serialize(buffer, boxed) + case let _1 as Api.BankCardOpenUrl: + _1.serialize(buffer, boxed) case let _1 as Api.account.Authorizations: _1.serialize(buffer, boxed) case let _1 as Api.ChatPhoto: diff --git a/submodules/TelegramApi/Sources/Api1.swift b/submodules/TelegramApi/Sources/Api1.swift index 6382732af6..280da4e641 100644 --- a/submodules/TelegramApi/Sources/Api1.swift +++ b/submodules/TelegramApi/Sources/Api1.swift @@ -15952,6 +15952,44 @@ public extension Api { return Api.DocumentAttribute.documentAttributeHasStickers } + } + public enum BankCardOpenUrl: TypeConstructorDescription { + case bankCardOpenUrl(url: String, name: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .bankCardOpenUrl(let url, let name): + if boxed { + buffer.appendInt32(-177732982) + } + serializeString(url, buffer: buffer, boxed: false) + serializeString(name, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .bankCardOpenUrl(let url, let name): + return ("bankCardOpenUrl", [("url", url), ("name", name)]) + } + } + + public static func parse_bankCardOpenUrl(_ reader: BufferReader) -> BankCardOpenUrl? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.BankCardOpenUrl.bankCardOpenUrl(url: _1!, name: _2!) + } + else { + return nil + } + } + } public enum ChatPhoto: TypeConstructorDescription { case chatPhotoEmpty diff --git a/submodules/TelegramApi/Sources/Api2.swift b/submodules/TelegramApi/Sources/Api2.swift index 261dc2d312..c4a1ac4fc5 100644 --- a/submodules/TelegramApi/Sources/Api2.swift +++ b/submodules/TelegramApi/Sources/Api2.swift @@ -491,44 +491,42 @@ public struct payments { } public enum BankCardData: TypeConstructorDescription { - case bankCardData(flags: Int32, title: String, url: String?, urlName: String?) + case bankCardData(title: String, openUrls: [Api.BankCardOpenUrl]) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .bankCardData(let flags, let title, let url, let urlName): + case .bankCardData(let title, let openUrls): if boxed { - buffer.appendInt32(-419239361) + buffer.appendInt32(1042605427) } - serializeInt32(flags, buffer: buffer, boxed: false) serializeString(title, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {serializeString(url!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 0) != 0 {serializeString(urlName!, buffer: buffer, boxed: false)} + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(openUrls.count)) + for item in openUrls { + item.serialize(buffer, true) + } break } } public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .bankCardData(let flags, let title, let url, let urlName): - return ("bankCardData", [("flags", flags), ("title", title), ("url", url), ("urlName", urlName)]) + case .bankCardData(let title, let openUrls): + return ("bankCardData", [("title", title), ("openUrls", openUrls)]) } } public static func parse_bankCardData(_ reader: BufferReader) -> BankCardData? { - var _1: Int32? - _1 = reader.readInt32() - var _2: String? - _2 = parseString(reader) - var _3: String? - if Int(_1!) & Int(1 << 0) != 0 {_3 = parseString(reader) } - var _4: String? - if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) } + var _1: String? + _1 = parseString(reader) + var _2: [Api.BankCardOpenUrl]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BankCardOpenUrl.self) + } let _c1 = _1 != nil let _c2 = _2 != nil - let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil - let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.payments.BankCardData.bankCardData(flags: _1!, title: _2!, url: _3, urlName: _4) + if _c1 && _c2 { + return Api.payments.BankCardData.bankCardData(title: _1!, openUrls: _2!) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api3.swift b/submodules/TelegramApi/Sources/Api3.swift index 106c437be6..326c59d924 100644 --- a/submodules/TelegramApi/Sources/Api3.swift +++ b/submodules/TelegramApi/Sources/Api3.swift @@ -3263,6 +3263,33 @@ public extension Api { }) } } + public static func inputMediaDice() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1358977017) + + return (FunctionDescription(name: "inputMediaDice", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.InputMedia? in + let reader = BufferReader(buffer) + var result: Api.InputMedia? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.InputMedia + } + return result + }) + } + + public static func messageMediaDice(value: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1670374507) + serializeInt32(value, buffer: buffer, boxed: false) + return (FunctionDescription(name: "messageMediaDice", parameters: [("value", value)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.MessageMedia? in + let reader = BufferReader(buffer) + var result: Api.MessageMedia? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.MessageMedia + } + return result + }) + } public struct channels { public static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() diff --git a/submodules/TelegramCore/Sources/BankCards.swift b/submodules/TelegramCore/Sources/BankCards.swift index f0db9d6304..b600491d83 100644 --- a/submodules/TelegramCore/Sources/BankCards.swift +++ b/submodules/TelegramCore/Sources/BankCards.swift @@ -2,33 +2,58 @@ import Foundation import Postbox import TelegramApi import SyncCore +import MtProtoKit import SwiftSignalKit +public struct BankCardUrl { + public let title: String + public let url: String +} + public struct BankCardInfo { public let title: String - public let url: String? - public let actionTitle: String? + public let urls: [BankCardUrl] } public func getBankCardInfo(account: Account, cardNumber: String) -> Signal { - return account.network.request(Api.functions.payments.getBankCardData(number: cardNumber)) - |> map { result -> BankCardInfo? in - return BankCardInfo(apiBankCardData: result) + return currentWebDocumentsHostDatacenterId(postbox: account.postbox, isTestingEnvironment: false) + |> mapToSignal { datacenterId in + let signal: Signal + if account.network.datacenterId != datacenterId { + signal = account.network.download(datacenterId: Int(datacenterId), isMedia: false, tag: nil) + |> castError(MTRpcError.self) + |> mapToSignal { worker in + return worker.request(Api.functions.payments.getBankCardData(number: cardNumber)) + } + } else { + signal = account.network.request(Api.functions.payments.getBankCardData(number: cardNumber)) + } + return signal + |> map { result -> BankCardInfo? in + return BankCardInfo(apiBankCardData: result) + } + |> `catch` { _ -> Signal in + return .single(nil) + } } - |> `catch` { _ -> Signal in - return .single(nil) +} + +extension BankCardUrl { + init(apiBankCardOpenUrl: Api.BankCardOpenUrl) { + switch apiBankCardOpenUrl { + case let .bankCardOpenUrl(url, name): + self.title = name + self.url = url + } } } extension BankCardInfo { init(apiBankCardData: Api.payments.BankCardData) { switch apiBankCardData { - case let .bankCardData(flags, title, url, urlName): + case let .bankCardData(title, urls): self.title = title - self.url = url - self.actionTitle = urlName + self.urls = urls.map { BankCardUrl(apiBankCardOpenUrl: $0) } } } } - - diff --git a/submodules/TelegramCore/Sources/PeersNearby.swift b/submodules/TelegramCore/Sources/PeersNearby.swift index 4ea533867d..b6eda7311b 100644 --- a/submodules/TelegramCore/Sources/PeersNearby.swift +++ b/submodules/TelegramCore/Sources/PeersNearby.swift @@ -25,7 +25,7 @@ public enum PeerNearbyVisibilityUpdate { case invisible } -public func peersNearbyUpdateVisibility(network: Network, stateManager: AccountStateManager, update: PeerNearbyVisibilityUpdate, background: Bool) -> Signal { +public func peersNearbyUpdateVisibility(account: Account, update: PeerNearbyVisibilityUpdate, background: Bool) -> Signal { var flags: Int32 = 0 var geoPoint: Api.InputGeoPoint var selfExpires: Int32? @@ -43,18 +43,30 @@ public func peersNearbyUpdateVisibility(network: Network, stateManager: AccountS selfExpires = 0 } + let _ = (account.postbox.transaction { transaction in + transaction.updatePreferencesEntry(key: PreferencesKeys.peersNearby, { entry in + var settings = entry as? PeersNearbyState ?? PeersNearbyState.default + if let expires = selfExpires { + settings.visibilityExpires = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) + expires + } else if case .invisible = update { + settings.visibilityExpires = nil + } + return settings + }) + }).start() + if background { flags |= (1 << 1) } - return network.request(Api.functions.contacts.getLocated(flags: flags, geoPoint: geoPoint, selfExpires: selfExpires)) + return account.network.request(Api.functions.contacts.getLocated(flags: flags, geoPoint: geoPoint, selfExpires: selfExpires)) |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } |> mapToSignal { updates -> Signal in if let updates = updates { - stateManager.addUpdates(updates) + account.stateManager.addUpdates(updates) } return .complete() } @@ -258,3 +270,33 @@ public func updateChannelGeoLocation(postbox: Postbox, network: Network, channel } } } + +public struct PeersNearbyState: PreferencesEntry, Equatable { + public var visibilityExpires: Int32? + + public static var `default` = PeersNearbyState(visibilityExpires: nil) + + public init(visibilityExpires: Int32?) { + self.visibilityExpires = visibilityExpires + } + + public init(decoder: PostboxDecoder) { + self.visibilityExpires = decoder.decodeOptionalInt32ForKey("expires") + } + + public func encode(_ encoder: PostboxEncoder) { + if let expires = self.visibilityExpires { + encoder.encodeInt32(expires, forKey: "expires") + } else { + encoder.encodeNil(forKey: "expires") + } + } + + public func isEqual(to: PreferencesEntry) -> Bool { + if let to = to as? PeersNearbyState, self == to { + return true + } else { + return false + } + } +} diff --git a/submodules/TelegramUI/TelegramUI/ChatController.swift b/submodules/TelegramUI/TelegramUI/ChatController.swift index 6f3df9a6e6..a5a67229ed 100644 --- a/submodules/TelegramUI/TelegramUI/ChatController.swift +++ b/submodules/TelegramUI/TelegramUI/ChatController.swift @@ -1357,17 +1357,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G guard let message = message else { return } + let _ = (getBankCardInfo(account: strongSelf.context.account, cardNumber: number) |> deliverOnMainQueue).start(next: { [weak self] info in if let strongSelf = self, let info = info { let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData) var items: [ActionSheetItem] = [] items.append(ActionSheetTextItem(title: info.title)) - if let url = info.url, let actionTitle = info.actionTitle { - items.append(ActionSheetButtonItem(title: actionTitle, color: .accent, action: { [weak actionSheet] in + for url in info.urls { + items.append(ActionSheetButtonItem(title: url.title, color: .accent, action: { [weak actionSheet] in actionSheet?.dismissAnimated() if let strongSelf = self { - strongSelf.controllerInteraction?.openUrl(url, false, false, message) + strongSelf.controllerInteraction?.openUrl(url.url, false, false, message) } })) } From fccb448731d1a2a0a6ad0fd703e4c613acd27d9e Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 11 Feb 2020 16:50:51 +0100 Subject: [PATCH 21/30] Semi-merge --- submodules/TelegramApi/Sources/Api0.swift | 31 +- submodules/TelegramApi/Sources/Api1.swift | 396 ++---------------- submodules/TelegramApi/Sources/Api2.swift | 158 +------ submodules/TelegramApi/Sources/Api3.swift | 78 ---- submodules/TelegramCore/Sources/Account.swift | 2 +- .../TelegramCore/Sources/AccountManager.swift | 2 +- .../Sources/ChatListFiltering.swift | 7 +- 7 files changed, 64 insertions(+), 610 deletions(-) diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index d5464fef60..da72996990 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -247,9 +247,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-2027964103] = { return Api.Update.parse_updateGeoLiveViewed($0) } dict[1448076945] = { return Api.Update.parse_updateLoginToken($0) } dict[1123585836] = { return Api.Update.parse_updateMessagePollVote($0) } - dict[654302845] = { return Api.Update.parse_updateDialogFilter($0) } - dict[-1512627963] = { return Api.Update.parse_updateDialogFilterOrder($0) } - dict[889491791] = { return Api.Update.parse_updateDialogFilters($0) } dict[136574537] = { return Api.messages.VotesList.parse_votesList($0) } dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) } dict[-373643672] = { return Api.FolderPeer.parse_folderPeer($0) } @@ -415,9 +412,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[2103482845] = { return Api.SecurePlainData.parse_securePlainPhone($0) } dict[569137759] = { return Api.SecurePlainData.parse_securePlainEmail($0) } dict[-1269012015] = { return Api.messages.AffectedHistory.parse_affectedHistory($0) } - dict[1244130093] = { return Api.StatsGraph.parse_statsGraphAsync($0) } - dict[-1092839390] = { return Api.StatsGraph.parse_statsGraphError($0) } - dict[-1057809608] = { return Api.StatsGraph.parse_statsGraph($0) } dict[-1036572727] = { return Api.account.PasswordInputSettings.parse_passwordInputSettings($0) } dict[878078826] = { return Api.PageTableCell.parse_pageTableCell($0) } dict[-1626209256] = { return Api.ChatBannedRights.parse_chatBannedRights($0) } @@ -486,7 +480,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-668391402] = { return Api.InputUser.parse_inputUser($0) } dict[-1366746132] = { return Api.Page.parse_page($0) } dict[871426631] = { return Api.SecureCredentialsEncrypted.parse_secureCredentialsEncrypted($0) } - dict[-875679776] = { return Api.StatsPercentValue.parse_statsPercentValue($0) } dict[157948117] = { return Api.upload.File.parse_file($0) } dict[-242427324] = { return Api.upload.File.parse_fileCdnRedirect($0) } dict[-1078612597] = { return Api.ChannelLocation.parse_channelLocationEmpty($0) } @@ -513,7 +506,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1160215659] = { return Api.InputMessage.parse_inputMessageReplyTo($0) } dict[-2037963464] = { return Api.InputMessage.parse_inputMessagePinned($0) } dict[-1564789301] = { return Api.PhoneCallProtocol.parse_phoneCallProtocol($0) } - dict[-1237848657] = { return Api.StatsDateRangeDays.parse_statsDateRangeDays($0) } dict[-1567175714] = { return Api.MessageFwdAuthor.parse_messageFwdAuthor($0) } dict[-1539849235] = { return Api.WallPaper.parse_wallPaper($0) } dict[-1963717851] = { return Api.WallPaper.parse_wallPaperNoFile($0) } @@ -528,7 +520,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1837345356] = { return Api.InputChatPhoto.parse_inputChatUploadedPhoto($0) } dict[-1991004873] = { return Api.InputChatPhoto.parse_inputChatPhoto($0) } dict[-368917890] = { return Api.PaymentCharge.parse_paymentCharge($0) } - dict[205195937] = { return Api.stats.BroadcastStats.parse_broadcastStats($0) } dict[-484987010] = { return Api.Updates.parse_updatesTooLong($0) } dict[-1857044719] = { return Api.Updates.parse_updateShortMessage($0) } dict[377562760] = { return Api.Updates.parse_updateShortChatMessage($0) } @@ -536,7 +527,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1918567619] = { return Api.Updates.parse_updatesCombined($0) } dict[1957577280] = { return Api.Updates.parse_updates($0) } dict[301019932] = { return Api.Updates.parse_updateShortSentMessage($0) } - dict[-884757282] = { return Api.StatsAbsValueAndPrev.parse_statsAbsValueAndPrev($0) } dict[1038967584] = { return Api.MessageMedia.parse_messageMediaEmpty($0) } dict[1457575028] = { return Api.MessageMedia.parse_messageMediaGeo($0) } dict[-1618676578] = { return Api.MessageMedia.parse_messageMediaUnsupported($0) } @@ -561,6 +551,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1739392570] = { return Api.DocumentAttribute.parse_documentAttributeAudio($0) } dict[358154344] = { return Api.DocumentAttribute.parse_documentAttributeFilename($0) } dict[-1744710921] = { return Api.DocumentAttribute.parse_documentAttributeHasStickers($0) } + dict[-177732982] = { return Api.BankCardOpenUrl.parse_bankCardOpenUrl($0) } dict[307276766] = { return Api.account.Authorizations.parse_authorizations($0) } dict[935395612] = { return Api.ChatPhoto.parse_chatPhotoEmpty($0) } dict[1197267925] = { return Api.ChatPhoto.parse_chatPhoto($0) } @@ -599,7 +590,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1551583367] = { return Api.ReceivedNotifyMessage.parse_receivedNotifyMessage($0) } dict[-57668565] = { return Api.ChatParticipants.parse_chatParticipantsForbidden($0) } dict[1061556205] = { return Api.ChatParticipants.parse_chatParticipants($0) } - dict[351868460] = { return Api.DialogFilter.parse_dialogFilter($0) } dict[-1056001329] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentialsSaved($0) } dict[873977640] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentials($0) } dict[178373535] = { return Api.InputPaymentCredentials.parse_inputPaymentCredentialsApplePay($0) } @@ -772,7 +762,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1041346555] = { return Api.updates.ChannelDifference.parse_channelDifferenceEmpty($0) } dict[543450958] = { return Api.updates.ChannelDifference.parse_channelDifference($0) } dict[-1531132162] = { return Api.updates.ChannelDifference.parse_channelDifferenceTooLong($0) } - dict[-581804346] = { return Api.StatsRowAbsValueAndPrev.parse_statsRowAbsValueAndPrev($0) } dict[-309659827] = { return Api.channels.AdminLogResults.parse_adminLogResults($0) } dict[-264117680] = { return Api.ChatOnlines.parse_chatOnlines($0) } dict[488313413] = { return Api.InputAppEvent.parse_inputAppEvent($0) } @@ -818,7 +807,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1707344487] = { return Api.messages.HighScores.parse_highScores($0) } dict[-892779534] = { return Api.WebAuthorization.parse_webAuthorization($0) } dict[-805141448] = { return Api.ImportedContact.parse_importedContact($0) } - dict[-419239361] = { return Api.payments.BankCardData.parse_bankCardData($0) } + dict[1042605427] = { return Api.payments.BankCardData.parse_bankCardData($0) } return dict }() @@ -1096,8 +1085,6 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.messages.AffectedHistory: _1.serialize(buffer, boxed) - case let _1 as Api.StatsGraph: - _1.serialize(buffer, boxed) case let _1 as Api.account.PasswordInputSettings: _1.serialize(buffer, boxed) case let _1 as Api.PageTableCell: @@ -1168,8 +1155,6 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.SecureCredentialsEncrypted: _1.serialize(buffer, boxed) - case let _1 as Api.StatsPercentValue: - _1.serialize(buffer, boxed) case let _1 as Api.upload.File: _1.serialize(buffer, boxed) case let _1 as Api.ChannelLocation: @@ -1204,8 +1189,6 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.PhoneCallProtocol: _1.serialize(buffer, boxed) - case let _1 as Api.StatsDateRangeDays: - _1.serialize(buffer, boxed) case let _1 as Api.MessageFwdAuthor: _1.serialize(buffer, boxed) case let _1 as Api.WallPaper: @@ -1222,12 +1205,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.PaymentCharge: _1.serialize(buffer, boxed) - case let _1 as Api.stats.BroadcastStats: - _1.serialize(buffer, boxed) case let _1 as Api.Updates: _1.serialize(buffer, boxed) - case let _1 as Api.StatsAbsValueAndPrev: - _1.serialize(buffer, boxed) case let _1 as Api.MessageMedia: _1.serialize(buffer, boxed) case let _1 as Api.PaymentSavedCredentials: @@ -1238,6 +1217,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.DocumentAttribute: _1.serialize(buffer, boxed) + case let _1 as Api.BankCardOpenUrl: + _1.serialize(buffer, boxed) case let _1 as Api.account.Authorizations: _1.serialize(buffer, boxed) case let _1 as Api.ChatPhoto: @@ -1276,8 +1257,6 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.ChatParticipants: _1.serialize(buffer, boxed) - case let _1 as Api.DialogFilter: - _1.serialize(buffer, boxed) case let _1 as Api.InputPaymentCredentials: _1.serialize(buffer, boxed) case let _1 as Api.ShippingOption: @@ -1408,8 +1387,6 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.updates.ChannelDifference: _1.serialize(buffer, boxed) - case let _1 as Api.StatsRowAbsValueAndPrev: - _1.serialize(buffer, boxed) case let _1 as Api.channels.AdminLogResults: _1.serialize(buffer, boxed) case let _1 as Api.ChatOnlines: diff --git a/submodules/TelegramApi/Sources/Api1.swift b/submodules/TelegramApi/Sources/Api1.swift index 6382732af6..be520b8f94 100644 --- a/submodules/TelegramApi/Sources/Api1.swift +++ b/submodules/TelegramApi/Sources/Api1.swift @@ -5861,9 +5861,6 @@ public extension Api { case updateGeoLiveViewed(peer: Api.Peer, msgId: Int32) case updateLoginToken case updateMessagePollVote(pollId: Int64, userId: Int32, options: [Buffer]) - case updateDialogFilter(flags: Int32, id: Int32, filter: Api.DialogFilter?) - case updateDialogFilterOrder(order: [Int32]) - case updateDialogFilters public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -6512,30 +6509,6 @@ public extension Api { for item in options { serializeBytes(item, buffer: buffer, boxed: false) } - break - case .updateDialogFilter(let flags, let id, let filter): - if boxed { - buffer.appendInt32(654302845) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeInt32(id, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {filter!.serialize(buffer, true)} - break - case .updateDialogFilterOrder(let order): - if boxed { - buffer.appendInt32(-1512627963) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(order.count)) - for item in order { - serializeInt32(item, buffer: buffer, boxed: false) - } - break - case .updateDialogFilters: - if boxed { - buffer.appendInt32(889491791) - } - break } } @@ -6696,12 +6669,6 @@ public extension Api { return ("updateLoginToken", []) case .updateMessagePollVote(let pollId, let userId, let options): return ("updateMessagePollVote", [("pollId", pollId), ("userId", userId), ("options", options)]) - case .updateDialogFilter(let flags, let id, let filter): - return ("updateDialogFilter", [("flags", flags), ("id", id), ("filter", filter)]) - case .updateDialogFilterOrder(let order): - return ("updateDialogFilterOrder", [("order", order)]) - case .updateDialogFilters: - return ("updateDialogFilters", []) } } @@ -7998,41 +7965,6 @@ public extension Api { return nil } } - public static func parse_updateDialogFilter(_ reader: BufferReader) -> Update? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Int32? - _2 = reader.readInt32() - var _3: Api.DialogFilter? - if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { - _3 = Api.parse(reader, signature: signature) as? Api.DialogFilter - } } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil - if _c1 && _c2 && _c3 { - return Api.Update.updateDialogFilter(flags: _1!, id: _2!, filter: _3) - } - else { - return nil - } - } - public static func parse_updateDialogFilterOrder(_ reader: BufferReader) -> Update? { - var _1: [Int32]? - if let _ = reader.readInt32() { - _1 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) - } - let _c1 = _1 != nil - if _c1 { - return Api.Update.updateDialogFilterOrder(order: _1!) - } - else { - return nil - } - } - public static func parse_updateDialogFilters(_ reader: BufferReader) -> Update? { - return Api.Update.updateDialogFilters - } } public enum PopularContact: TypeConstructorDescription { @@ -12024,82 +11956,6 @@ public extension Api { } } - } - public enum StatsGraph: TypeConstructorDescription { - case statsGraphAsync(token: String) - case statsGraphError(error: String) - case statsGraph(json: Api.DataJSON) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .statsGraphAsync(let token): - if boxed { - buffer.appendInt32(1244130093) - } - serializeString(token, buffer: buffer, boxed: false) - break - case .statsGraphError(let error): - if boxed { - buffer.appendInt32(-1092839390) - } - serializeString(error, buffer: buffer, boxed: false) - break - case .statsGraph(let json): - if boxed { - buffer.appendInt32(-1057809608) - } - json.serialize(buffer, true) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .statsGraphAsync(let token): - return ("statsGraphAsync", [("token", token)]) - case .statsGraphError(let error): - return ("statsGraphError", [("error", error)]) - case .statsGraph(let json): - return ("statsGraph", [("json", json)]) - } - } - - public static func parse_statsGraphAsync(_ reader: BufferReader) -> StatsGraph? { - var _1: String? - _1 = parseString(reader) - let _c1 = _1 != nil - if _c1 { - return Api.StatsGraph.statsGraphAsync(token: _1!) - } - else { - return nil - } - } - public static func parse_statsGraphError(_ reader: BufferReader) -> StatsGraph? { - var _1: String? - _1 = parseString(reader) - let _c1 = _1 != nil - if _c1 { - return Api.StatsGraph.statsGraphError(error: _1!) - } - else { - return nil - } - } - public static func parse_statsGraph(_ reader: BufferReader) -> StatsGraph? { - var _1: Api.DataJSON? - if let signature = reader.readInt32() { - _1 = Api.parse(reader, signature: signature) as? Api.DataJSON - } - let _c1 = _1 != nil - if _c1 { - return Api.StatsGraph.statsGraph(json: _1!) - } - else { - return nil - } - } - } public enum PageTableCell: TypeConstructorDescription { case pageTableCell(flags: Int32, text: Api.RichText?, colspan: Int32?, rowspan: Int32?) @@ -13806,44 +13662,6 @@ public extension Api { } } - } - public enum StatsPercentValue: TypeConstructorDescription { - case statsPercentValue(part: Double, total: Double) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .statsPercentValue(let part, let total): - if boxed { - buffer.appendInt32(-875679776) - } - serializeDouble(part, buffer: buffer, boxed: false) - serializeDouble(total, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .statsPercentValue(let part, let total): - return ("statsPercentValue", [("part", part), ("total", total)]) - } - } - - public static func parse_statsPercentValue(_ reader: BufferReader) -> StatsPercentValue? { - var _1: Double? - _1 = reader.readDouble() - var _2: Double? - _2 = reader.readDouble() - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.StatsPercentValue.statsPercentValue(part: _1!, total: _2!) - } - else { - return nil - } - } - } public enum ChannelLocation: TypeConstructorDescription { case channelLocationEmpty @@ -14616,44 +14434,6 @@ public extension Api { } } - } - public enum StatsDateRangeDays: TypeConstructorDescription { - case statsDateRangeDays(minDate: Int32, maxDate: Int32) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .statsDateRangeDays(let minDate, let maxDate): - if boxed { - buffer.appendInt32(-1237848657) - } - serializeInt32(minDate, buffer: buffer, boxed: false) - serializeInt32(maxDate, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .statsDateRangeDays(let minDate, let maxDate): - return ("statsDateRangeDays", [("minDate", minDate), ("maxDate", maxDate)]) - } - } - - public static func parse_statsDateRangeDays(_ reader: BufferReader) -> StatsDateRangeDays? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Int32? - _2 = reader.readInt32() - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.StatsDateRangeDays.statsDateRangeDays(minDate: _1!, maxDate: _2!) - } - else { - return nil - } - } - } public enum MessageFwdAuthor: TypeConstructorDescription { case messageFwdAuthor(channelId: Int32) @@ -15318,44 +15098,6 @@ public extension Api { } } - } - public enum StatsAbsValueAndPrev: TypeConstructorDescription { - case statsAbsValueAndPrev(current: Double, previous: Double) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .statsAbsValueAndPrev(let current, let previous): - if boxed { - buffer.appendInt32(-884757282) - } - serializeDouble(current, buffer: buffer, boxed: false) - serializeDouble(previous, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .statsAbsValueAndPrev(let current, let previous): - return ("statsAbsValueAndPrev", [("current", current), ("previous", previous)]) - } - } - - public static func parse_statsAbsValueAndPrev(_ reader: BufferReader) -> StatsAbsValueAndPrev? { - var _1: Double? - _1 = reader.readDouble() - var _2: Double? - _2 = reader.readDouble() - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.StatsAbsValueAndPrev.statsAbsValueAndPrev(current: _1!, previous: _2!) - } - else { - return nil - } - } - } public enum MessageMedia: TypeConstructorDescription { case messageMediaEmpty @@ -15952,6 +15694,44 @@ public extension Api { return Api.DocumentAttribute.documentAttributeHasStickers } + } + public enum BankCardOpenUrl: TypeConstructorDescription { + case bankCardOpenUrl(url: String, name: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .bankCardOpenUrl(let url, let name): + if boxed { + buffer.appendInt32(-177732982) + } + serializeString(url, buffer: buffer, boxed: false) + serializeString(name, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .bankCardOpenUrl(let url, let name): + return ("bankCardOpenUrl", [("url", url), ("name", name)]) + } + } + + public static func parse_bankCardOpenUrl(_ reader: BufferReader) -> BankCardOpenUrl? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.BankCardOpenUrl.bankCardOpenUrl(url: _1!, name: _2!) + } + else { + return nil + } + } + } public enum ChatPhoto: TypeConstructorDescription { case chatPhotoEmpty @@ -17072,58 +16852,6 @@ public extension Api { } } - } - public enum DialogFilter: TypeConstructorDescription { - case dialogFilter(flags: Int32, id: Int32, title: String, includePeers: [Api.InputPeer]) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .dialogFilter(let flags, let id, let title, let includePeers): - if boxed { - buffer.appendInt32(351868460) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeInt32(id, buffer: buffer, boxed: false) - serializeString(title, buffer: buffer, boxed: false) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(includePeers.count)) - for item in includePeers { - item.serialize(buffer, true) - } - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .dialogFilter(let flags, let id, let title, let includePeers): - return ("dialogFilter", [("flags", flags), ("id", id), ("title", title), ("includePeers", includePeers)]) - } - } - - public static func parse_dialogFilter(_ reader: BufferReader) -> DialogFilter? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Int32? - _2 = reader.readInt32() - var _3: String? - _3 = parseString(reader) - var _4: [Api.InputPeer]? - if let _ = reader.readInt32() { - _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputPeer.self) - } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.DialogFilter.dialogFilter(flags: _1!, id: _2!, title: _3!, includePeers: _4!) - } - else { - return nil - } - } - } public enum InputPaymentCredentials: TypeConstructorDescription { case inputPaymentCredentialsSaved(id: String, tmpPassword: Buffer) @@ -21190,54 +20918,6 @@ public extension Api { } } - } - public enum StatsRowAbsValueAndPrev: TypeConstructorDescription { - case statsRowAbsValueAndPrev(id: String, title: String, shortTitle: String, values: Api.StatsAbsValueAndPrev) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .statsRowAbsValueAndPrev(let id, let title, let shortTitle, let values): - if boxed { - buffer.appendInt32(-581804346) - } - serializeString(id, buffer: buffer, boxed: false) - serializeString(title, buffer: buffer, boxed: false) - serializeString(shortTitle, buffer: buffer, boxed: false) - values.serialize(buffer, true) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .statsRowAbsValueAndPrev(let id, let title, let shortTitle, let values): - return ("statsRowAbsValueAndPrev", [("id", id), ("title", title), ("shortTitle", shortTitle), ("values", values)]) - } - } - - public static func parse_statsRowAbsValueAndPrev(_ reader: BufferReader) -> StatsRowAbsValueAndPrev? { - var _1: String? - _1 = parseString(reader) - var _2: String? - _2 = parseString(reader) - var _3: String? - _3 = parseString(reader) - var _4: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _4 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.StatsRowAbsValueAndPrev.statsRowAbsValueAndPrev(id: _1!, title: _2!, shortTitle: _3!, values: _4!) - } - else { - return nil - } - } - } public enum ChatOnlines: TypeConstructorDescription { case chatOnlines(onlines: Int32) diff --git a/submodules/TelegramApi/Sources/Api2.swift b/submodules/TelegramApi/Sources/Api2.swift index 261dc2d312..b83eff3dc4 100644 --- a/submodules/TelegramApi/Sources/Api2.swift +++ b/submodules/TelegramApi/Sources/Api2.swift @@ -491,168 +491,42 @@ public struct payments { } public enum BankCardData: TypeConstructorDescription { - case bankCardData(flags: Int32, title: String, url: String?, urlName: String?) + case bankCardData(title: String, openUrls: [Api.BankCardOpenUrl]) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .bankCardData(let flags, let title, let url, let urlName): + case .bankCardData(let title, let openUrls): if boxed { - buffer.appendInt32(-419239361) + buffer.appendInt32(1042605427) } - serializeInt32(flags, buffer: buffer, boxed: false) serializeString(title, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {serializeString(url!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 0) != 0 {serializeString(urlName!, buffer: buffer, boxed: false)} + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(openUrls.count)) + for item in openUrls { + item.serialize(buffer, true) + } break } } public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .bankCardData(let flags, let title, let url, let urlName): - return ("bankCardData", [("flags", flags), ("title", title), ("url", url), ("urlName", urlName)]) + case .bankCardData(let title, let openUrls): + return ("bankCardData", [("title", title), ("openUrls", openUrls)]) } } public static func parse_bankCardData(_ reader: BufferReader) -> BankCardData? { - var _1: Int32? - _1 = reader.readInt32() - var _2: String? - _2 = parseString(reader) - var _3: String? - if Int(_1!) & Int(1 << 0) != 0 {_3 = parseString(reader) } - var _4: String? - if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil - let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.payments.BankCardData.bankCardData(flags: _1!, title: _2!, url: _3, urlName: _4) - } - else { - return nil - } - } - - } -} -} -public extension Api { -public struct stats { - public enum BroadcastStats: TypeConstructorDescription { - case broadcastStats(period: Api.StatsDateRangeDays, followers: Api.StatsAbsValueAndPrev, viewsPerPost: Api.StatsAbsValueAndPrev, sharesPerPost: Api.StatsAbsValueAndPrev, enabledNotifications: Api.StatsPercentValue, viewsBySource: [Api.StatsRowAbsValueAndPrev], newFollowersBySource: [Api.StatsRowAbsValueAndPrev], languages: [Api.StatsRowAbsValueAndPrev], growthGraph: Api.StatsGraph, followersGraph: Api.StatsGraph, muteGraph: Api.StatsGraph, topHoursGraph: Api.StatsGraph, interactionsGraph: Api.StatsGraph) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let enabledNotifications, let viewsBySource, let newFollowersBySource, let languages, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph): - if boxed { - buffer.appendInt32(205195937) - } - period.serialize(buffer, true) - followers.serialize(buffer, true) - viewsPerPost.serialize(buffer, true) - sharesPerPost.serialize(buffer, true) - enabledNotifications.serialize(buffer, true) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(viewsBySource.count)) - for item in viewsBySource { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(newFollowersBySource.count)) - for item in newFollowersBySource { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(languages.count)) - for item in languages { - item.serialize(buffer, true) - } - growthGraph.serialize(buffer, true) - followersGraph.serialize(buffer, true) - muteGraph.serialize(buffer, true) - topHoursGraph.serialize(buffer, true) - interactionsGraph.serialize(buffer, true) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let enabledNotifications, let viewsBySource, let newFollowersBySource, let languages, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph): - return ("broadcastStats", [("period", period), ("followers", followers), ("viewsPerPost", viewsPerPost), ("sharesPerPost", sharesPerPost), ("enabledNotifications", enabledNotifications), ("viewsBySource", viewsBySource), ("newFollowersBySource", newFollowersBySource), ("languages", languages), ("growthGraph", growthGraph), ("followersGraph", followersGraph), ("muteGraph", muteGraph), ("topHoursGraph", topHoursGraph), ("interactionsGraph", interactionsGraph)]) - } - } - - public static func parse_broadcastStats(_ reader: BufferReader) -> BroadcastStats? { - var _1: Api.StatsDateRangeDays? - if let signature = reader.readInt32() { - _1 = Api.parse(reader, signature: signature) as? Api.StatsDateRangeDays - } - var _2: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _3: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _3 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _4: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _4 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _5: Api.StatsPercentValue? - if let signature = reader.readInt32() { - _5 = Api.parse(reader, signature: signature) as? Api.StatsPercentValue - } - var _6: [Api.StatsRowAbsValueAndPrev]? + var _1: String? + _1 = parseString(reader) + var _2: [Api.BankCardOpenUrl]? if let _ = reader.readInt32() { - _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsRowAbsValueAndPrev.self) - } - var _7: [Api.StatsRowAbsValueAndPrev]? - if let _ = reader.readInt32() { - _7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsRowAbsValueAndPrev.self) - } - var _8: [Api.StatsRowAbsValueAndPrev]? - if let _ = reader.readInt32() { - _8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsRowAbsValueAndPrev.self) - } - var _9: Api.StatsGraph? - if let signature = reader.readInt32() { - _9 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _10: Api.StatsGraph? - if let signature = reader.readInt32() { - _10 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _11: Api.StatsGraph? - if let signature = reader.readInt32() { - _11 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _12: Api.StatsGraph? - if let signature = reader.readInt32() { - _12 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _13: Api.StatsGraph? - if let signature = reader.readInt32() { - _13 = Api.parse(reader, signature: signature) as? Api.StatsGraph + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.BankCardOpenUrl.self) } let _c1 = _1 != nil let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - let _c5 = _5 != nil - let _c6 = _6 != nil - let _c7 = _7 != nil - let _c8 = _8 != nil - let _c9 = _9 != nil - let _c10 = _10 != nil - let _c11 = _11 != nil - let _c12 = _12 != nil - let _c13 = _13 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 { - return Api.stats.BroadcastStats.broadcastStats(period: _1!, followers: _2!, viewsPerPost: _3!, sharesPerPost: _4!, enabledNotifications: _5!, viewsBySource: _6!, newFollowersBySource: _7!, languages: _8!, growthGraph: _9!, followersGraph: _10!, muteGraph: _11!, topHoursGraph: _12!, interactionsGraph: _13!) + if _c1 && _c2 { + return Api.payments.BankCardData.bankCardData(title: _1!, openUrls: _2!) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api3.swift b/submodules/TelegramApi/Sources/Api3.swift index 106c437be6..9d5351bb9e 100644 --- a/submodules/TelegramApi/Sources/Api3.swift +++ b/submodules/TelegramApi/Sources/Api3.swift @@ -3214,54 +3214,6 @@ public extension Api { return result }) } - - public static func getDialogFilters() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.DialogFilter]>) { - let buffer = Buffer() - buffer.appendInt32(-241247891) - - return (FunctionDescription(name: "messages.getDialogFilters", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> [Api.DialogFilter]? in - let reader = BufferReader(buffer) - var result: [Api.DialogFilter]? - if let _ = reader.readInt32() { - result = Api.parseVector(reader, elementSignature: 0, elementType: Api.DialogFilter.self) - } - return result - }) - } - - public static func updateDialogFilter(flags: Int32, id: Int32, filter: Api.DialogFilter?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { - let buffer = Buffer() - buffer.appendInt32(450142282) - serializeInt32(flags, buffer: buffer, boxed: false) - serializeInt32(id, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {filter!.serialize(buffer, true)} - return (FunctionDescription(name: "messages.updateDialogFilter", parameters: [("flags", flags), ("id", id), ("filter", filter)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in - let reader = BufferReader(buffer) - var result: Api.Bool? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.Bool - } - return result - }) - } - - public static func updateDialogFiltersOrder(order: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { - let buffer = Buffer() - buffer.appendInt32(-983318044) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(order.count)) - for item in order { - serializeInt32(item, buffer: buffer, boxed: false) - } - return (FunctionDescription(name: "messages.updateDialogFiltersOrder", parameters: [("order", order)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in - let reader = BufferReader(buffer) - var result: Api.Bool? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.Bool - } - return result - }) - } } public struct channels { public static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { @@ -3948,36 +3900,6 @@ public extension Api { }) } } - public struct stats { - public static func getBroadcastStats(flags: Int32, channel: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { - let buffer = Buffer() - buffer.appendInt32(-1421720550) - serializeInt32(flags, buffer: buffer, boxed: false) - channel.serialize(buffer, true) - return (FunctionDescription(name: "stats.getBroadcastStats", parameters: [("flags", flags), ("channel", channel)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.stats.BroadcastStats? in - let reader = BufferReader(buffer) - var result: Api.stats.BroadcastStats? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.stats.BroadcastStats - } - return result - }) - } - - public static func loadAsyncGraph(token: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { - let buffer = Buffer() - buffer.appendInt32(1749505346) - serializeString(token, buffer: buffer, boxed: false) - return (FunctionDescription(name: "stats.loadAsyncGraph", parameters: [("token", token)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.StatsGraph? in - let reader = BufferReader(buffer) - var result: Api.StatsGraph? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - return result - }) - } - } public struct auth { public static func checkPhone(phoneNumber: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() diff --git a/submodules/TelegramCore/Sources/Account.swift b/submodules/TelegramCore/Sources/Account.swift index cec053cf33..d28d1ee0a1 100644 --- a/submodules/TelegramCore/Sources/Account.swift +++ b/submodules/TelegramCore/Sources/Account.swift @@ -1044,7 +1044,7 @@ public class Account { self.managedOperationsDisposable.add(managedApplyPendingMessageReactionsActions(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) self.managedOperationsDisposable.add(managedSynchronizeEmojiKeywordsOperations(postbox: self.postbox, network: self.network).start()) self.managedOperationsDisposable.add(managedApplyPendingScheduledMessagesActions(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) - self.managedOperationsDisposable.add(managedChatListFilters(postbox: self.postbox, network: self.network).start()) + //self.managedOperationsDisposable.add(managedChatListFilters(postbox: self.postbox, network: self.network).start()) let importantBackgroundOperations: [Signal] = [ managedSynchronizeChatInputStateOperations(postbox: self.postbox, network: self.network) |> map { $0 ? AccountRunningImportantTasks.other : [] }, diff --git a/submodules/TelegramCore/Sources/AccountManager.swift b/submodules/TelegramCore/Sources/AccountManager.swift index eb61eb0fec..95a689aa1d 100644 --- a/submodules/TelegramCore/Sources/AccountManager.swift +++ b/submodules/TelegramCore/Sources/AccountManager.swift @@ -152,7 +152,7 @@ private var declaredEncodables: Void = { declareEncodable(EmbeddedMediaStickersMessageAttribute.self, f: { EmbeddedMediaStickersMessageAttribute(decoder: $0) }) declareEncodable(TelegramMediaWebpageAttribute.self, f: { TelegramMediaWebpageAttribute(decoder: $0) }) declareEncodable(CachedPollOptionResult.self, f: { CachedPollOptionResult(decoder: $0) }) - declareEncodable(ChatListFiltersState.self, f: { ChatListFiltersState(decoder: $0) }) + //declareEncodable(ChatListFiltersState.self, f: { ChatListFiltersState(decoder: $0) }) return }() diff --git a/submodules/TelegramCore/Sources/ChatListFiltering.swift b/submodules/TelegramCore/Sources/ChatListFiltering.swift index 1e01e92c02..f9966602c1 100644 --- a/submodules/TelegramCore/Sources/ChatListFiltering.swift +++ b/submodules/TelegramCore/Sources/ChatListFiltering.swift @@ -140,7 +140,7 @@ public struct ChatListFilter: PostboxCoding, Equatable { } } -extension ChatListFilter { +/*extension ChatListFilter { init(apiFilter: Api.DialogFilter) { switch apiFilter { case let .dialogFilter(flags, id, title, includePeers): @@ -179,13 +179,13 @@ extension ChatListFilter { return transaction.getPeer(peerId).flatMap(apiInputPeer) }) } -} +}*/ public enum RequestUpdateChatListFilterError { case generic } -public func requestUpdateChatListFilter(account: Account, id: Int32, filter: ChatListFilter?) -> Signal { +/*public func requestUpdateChatListFilter(account: Account, id: Int32, filter: ChatListFilter?) -> Signal { return account.postbox.transaction { transaction -> Api.DialogFilter? in return filter?.apiFilter(transaction: transaction) } @@ -376,3 +376,4 @@ public func updateChatListFilterSettingsInteractively(postbox: Postbox, _ f: @es return result ?? .default } } +*/ From cae526172fa65c9da240cae634b0d1d698646668 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 11 Feb 2020 17:03:36 +0100 Subject: [PATCH 22/30] Fix username sharing --- .../TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift index aa8dec56dd..e849ff7995 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift @@ -2110,7 +2110,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } private func openUsername(value: String) { - let shareController = ShareController(context: context, subject: .url("\(value)")) + let shareController = ShareController(context: self.context, subject: .url("https://t.me/\(value)")) self.view.endEditing(true) self.controller?.present(shareController, in: .window(.root)) } @@ -2645,7 +2645,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD case .link: if let addressName = peer.addressName { let contextMenuController = ContextMenuController(actions: [ContextMenuAction(content: .text(title: self.presentationData.strings.Conversation_ContextMenuCopy, accessibilityLabel: self.presentationData.strings.Conversation_ContextMenuCopy), action: { - UIPasteboard.general.string = addressName + UIPasteboard.general.string = "@" + addressName })]) controller.present(contextMenuController, in: .window(.root), with: ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self, weak sourceNode] in if let controller = self?.controller, let sourceNode = sourceNode { From 677b91f35065be6463746c50454b92ecfce33936 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 11 Feb 2020 17:42:54 +0100 Subject: [PATCH 23/30] Automatic updates --- Config/app_configuration.bzl | 4 +- Makefile | 2 +- submodules/BuildConfig/BUCK | 2 +- submodules/BuildConfig/Sources/BuildConfig.h | 2 +- submodules/BuildConfig/Sources/BuildConfig.m | 8 +- .../TelegramUI/TelegramUI/AppDelegate.swift | 129 ++++++++++++------ 6 files changed, 96 insertions(+), 51 deletions(-) diff --git a/Config/app_configuration.bzl b/Config/app_configuration.bzl index dbc6f547a5..da3e824e1e 100644 --- a/Config/app_configuration.bzl +++ b/Config/app_configuration.bzl @@ -2,7 +2,7 @@ def appConfig(): apiId = native.read_config("custom", "apiId") apiHash = native.read_config("custom", "apiHash") - hockeyAppId = native.read_config("custom", "hockeyAppId") + appCenterId = native.read_config("custom", "appCenterId") isInternalBuild = native.read_config("custom", "isInternalBuild") isAppStoreBuild = native.read_config("custom", "isAppStoreBuild") appStoreId = native.read_config("custom", "appStoreId") @@ -11,7 +11,7 @@ def appConfig(): return { "apiId": apiId, "apiHash": apiHash, - "hockeyAppId": hockeyAppId, + "appCenterId": appCenterId, "isInternalBuild": isInternalBuild, "isAppStoreBuild": isAppStoreBuild, "appStoreId": appStoreId, diff --git a/Makefile b/Makefile index ff68b48e5b..fccbd74086 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ BUCK_OPTIONS=\ --config custom.baseApplicationBundleId="${BUNDLE_ID}" \ --config custom.apiId="${API_ID}" \ --config custom.apiHash="${API_HASH}" \ - --config custom.hockeyAppId="${HOCKEYAPP_ID}" \ + --config custom.appCenterId="${APP_CENTER_ID}" \ --config custom.isInternalBuild="${IS_INTERNAL_BUILD}" \ --config custom.isAppStoreBuild="${IS_APPSTORE_BUILD}" \ --config custom.appStoreId="${APPSTORE_ID}" \ diff --git a/submodules/BuildConfig/BUCK b/submodules/BuildConfig/BUCK index 6298c2a05c..91dd26cf19 100644 --- a/submodules/BuildConfig/BUCK +++ b/submodules/BuildConfig/BUCK @@ -9,7 +9,7 @@ static_library( compiler_flags = [ '-DAPP_CONFIG_API_ID=' + appConfig()["apiId"], '-DAPP_CONFIG_API_HASH="' + appConfig()["apiHash"] + '"', - '-DAPP_CONFIG_HOCKEYAPP_ID="' + appConfig()["hockeyAppId"] + '"', + '-DAPP_CONFIG_APP_CENTER_ID="' + appConfig()["appCenterId"] + '"', '-DAPP_CONFIG_IS_INTERNAL_BUILD=' + appConfig()["isInternalBuild"], '-DAPP_CONFIG_IS_APPSTORE_BUILD=' + appConfig()["isAppStoreBuild"], '-DAPP_CONFIG_APPSTORE_ID=' + appConfig()["appStoreId"], diff --git a/submodules/BuildConfig/Sources/BuildConfig.h b/submodules/BuildConfig/Sources/BuildConfig.h index d13c28dc3f..562a63ce27 100644 --- a/submodules/BuildConfig/Sources/BuildConfig.h +++ b/submodules/BuildConfig/Sources/BuildConfig.h @@ -11,7 +11,7 @@ - (instancetype _Nonnull)initWithBaseAppBundleId:(NSString * _Nonnull)baseAppBundleId; -@property (nonatomic, strong, readonly) NSString * _Nullable hockeyAppId; +@property (nonatomic, strong, readonly) NSString * _Nullable appCenterId; @property (nonatomic, readonly) int32_t apiId; @property (nonatomic, strong, readonly) NSString * _Nonnull apiHash; @property (nonatomic, readonly) bool isInternalBuild; diff --git a/submodules/BuildConfig/Sources/BuildConfig.m b/submodules/BuildConfig/Sources/BuildConfig.m index 6c17f8f9eb..f4808b26cb 100644 --- a/submodules/BuildConfig/Sources/BuildConfig.m +++ b/submodules/BuildConfig/Sources/BuildConfig.m @@ -72,7 +72,7 @@ API_AVAILABLE(ios(10)) NSData * _Nullable _bundleData; int32_t _apiId; NSString * _Nonnull _apiHash; - NSString * _Nullable _hockeyAppId; + NSString * _Nullable _appCenterId; NSMutableDictionary * _Nonnull _dataDict; } @@ -129,7 +129,7 @@ API_AVAILABLE(ios(10)) if (self != nil) { _apiId = APP_CONFIG_API_ID; _apiHash = @(APP_CONFIG_API_HASH); - _hockeyAppId = @(APP_CONFIG_HOCKEYAPP_ID); + _appCenterId = @(APP_CONFIG_APP_CENTER_ID); _dataDict = [[NSMutableDictionary alloc] init]; @@ -163,8 +163,8 @@ API_AVAILABLE(ios(10)) return _apiHash; } -- (NSString * _Nullable)hockeyAppId { - return _hockeyAppId; +- (NSString * _Nullable)appCenterId { + return _appCenterId; } - (bool)isInternalBuild { diff --git a/submodules/TelegramUI/TelegramUI/AppDelegate.swift b/submodules/TelegramUI/TelegramUI/AppDelegate.swift index 02bcf8dd75..3750a848fd 100644 --- a/submodules/TelegramUI/TelegramUI/AppDelegate.swift +++ b/submodules/TelegramUI/TelegramUI/AppDelegate.swift @@ -5,7 +5,6 @@ import TelegramCore import SyncCore import UserNotifications import Intents -//import HockeySDK import Postbox import PushKit import AsyncDisplayKit @@ -157,12 +156,13 @@ final class SharedApplicationContext { } } -@objc(AppDelegate) class AppDelegate: UIResponder, UIApplicationDelegate, PKPushRegistryDelegate/*, BITHockeyManagerDelegate*/, UNUserNotificationCenterDelegate, UIAlertViewDelegate { +@objc(AppDelegate) class AppDelegate: UIResponder, UIApplicationDelegate, PKPushRegistryDelegate, UNUserNotificationCenterDelegate, UIAlertViewDelegate { @objc var window: UIWindow? var nativeWindow: (UIWindow & WindowHost)? var mainWindow: Window1! private var dataImportSplash: LegacyDataImportSplash? + private var buildConfig: BuildConfig? let episodeId = arc4random() private let isInForegroundPromise = ValuePromise(false, ignoreRepeated: true) @@ -369,6 +369,7 @@ final class SharedApplicationContext { let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName) let buildConfig = BuildConfig(baseAppBundleId: baseAppBundleId) + self.buildConfig = buildConfig let signatureDict = BuildConfigExtra.signatureDict() let apiId: Int32 = buildConfig.apiId @@ -1338,46 +1339,6 @@ final class SharedApplicationContext { self.isActivePromise.set(true) } - /*BITHockeyBaseManager.setPresentAlert({ [weak self] alert in - if let strongSelf = self, let alert = alert { - var actions: [TextAlertAction] = [] - for action in alert.actions { - let isDefault = action.style == .default - actions.append(TextAlertAction(type: isDefault ? .defaultAction : .genericAction, title: action.title ?? "", action: { - if let action = action as? BITAlertAction { - action.invokeAction() - } - })) - } - if let sharedContext = strongSelf.contextValue?.context.sharedContext { - let presentationData = sharedContext.currentPresentationData.with { $0 } - strongSelf.mainWindow.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: alert.title, text: alert.message ?? "", actions: actions), on: .root) - } - } - }) - - BITHockeyBaseManager.setPresentView({ [weak self] controller in - if let strongSelf = self, let controller = controller { - let parent = LegacyController(presentation: .modal(animateIn: true), theme: nil) - let navigationController = UINavigationController(rootViewController: controller) - controller.navigation_setDismiss({ [weak parent] in - parent?.dismiss() - }, rootController: nil) - parent.bind(controller: navigationController) - strongSelf.mainWindow.present(parent, on: .root) - } - }) - - if let hockeyAppId = buildConfig.hockeyAppId, !hockeyAppId.isEmpty { - BITHockeyManager.shared().configure(withIdentifier: hockeyAppId, delegate: self) - BITHockeyManager.shared().crashManager.crashManagerStatus = .alwaysAsk - BITHockeyManager.shared().start() - #if targetEnvironment(simulator) - #else - BITHockeyManager.shared().authenticator.authenticateInstallation() - #endif - }*/ - if UIApplication.shared.isStatusBarHidden { UIApplication.shared.setStatusBarHidden(false, with: .none) } @@ -1403,6 +1364,8 @@ final class SharedApplicationContext { }) }*/ + self.maybeCheckForUpdates() + return true } @@ -1486,6 +1449,8 @@ final class SharedApplicationContext { self.isInForegroundPromise.set(true) self.isActiveValue = true self.isActivePromise.set(true) + + self.maybeCheckForUpdates() } func applicationWillTerminate(_ application: UIApplication) { @@ -2204,6 +2169,60 @@ final class SharedApplicationContext { completionHandler() } + private var lastCheckForUpdatesTimestamp: Double? + private let currentCheckForUpdatesDisposable = MetaDisposable() + + private func maybeCheckForUpdates() { + #if targetEnvironment(simulator) + return; + #endif + + guard let buildConfig = self.buildConfig, !buildConfig.isAppStoreBuild, let appCenterId = buildConfig.appCenterId, !appCenterId.isEmpty else { + return + } + let timestamp = CFAbsoluteTimeGetCurrent() + if self.lastCheckForUpdatesTimestamp == nil || self.lastCheckForUpdatesTimestamp! < timestamp - 10.0 * 60.0 { + self.lastCheckForUpdatesTimestamp = timestamp + + if let url = URL(string: "https://api.appcenter.ms/v0.1/public/sdk/apps/\(appCenterId)/releases/latest") { + self.currentCheckForUpdatesDisposable.set((downloadHTTPData(url: url) + |> deliverOnMainQueue).start(next: { [weak self] data in + guard let strongSelf = self else { + return + } + guard let json = try? JSONSerialization.jsonObject(with: data, options: []) else { + return + } + guard let dict = json as? [String: Any] else { + return + } + guard let versionString = dict["version"] as? String, let version = Int(versionString) else { + return + } + guard let releaseNotesUrl = dict["release_notes_url"] as? String else { + return + } + guard let currentVersionString = Bundle.main.infoDictionary?["CFBundleVersion"] as? String, let currentVersion = Int(currentVersionString) else { + return + } + if currentVersion < version { + let _ = (strongSelf.sharedContextPromise.get() + |> take(1) + |> deliverOnMainQueue).start(next: { sharedContext in + let presentationData = sharedContext.sharedContext.currentPresentationData.with { $0 } + sharedContext.sharedContext.mainWindow?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: "A new build is available", actions: [ + TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), + TextAlertAction(type: .defaultAction, title: "Show", action: { + sharedContext.sharedContext.applicationBindings.openUrl(releaseNotesUrl) + }) + ]), on: .root, blockInteraction: false, completion: {}) + }) + } + })) + } + } + } + override var next: UIResponder? { if let context = self.contextValue, let controller = context.context.keyShortcutsController { return controller @@ -2345,3 +2364,29 @@ private func messageIdFromNotification(peerId: PeerId, notification: UNNotificat } return nil } + +private enum DownloadFileError { + case network +} + +private func downloadHTTPData(url: URL) -> Signal { + return Signal { subscriber in + let completed = Atomic(value: false) + let downloadTask = URLSession.shared.downloadTask(with: url, completionHandler: { location, _, error in + let _ = completed.swap(true) + if let location = location, let data = try? Data(contentsOf: location) { + subscriber.putNext(data) + subscriber.putCompletion() + } else { + subscriber.putError(.network) + } + }) + downloadTask.resume() + + return ActionDisposable { + if !completed.with({ $0 }) { + downloadTask.cancel() + } + } + } +} From fb3bed8ec5a94421be8084a8037ea82535547035 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 11 Feb 2020 22:43:41 +0400 Subject: [PATCH 24/30] Various fixes --- Telegram-iOS/en.lproj/Localizable.strings | 2 +- .../Sources/PeersNearbyController.swift | 35 ++++++++++--------- .../TelegramCore/Sources/PeersNearby.swift | 8 ++--- .../TelegramUI/ChatController.swift | 4 +++ 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/Telegram-iOS/en.lproj/Localizable.strings b/Telegram-iOS/en.lproj/Localizable.strings index ca26c1740e..363e615909 100644 --- a/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram-iOS/en.lproj/Localizable.strings @@ -5317,7 +5317,7 @@ Any member of this group will be able to see messages in the channel."; "PeopleNearby.VisibleUntil" = "visible until %@"; "PeopleNearby.MakeVisibleTitle" = "Make Myself Visible"; -"PeopleNearby.MakeVisibleDescription" = "Allow people nearby to view your profile for 24 hours?\n\nYour phone number will remain hidden."; +"PeopleNearby.MakeVisibleDescription" = "Users nearby will be able to view your profile and send you messages. This may help you find new friends, but could also attract excessive attention. You can stop sharing your profile and location at any time.\n\nYour phone number will remain hidden."; "PeopleNearby.DiscoverDescription" = "Exchange contact info with people nearby\nand find new friends."; diff --git a/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift b/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift index 2a38f9c55b..046903065c 100644 --- a/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift +++ b/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift @@ -293,32 +293,34 @@ private struct PeersNearbyData: Equatable { let longitude: Double let address: String? let visible: Bool + let accountPeerId: PeerId let users: [PeerNearbyEntry] let groups: [PeerNearbyEntry] let channels: [PeerNearbyEntry] - init(latitude: Double, longitude: Double, address: String?, visible: Bool, users: [PeerNearbyEntry], groups: [PeerNearbyEntry], channels: [PeerNearbyEntry]) { + init(latitude: Double, longitude: Double, address: String?, visible: Bool, accountPeerId: PeerId, users: [PeerNearbyEntry], groups: [PeerNearbyEntry], channels: [PeerNearbyEntry]) { self.latitude = latitude self.longitude = longitude self.address = address self.visible = visible + self.accountPeerId = accountPeerId self.users = users self.groups = groups self.channels = channels } static func ==(lhs: PeersNearbyData, rhs: PeersNearbyData) -> Bool { - return lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude && lhs.address == rhs.address && lhs.visible == rhs.visible && arePeerNearbyArraysEqual(lhs.users, rhs.users) && arePeerNearbyArraysEqual(lhs.groups, rhs.groups) && arePeerNearbyArraysEqual(lhs.channels, rhs.channels) + return lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude && lhs.address == rhs.address && lhs.visible == rhs.visible && lhs.accountPeerId == rhs.accountPeerId && arePeerNearbyArraysEqual(lhs.users, rhs.users) && arePeerNearbyArraysEqual(lhs.groups, rhs.groups) && arePeerNearbyArraysEqual(lhs.channels, rhs.channels) } } -private func peersNearbyControllerEntries(data: PeersNearbyData?, presentationData: PresentationData, displayLoading: Bool, expanded: Bool) -> [PeersNearbyEntry] { +private func peersNearbyControllerEntries(data: PeersNearbyData?, state: PeersNearbyState, presentationData: PresentationData, displayLoading: Bool, expanded: Bool) -> [PeersNearbyEntry] { var entries: [PeersNearbyEntry] = [] entries.append(.header(presentationData.theme, presentationData.strings.PeopleNearby_DiscoverDescription)) entries.append(.usersHeader(presentationData.theme, presentationData.strings.PeopleNearby_Users.uppercased(), displayLoading && data == nil)) - let visible = data?.visible ?? false + let visible = state.visibilityExpires != nil entries.append(.visibility(presentationData.theme, visible ? presentationData.strings.PeopleNearby_MakeInvisible : presentationData.strings.PeopleNearby_MakeVisible, visible)) if let data = data, !data.users.isEmpty { @@ -332,8 +334,10 @@ private func peersNearbyControllerEntries(data: PeersNearbyData?, presentationDa } for user in users { - entries.append(.user(i, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, user)) - i += 1 + if user.peer.0.id != data.accountPeerId { + entries.append(.user(i, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, user)) + i += 1 + } } if !effectiveExpanded { @@ -458,8 +462,6 @@ public func peersNearbyController(context: AccountContext) -> ViewController { let dataPromise = Promise(nil) let addressPromise = Promise(nil) - - let visibilityPromise = ValuePromise(true) let expandedPromise = ValuePromise(false) let coordinatePromise = Promise(nil) @@ -478,11 +480,9 @@ public func peersNearbyController(context: AccountContext) -> ViewController { }) })]), nil) - visibilityPromise.set(true) + } else { let _ = peersNearbyUpdateVisibility(account: context.account, update: .invisible, background: false).start() - - visibilityPromise.set(false) } }, openProfile: { peer in navigateToProfileImpl?(peer) @@ -585,7 +585,7 @@ public func peersNearbyController(context: AccountContext) -> ViewController { } } } - return PeersNearbyData(latitude: coordinate.latitude, longitude: coordinate.longitude, address: address, visible: visible, users: users, groups: groups, channels: []) + return PeersNearbyData(latitude: coordinate.latitude, longitude: coordinate.longitude, address: address, visible: visible, accountPeerId: context.account.peerId, users: users, groups: groups, channels: []) } } @@ -607,11 +607,12 @@ public func peersNearbyController(context: AccountContext) -> ViewController { .single(true) |> delay(1.0, queue: Queue.mainQueue()) ) - - let signal = combineLatest(context.sharedContext.presentationData, dataPromise.get(), displayLoading, visibilityPromise.get(), expandedPromise.get()) + + let signal = combineLatest(context.sharedContext.presentationData, dataPromise.get(), displayLoading, expandedPromise.get(), context.account.postbox.preferencesView(keys: [PreferencesKeys.peersNearby])) |> deliverOnMainQueue - |> map { presentationData, data, displayLoading, visibility, expanded -> (ItemListControllerState, (ItemListNodeState, Any)) in + |> map { presentationData, data, displayLoading, expanded, view -> (ItemListControllerState, (ItemListNodeState, Any)) in let previous = previousData.swap(data) + let state = view.values[PreferencesKeys.peersNearby] as? PeersNearbyState ?? .default var crossfade = false if (data?.users.isEmpty ?? true) != (previous?.users.isEmpty ?? true) { @@ -622,7 +623,7 @@ public func peersNearbyController(context: AccountContext) -> ViewController { } let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.PeopleNearby_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true) - let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: peersNearbyControllerEntries(data: data, presentationData: presentationData, displayLoading: displayLoading, expanded: expanded), style: .blocks, emptyStateItem: nil, crossfadeState: crossfade, animateChanges: !crossfade) + let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: peersNearbyControllerEntries(data: data, state: state, presentationData: presentationData, displayLoading: displayLoading, expanded: expanded), style: .blocks, emptyStateItem: nil, crossfadeState: crossfade, animateChanges: !crossfade) return (controllerState, (listState, arguments)) } @@ -635,7 +636,7 @@ public func peersNearbyController(context: AccountContext) -> ViewController { controller?.clearItemNodesHighlight(animated: true) } navigateToProfileImpl = { [weak controller] peer in - if let navigationController = controller?.navigationController as? NavigationController, let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false) { + if let navigationController = controller?.navigationController as? NavigationController, let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: peer.largeProfileImage != nil) { (navigationController as? NavigationController)?.pushViewController(controller) } } diff --git a/submodules/TelegramCore/Sources/PeersNearby.swift b/submodules/TelegramCore/Sources/PeersNearby.swift index b6eda7311b..99e8dedf7e 100644 --- a/submodules/TelegramCore/Sources/PeersNearby.swift +++ b/submodules/TelegramCore/Sources/PeersNearby.swift @@ -34,7 +34,7 @@ public func peersNearbyUpdateVisibility(account: Account, update: PeerNearbyVisi case let .visible(latitude, longitude): flags |= (1 << 0) geoPoint = .inputGeoPoint(lat: latitude, long: longitude) - selfExpires = 86400 + selfExpires = 0x7fffffff case let .location(latitude, longitude): geoPoint = .inputGeoPoint(lat: latitude, long: longitude) case .invisible: @@ -46,10 +46,10 @@ public func peersNearbyUpdateVisibility(account: Account, update: PeerNearbyVisi let _ = (account.postbox.transaction { transaction in transaction.updatePreferencesEntry(key: PreferencesKeys.peersNearby, { entry in var settings = entry as? PeersNearbyState ?? PeersNearbyState.default - if let expires = selfExpires { - settings.visibilityExpires = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) + expires - } else if case .invisible = update { + if case .invisible = update { settings.visibilityExpires = nil + } else if let expires = selfExpires { + settings.visibilityExpires = expires } return settings }) diff --git a/submodules/TelegramUI/TelegramUI/ChatController.swift b/submodules/TelegramUI/TelegramUI/ChatController.swift index a5a67229ed..aa050af1d9 100644 --- a/submodules/TelegramUI/TelegramUI/ChatController.swift +++ b/submodules/TelegramUI/TelegramUI/ChatController.swift @@ -1372,6 +1372,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } })) } + items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + UIPasteboard.general.string = number + })) actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [ ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in actionSheet?.dismissAnimated() From 79c48784b2e289b3b3b8080c0312d61d4a6fd3e0 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 11 Feb 2020 21:22:17 +0100 Subject: [PATCH 25/30] Peer info fixes --- Telegram-iOS/en.lproj/Localizable.strings | 8 + .../Display/NavigationButtonNode.swift | 2 +- .../TelegramCore/Sources/GroupsInCommon.swift | 153 +- .../Sources/PresentationStrings.swift | 6969 +++++++++-------- .../VerifiedIcon.imageset/Contents.json | 12 + .../VerifiedIcon.imageset/ic_verify_big.pdf | Bin 0 -> 4624 bytes .../PeerInfoGroupsInCommonPaneNode.swift | 41 +- .../PeerInfo/Panes/PeerInfoMembersPane.swift | 9 +- .../Panes/PeerInfoVisualMediaPaneNode.swift | 2 + .../TelegramUI/PeerInfo/PeerInfoData.swift | 115 +- .../PeerInfo/PeerInfoHeaderNode.swift | 57 +- .../PeerInfo/PeerInfoPaneContainerNode.swift | 53 +- .../TelegramUI/PeerInfo/PeerInfoScreen.swift | 141 +- .../Resources/PresentationStrings.mapping | Bin 145010 -> 145240 bytes .../WalletUI/Resources/WalletStrings.mapping | Bin 8384 -> 8384 bytes .../WalletUI/Sources/WalletStrings.swift | 4 +- 16 files changed, 3933 insertions(+), 3633 deletions(-) create mode 100644 submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIcon.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIcon.imageset/ic_verify_big.pdf diff --git a/Telegram-iOS/en.lproj/Localizable.strings b/Telegram-iOS/en.lproj/Localizable.strings index ca26c1740e..68f86b2920 100644 --- a/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram-iOS/en.lproj/Localizable.strings @@ -5322,3 +5322,11 @@ Any member of this group will be able to see messages in the channel."; "PeopleNearby.DiscoverDescription" = "Exchange contact info with people nearby\nand find new friends."; "Time.TomorrowAt" = "tomorrow at %@"; + +"PeerInfo.ButtonMessage" = "Message"; +"PeerInfo.ButtonDiscuss" = "Discuss"; +"PeerInfo.ButtonCall" = "Call"; +"PeerInfo.ButtonMute" = "Mute"; +"PeerInfo.ButtonUnmute" = "Unmute"; +"PeerInfo.ButtonMore" = "More"; +"PeerInfo.ButtonAddMember" = "Add Members"; diff --git a/submodules/Display/Display/NavigationButtonNode.swift b/submodules/Display/Display/NavigationButtonNode.swift index a21f37823f..17c2f5b747 100644 --- a/submodules/Display/Display/NavigationButtonNode.swift +++ b/submodules/Display/Display/NavigationButtonNode.swift @@ -68,7 +68,7 @@ private final class NavigationButtonItemNode: ASTextNode { imageNode.displayWithoutProcessing = true imageNode.displaysAsynchronously = false self.imageNode = imageNode - if value.size == CGSize(width: 30.0, height: 30.0) { + if false, value.size == CGSize(width: 30.0, height: 30.0) { if self.imageRippleNode.supernode == nil { self.addSubnode(self.imageRippleNode) self.imageRippleNode.image = generateFilledCircleImage(diameter: 30.0, color: self.rippleColor) diff --git a/submodules/TelegramCore/Sources/GroupsInCommon.swift b/submodules/TelegramCore/Sources/GroupsInCommon.swift index 4c4efd13c5..2a6d4eb7cf 100644 --- a/submodules/TelegramCore/Sources/GroupsInCommon.swift +++ b/submodules/TelegramCore/Sources/GroupsInCommon.swift @@ -3,7 +3,156 @@ import Postbox import TelegramApi import SwiftSignalKit -public func groupsInCommon(account:Account, peerId:PeerId) -> Signal<[Peer], NoError> { +public enum GroupsInCommonDataState: Equatable { + case loading + case ready(canLoadMore: Bool) +} + +public struct GroupsInCommonState: Equatable { + public var peers: [RenderedPeer] + public var count: Int? + public var dataState: GroupsInCommonDataState +} + +private final class GroupsInCommonContextImpl { + private let queue: Queue + private let account: Account + private let peerId: PeerId + + private let disposable = MetaDisposable() + + private var peers: [RenderedPeer] = [] + private var count: Int? + private var dataState: GroupsInCommonDataState = .ready(canLoadMore: true) + + private let stateValue = Promise() + var state: Signal { + return self.stateValue.get() + } + + init(queue: Queue, account: Account, peerId: PeerId) { + self.queue = queue + self.account = account + self.peerId = peerId + + self.loadMore(limit: 32) + } + + deinit { + self.disposable.dispose() + } + + func loadMore(limit: Int32) { + if case .ready(true) = self.dataState { + self.dataState = .loading + self.pushState() + + let maxId = self.peers.last?.peerId.id + let peerId = self.peerId + let network = self.account.network + let postbox = self.account.postbox + let signal: Signal<([Peer], Int), NoError> = self.account.postbox.transaction { transaction -> Api.InputUser? in + return transaction.getPeer(peerId).flatMap(apiInputUser) + } + |> mapToSignal { inputUser -> Signal<([Peer], Int), NoError> in + guard let inputUser = inputUser else { + return .single(([], 0)) + } + return network.request(Api.functions.messages.getCommonChats(userId: inputUser, maxId: maxId ?? 0, limit: limit)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal<([Peer], Int), NoError> in + let chats: [Api.Chat] + let count: Int? + switch result { + case .none: + chats = [] + count = nil + case let .chats(apiChats): + chats = apiChats + count = nil + case let .chatsSlice(apiCount, apiChats): + chats = apiChats + count = Int(apiCount) + } + + return postbox.transaction { transaction -> ([Peer], Int) in + var peers: [Peer] = [] + for chat in chats { + if let peer = parseTelegramGroupOrChannel(chat: chat) { + peers.append(peer) + } + } + updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer? in + return updated + }) + + return (peers, count ?? 0) + } + } + } + + self.disposable.set((signal + |> deliverOn(self.queue)).start(next: { [weak self] (peers, count) in + guard let strongSelf = self else { + return + } + var existingPeers = Set(strongSelf.peers.map { $0.peerId }) + for peer in peers { + if !existingPeers.contains(peer.id) { + existingPeers.insert(peer.id) + strongSelf.peers.append(RenderedPeer(peer: peer)) + } + } + + let updatedCount = max(strongSelf.peers.count, count) + strongSelf.count = updatedCount + strongSelf.dataState = .ready(canLoadMore: count != 0 && updatedCount > strongSelf.peers.count) + strongSelf.pushState() + })) + } + } + + private func pushState() { + self.stateValue.set(.single(GroupsInCommonState(peers: self.peers, count: self.count, dataState: self.dataState))) + } +} + +public final class GroupsInCommonContext { + private let queue: Queue = .mainQueue() + private let impl: QueueLocalObject + + public var state: Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + + self.impl.with { impl in + disposable.set(impl.state.start(next: { value in + subscriber.putNext(value) + })) + } + + return disposable + } + } + + public init(account: Account, peerId: PeerId) { + let queue = self.queue + self.impl = QueueLocalObject(queue: queue, generate: { + return GroupsInCommonContextImpl(queue: queue, account: account, peerId: peerId) + }) + } + + public func loadMore() { + self.impl.with { impl in + impl.loadMore(limit: 32) + } + } +} + +public func groupsInCommon(account: Account, peerId: PeerId) -> Signal<[Peer], NoError> { return account.postbox.transaction { transaction -> Signal<[Peer], NoError> in if let peer = transaction.getPeer(peerId), let inputUser = apiInputUser(peer) { return account.network.request(Api.functions.messages.getCommonChats(userId: inputUser, maxId: 0, limit: 100)) @@ -18,7 +167,7 @@ public func groupsInCommon(account:Account, peerId:PeerId) -> Signal<[Peer], NoE } return account.postbox.transaction { transaction -> [Peer] in - var peers:[Peer] = [] + var peers: [Peer] = [] for chat in chats { if let peer = parseTelegramGroupOrChannel(chat: chat) { peers.append(peer) diff --git a/submodules/TelegramPresentationData/Sources/PresentationStrings.swift b/submodules/TelegramPresentationData/Sources/PresentationStrings.swift index e8cef3ecce..acb68d246d 100644 --- a/submodules/TelegramPresentationData/Sources/PresentationStrings.swift +++ b/submodules/TelegramPresentationData/Sources/PresentationStrings.swift @@ -1026,4317 +1026,4324 @@ public final class PresentationStrings: Equatable { public var Conversation_FilePhotoOrVideo: String { return self._s[774]! } public var AccessDenied_Camera: String { return self._s[775]! } public var Watch_Compose_CurrentLocation: String { return self._s[776]! } - public var Channel_DiscussionGroup_MakeHistoryPublicProceed: String { return self._s[778]! } + public var PeerInfo_ButtonMessage: String { return self._s[778]! } + public var Channel_DiscussionGroup_MakeHistoryPublicProceed: String { return self._s[779]! } public func SecretImage_NotViewedYet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[779]!, self._r[779]!, [_0]) + return formatWithArgumentRanges(self._s[780]!, self._r[780]!, [_0]) } - public var GroupInfo_InvitationLinkDoesNotExist: String { return self._s[780]! } - public var Passport_Language_ro: String { return self._s[781]! } - public var EditTheme_UploadNewTheme: String { return self._s[782]! } - public var CheckoutInfo_SaveInfoHelp: String { return self._s[783]! } - public var Wallet_Intro_Terms: String { return self._s[784]! } + public var GroupInfo_InvitationLinkDoesNotExist: String { return self._s[781]! } + public var Passport_Language_ro: String { return self._s[782]! } + public var EditTheme_UploadNewTheme: String { return self._s[783]! } + public var CheckoutInfo_SaveInfoHelp: String { return self._s[784]! } + public var Wallet_Intro_Terms: String { return self._s[785]! } public func Notification_SecretChatMessageScreenshot(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[785]!, self._r[785]!, [_0]) + return formatWithArgumentRanges(self._s[786]!, self._r[786]!, [_0]) } - public var Login_CancelPhoneVerification: String { return self._s[786]! } - public var State_ConnectingToProxy: String { return self._s[787]! } - public var Calls_RatingTitle: String { return self._s[788]! } - public var Generic_ErrorMoreInfo: String { return self._s[789]! } - public var ChatList_Search_ShowMore: String { return self._s[790]! } - public var Appearance_PreviewReplyText: String { return self._s[791]! } - public var CheckoutInfo_ShippingInfoPostcodePlaceholder: String { return self._s[792]! } + public var Login_CancelPhoneVerification: String { return self._s[787]! } + public var State_ConnectingToProxy: String { return self._s[788]! } + public var Calls_RatingTitle: String { return self._s[789]! } + public var Generic_ErrorMoreInfo: String { return self._s[790]! } + public var ChatList_Search_ShowMore: String { return self._s[791]! } + public var Appearance_PreviewReplyText: String { return self._s[792]! } + public var CheckoutInfo_ShippingInfoPostcodePlaceholder: String { return self._s[793]! } public func Wallet_Send_Balance(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[793]!, self._r[793]!, [_0]) + return formatWithArgumentRanges(self._s[794]!, self._r[794]!, [_0]) } - public var IntentsSettings_SuggestedChatsContacts: String { return self._s[794]! } - public var SharedMedia_CategoryLinks: String { return self._s[795]! } - public var Calls_Missed: String { return self._s[796]! } - public var Cache_Photos: String { return self._s[800]! } - public var GroupPermission_NoAddMembers: String { return self._s[801]! } - public var ScheduledMessages_Title: String { return self._s[802]! } + public var IntentsSettings_SuggestedChatsContacts: String { return self._s[795]! } + public var SharedMedia_CategoryLinks: String { return self._s[796]! } + public var Calls_Missed: String { return self._s[797]! } + public var Cache_Photos: String { return self._s[801]! } + public var GroupPermission_NoAddMembers: String { return self._s[802]! } + public var ScheduledMessages_Title: String { return self._s[803]! } public func Channel_AdminLog_MessageUnpinned(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[803]!, self._r[803]!, [_0]) + return formatWithArgumentRanges(self._s[804]!, self._r[804]!, [_0]) } - public var Conversation_ShareBotLocationConfirmationTitle: String { return self._s[804]! } - public var Settings_ProxyDisabled: String { return self._s[805]! } + public var Conversation_ShareBotLocationConfirmationTitle: String { return self._s[805]! } + public var Settings_ProxyDisabled: String { return self._s[806]! } public func Settings_ApplyProxyAlertCredentials(_ _1: String, _ _2: String, _ _3: String, _ _4: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[806]!, self._r[806]!, [_1, _2, _3, _4]) + return formatWithArgumentRanges(self._s[807]!, self._r[807]!, [_1, _2, _3, _4]) } public func Conversation_RestrictedMediaTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[807]!, self._r[807]!, [_0]) + return formatWithArgumentRanges(self._s[808]!, self._r[808]!, [_0]) } - public var ChatList_Context_RemoveFromRecents: String { return self._s[809]! } - public var Appearance_Title: String { return self._s[810]! } + public var ChatList_Context_RemoveFromRecents: String { return self._s[810]! } + public var Appearance_Title: String { return self._s[811]! } public func Time_MonthOfYear_m2(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[812]!, self._r[812]!, [_0]) + return formatWithArgumentRanges(self._s[813]!, self._r[813]!, [_0]) } - public var Conversation_WalletRequiredText: String { return self._s[813]! } - public var StickerPacksSettings_ShowStickersButtonHelp: String { return self._s[814]! } - public var OldChannels_NoticeCreateText: String { return self._s[815]! } - public var Channel_EditMessageErrorGeneric: String { return self._s[816]! } - public var Privacy_Calls_IntegrationHelp: String { return self._s[817]! } - public var Preview_DeletePhoto: String { return self._s[818]! } - public var Appearance_AppIconFilledX: String { return self._s[819]! } - public var PrivacySettings_PrivacyTitle: String { return self._s[820]! } + public var Conversation_WalletRequiredText: String { return self._s[814]! } + public var StickerPacksSettings_ShowStickersButtonHelp: String { return self._s[815]! } + public var OldChannels_NoticeCreateText: String { return self._s[816]! } + public var Channel_EditMessageErrorGeneric: String { return self._s[817]! } + public var Privacy_Calls_IntegrationHelp: String { return self._s[818]! } + public var Preview_DeletePhoto: String { return self._s[819]! } + public var Appearance_AppIconFilledX: String { return self._s[820]! } + public var PrivacySettings_PrivacyTitle: String { return self._s[821]! } public func Conversation_BotInteractiveUrlAlert(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[821]!, self._r[821]!, [_0]) + return formatWithArgumentRanges(self._s[822]!, self._r[822]!, [_0]) } - public var Coub_TapForSound: String { return self._s[824]! } - public var Map_LocatingError: String { return self._s[825]! } - public var TwoStepAuth_EmailChangeSuccess: String { return self._s[827]! } - public var Conversation_SendMessage_SendSilently: String { return self._s[828]! } - public var VoiceOver_MessageContextOpenMessageMenu: String { return self._s[829]! } + public var Coub_TapForSound: String { return self._s[825]! } + public var Map_LocatingError: String { return self._s[826]! } + public var TwoStepAuth_EmailChangeSuccess: String { return self._s[828]! } + public var Conversation_SendMessage_SendSilently: String { return self._s[829]! } + public var VoiceOver_MessageContextOpenMessageMenu: String { return self._s[830]! } public func Wallet_Time_PreciseDate_m8(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[830]!, self._r[830]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[831]!, self._r[831]!, [_1, _2, _3]) } - public var Passport_ForgottenPassword: String { return self._s[831]! } - public var GroupInfo_InviteLink_RevokeLink: String { return self._s[832]! } - public var StickerPacksSettings_ArchivedPacks: String { return self._s[833]! } - public var Login_TermsOfServiceSignupDecline: String { return self._s[835]! } - public var Channel_Moderator_AccessLevelRevoke: String { return self._s[836]! } - public var Message_Location: String { return self._s[837]! } - public var Passport_Identity_NamePlaceholder: String { return self._s[838]! } - public var Channel_Management_Title: String { return self._s[839]! } - public var DialogList_SearchSectionDialogs: String { return self._s[841]! } - public var Compose_NewChannel_Members: String { return self._s[842]! } + public var Passport_ForgottenPassword: String { return self._s[832]! } + public var GroupInfo_InviteLink_RevokeLink: String { return self._s[833]! } + public var StickerPacksSettings_ArchivedPacks: String { return self._s[834]! } + public var Login_TermsOfServiceSignupDecline: String { return self._s[836]! } + public var Channel_Moderator_AccessLevelRevoke: String { return self._s[837]! } + public var Message_Location: String { return self._s[838]! } + public var Passport_Identity_NamePlaceholder: String { return self._s[839]! } + public var Channel_Management_Title: String { return self._s[840]! } + public var DialogList_SearchSectionDialogs: String { return self._s[842]! } + public var Compose_NewChannel_Members: String { return self._s[843]! } public func DialogList_SingleUploadingFileSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[843]!, self._r[843]!, [_0]) + return formatWithArgumentRanges(self._s[844]!, self._r[844]!, [_0]) } - public var GroupInfo_Location: String { return self._s[844]! } - public var Appearance_ThemePreview_ChatList_5_Name: String { return self._s[845]! } - public var ClearCache_Clear: String { return self._s[846]! } - public var AutoNightTheme_ScheduledFrom: String { return self._s[847]! } - public var PhotoEditor_WarmthTool: String { return self._s[848]! } - public var Passport_Language_tr: String { return self._s[849]! } + public var GroupInfo_Location: String { return self._s[845]! } + public var Appearance_ThemePreview_ChatList_5_Name: String { return self._s[846]! } + public var ClearCache_Clear: String { return self._s[847]! } + public var AutoNightTheme_ScheduledFrom: String { return self._s[848]! } + public var PhotoEditor_WarmthTool: String { return self._s[849]! } + public var Passport_Language_tr: String { return self._s[850]! } public func PUSH_MESSAGE_GAME_SCORE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[850]!, self._r[850]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[851]!, self._r[851]!, [_1, _2, _3]) } - public var OldChannels_NoticeUpgradeText: String { return self._s[851]! } - public var Login_ResetAccountProtected_Reset: String { return self._s[853]! } - public var Watch_PhotoView_Title: String { return self._s[854]! } - public var Passport_Phone_Delete: String { return self._s[855]! } - public var Undo_ChatDeletedForBothSides: String { return self._s[856]! } - public var Conversation_EditingMessageMediaEditCurrentPhoto: String { return self._s[857]! } - public var GroupInfo_Permissions: String { return self._s[858]! } - public var PasscodeSettings_TurnPasscodeOff: String { return self._s[859]! } - public var Profile_ShareContactButton: String { return self._s[860]! } - public var ChatSettings_Other: String { return self._s[861]! } - public var UserInfo_NotificationsDisabled: String { return self._s[862]! } - public var CheckoutInfo_ShippingInfoCity: String { return self._s[863]! } - public var LastSeen_WithinAMonth: String { return self._s[864]! } - public var VoiceOver_Chat_PlayHint: String { return self._s[865]! } - public var Conversation_ReportGroupLocation: String { return self._s[866]! } - public var Conversation_EncryptionCanceled: String { return self._s[867]! } - public var MediaPicker_GroupDescription: String { return self._s[868]! } - public var WebSearch_Images: String { return self._s[869]! } + public var OldChannels_NoticeUpgradeText: String { return self._s[852]! } + public var Login_ResetAccountProtected_Reset: String { return self._s[854]! } + public var Watch_PhotoView_Title: String { return self._s[855]! } + public var Passport_Phone_Delete: String { return self._s[856]! } + public var Undo_ChatDeletedForBothSides: String { return self._s[857]! } + public var Conversation_EditingMessageMediaEditCurrentPhoto: String { return self._s[858]! } + public var GroupInfo_Permissions: String { return self._s[859]! } + public var PasscodeSettings_TurnPasscodeOff: String { return self._s[860]! } + public var Profile_ShareContactButton: String { return self._s[861]! } + public var ChatSettings_Other: String { return self._s[862]! } + public var UserInfo_NotificationsDisabled: String { return self._s[863]! } + public var CheckoutInfo_ShippingInfoCity: String { return self._s[864]! } + public var LastSeen_WithinAMonth: String { return self._s[865]! } + public var VoiceOver_Chat_PlayHint: String { return self._s[866]! } + public var Conversation_ReportGroupLocation: String { return self._s[867]! } + public var Conversation_EncryptionCanceled: String { return self._s[868]! } + public var MediaPicker_GroupDescription: String { return self._s[869]! } + public var WebSearch_Images: String { return self._s[870]! } public func Channel_Management_PromotedBy(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[870]!, self._r[870]!, [_0]) + return formatWithArgumentRanges(self._s[871]!, self._r[871]!, [_0]) } - public var Message_Photo: String { return self._s[871]! } - public var PasscodeSettings_HelpBottom: String { return self._s[872]! } - public var AutoDownloadSettings_VideosTitle: String { return self._s[873]! } - public var VoiceOver_Media_PlaybackRateChange: String { return self._s[874]! } - public var Passport_Identity_AddDriversLicense: String { return self._s[875]! } - public var TwoStepAuth_EnterPasswordPassword: String { return self._s[876]! } - public var NotificationsSound_Calypso: String { return self._s[877]! } - public var Map_Map: String { return self._s[878]! } + public var Message_Photo: String { return self._s[872]! } + public var PasscodeSettings_HelpBottom: String { return self._s[873]! } + public var AutoDownloadSettings_VideosTitle: String { return self._s[874]! } + public var VoiceOver_Media_PlaybackRateChange: String { return self._s[875]! } + public var Passport_Identity_AddDriversLicense: String { return self._s[876]! } + public var TwoStepAuth_EnterPasswordPassword: String { return self._s[877]! } + public var NotificationsSound_Calypso: String { return self._s[878]! } + public var Map_Map: String { return self._s[879]! } public func Conversation_LiveLocationYouAndOther(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[879]!, self._r[879]!, [_0]) + return formatWithArgumentRanges(self._s[880]!, self._r[880]!, [_0]) } - public var CheckoutInfo_ReceiverInfoTitle: String { return self._s[881]! } - public var ChatSettings_TextSizeUnits: String { return self._s[882]! } + public var CheckoutInfo_ReceiverInfoTitle: String { return self._s[882]! } + public var ChatSettings_TextSizeUnits: String { return self._s[883]! } public func VoiceOver_Chat_FileFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[883]!, self._r[883]!, [_0]) + return formatWithArgumentRanges(self._s[884]!, self._r[884]!, [_0]) } - public var Common_of: String { return self._s[884]! } - public var Conversation_ForwardContacts: String { return self._s[887]! } - public var IntentsSettings_SuggestByAll: String { return self._s[889]! } + public var Common_of: String { return self._s[885]! } + public var Conversation_ForwardContacts: String { return self._s[888]! } + public var IntentsSettings_SuggestByAll: String { return self._s[890]! } public func Call_AnsweringWithAccount(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[890]!, self._r[890]!, [_0]) + return formatWithArgumentRanges(self._s[891]!, self._r[891]!, [_0]) } - public var Passport_Language_hy: String { return self._s[891]! } - public var Notifications_MessageNotificationsHelp: String { return self._s[892]! } - public var AutoDownloadSettings_Reset: String { return self._s[893]! } - public var Wallet_TransactionInfo_AddressCopied: String { return self._s[894]! } - public var Paint_ClearConfirm: String { return self._s[895]! } - public var Camera_VideoMode: String { return self._s[896]! } + public var Passport_Language_hy: String { return self._s[892]! } + public var Notifications_MessageNotificationsHelp: String { return self._s[893]! } + public var AutoDownloadSettings_Reset: String { return self._s[894]! } + public var Wallet_TransactionInfo_AddressCopied: String { return self._s[895]! } + public var Paint_ClearConfirm: String { return self._s[896]! } + public var Camera_VideoMode: String { return self._s[897]! } public func Conversation_RestrictedStickersTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[897]!, self._r[897]!, [_0]) + return formatWithArgumentRanges(self._s[898]!, self._r[898]!, [_0]) } - public var Privacy_Calls_AlwaysAllow_Placeholder: String { return self._s[898]! } - public var Conversation_ViewBackground: String { return self._s[899]! } + public var Privacy_Calls_AlwaysAllow_Placeholder: String { return self._s[899]! } + public var Conversation_ViewBackground: String { return self._s[900]! } public func Wallet_Info_TransactionDateHeaderYear(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[900]!, self._r[900]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[901]!, self._r[901]!, [_1, _2, _3]) } - public var Passport_Language_el: String { return self._s[901]! } - public var PhotoEditor_Original: String { return self._s[902]! } - public var Settings_FAQ_Button: String { return self._s[904]! } - public var Channel_Setup_PublicNoLink: String { return self._s[906]! } - public var Conversation_UnsupportedMedia: String { return self._s[907]! } - public var Conversation_SlideToCancel: String { return self._s[908]! } - public var Appearance_ThemePreview_ChatList_4_Name: String { return self._s[909]! } - public var Passport_Identity_OneOfTypeInternalPassport: String { return self._s[910]! } - public var CheckoutInfo_ShippingInfoPostcode: String { return self._s[911]! } - public var Conversation_ReportSpamChannelConfirmation: String { return self._s[912]! } - public var AutoNightTheme_NotAvailable: String { return self._s[913]! } - public var Conversation_Owner: String { return self._s[914]! } - public var Common_Create: String { return self._s[915]! } - public var Settings_ApplyProxyAlertEnable: String { return self._s[916]! } - public var ContactList_Context_Call: String { return self._s[917]! } - public var Localization_ChooseLanguage: String { return self._s[919]! } - public var ChatList_Context_AddToContacts: String { return self._s[921]! } - public var OldChannels_NoticeTitle: String { return self._s[922]! } - public var Settings_Proxy: String { return self._s[924]! } - public var Privacy_TopPeersHelp: String { return self._s[925]! } - public var CheckoutInfo_ShippingInfoCountryPlaceholder: String { return self._s[926]! } - public var Chat_UnsendMyMessages: String { return self._s[927]! } + public var Passport_Language_el: String { return self._s[902]! } + public var PhotoEditor_Original: String { return self._s[903]! } + public var Settings_FAQ_Button: String { return self._s[905]! } + public var Channel_Setup_PublicNoLink: String { return self._s[907]! } + public var Conversation_UnsupportedMedia: String { return self._s[908]! } + public var Conversation_SlideToCancel: String { return self._s[909]! } + public var Appearance_ThemePreview_ChatList_4_Name: String { return self._s[910]! } + public var Passport_Identity_OneOfTypeInternalPassport: String { return self._s[911]! } + public var CheckoutInfo_ShippingInfoPostcode: String { return self._s[912]! } + public var Conversation_ReportSpamChannelConfirmation: String { return self._s[913]! } + public var AutoNightTheme_NotAvailable: String { return self._s[914]! } + public var Conversation_Owner: String { return self._s[915]! } + public var Common_Create: String { return self._s[916]! } + public var Settings_ApplyProxyAlertEnable: String { return self._s[917]! } + public var ContactList_Context_Call: String { return self._s[918]! } + public var Localization_ChooseLanguage: String { return self._s[920]! } + public var ChatList_Context_AddToContacts: String { return self._s[922]! } + public var OldChannels_NoticeTitle: String { return self._s[923]! } + public var Settings_Proxy: String { return self._s[925]! } + public var Privacy_TopPeersHelp: String { return self._s[926]! } + public var CheckoutInfo_ShippingInfoCountryPlaceholder: String { return self._s[927]! } + public var Chat_UnsendMyMessages: String { return self._s[928]! } public func VoiceOver_Chat_Duration(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[928]!, self._r[928]!, [_0]) + return formatWithArgumentRanges(self._s[929]!, self._r[929]!, [_0]) } - public var TwoStepAuth_ConfirmationAbort: String { return self._s[929]! } + public var TwoStepAuth_ConfirmationAbort: String { return self._s[930]! } public func Contacts_AccessDeniedHelpPortrait(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[931]!, self._r[931]!, [_0]) + return formatWithArgumentRanges(self._s[932]!, self._r[932]!, [_0]) } - public var Contacts_SortedByPresence: String { return self._s[932]! } - public var Passport_Identity_SurnamePlaceholder: String { return self._s[933]! } - public var Cache_Title: String { return self._s[934]! } + public var Contacts_SortedByPresence: String { return self._s[933]! } + public var Passport_Identity_SurnamePlaceholder: String { return self._s[934]! } + public var Cache_Title: String { return self._s[935]! } public func Login_PhoneBannedEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[935]!, self._r[935]!, [_0]) + return formatWithArgumentRanges(self._s[936]!, self._r[936]!, [_0]) } - public var TwoStepAuth_EmailCodeExpired: String { return self._s[936]! } - public var Channel_Moderator_Title: String { return self._s[937]! } - public var InstantPage_AutoNightTheme: String { return self._s[939]! } + public var TwoStepAuth_EmailCodeExpired: String { return self._s[937]! } + public var Channel_Moderator_Title: String { return self._s[938]! } + public var InstantPage_AutoNightTheme: String { return self._s[940]! } public func PUSH_MESSAGE_POLL(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[942]!, self._r[942]!, [_1]) + return formatWithArgumentRanges(self._s[943]!, self._r[943]!, [_1]) } - public var Passport_Scans_Upload: String { return self._s[943]! } - public var Undo_Undo: String { return self._s[945]! } - public var Contacts_AccessDeniedHelpON: String { return self._s[946]! } - public var TwoStepAuth_RemovePassword: String { return self._s[947]! } - public var Common_Delete: String { return self._s[948]! } - public var Contacts_AddPeopleNearby: String { return self._s[950]! } - public var Conversation_ContextMenuDelete: String { return self._s[951]! } - public var SocksProxySetup_Credentials: String { return self._s[952]! } - public var Appearance_EditTheme: String { return self._s[954]! } - public var ClearCache_StorageOtherApps: String { return self._s[955]! } - public var PasscodeSettings_AutoLock_Disabled: String { return self._s[956]! } - public var Wallet_Send_NetworkErrorText: String { return self._s[957]! } - public var AuthSessions_DevicesTitle: String { return self._s[959]! } - public var Passport_Address_OneOfTypeRentalAgreement: String { return self._s[961]! } - public var Conversation_ShareBotContactConfirmationTitle: String { return self._s[962]! } - public var Passport_Language_id: String { return self._s[964]! } - public var WallpaperSearch_ColorTeal: String { return self._s[965]! } - public var ChannelIntro_Title: String { return self._s[966]! } + public var Passport_Scans_Upload: String { return self._s[944]! } + public var Undo_Undo: String { return self._s[946]! } + public var Contacts_AccessDeniedHelpON: String { return self._s[947]! } + public var TwoStepAuth_RemovePassword: String { return self._s[948]! } + public var Common_Delete: String { return self._s[949]! } + public var Contacts_AddPeopleNearby: String { return self._s[951]! } + public var Conversation_ContextMenuDelete: String { return self._s[952]! } + public var SocksProxySetup_Credentials: String { return self._s[953]! } + public var Appearance_EditTheme: String { return self._s[955]! } + public var ClearCache_StorageOtherApps: String { return self._s[956]! } + public var PasscodeSettings_AutoLock_Disabled: String { return self._s[957]! } + public var Wallet_Send_NetworkErrorText: String { return self._s[958]! } + public var AuthSessions_DevicesTitle: String { return self._s[960]! } + public var Passport_Address_OneOfTypeRentalAgreement: String { return self._s[962]! } + public var Conversation_ShareBotContactConfirmationTitle: String { return self._s[963]! } + public var Passport_Language_id: String { return self._s[965]! } + public var WallpaperSearch_ColorTeal: String { return self._s[966]! } + public var ChannelIntro_Title: String { return self._s[967]! } public func Channel_AdminLog_MessageToggleSignaturesOff(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[967]!, self._r[967]!, [_0]) + return formatWithArgumentRanges(self._s[968]!, self._r[968]!, [_0]) } - public var VoiceOver_Chat_OpenLinkHint: String { return self._s[969]! } - public var VoiceOver_Chat_Reply: String { return self._s[970]! } - public var ScheduledMessages_BotActionUnavailable: String { return self._s[971]! } - public var Channel_Info_Description: String { return self._s[972]! } - public var Stickers_FavoriteStickers: String { return self._s[973]! } - public var Channel_BanUser_PermissionAddMembers: String { return self._s[974]! } - public var Notifications_DisplayNamesOnLockScreen: String { return self._s[975]! } - public var ChatSearch_ResultsTooltip: String { return self._s[976]! } - public var Wallet_VoiceOver_Editing_ClearText: String { return self._s[977]! } - public var Calls_NoMissedCallsPlacehoder: String { return self._s[978]! } - public var Group_PublicLink_Placeholder: String { return self._s[979]! } - public var Notifications_ExceptionsDefaultSound: String { return self._s[980]! } + public var VoiceOver_Chat_OpenLinkHint: String { return self._s[970]! } + public var VoiceOver_Chat_Reply: String { return self._s[971]! } + public var ScheduledMessages_BotActionUnavailable: String { return self._s[972]! } + public var Channel_Info_Description: String { return self._s[973]! } + public var Stickers_FavoriteStickers: String { return self._s[974]! } + public var Channel_BanUser_PermissionAddMembers: String { return self._s[975]! } + public var Notifications_DisplayNamesOnLockScreen: String { return self._s[976]! } + public var ChatSearch_ResultsTooltip: String { return self._s[977]! } + public var Wallet_VoiceOver_Editing_ClearText: String { return self._s[978]! } + public var Calls_NoMissedCallsPlacehoder: String { return self._s[979]! } + public var Group_PublicLink_Placeholder: String { return self._s[980]! } + public var Notifications_ExceptionsDefaultSound: String { return self._s[981]! } public func PUSH_CHANNEL_MESSAGE_POLL(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[981]!, self._r[981]!, [_1]) + return formatWithArgumentRanges(self._s[982]!, self._r[982]!, [_1]) } - public var TextFormat_Underline: String { return self._s[982]! } + public var TextFormat_Underline: String { return self._s[983]! } public func DialogList_SearchSubtitleFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[984]!, self._r[984]!, [_1, _2]) + return formatWithArgumentRanges(self._s[985]!, self._r[985]!, [_1, _2]) } public func Channel_AdminLog_MessageRemovedGroupStickerPack(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[985]!, self._r[985]!, [_0]) + return formatWithArgumentRanges(self._s[986]!, self._r[986]!, [_0]) } - public var Appearance_ThemePreview_ChatList_3_Name: String { return self._s[986]! } + public var Appearance_ThemePreview_ChatList_3_Name: String { return self._s[987]! } public func Channel_OwnershipTransfer_TransferCompleted(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[987]!, self._r[987]!, [_1, _2]) + return formatWithArgumentRanges(self._s[988]!, self._r[988]!, [_1, _2]) } - public var Wallet_Intro_ImportExisting: String { return self._s[988]! } - public var GroupPermission_Delete: String { return self._s[989]! } - public var Passport_Language_uk: String { return self._s[990]! } - public var StickerPack_HideStickers: String { return self._s[992]! } - public var ChangePhoneNumberNumber_NumberPlaceholder: String { return self._s[993]! } + public var Wallet_Intro_ImportExisting: String { return self._s[989]! } + public var GroupPermission_Delete: String { return self._s[990]! } + public var Passport_Language_uk: String { return self._s[991]! } + public var StickerPack_HideStickers: String { return self._s[993]! } + public var ChangePhoneNumberNumber_NumberPlaceholder: String { return self._s[994]! } public func PUSH_CHAT_MESSAGE_PHOTO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[994]!, self._r[994]!, [_1, _2]) + return formatWithArgumentRanges(self._s[995]!, self._r[995]!, [_1, _2]) } - public var Activity_UploadingVideoMessage: String { return self._s[995]! } + public var Activity_UploadingVideoMessage: String { return self._s[996]! } public func GroupPermission_ApplyAlertText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[996]!, self._r[996]!, [_0]) + return formatWithArgumentRanges(self._s[997]!, self._r[997]!, [_0]) } - public var Channel_TitleInfo: String { return self._s[997]! } - public var StickerPacksSettings_ArchivedPacks_Info: String { return self._s[998]! } - public var Settings_CallSettings: String { return self._s[999]! } - public var Camera_SquareMode: String { return self._s[1000]! } - public var Conversation_SendMessage_ScheduleMessage: String { return self._s[1001]! } - public var GroupInfo_SharedMediaNone: String { return self._s[1002]! } + public var Channel_TitleInfo: String { return self._s[998]! } + public var StickerPacksSettings_ArchivedPacks_Info: String { return self._s[999]! } + public var Settings_CallSettings: String { return self._s[1000]! } + public var Camera_SquareMode: String { return self._s[1001]! } + public var Conversation_SendMessage_ScheduleMessage: String { return self._s[1002]! } + public var GroupInfo_SharedMediaNone: String { return self._s[1003]! } public func PUSH_MESSAGE_VIDEO_SECRET(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1003]!, self._r[1003]!, [_1]) + return formatWithArgumentRanges(self._s[1004]!, self._r[1004]!, [_1]) } - public var Bot_GenericBotStatus: String { return self._s[1004]! } - public var Application_Update: String { return self._s[1006]! } - public var Month_ShortJanuary: String { return self._s[1007]! } - public var Contacts_PermissionsKeepDisabled: String { return self._s[1008]! } - public var Channel_AdminLog_BanReadMessages: String { return self._s[1009]! } - public var Settings_AppLanguage_Unofficial: String { return self._s[1010]! } - public var Passport_Address_Street2Placeholder: String { return self._s[1011]! } + public var Bot_GenericBotStatus: String { return self._s[1005]! } + public var Application_Update: String { return self._s[1007]! } + public var Month_ShortJanuary: String { return self._s[1008]! } + public var Contacts_PermissionsKeepDisabled: String { return self._s[1009]! } + public var Channel_AdminLog_BanReadMessages: String { return self._s[1010]! } + public var Settings_AppLanguage_Unofficial: String { return self._s[1011]! } + public var Passport_Address_Street2Placeholder: String { return self._s[1012]! } public func Map_LiveLocationShortHour(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1012]!, self._r[1012]!, [_0]) + return formatWithArgumentRanges(self._s[1013]!, self._r[1013]!, [_0]) } - public var NetworkUsageSettings_Cellular: String { return self._s[1013]! } - public var Appearance_PreviewOutgoingText: String { return self._s[1014]! } + public var NetworkUsageSettings_Cellular: String { return self._s[1014]! } + public var Appearance_PreviewOutgoingText: String { return self._s[1015]! } public func StickerPackActionInfo_RemovedText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1015]!, self._r[1015]!, [_0]) + return formatWithArgumentRanges(self._s[1016]!, self._r[1016]!, [_0]) } - public var Notifications_PermissionsAllowInSettings: String { return self._s[1016]! } - public var AutoDownloadSettings_OnForAll: String { return self._s[1018]! } - public var Map_Directions: String { return self._s[1019]! } - public var Passport_FieldIdentityTranslationHelp: String { return self._s[1021]! } - public var Appearance_ThemeDay: String { return self._s[1022]! } - public var LogoutOptions_LogOut: String { return self._s[1023]! } - public var Group_PublicLink_Title: String { return self._s[1025]! } - public var Channel_AddBotErrorNoRights: String { return self._s[1026]! } - public var ChatList_Search_ShowLess: String { return self._s[1027]! } - public var Passport_Identity_AddPassport: String { return self._s[1028]! } - public var LocalGroup_ButtonTitle: String { return self._s[1029]! } - public var Call_Message: String { return self._s[1030]! } - public var PhotoEditor_ExposureTool: String { return self._s[1031]! } - public var Wallet_Receive_CommentInfo: String { return self._s[1033]! } - public var Passport_FieldOneOf_Delimeter: String { return self._s[1034]! } - public var Channel_AdminLog_CanBanUsers: String { return self._s[1036]! } - public var Appearance_ThemePreview_ChatList_2_Name: String { return self._s[1037]! } - public var Appearance_Preview: String { return self._s[1038]! } - public var Compose_ChannelMembers: String { return self._s[1039]! } - public var Conversation_DeleteManyMessages: String { return self._s[1040]! } - public var ReportPeer_ReasonOther_Title: String { return self._s[1041]! } - public var Checkout_ErrorProviderAccountTimeout: String { return self._s[1042]! } - public var TwoStepAuth_ResetAccountConfirmation: String { return self._s[1043]! } - public var Channel_Stickers_CreateYourOwn: String { return self._s[1046]! } - public var Conversation_UpdateTelegram: String { return self._s[1047]! } - public var EditTheme_Create_TopInfo: String { return self._s[1048]! } + public var Notifications_PermissionsAllowInSettings: String { return self._s[1017]! } + public var AutoDownloadSettings_OnForAll: String { return self._s[1019]! } + public var Map_Directions: String { return self._s[1020]! } + public var Passport_FieldIdentityTranslationHelp: String { return self._s[1022]! } + public var Appearance_ThemeDay: String { return self._s[1023]! } + public var LogoutOptions_LogOut: String { return self._s[1024]! } + public var Group_PublicLink_Title: String { return self._s[1026]! } + public var Channel_AddBotErrorNoRights: String { return self._s[1027]! } + public var ChatList_Search_ShowLess: String { return self._s[1028]! } + public var Passport_Identity_AddPassport: String { return self._s[1029]! } + public var LocalGroup_ButtonTitle: String { return self._s[1030]! } + public var Call_Message: String { return self._s[1031]! } + public var PhotoEditor_ExposureTool: String { return self._s[1032]! } + public var Wallet_Receive_CommentInfo: String { return self._s[1034]! } + public var Passport_FieldOneOf_Delimeter: String { return self._s[1035]! } + public var Channel_AdminLog_CanBanUsers: String { return self._s[1037]! } + public var Appearance_ThemePreview_ChatList_2_Name: String { return self._s[1038]! } + public var Appearance_Preview: String { return self._s[1039]! } + public var Compose_ChannelMembers: String { return self._s[1040]! } + public var Conversation_DeleteManyMessages: String { return self._s[1041]! } + public var ReportPeer_ReasonOther_Title: String { return self._s[1042]! } + public var Checkout_ErrorProviderAccountTimeout: String { return self._s[1043]! } + public var TwoStepAuth_ResetAccountConfirmation: String { return self._s[1044]! } + public var Channel_Stickers_CreateYourOwn: String { return self._s[1047]! } + public var Conversation_UpdateTelegram: String { return self._s[1048]! } + public var EditTheme_Create_TopInfo: String { return self._s[1049]! } public func Notification_PinnedPhotoMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1049]!, self._r[1049]!, [_0]) + return formatWithArgumentRanges(self._s[1050]!, self._r[1050]!, [_0]) } - public var Wallet_WordCheck_Continue: String { return self._s[1050]! } - public var TwoFactorSetup_Hint_Action: String { return self._s[1051]! } - public var IntentsSettings_ResetAll: String { return self._s[1052]! } + public var Wallet_WordCheck_Continue: String { return self._s[1051]! } + public var TwoFactorSetup_Hint_Action: String { return self._s[1052]! } + public var IntentsSettings_ResetAll: String { return self._s[1053]! } public func PUSH_PINNED_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1053]!, self._r[1053]!, [_1]) + return formatWithArgumentRanges(self._s[1054]!, self._r[1054]!, [_1]) } - public var GroupInfo_Administrators_Title: String { return self._s[1054]! } - public var Privacy_Forwards_PreviewMessageText: String { return self._s[1055]! } + public var GroupInfo_Administrators_Title: String { return self._s[1055]! } + public var Privacy_Forwards_PreviewMessageText: String { return self._s[1056]! } public func PrivacySettings_LastSeenNobodyPlus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1056]!, self._r[1056]!, [_0]) + return formatWithArgumentRanges(self._s[1057]!, self._r[1057]!, [_0]) } - public var Tour_Title3: String { return self._s[1057]! } - public var Channel_EditAdmin_PermissionInviteSubscribers: String { return self._s[1058]! } - public var Clipboard_SendPhoto: String { return self._s[1062]! } - public var MediaPicker_Videos: String { return self._s[1063]! } - public var Passport_Email_Title: String { return self._s[1064]! } + public var Tour_Title3: String { return self._s[1058]! } + public var Channel_EditAdmin_PermissionInviteSubscribers: String { return self._s[1059]! } + public var Clipboard_SendPhoto: String { return self._s[1063]! } + public var MediaPicker_Videos: String { return self._s[1064]! } + public var Passport_Email_Title: String { return self._s[1065]! } public func PrivacySettings_LastSeenEverybodyMinus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1065]!, self._r[1065]!, [_0]) + return formatWithArgumentRanges(self._s[1066]!, self._r[1066]!, [_0]) } - public var StickerPacksSettings_Title: String { return self._s[1066]! } - public var Conversation_MessageDialogDelete: String { return self._s[1067]! } - public var Privacy_Calls_CustomHelp: String { return self._s[1069]! } - public var Message_Wallpaper: String { return self._s[1070]! } - public var MemberSearch_BotSection: String { return self._s[1071]! } - public var GroupInfo_SetSound: String { return self._s[1072]! } + public var StickerPacksSettings_Title: String { return self._s[1067]! } + public var Conversation_MessageDialogDelete: String { return self._s[1068]! } + public var Privacy_Calls_CustomHelp: String { return self._s[1070]! } + public var Message_Wallpaper: String { return self._s[1071]! } + public var MemberSearch_BotSection: String { return self._s[1072]! } + public var GroupInfo_SetSound: String { return self._s[1073]! } public func Time_TomorrowAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1073]!, self._r[1073]!, [_0]) + return formatWithArgumentRanges(self._s[1074]!, self._r[1074]!, [_0]) } - public var Core_ServiceUserStatus: String { return self._s[1074]! } - public var LiveLocationUpdated_JustNow: String { return self._s[1075]! } - public var Call_StatusFailed: String { return self._s[1076]! } - public var TwoFactorSetup_Email_Placeholder: String { return self._s[1077]! } - public var TwoStepAuth_SetupPasswordDescription: String { return self._s[1078]! } - public var TwoStepAuth_SetPassword: String { return self._s[1079]! } - public var Permissions_PeopleNearbyText_v0: String { return self._s[1080]! } + public var Core_ServiceUserStatus: String { return self._s[1075]! } + public var LiveLocationUpdated_JustNow: String { return self._s[1076]! } + public var Call_StatusFailed: String { return self._s[1077]! } + public var TwoFactorSetup_Email_Placeholder: String { return self._s[1078]! } + public var TwoStepAuth_SetupPasswordDescription: String { return self._s[1079]! } + public var TwoStepAuth_SetPassword: String { return self._s[1080]! } + public var Permissions_PeopleNearbyText_v0: String { return self._s[1081]! } public func SocksProxySetup_ProxyStatusPing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1082]!, self._r[1082]!, [_0]) + return formatWithArgumentRanges(self._s[1083]!, self._r[1083]!, [_0]) } - public var Calls_SubmitRating: String { return self._s[1083]! } - public var Map_NoPlacesNearby: String { return self._s[1084]! } - public var Profile_Username: String { return self._s[1085]! } - public var Bot_DescriptionTitle: String { return self._s[1086]! } - public var MaskStickerSettings_Title: String { return self._s[1087]! } - public var SharedMedia_CategoryOther: String { return self._s[1088]! } - public var GroupInfo_SetGroupPhoto: String { return self._s[1089]! } - public var Common_NotNow: String { return self._s[1090]! } - public var CallFeedback_IncludeLogsInfo: String { return self._s[1091]! } - public var Conversation_ShareMyPhoneNumber: String { return self._s[1092]! } - public var Map_Location: String { return self._s[1093]! } - public var Invitation_JoinGroup: String { return self._s[1094]! } - public var AutoDownloadSettings_Title: String { return self._s[1096]! } - public var Conversation_DiscardVoiceMessageDescription: String { return self._s[1097]! } - public var Channel_ErrorAddBlocked: String { return self._s[1098]! } - public var Conversation_UnblockUser: String { return self._s[1099]! } - public var EditTheme_Edit_TopInfo: String { return self._s[1100]! } - public var Watch_Bot_Restart: String { return self._s[1101]! } - public var TwoStepAuth_Title: String { return self._s[1102]! } - public var Channel_AdminLog_BanSendMessages: String { return self._s[1103]! } - public var Checkout_ShippingMethod: String { return self._s[1104]! } - public var Passport_Identity_OneOfTypeIdentityCard: String { return self._s[1105]! } + public var Calls_SubmitRating: String { return self._s[1084]! } + public var Map_NoPlacesNearby: String { return self._s[1085]! } + public var Profile_Username: String { return self._s[1086]! } + public var Bot_DescriptionTitle: String { return self._s[1087]! } + public var MaskStickerSettings_Title: String { return self._s[1088]! } + public var SharedMedia_CategoryOther: String { return self._s[1089]! } + public var GroupInfo_SetGroupPhoto: String { return self._s[1090]! } + public var Common_NotNow: String { return self._s[1091]! } + public var CallFeedback_IncludeLogsInfo: String { return self._s[1092]! } + public var Conversation_ShareMyPhoneNumber: String { return self._s[1093]! } + public var Map_Location: String { return self._s[1094]! } + public var Invitation_JoinGroup: String { return self._s[1095]! } + public var AutoDownloadSettings_Title: String { return self._s[1097]! } + public var Conversation_DiscardVoiceMessageDescription: String { return self._s[1098]! } + public var Channel_ErrorAddBlocked: String { return self._s[1099]! } + public var Conversation_UnblockUser: String { return self._s[1100]! } + public var EditTheme_Edit_TopInfo: String { return self._s[1101]! } + public var Watch_Bot_Restart: String { return self._s[1102]! } + public var TwoStepAuth_Title: String { return self._s[1103]! } + public var Channel_AdminLog_BanSendMessages: String { return self._s[1104]! } + public var Checkout_ShippingMethod: String { return self._s[1105]! } + public var Passport_Identity_OneOfTypeIdentityCard: String { return self._s[1106]! } public func PUSH_CHAT_MESSAGE_STICKER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1106]!, self._r[1106]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1107]!, self._r[1107]!, [_1, _2, _3]) } - public var EditTheme_ChangeColors: String { return self._s[1108]! } + public var PeerInfo_ButtonDiscuss: String { return self._s[1108]! } + public var EditTheme_ChangeColors: String { return self._s[1110]! } public func Chat_UnsendMyMessagesAlertTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1109]!, self._r[1109]!, [_0]) + return formatWithArgumentRanges(self._s[1111]!, self._r[1111]!, [_0]) } public func Channel_Username_LinkHint(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1110]!, self._r[1110]!, [_0]) + return formatWithArgumentRanges(self._s[1112]!, self._r[1112]!, [_0]) } - public var Appearance_ThemePreview_ChatList_1_Name: String { return self._s[1111]! } - public var SettingsSearch_Synonyms_Data_AutoplayGifs: String { return self._s[1112]! } - public var AuthSessions_TerminateOtherSessions: String { return self._s[1113]! } - public var Contacts_FailedToSendInvitesMessage: String { return self._s[1114]! } - public var PrivacySettings_TwoStepAuth: String { return self._s[1115]! } - public var Notification_Exceptions_PreviewAlwaysOn: String { return self._s[1116]! } - public var SettingsSearch_Synonyms_Privacy_Passcode: String { return self._s[1117]! } - public var Conversation_EditingMessagePanelMedia: String { return self._s[1118]! } - public var Checkout_PaymentMethod_Title: String { return self._s[1119]! } - public var SocksProxySetup_Connection: String { return self._s[1120]! } - public var Group_MessagePhotoRemoved: String { return self._s[1121]! } - public var PeopleNearby_MakeInvisible: String { return self._s[1123]! } - public var Channel_Stickers_NotFound: String { return self._s[1125]! } - public var Group_About_Help: String { return self._s[1126]! } - public var Notification_PassportValueProofOfIdentity: String { return self._s[1127]! } - public var PeopleNearby_Title: String { return self._s[1129]! } + public var Appearance_ThemePreview_ChatList_1_Name: String { return self._s[1113]! } + public var SettingsSearch_Synonyms_Data_AutoplayGifs: String { return self._s[1114]! } + public var AuthSessions_TerminateOtherSessions: String { return self._s[1115]! } + public var Contacts_FailedToSendInvitesMessage: String { return self._s[1116]! } + public var PrivacySettings_TwoStepAuth: String { return self._s[1117]! } + public var Notification_Exceptions_PreviewAlwaysOn: String { return self._s[1118]! } + public var SettingsSearch_Synonyms_Privacy_Passcode: String { return self._s[1119]! } + public var Conversation_EditingMessagePanelMedia: String { return self._s[1120]! } + public var Checkout_PaymentMethod_Title: String { return self._s[1121]! } + public var SocksProxySetup_Connection: String { return self._s[1122]! } + public var Group_MessagePhotoRemoved: String { return self._s[1123]! } + public var PeopleNearby_MakeInvisible: String { return self._s[1125]! } + public var Channel_Stickers_NotFound: String { return self._s[1127]! } + public var Group_About_Help: String { return self._s[1128]! } + public var Notification_PassportValueProofOfIdentity: String { return self._s[1129]! } + public var PeopleNearby_Title: String { return self._s[1131]! } public func ApplyLanguage_ChangeLanguageOfficialText(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1130]!, self._r[1130]!, [_1]) + return formatWithArgumentRanges(self._s[1132]!, self._r[1132]!, [_1]) } - public var Map_Home: String { return self._s[1131]! } - public var CheckoutInfo_ShippingInfoStatePlaceholder: String { return self._s[1133]! } - public var Notifications_GroupNotificationsExceptionsHelp: String { return self._s[1134]! } - public var SocksProxySetup_Password: String { return self._s[1135]! } - public var Notifications_PermissionsEnable: String { return self._s[1136]! } - public var TwoStepAuth_ChangeEmail: String { return self._s[1138]! } + public var Map_Home: String { return self._s[1133]! } + public var CheckoutInfo_ShippingInfoStatePlaceholder: String { return self._s[1135]! } + public var Notifications_GroupNotificationsExceptionsHelp: String { return self._s[1136]! } + public var SocksProxySetup_Password: String { return self._s[1137]! } + public var Notifications_PermissionsEnable: String { return self._s[1138]! } + public var TwoStepAuth_ChangeEmail: String { return self._s[1140]! } public func Channel_AdminLog_MessageInvitedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1139]!, self._r[1139]!, [_1]) + return formatWithArgumentRanges(self._s[1141]!, self._r[1141]!, [_1]) } public func Time_MonthOfYear_m10(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1141]!, self._r[1141]!, [_0]) + return formatWithArgumentRanges(self._s[1143]!, self._r[1143]!, [_0]) } - public var Passport_Identity_TypeDriversLicense: String { return self._s[1142]! } - public var ArchivedPacksAlert_Title: String { return self._s[1143]! } - public var Wallet_Receive_InvoiceUrlCopied: String { return self._s[1144]! } - public var Map_PlacesNearby: String { return self._s[1145]! } + public var Passport_Identity_TypeDriversLicense: String { return self._s[1144]! } + public var ArchivedPacksAlert_Title: String { return self._s[1145]! } + public var Wallet_Receive_InvoiceUrlCopied: String { return self._s[1146]! } + public var Map_PlacesNearby: String { return self._s[1147]! } public func Time_PreciseDate_m7(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1146]!, self._r[1146]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1148]!, self._r[1148]!, [_1, _2, _3]) } - public var PrivacyLastSeenSettings_GroupsAndChannelsHelp: String { return self._s[1147]! } - public var Privacy_Calls_NeverAllow_Placeholder: String { return self._s[1149]! } - public var Conversation_StatusTyping: String { return self._s[1150]! } - public var Broadcast_AdminLog_EmptyText: String { return self._s[1151]! } - public var Notification_PassportValueProofOfAddress: String { return self._s[1152]! } - public var UserInfo_CreateNewContact: String { return self._s[1153]! } - public var Passport_Identity_FrontSide: String { return self._s[1154]! } - public var Login_PhoneNumberAlreadyAuthorizedSwitch: String { return self._s[1155]! } - public var Calls_CallTabTitle: String { return self._s[1156]! } - public var Channel_AdminLog_ChannelEmptyText: String { return self._s[1157]! } + public var PrivacyLastSeenSettings_GroupsAndChannelsHelp: String { return self._s[1149]! } + public var Privacy_Calls_NeverAllow_Placeholder: String { return self._s[1151]! } + public var Conversation_StatusTyping: String { return self._s[1152]! } + public var Broadcast_AdminLog_EmptyText: String { return self._s[1153]! } + public var Notification_PassportValueProofOfAddress: String { return self._s[1154]! } + public var UserInfo_CreateNewContact: String { return self._s[1155]! } + public var Passport_Identity_FrontSide: String { return self._s[1156]! } + public var Login_PhoneNumberAlreadyAuthorizedSwitch: String { return self._s[1157]! } + public var Calls_CallTabTitle: String { return self._s[1158]! } + public var Channel_AdminLog_ChannelEmptyText: String { return self._s[1159]! } public func Login_BannedPhoneBody(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1159]!, self._r[1159]!, [_0]) + return formatWithArgumentRanges(self._s[1161]!, self._r[1161]!, [_0]) } - public var Watch_UserInfo_MuteTitle: String { return self._s[1160]! } - public var Group_EditAdmin_RankAdminPlaceholder: String { return self._s[1161]! } - public var SharedMedia_EmptyMusicText: String { return self._s[1162]! } - public var Wallet_Completed_Text: String { return self._s[1163]! } - public var PasscodeSettings_AutoLock_IfAwayFor_1minute: String { return self._s[1164]! } - public var Paint_Stickers: String { return self._s[1165]! } - public var Privacy_GroupsAndChannels: String { return self._s[1166]! } - public var ChatList_Context_Delete: String { return self._s[1168]! } - public var UserInfo_AddContact: String { return self._s[1169]! } + public var Watch_UserInfo_MuteTitle: String { return self._s[1162]! } + public var Group_EditAdmin_RankAdminPlaceholder: String { return self._s[1163]! } + public var SharedMedia_EmptyMusicText: String { return self._s[1164]! } + public var Wallet_Completed_Text: String { return self._s[1165]! } + public var PasscodeSettings_AutoLock_IfAwayFor_1minute: String { return self._s[1166]! } + public var Paint_Stickers: String { return self._s[1167]! } + public var Privacy_GroupsAndChannels: String { return self._s[1168]! } + public var ChatList_Context_Delete: String { return self._s[1170]! } + public var UserInfo_AddContact: String { return self._s[1171]! } public func Conversation_MessageViaUser(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1170]!, self._r[1170]!, [_0]) + return formatWithArgumentRanges(self._s[1172]!, self._r[1172]!, [_0]) } - public var PhoneNumberHelp_ChangeNumber: String { return self._s[1172]! } + public var PhoneNumberHelp_ChangeNumber: String { return self._s[1174]! } public func ChatList_ClearChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1174]!, self._r[1174]!, [_0]) + return formatWithArgumentRanges(self._s[1176]!, self._r[1176]!, [_0]) } - public var DialogList_NoMessagesTitle: String { return self._s[1175]! } - public var EditProfile_NameAndPhotoHelp: String { return self._s[1176]! } - public var BlockedUsers_BlockUser: String { return self._s[1177]! } - public var Notifications_PermissionsOpenSettings: String { return self._s[1178]! } - public var MediaPicker_UngroupDescription: String { return self._s[1180]! } - public var Watch_NoConnection: String { return self._s[1181]! } - public var Month_GenSeptember: String { return self._s[1182]! } - public var Conversation_ViewGroup: String { return self._s[1184]! } - public var Channel_AdminLogFilter_EventsLeavingSubscribers: String { return self._s[1187]! } - public var Privacy_Forwards_AlwaysLink: String { return self._s[1188]! } - public var Channel_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[1189]! } - public var Passport_FieldOneOf_FinalDelimeter: String { return self._s[1190]! } - public var Wallet_WordCheck_IncorrectHeader: String { return self._s[1191]! } - public var MediaPicker_CameraRoll: String { return self._s[1193]! } - public var Month_GenAugust: String { return self._s[1194]! } - public var Wallet_Configuration_SourceHeader: String { return self._s[1195]! } - public var AccessDenied_VideoMessageMicrophone: String { return self._s[1196]! } - public var SharedMedia_EmptyText: String { return self._s[1197]! } - public var Map_ShareLiveLocation: String { return self._s[1198]! } - public var Calls_All: String { return self._s[1199]! } - public var Map_SendThisPlace: String { return self._s[1201]! } - public var Appearance_ThemeNight: String { return self._s[1203]! } - public var Conversation_HoldForAudio: String { return self._s[1204]! } - public var SettingsSearch_Synonyms_Support: String { return self._s[1207]! } - public var GroupInfo_GroupHistoryHidden: String { return self._s[1208]! } - public var SocksProxySetup_Secret: String { return self._s[1209]! } + public var DialogList_NoMessagesTitle: String { return self._s[1177]! } + public var EditProfile_NameAndPhotoHelp: String { return self._s[1178]! } + public var BlockedUsers_BlockUser: String { return self._s[1179]! } + public var Notifications_PermissionsOpenSettings: String { return self._s[1180]! } + public var MediaPicker_UngroupDescription: String { return self._s[1182]! } + public var Watch_NoConnection: String { return self._s[1183]! } + public var Month_GenSeptember: String { return self._s[1184]! } + public var Conversation_ViewGroup: String { return self._s[1186]! } + public var Channel_AdminLogFilter_EventsLeavingSubscribers: String { return self._s[1189]! } + public var Privacy_Forwards_AlwaysLink: String { return self._s[1190]! } + public var Channel_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[1191]! } + public var Passport_FieldOneOf_FinalDelimeter: String { return self._s[1192]! } + public var Wallet_WordCheck_IncorrectHeader: String { return self._s[1193]! } + public var MediaPicker_CameraRoll: String { return self._s[1195]! } + public var Month_GenAugust: String { return self._s[1196]! } + public var Wallet_Configuration_SourceHeader: String { return self._s[1197]! } + public var AccessDenied_VideoMessageMicrophone: String { return self._s[1198]! } + public var SharedMedia_EmptyText: String { return self._s[1199]! } + public var Map_ShareLiveLocation: String { return self._s[1200]! } + public var Calls_All: String { return self._s[1201]! } + public var Map_SendThisPlace: String { return self._s[1203]! } + public var Appearance_ThemeNight: String { return self._s[1205]! } + public var Conversation_HoldForAudio: String { return self._s[1206]! } + public var SettingsSearch_Synonyms_Support: String { return self._s[1209]! } + public var GroupInfo_GroupHistoryHidden: String { return self._s[1210]! } + public var SocksProxySetup_Secret: String { return self._s[1211]! } public func Activity_RemindAboutChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1210]!, self._r[1210]!, [_0]) + return formatWithArgumentRanges(self._s[1212]!, self._r[1212]!, [_0]) } - public var Channel_BanList_RestrictedTitle: String { return self._s[1212]! } - public var Conversation_Location: String { return self._s[1213]! } + public var Channel_BanList_RestrictedTitle: String { return self._s[1214]! } + public var Conversation_Location: String { return self._s[1215]! } public func AutoDownloadSettings_UpToFor(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1214]!, self._r[1214]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1216]!, self._r[1216]!, [_1, _2]) } - public var ChatSettings_AutoDownloadPhotos: String { return self._s[1216]! } - public var SettingsSearch_Synonyms_Privacy_Title: String { return self._s[1217]! } - public var Notifications_PermissionsText: String { return self._s[1218]! } - public var SettingsSearch_Synonyms_Data_SaveIncomingPhotos: String { return self._s[1219]! } - public var Call_Flip: String { return self._s[1220]! } - public var Channel_AdminLog_CanDeleteMessagesOfOthers: String { return self._s[1222]! } - public var SocksProxySetup_ProxyStatusConnecting: String { return self._s[1223]! } - public var Wallet_TransactionInfo_StorageFeeInfoUrl: String { return self._s[1224]! } - public var PrivacyPhoneNumberSettings_DiscoveryHeader: String { return self._s[1225]! } - public var Channel_EditAdmin_PermissionPinMessages: String { return self._s[1227]! } - public var TwoStepAuth_ReEnterPasswordDescription: String { return self._s[1229]! } - public var Channel_TooMuchBots: String { return self._s[1231]! } - public var Passport_DeletePassportConfirmation: String { return self._s[1232]! } - public var Login_InvalidCodeError: String { return self._s[1233]! } - public var StickerPacksSettings_FeaturedPacks: String { return self._s[1234]! } + public var ChatSettings_AutoDownloadPhotos: String { return self._s[1218]! } + public var SettingsSearch_Synonyms_Privacy_Title: String { return self._s[1219]! } + public var Notifications_PermissionsText: String { return self._s[1220]! } + public var SettingsSearch_Synonyms_Data_SaveIncomingPhotos: String { return self._s[1221]! } + public var Call_Flip: String { return self._s[1222]! } + public var Channel_AdminLog_CanDeleteMessagesOfOthers: String { return self._s[1224]! } + public var SocksProxySetup_ProxyStatusConnecting: String { return self._s[1225]! } + public var Wallet_TransactionInfo_StorageFeeInfoUrl: String { return self._s[1226]! } + public var PrivacyPhoneNumberSettings_DiscoveryHeader: String { return self._s[1227]! } + public var Channel_EditAdmin_PermissionPinMessages: String { return self._s[1229]! } + public var TwoStepAuth_ReEnterPasswordDescription: String { return self._s[1231]! } + public var Channel_TooMuchBots: String { return self._s[1233]! } + public var Passport_DeletePassportConfirmation: String { return self._s[1234]! } + public var Login_InvalidCodeError: String { return self._s[1235]! } + public var StickerPacksSettings_FeaturedPacks: String { return self._s[1236]! } public func ChatList_DeleteSecretChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1235]!, self._r[1235]!, [_0]) + return formatWithArgumentRanges(self._s[1237]!, self._r[1237]!, [_0]) } public func GroupInfo_InvitationLinkAcceptChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1236]!, self._r[1236]!, [_0]) + return formatWithArgumentRanges(self._s[1238]!, self._r[1238]!, [_0]) } - public var VoiceOver_Navigation_ProxySettings: String { return self._s[1237]! } - public var Call_CallInProgressTitle: String { return self._s[1238]! } - public var Month_ShortSeptember: String { return self._s[1239]! } - public var Watch_ChannelInfo_Title: String { return self._s[1240]! } - public var ChatList_DeleteSavedMessagesConfirmation: String { return self._s[1243]! } - public var DialogList_PasscodeLockHelp: String { return self._s[1244]! } - public var Chat_MultipleTextMessagesDisabled: String { return self._s[1245]! } - public var Wallet_Receive_Title: String { return self._s[1246]! } - public var Notifications_Badge_IncludePublicGroups: String { return self._s[1247]! } - public var Channel_AdminLogFilter_EventsTitle: String { return self._s[1248]! } - public var PhotoEditor_CropReset: String { return self._s[1249]! } - public var Group_Username_CreatePrivateLinkHelp: String { return self._s[1251]! } - public var Channel_Management_LabelEditor: String { return self._s[1252]! } - public var Passport_Identity_LatinNameHelp: String { return self._s[1254]! } - public var PhotoEditor_HighlightsTool: String { return self._s[1255]! } - public var Wallet_Info_WalletCreated: String { return self._s[1256]! } - public var UserInfo_Title: String { return self._s[1257]! } - public var ChatList_HideAction: String { return self._s[1258]! } - public var AccessDenied_Title: String { return self._s[1259]! } - public var DialogList_SearchLabel: String { return self._s[1260]! } - public var Group_Setup_HistoryHidden: String { return self._s[1261]! } - public var TwoStepAuth_PasswordChangeSuccess: String { return self._s[1262]! } - public var State_Updating: String { return self._s[1264]! } - public var Contacts_TabTitle: String { return self._s[1265]! } - public var Notifications_Badge_CountUnreadMessages: String { return self._s[1267]! } - public var GroupInfo_GroupHistory: String { return self._s[1268]! } - public var Conversation_UnsupportedMediaPlaceholder: String { return self._s[1269]! } - public var Wallpaper_SetColor: String { return self._s[1270]! } - public var CheckoutInfo_ShippingInfoCountry: String { return self._s[1271]! } - public var SettingsSearch_Synonyms_SavedMessages: String { return self._s[1272]! } - public var Chat_AttachmentLimitReached: String { return self._s[1273]! } - public var Passport_Identity_OneOfTypeDriversLicense: String { return self._s[1274]! } - public var Contacts_NotRegisteredSection: String { return self._s[1275]! } + public var VoiceOver_Navigation_ProxySettings: String { return self._s[1239]! } + public var Call_CallInProgressTitle: String { return self._s[1240]! } + public var Month_ShortSeptember: String { return self._s[1241]! } + public var Watch_ChannelInfo_Title: String { return self._s[1242]! } + public var ChatList_DeleteSavedMessagesConfirmation: String { return self._s[1245]! } + public var DialogList_PasscodeLockHelp: String { return self._s[1246]! } + public var Chat_MultipleTextMessagesDisabled: String { return self._s[1247]! } + public var Wallet_Receive_Title: String { return self._s[1248]! } + public var Notifications_Badge_IncludePublicGroups: String { return self._s[1249]! } + public var Channel_AdminLogFilter_EventsTitle: String { return self._s[1250]! } + public var PhotoEditor_CropReset: String { return self._s[1251]! } + public var Group_Username_CreatePrivateLinkHelp: String { return self._s[1253]! } + public var Channel_Management_LabelEditor: String { return self._s[1254]! } + public var Passport_Identity_LatinNameHelp: String { return self._s[1256]! } + public var PhotoEditor_HighlightsTool: String { return self._s[1257]! } + public var Wallet_Info_WalletCreated: String { return self._s[1258]! } + public var UserInfo_Title: String { return self._s[1259]! } + public var ChatList_HideAction: String { return self._s[1260]! } + public var AccessDenied_Title: String { return self._s[1261]! } + public var DialogList_SearchLabel: String { return self._s[1262]! } + public var Group_Setup_HistoryHidden: String { return self._s[1263]! } + public var TwoStepAuth_PasswordChangeSuccess: String { return self._s[1264]! } + public var State_Updating: String { return self._s[1266]! } + public var Contacts_TabTitle: String { return self._s[1267]! } + public var Notifications_Badge_CountUnreadMessages: String { return self._s[1269]! } + public var GroupInfo_GroupHistory: String { return self._s[1270]! } + public var Conversation_UnsupportedMediaPlaceholder: String { return self._s[1271]! } + public var Wallpaper_SetColor: String { return self._s[1272]! } + public var CheckoutInfo_ShippingInfoCountry: String { return self._s[1273]! } + public var SettingsSearch_Synonyms_SavedMessages: String { return self._s[1274]! } + public var Chat_AttachmentLimitReached: String { return self._s[1275]! } + public var Passport_Identity_OneOfTypeDriversLicense: String { return self._s[1276]! } + public var Contacts_NotRegisteredSection: String { return self._s[1277]! } public func Time_PreciseDate_m4(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1276]!, self._r[1276]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1278]!, self._r[1278]!, [_1, _2, _3]) } - public var Paint_Clear: String { return self._s[1277]! } - public var StickerPacksSettings_ArchivedMasks: String { return self._s[1278]! } - public var SocksProxySetup_Connecting: String { return self._s[1279]! } - public var ExplicitContent_AlertChannel: String { return self._s[1280]! } - public var CreatePoll_AllOptionsAdded: String { return self._s[1281]! } - public var Conversation_Contact: String { return self._s[1282]! } - public var Login_CodeExpired: String { return self._s[1283]! } - public var Passport_DiscardMessageAction: String { return self._s[1284]! } - public var ChatList_Context_Unpin: String { return self._s[1285]! } - public var Channel_AdminLog_MessagePreviousDescription: String { return self._s[1286]! } + public var Paint_Clear: String { return self._s[1279]! } + public var StickerPacksSettings_ArchivedMasks: String { return self._s[1280]! } + public var SocksProxySetup_Connecting: String { return self._s[1281]! } + public var ExplicitContent_AlertChannel: String { return self._s[1282]! } + public var CreatePoll_AllOptionsAdded: String { return self._s[1283]! } + public var Conversation_Contact: String { return self._s[1284]! } + public var Login_CodeExpired: String { return self._s[1285]! } + public var Passport_DiscardMessageAction: String { return self._s[1286]! } + public var ChatList_Context_Unpin: String { return self._s[1287]! } + public var Channel_AdminLog_MessagePreviousDescription: String { return self._s[1288]! } public func VoiceOver_Chat_MusicFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1287]!, self._r[1287]!, [_0]) + return formatWithArgumentRanges(self._s[1289]!, self._r[1289]!, [_0]) } - public var Channel_AdminLog_EmptyMessageText: String { return self._s[1288]! } - public var SettingsSearch_Synonyms_Data_NetworkUsage: String { return self._s[1289]! } + public var Channel_AdminLog_EmptyMessageText: String { return self._s[1290]! } + public var SettingsSearch_Synonyms_Data_NetworkUsage: String { return self._s[1291]! } public func Group_EditAdmin_RankInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1290]!, self._r[1290]!, [_0]) + return formatWithArgumentRanges(self._s[1292]!, self._r[1292]!, [_0]) } - public var Month_ShortApril: String { return self._s[1291]! } - public var AuthSessions_CurrentSession: String { return self._s[1292]! } - public var Chat_AttachmentMultipleFilesDisabled: String { return self._s[1295]! } - public var Wallet_Navigation_Cancel: String { return self._s[1297]! } - public var WallpaperPreview_CropTopText: String { return self._s[1298]! } - public var PrivacySettings_DeleteAccountIfAwayFor: String { return self._s[1299]! } - public var CheckoutInfo_ShippingInfoTitle: String { return self._s[1300]! } + public var Month_ShortApril: String { return self._s[1293]! } + public var AuthSessions_CurrentSession: String { return self._s[1294]! } + public var Chat_AttachmentMultipleFilesDisabled: String { return self._s[1297]! } + public var Wallet_Navigation_Cancel: String { return self._s[1299]! } + public var WallpaperPreview_CropTopText: String { return self._s[1300]! } + public var PrivacySettings_DeleteAccountIfAwayFor: String { return self._s[1301]! } + public var CheckoutInfo_ShippingInfoTitle: String { return self._s[1302]! } public func Conversation_ScheduleMessage_SendOn(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1301]!, self._r[1301]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1303]!, self._r[1303]!, [_0, _1]) } - public var Appearance_ThemePreview_Chat_2_Text: String { return self._s[1302]! } - public var Channel_Setup_TypePrivate: String { return self._s[1304]! } - public var Forward_ChannelReadOnly: String { return self._s[1307]! } - public var PhotoEditor_CurvesBlue: String { return self._s[1308]! } - public var AddContact_SharedContactException: String { return self._s[1309]! } - public var UserInfo_BotPrivacy: String { return self._s[1311]! } - public var Wallet_CreateInvoice_Title: String { return self._s[1312]! } - public var Notification_PassportValueEmail: String { return self._s[1313]! } - public var EmptyGroupInfo_Subtitle: String { return self._s[1314]! } - public var GroupPermission_NewTitle: String { return self._s[1315]! } - public var CallFeedback_ReasonDropped: String { return self._s[1316]! } - public var GroupInfo_Permissions_AddException: String { return self._s[1317]! } - public var Channel_SignMessages_Help: String { return self._s[1319]! } - public var Undo_ChatDeleted: String { return self._s[1321]! } - public var Conversation_ChatBackground: String { return self._s[1322]! } + public var Appearance_ThemePreview_Chat_2_Text: String { return self._s[1304]! } + public var Channel_Setup_TypePrivate: String { return self._s[1306]! } + public var Forward_ChannelReadOnly: String { return self._s[1309]! } + public var PhotoEditor_CurvesBlue: String { return self._s[1310]! } + public var AddContact_SharedContactException: String { return self._s[1311]! } + public var UserInfo_BotPrivacy: String { return self._s[1313]! } + public var Wallet_CreateInvoice_Title: String { return self._s[1314]! } + public var Notification_PassportValueEmail: String { return self._s[1315]! } + public var EmptyGroupInfo_Subtitle: String { return self._s[1316]! } + public var GroupPermission_NewTitle: String { return self._s[1317]! } + public var CallFeedback_ReasonDropped: String { return self._s[1318]! } + public var GroupInfo_Permissions_AddException: String { return self._s[1319]! } + public var Channel_SignMessages_Help: String { return self._s[1321]! } + public var Undo_ChatDeleted: String { return self._s[1323]! } + public var Conversation_ChatBackground: String { return self._s[1324]! } public func Wallet_WordCheck_Text(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1323]!, self._r[1323]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1325]!, self._r[1325]!, [_1, _2, _3]) } public func PUSH_CHAT_MESSAGE_QUIZ(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1324]!, self._r[1324]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1326]!, self._r[1326]!, [_1, _2, _3]) } - public var ChannelMembers_WhoCanAddMembers_Admins: String { return self._s[1325]! } - public var FastTwoStepSetup_EmailPlaceholder: String { return self._s[1326]! } - public var Passport_Language_pt: String { return self._s[1327]! } - public var VoiceOver_Chat_YourVoiceMessage: String { return self._s[1328]! } - public var NotificationsSound_Popcorn: String { return self._s[1331]! } - public var AutoNightTheme_Disabled: String { return self._s[1332]! } - public var BlockedUsers_LeavePrefix: String { return self._s[1333]! } - public var WallpaperPreview_CustomColorTopText: String { return self._s[1334]! } - public var Contacts_PermissionsSuppressWarningText: String { return self._s[1335]! } - public var WallpaperSearch_ColorBlue: String { return self._s[1336]! } + public var ChannelMembers_WhoCanAddMembers_Admins: String { return self._s[1327]! } + public var FastTwoStepSetup_EmailPlaceholder: String { return self._s[1328]! } + public var Passport_Language_pt: String { return self._s[1329]! } + public var VoiceOver_Chat_YourVoiceMessage: String { return self._s[1330]! } + public var NotificationsSound_Popcorn: String { return self._s[1333]! } + public var AutoNightTheme_Disabled: String { return self._s[1334]! } + public var BlockedUsers_LeavePrefix: String { return self._s[1335]! } + public var WallpaperPreview_CustomColorTopText: String { return self._s[1336]! } + public var Contacts_PermissionsSuppressWarningText: String { return self._s[1337]! } + public var WallpaperSearch_ColorBlue: String { return self._s[1338]! } public func CancelResetAccount_TextSMS(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1337]!, self._r[1337]!, [_0]) + return formatWithArgumentRanges(self._s[1339]!, self._r[1339]!, [_0]) } - public var CheckoutInfo_ErrorNameInvalid: String { return self._s[1338]! } - public var SocksProxySetup_UseForCalls: String { return self._s[1339]! } - public var Passport_DeleteDocumentConfirmation: String { return self._s[1341]! } + public var CheckoutInfo_ErrorNameInvalid: String { return self._s[1340]! } + public var SocksProxySetup_UseForCalls: String { return self._s[1341]! } + public var Passport_DeleteDocumentConfirmation: String { return self._s[1343]! } public func Conversation_Megabytes(_ _0: Float) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1342]!, self._r[1342]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[1344]!, self._r[1344]!, ["\(_0)"]) } - public var SocksProxySetup_Hostname: String { return self._s[1345]! } - public var ChatSettings_AutoDownloadSettings_OffForAll: String { return self._s[1346]! } - public var Compose_NewEncryptedChat: String { return self._s[1347]! } - public var Login_CodeFloodError: String { return self._s[1348]! } - public var Calls_TabTitle: String { return self._s[1349]! } - public var Privacy_ProfilePhoto: String { return self._s[1350]! } - public var Passport_Language_he: String { return self._s[1351]! } + public var SocksProxySetup_Hostname: String { return self._s[1347]! } + public var ChatSettings_AutoDownloadSettings_OffForAll: String { return self._s[1348]! } + public var Compose_NewEncryptedChat: String { return self._s[1349]! } + public var Login_CodeFloodError: String { return self._s[1350]! } + public var Calls_TabTitle: String { return self._s[1351]! } + public var Privacy_ProfilePhoto: String { return self._s[1352]! } + public var Passport_Language_he: String { return self._s[1353]! } public func Conversation_SetReminder_RemindToday(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1352]!, self._r[1352]!, [_0]) - } - public var GroupPermission_Title: String { return self._s[1353]! } - public func Channel_AdminLog_MessageGroupPreHistoryHidden(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1354]!, self._r[1354]!, [_0]) } - public var Wallet_TransactionInfo_SenderHeader: String { return self._s[1355]! } - public var GroupPermission_NoChangeInfo: String { return self._s[1356]! } - public var ChatList_DeleteForCurrentUser: String { return self._s[1357]! } - public var Tour_Text1: String { return self._s[1358]! } - public var Channel_EditAdmin_TransferOwnership: String { return self._s[1359]! } - public var Month_ShortFebruary: String { return self._s[1360]! } - public var TwoStepAuth_EmailSkip: String { return self._s[1361]! } + public var GroupPermission_Title: String { return self._s[1355]! } + public func Channel_AdminLog_MessageGroupPreHistoryHidden(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1356]!, self._r[1356]!, [_0]) + } + public var Wallet_TransactionInfo_SenderHeader: String { return self._s[1357]! } + public var GroupPermission_NoChangeInfo: String { return self._s[1358]! } + public var ChatList_DeleteForCurrentUser: String { return self._s[1359]! } + public var Tour_Text1: String { return self._s[1360]! } + public var Channel_EditAdmin_TransferOwnership: String { return self._s[1361]! } + public var Month_ShortFebruary: String { return self._s[1362]! } + public var TwoStepAuth_EmailSkip: String { return self._s[1363]! } public func Wallet_Time_PreciseDate_m4(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1362]!, self._r[1362]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1364]!, self._r[1364]!, [_1, _2, _3]) } - public var NotificationsSound_Glass: String { return self._s[1363]! } - public var Appearance_ThemeNightBlue: String { return self._s[1364]! } - public var CheckoutInfo_Pay: String { return self._s[1365]! } - public var Invite_LargeRecipientsCountWarning: String { return self._s[1367]! } - public var Call_CallAgain: String { return self._s[1369]! } - public var AttachmentMenu_SendAsFile: String { return self._s[1370]! } - public var AccessDenied_MicrophoneRestricted: String { return self._s[1371]! } - public var Passport_InvalidPasswordError: String { return self._s[1372]! } - public var Watch_Message_Game: String { return self._s[1373]! } - public var Stickers_Install: String { return self._s[1374]! } - public var VoiceOver_Chat_Message: String { return self._s[1375]! } - public var PrivacyLastSeenSettings_NeverShareWith: String { return self._s[1376]! } - public var Passport_Identity_ResidenceCountry: String { return self._s[1378]! } - public var Notifications_GroupNotificationsHelp: String { return self._s[1379]! } - public var AuthSessions_OtherSessions: String { return self._s[1380]! } - public var Channel_Username_Help: String { return self._s[1381]! } - public var Camera_Title: String { return self._s[1382]! } - public var IntentsSettings_Title: String { return self._s[1383]! } - public var GroupInfo_SetGroupPhotoDelete: String { return self._s[1385]! } - public var Privacy_ProfilePhoto_NeverShareWith_Title: String { return self._s[1386]! } - public var Channel_AdminLog_SendPolls: String { return self._s[1387]! } - public var Channel_AdminLog_TitleAllEvents: String { return self._s[1388]! } - public var Channel_EditAdmin_PermissionInviteMembers: String { return self._s[1389]! } - public var Contacts_MemberSearchSectionTitleGroup: String { return self._s[1390]! } - public var ScheduledMessages_DeleteMany: String { return self._s[1391]! } - public var Conversation_RestrictedStickers: String { return self._s[1392]! } - public var Notifications_ExceptionsResetToDefaults: String { return self._s[1394]! } - public var UserInfo_TelegramCall: String { return self._s[1396]! } - public var TwoStepAuth_SetupResendEmailCode: String { return self._s[1397]! } - public var CreatePoll_OptionsHeader: String { return self._s[1398]! } - public var SettingsSearch_Synonyms_Data_CallsUseLessData: String { return self._s[1399]! } - public var ArchivedChats_IntroTitle1: String { return self._s[1400]! } - public var Privacy_GroupsAndChannels_AlwaysAllow_Title: String { return self._s[1401]! } - public var Theme_Colors_Proceed: String { return self._s[1402]! } - public var Passport_Identity_EditPersonalDetails: String { return self._s[1403]! } + public var NotificationsSound_Glass: String { return self._s[1365]! } + public var Appearance_ThemeNightBlue: String { return self._s[1366]! } + public var CheckoutInfo_Pay: String { return self._s[1367]! } + public var Invite_LargeRecipientsCountWarning: String { return self._s[1369]! } + public var Call_CallAgain: String { return self._s[1371]! } + public var AttachmentMenu_SendAsFile: String { return self._s[1372]! } + public var AccessDenied_MicrophoneRestricted: String { return self._s[1373]! } + public var Passport_InvalidPasswordError: String { return self._s[1374]! } + public var Watch_Message_Game: String { return self._s[1375]! } + public var Stickers_Install: String { return self._s[1376]! } + public var VoiceOver_Chat_Message: String { return self._s[1377]! } + public var PrivacyLastSeenSettings_NeverShareWith: String { return self._s[1378]! } + public var Passport_Identity_ResidenceCountry: String { return self._s[1380]! } + public var Notifications_GroupNotificationsHelp: String { return self._s[1381]! } + public var AuthSessions_OtherSessions: String { return self._s[1382]! } + public var Channel_Username_Help: String { return self._s[1383]! } + public var Camera_Title: String { return self._s[1384]! } + public var IntentsSettings_Title: String { return self._s[1385]! } + public var GroupInfo_SetGroupPhotoDelete: String { return self._s[1387]! } + public var Privacy_ProfilePhoto_NeverShareWith_Title: String { return self._s[1388]! } + public var Channel_AdminLog_SendPolls: String { return self._s[1389]! } + public var Channel_AdminLog_TitleAllEvents: String { return self._s[1390]! } + public var Channel_EditAdmin_PermissionInviteMembers: String { return self._s[1391]! } + public var Contacts_MemberSearchSectionTitleGroup: String { return self._s[1392]! } + public var ScheduledMessages_DeleteMany: String { return self._s[1393]! } + public var Conversation_RestrictedStickers: String { return self._s[1394]! } + public var Notifications_ExceptionsResetToDefaults: String { return self._s[1396]! } + public var UserInfo_TelegramCall: String { return self._s[1398]! } + public var TwoStepAuth_SetupResendEmailCode: String { return self._s[1399]! } + public var CreatePoll_OptionsHeader: String { return self._s[1400]! } + public var SettingsSearch_Synonyms_Data_CallsUseLessData: String { return self._s[1401]! } + public var ArchivedChats_IntroTitle1: String { return self._s[1402]! } + public var Privacy_GroupsAndChannels_AlwaysAllow_Title: String { return self._s[1403]! } + public var Theme_Colors_Proceed: String { return self._s[1404]! } + public var Passport_Identity_EditPersonalDetails: String { return self._s[1405]! } public func Time_PreciseDate_m1(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1404]!, self._r[1404]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1406]!, self._r[1406]!, [_1, _2, _3]) } - public var Wallet_Month_GenAugust: String { return self._s[1405]! } - public var Settings_SaveEditedPhotos: String { return self._s[1406]! } - public var TwoStepAuth_ConfirmationTitle: String { return self._s[1407]! } - public var Privacy_GroupsAndChannels_NeverAllow_Title: String { return self._s[1408]! } - public var Conversation_MessageDialogRetry: String { return self._s[1409]! } - public var ChatList_Context_MarkAsUnread: String { return self._s[1410]! } - public var MessagePoll_SubmitVote: String { return self._s[1411]! } - public var Conversation_DiscardVoiceMessageAction: String { return self._s[1412]! } - public var Permissions_PeopleNearbyTitle_v0: String { return self._s[1413]! } - public var Group_Setup_TypeHeader: String { return self._s[1414]! } - public var Paint_RecentStickers: String { return self._s[1415]! } - public var PhotoEditor_GrainTool: String { return self._s[1416]! } - public var CheckoutInfo_ShippingInfoState: String { return self._s[1417]! } - public var EmptyGroupInfo_Line4: String { return self._s[1418]! } - public var Watch_AuthRequired: String { return self._s[1420]! } + public var Wallet_Month_GenAugust: String { return self._s[1407]! } + public var Settings_SaveEditedPhotos: String { return self._s[1408]! } + public var TwoStepAuth_ConfirmationTitle: String { return self._s[1409]! } + public var Privacy_GroupsAndChannels_NeverAllow_Title: String { return self._s[1410]! } + public var Conversation_MessageDialogRetry: String { return self._s[1411]! } + public var ChatList_Context_MarkAsUnread: String { return self._s[1412]! } + public var MessagePoll_SubmitVote: String { return self._s[1413]! } + public var Conversation_DiscardVoiceMessageAction: String { return self._s[1414]! } + public var Permissions_PeopleNearbyTitle_v0: String { return self._s[1415]! } + public var Group_Setup_TypeHeader: String { return self._s[1416]! } + public var Paint_RecentStickers: String { return self._s[1417]! } + public var PhotoEditor_GrainTool: String { return self._s[1418]! } + public var CheckoutInfo_ShippingInfoState: String { return self._s[1419]! } + public var EmptyGroupInfo_Line4: String { return self._s[1420]! } + public var Watch_AuthRequired: String { return self._s[1422]! } public func Passport_Email_UseTelegramEmail(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1421]!, self._r[1421]!, [_0]) + return formatWithArgumentRanges(self._s[1423]!, self._r[1423]!, [_0]) } - public var Conversation_EncryptedDescriptionTitle: String { return self._s[1422]! } - public var ChannelIntro_Text: String { return self._s[1423]! } - public var DialogList_DeleteBotConfirmation: String { return self._s[1424]! } - public var GroupPermission_NoSendMedia: String { return self._s[1425]! } - public var Calls_AddTab: String { return self._s[1426]! } - public var Message_ReplyActionButtonShowReceipt: String { return self._s[1427]! } - public var Channel_AdminLog_EmptyFilterText: String { return self._s[1428]! } - public var Conversation_WalletRequiredSetup: String { return self._s[1429]! } - public var Notification_MessageLifetime1d: String { return self._s[1430]! } - public var Notifications_ChannelNotificationsExceptionsHelp: String { return self._s[1431]! } - public var Channel_BanUser_PermissionsHeader: String { return self._s[1432]! } - public var Passport_Identity_GenderFemale: String { return self._s[1433]! } - public var BlockedUsers_BlockTitle: String { return self._s[1434]! } + public var Conversation_EncryptedDescriptionTitle: String { return self._s[1424]! } + public var ChannelIntro_Text: String { return self._s[1425]! } + public var DialogList_DeleteBotConfirmation: String { return self._s[1426]! } + public var GroupPermission_NoSendMedia: String { return self._s[1427]! } + public var Calls_AddTab: String { return self._s[1428]! } + public var Message_ReplyActionButtonShowReceipt: String { return self._s[1429]! } + public var Channel_AdminLog_EmptyFilterText: String { return self._s[1430]! } + public var Conversation_WalletRequiredSetup: String { return self._s[1431]! } + public var Notification_MessageLifetime1d: String { return self._s[1432]! } + public var Notifications_ChannelNotificationsExceptionsHelp: String { return self._s[1433]! } + public var Channel_BanUser_PermissionsHeader: String { return self._s[1434]! } + public var Passport_Identity_GenderFemale: String { return self._s[1435]! } + public var BlockedUsers_BlockTitle: String { return self._s[1436]! } public func PUSH_CHANNEL_MESSAGE_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1435]!, self._r[1435]!, [_1]) + return formatWithArgumentRanges(self._s[1437]!, self._r[1437]!, [_1]) } - public var Weekday_Yesterday: String { return self._s[1436]! } - public var WallpaperSearch_ColorBlack: String { return self._s[1437]! } - public var Settings_Context_Logout: String { return self._s[1438]! } - public var Wallet_Info_UnknownTransaction: String { return self._s[1439]! } - public var ChatList_ArchiveAction: String { return self._s[1440]! } - public var AutoNightTheme_Scheduled: String { return self._s[1441]! } - public var TwoFactorSetup_Email_SkipAction: String { return self._s[1442]! } - public var Settings_Devices: String { return self._s[1443]! } - public var ContactInfo_Note: String { return self._s[1444]! } + public var Weekday_Yesterday: String { return self._s[1438]! } + public var WallpaperSearch_ColorBlack: String { return self._s[1439]! } + public var Settings_Context_Logout: String { return self._s[1440]! } + public var Wallet_Info_UnknownTransaction: String { return self._s[1441]! } + public var ChatList_ArchiveAction: String { return self._s[1442]! } + public var AutoNightTheme_Scheduled: String { return self._s[1443]! } + public var TwoFactorSetup_Email_SkipAction: String { return self._s[1444]! } + public var Settings_Devices: String { return self._s[1445]! } + public var ContactInfo_Note: String { return self._s[1446]! } public func Login_PhoneGenericEmailBody(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String, _ _6: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1445]!, self._r[1445]!, [_1, _2, _3, _4, _5, _6]) + return formatWithArgumentRanges(self._s[1447]!, self._r[1447]!, [_1, _2, _3, _4, _5, _6]) } - public var EditTheme_ThemeTemplateAlertTitle: String { return self._s[1446]! } - public var Wallet_Receive_CreateInvoice: String { return self._s[1447]! } - public var PrivacyPolicy_DeclineDeleteNow: String { return self._s[1448]! } - public var Theme_Colors_ColorWallpaperWarningProceed: String { return self._s[1449]! } + public var EditTheme_ThemeTemplateAlertTitle: String { return self._s[1448]! } + public var Wallet_Receive_CreateInvoice: String { return self._s[1449]! } + public var PrivacyPolicy_DeclineDeleteNow: String { return self._s[1450]! } + public var Theme_Colors_ColorWallpaperWarningProceed: String { return self._s[1451]! } public func PUSH_CHAT_JOINED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1450]!, self._r[1450]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1452]!, self._r[1452]!, [_1, _2]) } - public var CreatePoll_Create: String { return self._s[1451]! } - public var Channel_Members_AddBannedErrorAdmin: String { return self._s[1452]! } + public var CreatePoll_Create: String { return self._s[1453]! } + public var Channel_Members_AddBannedErrorAdmin: String { return self._s[1454]! } public func Notification_CallFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1453]!, self._r[1453]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1455]!, self._r[1455]!, [_1, _2]) } - public var ScheduledMessages_ClearAllConfirmation: String { return self._s[1454]! } - public var Checkout_ErrorProviderAccountInvalid: String { return self._s[1455]! } - public var Notifications_InAppNotificationsSounds: String { return self._s[1457]! } + public var ScheduledMessages_ClearAllConfirmation: String { return self._s[1456]! } + public var Checkout_ErrorProviderAccountInvalid: String { return self._s[1457]! } + public var Notifications_InAppNotificationsSounds: String { return self._s[1459]! } public func PUSH_PINNED_GAME_SCORE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1458]!, self._r[1458]!, [_1]) + return formatWithArgumentRanges(self._s[1460]!, self._r[1460]!, [_1]) } - public var Preview_OpenInInstagram: String { return self._s[1459]! } - public var Notification_MessageLifetimeRemovedOutgoing: String { return self._s[1460]! } + public var Preview_OpenInInstagram: String { return self._s[1461]! } + public var Notification_MessageLifetimeRemovedOutgoing: String { return self._s[1462]! } public func PUSH_CHAT_ADD_MEMBER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1461]!, self._r[1461]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1463]!, self._r[1463]!, [_1, _2, _3]) } public func Passport_PrivacyPolicy(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1462]!, self._r[1462]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1464]!, self._r[1464]!, [_1, _2]) } - public var Channel_AdminLog_InfoPanelAlertTitle: String { return self._s[1463]! } - public var ArchivedChats_IntroText3: String { return self._s[1464]! } - public var ChatList_UndoArchiveHiddenText: String { return self._s[1465]! } - public var NetworkUsageSettings_TotalSection: String { return self._s[1466]! } - public var Wallet_Month_GenSeptember: String { return self._s[1467]! } - public var Channel_Setup_TypePrivateHelp: String { return self._s[1468]! } + public var Channel_AdminLog_InfoPanelAlertTitle: String { return self._s[1465]! } + public var ArchivedChats_IntroText3: String { return self._s[1466]! } + public var ChatList_UndoArchiveHiddenText: String { return self._s[1467]! } + public var NetworkUsageSettings_TotalSection: String { return self._s[1468]! } + public var Wallet_Month_GenSeptember: String { return self._s[1469]! } + public var Channel_Setup_TypePrivateHelp: String { return self._s[1470]! } public func PUSH_CHAT_MESSAGE_POLL(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1469]!, self._r[1469]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1471]!, self._r[1471]!, [_1, _2, _3]) } - public var Privacy_GroupsAndChannels_NeverAllow_Placeholder: String { return self._s[1471]! } - public var FastTwoStepSetup_HintSection: String { return self._s[1472]! } - public var Wallpaper_PhotoLibrary: String { return self._s[1473]! } - public var TwoStepAuth_SetupResendEmailCodeAlert: String { return self._s[1474]! } - public var Gif_NoGifsFound: String { return self._s[1475]! } - public var Watch_LastSeen_WithinAMonth: String { return self._s[1476]! } - public var VoiceOver_MessageContextDelete: String { return self._s[1477]! } - public var EditTheme_Preview: String { return self._s[1478]! } + public var Privacy_GroupsAndChannels_NeverAllow_Placeholder: String { return self._s[1473]! } + public var FastTwoStepSetup_HintSection: String { return self._s[1474]! } + public var Wallpaper_PhotoLibrary: String { return self._s[1475]! } + public var TwoStepAuth_SetupResendEmailCodeAlert: String { return self._s[1476]! } + public var Gif_NoGifsFound: String { return self._s[1477]! } + public var Watch_LastSeen_WithinAMonth: String { return self._s[1478]! } + public var VoiceOver_MessageContextDelete: String { return self._s[1479]! } + public var EditTheme_Preview: String { return self._s[1480]! } public func ClearCache_StorageTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1479]!, self._r[1479]!, [_0]) + return formatWithArgumentRanges(self._s[1481]!, self._r[1481]!, [_0]) } - public var GroupInfo_ActionPromote: String { return self._s[1480]! } - public var PasscodeSettings_SimplePasscode: String { return self._s[1481]! } - public var GroupInfo_Permissions_Title: String { return self._s[1482]! } - public var Permissions_ContactsText_v0: String { return self._s[1483]! } - public var PrivacyPhoneNumberSettings_CustomDisabledHelp: String { return self._s[1484]! } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedPublicGroups: String { return self._s[1485]! } - public var PrivacySettings_DataSettingsHelp: String { return self._s[1488]! } - public var Passport_FieldEmailHelp: String { return self._s[1489]! } + public var GroupInfo_ActionPromote: String { return self._s[1482]! } + public var PasscodeSettings_SimplePasscode: String { return self._s[1483]! } + public var GroupInfo_Permissions_Title: String { return self._s[1484]! } + public var Permissions_ContactsText_v0: String { return self._s[1485]! } + public var PrivacyPhoneNumberSettings_CustomDisabledHelp: String { return self._s[1486]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedPublicGroups: String { return self._s[1487]! } + public var PrivacySettings_DataSettingsHelp: String { return self._s[1490]! } + public var Passport_FieldEmailHelp: String { return self._s[1491]! } public func Activity_RemindAboutUser(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1490]!, self._r[1490]!, [_0]) + return formatWithArgumentRanges(self._s[1492]!, self._r[1492]!, [_0]) } - public var Passport_Identity_GenderPlaceholder: String { return self._s[1491]! } - public var Weekday_ShortSaturday: String { return self._s[1492]! } - public var ContactInfo_PhoneLabelMain: String { return self._s[1493]! } - public var Watch_Conversation_UserInfo: String { return self._s[1494]! } - public var CheckoutInfo_ShippingInfoCityPlaceholder: String { return self._s[1495]! } - public var GroupPermission_PermissionDisabledByDefault: String { return self._s[1496]! } - public var PrivacyLastSeenSettings_Title: String { return self._s[1497]! } - public var Conversation_ShareBotLocationConfirmation: String { return self._s[1498]! } - public var PhotoEditor_VignetteTool: String { return self._s[1499]! } - public var Passport_Address_Street1Placeholder: String { return self._s[1500]! } - public var Passport_Language_et: String { return self._s[1501]! } - public var AppUpgrade_Running: String { return self._s[1502]! } - public var Channel_DiscussionGroup_Info: String { return self._s[1504]! } - public var EditTheme_Create_Preview_IncomingReplyName: String { return self._s[1505]! } - public var Passport_Language_bg: String { return self._s[1506]! } - public var Stickers_NoStickersFound: String { return self._s[1508]! } + public var Passport_Identity_GenderPlaceholder: String { return self._s[1493]! } + public var Weekday_ShortSaturday: String { return self._s[1494]! } + public var ContactInfo_PhoneLabelMain: String { return self._s[1495]! } + public var Watch_Conversation_UserInfo: String { return self._s[1496]! } + public var CheckoutInfo_ShippingInfoCityPlaceholder: String { return self._s[1497]! } + public var GroupPermission_PermissionDisabledByDefault: String { return self._s[1498]! } + public var PrivacyLastSeenSettings_Title: String { return self._s[1499]! } + public var Conversation_ShareBotLocationConfirmation: String { return self._s[1500]! } + public var PhotoEditor_VignetteTool: String { return self._s[1501]! } + public var Passport_Address_Street1Placeholder: String { return self._s[1502]! } + public var Passport_Language_et: String { return self._s[1503]! } + public var AppUpgrade_Running: String { return self._s[1504]! } + public var Channel_DiscussionGroup_Info: String { return self._s[1506]! } + public var EditTheme_Create_Preview_IncomingReplyName: String { return self._s[1507]! } + public var Passport_Language_bg: String { return self._s[1508]! } + public var Stickers_NoStickersFound: String { return self._s[1510]! } public func PUSH_CHANNEL_MESSAGE_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1510]!, self._r[1510]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1512]!, self._r[1512]!, [_1, _2]) } public func VoiceOver_Chat_ContactFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1511]!, self._r[1511]!, [_0]) + return formatWithArgumentRanges(self._s[1513]!, self._r[1513]!, [_0]) } - public var Wallet_Month_GenJuly: String { return self._s[1512]! } - public var Wallet_Receive_AddressHeader: String { return self._s[1513]! } - public var Wallet_Send_AmountText: String { return self._s[1514]! } - public var Settings_About: String { return self._s[1515]! } + public var Wallet_Month_GenJuly: String { return self._s[1514]! } + public var Wallet_Receive_AddressHeader: String { return self._s[1515]! } + public var Wallet_Send_AmountText: String { return self._s[1516]! } + public var Settings_About: String { return self._s[1517]! } public func Channel_AdminLog_MessageRestricted(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1516]!, self._r[1516]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[1518]!, self._r[1518]!, [_0, _1, _2]) } - public var ChatList_Context_MarkAsRead: String { return self._s[1518]! } - public var KeyCommand_NewMessage: String { return self._s[1519]! } - public var Group_ErrorAddBlocked: String { return self._s[1520]! } + public var ChatList_Context_MarkAsRead: String { return self._s[1520]! } + public var KeyCommand_NewMessage: String { return self._s[1521]! } + public var Group_ErrorAddBlocked: String { return self._s[1522]! } public func Message_PaymentSent(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1521]!, self._r[1521]!, [_0]) + return formatWithArgumentRanges(self._s[1523]!, self._r[1523]!, [_0]) } - public var Map_LocationTitle: String { return self._s[1522]! } - public var ReportGroupLocation_Title: String { return self._s[1523]! } - public var CallSettings_UseLessDataLongDescription: String { return self._s[1524]! } - public var Cache_ClearProgress: String { return self._s[1525]! } + public var Map_LocationTitle: String { return self._s[1524]! } + public var ReportGroupLocation_Title: String { return self._s[1525]! } + public var CallSettings_UseLessDataLongDescription: String { return self._s[1526]! } + public var Cache_ClearProgress: String { return self._s[1527]! } public func Channel_Management_ErrorNotMember(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1526]!, self._r[1526]!, [_0]) + return formatWithArgumentRanges(self._s[1528]!, self._r[1528]!, [_0]) } - public var GroupRemoved_AddToGroup: String { return self._s[1527]! } - public var Passport_UpdateRequiredError: String { return self._s[1528]! } - public var Wallet_SecureStorageNotAvailable_Text: String { return self._s[1529]! } + public var GroupRemoved_AddToGroup: String { return self._s[1529]! } + public var Passport_UpdateRequiredError: String { return self._s[1530]! } + public var Wallet_SecureStorageNotAvailable_Text: String { return self._s[1531]! } public func PUSH_MESSAGE_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1530]!, self._r[1530]!, [_1]) + return formatWithArgumentRanges(self._s[1532]!, self._r[1532]!, [_1]) } - public var Notifications_PermissionsSuppressWarningText: String { return self._s[1532]! } - public var Passport_Identity_MainPageHelp: String { return self._s[1533]! } - public var Conversation_StatusKickedFromGroup: String { return self._s[1534]! } - public var Passport_Language_ka: String { return self._s[1535]! } + public var Notifications_PermissionsSuppressWarningText: String { return self._s[1534]! } + public var Passport_Identity_MainPageHelp: String { return self._s[1535]! } + public var Conversation_StatusKickedFromGroup: String { return self._s[1536]! } + public var Passport_Language_ka: String { return self._s[1537]! } public func Wallet_Time_PreciseDate_m12(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1536]!, self._r[1536]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1538]!, self._r[1538]!, [_1, _2, _3]) } - public var Call_Decline: String { return self._s[1537]! } - public var SocksProxySetup_ProxyEnabled: String { return self._s[1538]! } - public var TwoFactorSetup_Email_SkipConfirmationText: String { return self._s[1541]! } + public var Call_Decline: String { return self._s[1539]! } + public var SocksProxySetup_ProxyEnabled: String { return self._s[1540]! } + public var TwoFactorSetup_Email_SkipConfirmationText: String { return self._s[1543]! } public func AuthCode_Alert(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1542]!, self._r[1542]!, [_0]) + return formatWithArgumentRanges(self._s[1544]!, self._r[1544]!, [_0]) } - public var CallFeedback_Send: String { return self._s[1543]! } - public var EditTheme_EditTitle: String { return self._s[1544]! } + public var CallFeedback_Send: String { return self._s[1545]! } + public var EditTheme_EditTitle: String { return self._s[1546]! } public func Channel_AdminLog_MessagePromotedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1545]!, self._r[1545]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1547]!, self._r[1547]!, [_1, _2]) } - public var Passport_Phone_UseTelegramNumberHelp: String { return self._s[1546]! } + public var Passport_Phone_UseTelegramNumberHelp: String { return self._s[1548]! } public func Wallet_Updated_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1548]!, self._r[1548]!, [_0]) + return formatWithArgumentRanges(self._s[1550]!, self._r[1550]!, [_0]) } - public var SettingsSearch_Synonyms_Data_Title: String { return self._s[1549]! } - public var Passport_DeletePassport: String { return self._s[1550]! } - public var Appearance_AppIconFilled: String { return self._s[1551]! } - public var Privacy_Calls_P2PAlways: String { return self._s[1552]! } - public var Month_ShortDecember: String { return self._s[1553]! } - public var Channel_AdminLog_CanEditMessages: String { return self._s[1555]! } + public var SettingsSearch_Synonyms_Data_Title: String { return self._s[1551]! } + public var Passport_DeletePassport: String { return self._s[1552]! } + public var Appearance_AppIconFilled: String { return self._s[1553]! } + public var Privacy_Calls_P2PAlways: String { return self._s[1554]! } + public var Month_ShortDecember: String { return self._s[1555]! } + public var Channel_AdminLog_CanEditMessages: String { return self._s[1557]! } public func Contacts_AccessDeniedHelpLandscape(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1556]!, self._r[1556]!, [_0]) + return formatWithArgumentRanges(self._s[1558]!, self._r[1558]!, [_0]) } - public var Channel_Stickers_Searching: String { return self._s[1557]! } - public var Conversation_EncryptedDescription1: String { return self._s[1558]! } - public var Conversation_EncryptedDescription2: String { return self._s[1559]! } - public var PasscodeSettings_PasscodeOptions: String { return self._s[1560]! } - public var Conversation_EncryptedDescription3: String { return self._s[1562]! } - public var PhotoEditor_SharpenTool: String { return self._s[1563]! } - public var Wallet_Configuration_Title: String { return self._s[1564]! } + public var Channel_Stickers_Searching: String { return self._s[1559]! } + public var Conversation_EncryptedDescription1: String { return self._s[1560]! } + public var Conversation_EncryptedDescription2: String { return self._s[1561]! } + public var PasscodeSettings_PasscodeOptions: String { return self._s[1562]! } + public var Conversation_EncryptedDescription3: String { return self._s[1564]! } + public var PhotoEditor_SharpenTool: String { return self._s[1565]! } + public var Wallet_Configuration_Title: String { return self._s[1566]! } public func Conversation_AddNameToContacts(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1565]!, self._r[1565]!, [_0]) + return formatWithArgumentRanges(self._s[1567]!, self._r[1567]!, [_0]) } - public var Conversation_EncryptedDescription4: String { return self._s[1567]! } - public var Channel_Members_AddMembers: String { return self._s[1568]! } - public var Wallpaper_Search: String { return self._s[1569]! } - public var Weekday_Friday: String { return self._s[1571]! } - public var Privacy_ContactsSync: String { return self._s[1572]! } - public var SettingsSearch_Synonyms_Privacy_Data_ContactsReset: String { return self._s[1573]! } - public var ApplyLanguage_ChangeLanguageAction: String { return self._s[1574]! } + public var Conversation_EncryptedDescription4: String { return self._s[1569]! } + public var Channel_Members_AddMembers: String { return self._s[1570]! } + public var Wallpaper_Search: String { return self._s[1571]! } + public var Weekday_Friday: String { return self._s[1573]! } + public var Privacy_ContactsSync: String { return self._s[1574]! } + public var SettingsSearch_Synonyms_Privacy_Data_ContactsReset: String { return self._s[1575]! } + public var ApplyLanguage_ChangeLanguageAction: String { return self._s[1576]! } public func Channel_Management_RestrictedBy(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1575]!, self._r[1575]!, [_0]) + return formatWithArgumentRanges(self._s[1577]!, self._r[1577]!, [_0]) } - public var Wallet_Configuration_BlockchainIdHeader: String { return self._s[1576]! } - public var GroupInfo_Permissions_Removed: String { return self._s[1577]! } - public var ScheduledMessages_ScheduledOnline: String { return self._s[1578]! } - public var Passport_Identity_GenderMale: String { return self._s[1579]! } + public var Wallet_Configuration_BlockchainIdHeader: String { return self._s[1578]! } + public var GroupInfo_Permissions_Removed: String { return self._s[1579]! } + public var ScheduledMessages_ScheduledOnline: String { return self._s[1580]! } + public var Passport_Identity_GenderMale: String { return self._s[1581]! } public func Call_StatusBar(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1580]!, self._r[1580]!, [_0]) + return formatWithArgumentRanges(self._s[1582]!, self._r[1582]!, [_0]) } - public var Notifications_PermissionsKeepDisabled: String { return self._s[1581]! } - public var Conversation_JumpToDate: String { return self._s[1582]! } - public var Contacts_GlobalSearch: String { return self._s[1583]! } - public var AutoDownloadSettings_ResetHelp: String { return self._s[1584]! } - public var SettingsSearch_Synonyms_FAQ: String { return self._s[1585]! } - public var Profile_MessageLifetime1d: String { return self._s[1586]! } + public var Notifications_PermissionsKeepDisabled: String { return self._s[1583]! } + public var Conversation_JumpToDate: String { return self._s[1584]! } + public var Contacts_GlobalSearch: String { return self._s[1585]! } + public var AutoDownloadSettings_ResetHelp: String { return self._s[1586]! } + public var SettingsSearch_Synonyms_FAQ: String { return self._s[1587]! } + public var Profile_MessageLifetime1d: String { return self._s[1588]! } public func MESSAGE_INVOICE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1587]!, self._r[1587]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1589]!, self._r[1589]!, [_1, _2]) } - public var StickerPack_BuiltinPackName: String { return self._s[1590]! } + public var StickerPack_BuiltinPackName: String { return self._s[1592]! } public func PUSH_CHAT_MESSAGE_AUDIO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1591]!, self._r[1591]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1593]!, self._r[1593]!, [_1, _2]) } - public var VoiceOver_Chat_RecordModeVoiceMessageInfo: String { return self._s[1592]! } - public var Passport_InfoTitle: String { return self._s[1594]! } - public var Notifications_PermissionsUnreachableText: String { return self._s[1595]! } + public var VoiceOver_Chat_RecordModeVoiceMessageInfo: String { return self._s[1594]! } + public var Passport_InfoTitle: String { return self._s[1596]! } + public var Notifications_PermissionsUnreachableText: String { return self._s[1597]! } public func NetworkUsageSettings_CellularUsageSince(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1599]!, self._r[1599]!, [_0]) + return formatWithArgumentRanges(self._s[1601]!, self._r[1601]!, [_0]) } public func PUSH_CHAT_MESSAGE_GEO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1600]!, self._r[1600]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1602]!, self._r[1602]!, [_1, _2]) } - public var Passport_Address_TypePassportRegistrationUploadScan: String { return self._s[1601]! } - public var Profile_BotInfo: String { return self._s[1602]! } - public var Watch_Compose_CreateMessage: String { return self._s[1603]! } - public var AutoDownloadSettings_VoiceMessagesInfo: String { return self._s[1604]! } - public var Month_ShortNovember: String { return self._s[1605]! } - public var Conversation_ScamWarning: String { return self._s[1606]! } - public var Wallpaper_SetCustomBackground: String { return self._s[1607]! } - public var Appearance_TextSize_Title: String { return self._s[1608]! } - public var Passport_Identity_TranslationsHelp: String { return self._s[1609]! } - public var NotificationsSound_Chime: String { return self._s[1610]! } - public var Passport_Language_ko: String { return self._s[1612]! } - public var InviteText_URL: String { return self._s[1613]! } - public var TextFormat_Monospace: String { return self._s[1614]! } + public var Passport_Address_TypePassportRegistrationUploadScan: String { return self._s[1603]! } + public var Profile_BotInfo: String { return self._s[1604]! } + public var Watch_Compose_CreateMessage: String { return self._s[1605]! } + public var AutoDownloadSettings_VoiceMessagesInfo: String { return self._s[1606]! } + public var Month_ShortNovember: String { return self._s[1607]! } + public var Conversation_ScamWarning: String { return self._s[1608]! } + public var Wallpaper_SetCustomBackground: String { return self._s[1609]! } + public var Appearance_TextSize_Title: String { return self._s[1610]! } + public var Passport_Identity_TranslationsHelp: String { return self._s[1611]! } + public var NotificationsSound_Chime: String { return self._s[1612]! } + public var Passport_Language_ko: String { return self._s[1614]! } + public var InviteText_URL: String { return self._s[1615]! } + public var TextFormat_Monospace: String { return self._s[1616]! } public func Time_PreciseDate_m11(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1615]!, self._r[1615]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1617]!, self._r[1617]!, [_1, _2, _3]) } - public var EditTheme_Edit_BottomInfo: String { return self._s[1616]! } + public var EditTheme_Edit_BottomInfo: String { return self._s[1618]! } public func Login_WillSendSms(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1617]!, self._r[1617]!, [_0]) + return formatWithArgumentRanges(self._s[1619]!, self._r[1619]!, [_0]) } public func Watch_Time_ShortWeekdayAt(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1618]!, self._r[1618]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1620]!, self._r[1620]!, [_1, _2]) } - public var Wallet_Words_Title: String { return self._s[1619]! } - public var Wallet_Month_ShortMay: String { return self._s[1620]! } - public var EditTheme_CreateTitle: String { return self._s[1622]! } - public var Passport_InfoLearnMore: String { return self._s[1623]! } - public var TwoStepAuth_EmailPlaceholder: String { return self._s[1624]! } - public var Passport_Identity_AddIdentityCard: String { return self._s[1625]! } - public var Your_card_has_expired: String { return self._s[1626]! } - public var StickerPacksSettings_StickerPacksSection: String { return self._s[1627]! } - public var GroupInfo_InviteLink_Help: String { return self._s[1628]! } - public var TwoFactorSetup_EmailVerification_ResendAction: String { return self._s[1632]! } - public var Conversation_Report: String { return self._s[1634]! } - public var Notifications_MessageNotificationsSound: String { return self._s[1635]! } - public var Notification_MessageLifetime1m: String { return self._s[1636]! } - public var Privacy_ContactsTitle: String { return self._s[1637]! } - public var Conversation_ShareMyContactInfo: String { return self._s[1638]! } - public var Wallet_WordCheck_Title: String { return self._s[1639]! } - public var ChannelMembers_WhoCanAddMembersAdminsHelp: String { return self._s[1640]! } - public var Channel_Members_Title: String { return self._s[1641]! } - public var Map_OpenInWaze: String { return self._s[1642]! } - public var Appearance_RemoveThemeColorConfirmation: String { return self._s[1643]! } - public var Login_PhoneBannedError: String { return self._s[1644]! } + public var Wallet_Words_Title: String { return self._s[1621]! } + public var Wallet_Month_ShortMay: String { return self._s[1622]! } + public var EditTheme_CreateTitle: String { return self._s[1624]! } + public var Passport_InfoLearnMore: String { return self._s[1625]! } + public var TwoStepAuth_EmailPlaceholder: String { return self._s[1626]! } + public var Passport_Identity_AddIdentityCard: String { return self._s[1627]! } + public var Your_card_has_expired: String { return self._s[1628]! } + public var StickerPacksSettings_StickerPacksSection: String { return self._s[1629]! } + public var GroupInfo_InviteLink_Help: String { return self._s[1630]! } + public var TwoFactorSetup_EmailVerification_ResendAction: String { return self._s[1634]! } + public var Conversation_Report: String { return self._s[1636]! } + public var Notifications_MessageNotificationsSound: String { return self._s[1637]! } + public var Notification_MessageLifetime1m: String { return self._s[1638]! } + public var Privacy_ContactsTitle: String { return self._s[1639]! } + public var Conversation_ShareMyContactInfo: String { return self._s[1640]! } + public var Wallet_WordCheck_Title: String { return self._s[1641]! } + public var ChannelMembers_WhoCanAddMembersAdminsHelp: String { return self._s[1642]! } + public var Channel_Members_Title: String { return self._s[1643]! } + public var Map_OpenInWaze: String { return self._s[1644]! } + public var Appearance_RemoveThemeColorConfirmation: String { return self._s[1645]! } + public var Login_PhoneBannedError: String { return self._s[1646]! } public func LiveLocationUpdated_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1645]!, self._r[1645]!, [_0]) + return formatWithArgumentRanges(self._s[1647]!, self._r[1647]!, [_0]) } - public var IntentsSettings_MainAccount: String { return self._s[1646]! } - public var Group_Management_AddModeratorHelp: String { return self._s[1647]! } - public var AutoDownloadSettings_WifiTitle: String { return self._s[1648]! } - public var Common_OK: String { return self._s[1649]! } - public var Passport_Address_TypeBankStatementUploadScan: String { return self._s[1650]! } - public var Wallet_Words_NotDoneResponse: String { return self._s[1651]! } - public var Cache_Music: String { return self._s[1652]! } - public var Wallet_Configuration_SourceURL: String { return self._s[1653]! } - public var SettingsSearch_Synonyms_EditProfile_PhoneNumber: String { return self._s[1654]! } - public var PasscodeSettings_UnlockWithTouchId: String { return self._s[1657]! } - public var TwoStepAuth_HintPlaceholder: String { return self._s[1658]! } + public var IntentsSettings_MainAccount: String { return self._s[1648]! } + public var Group_Management_AddModeratorHelp: String { return self._s[1649]! } + public var AutoDownloadSettings_WifiTitle: String { return self._s[1650]! } + public var Common_OK: String { return self._s[1651]! } + public var Passport_Address_TypeBankStatementUploadScan: String { return self._s[1652]! } + public var Wallet_Words_NotDoneResponse: String { return self._s[1653]! } + public var Cache_Music: String { return self._s[1654]! } + public var Wallet_Configuration_SourceURL: String { return self._s[1655]! } + public var SettingsSearch_Synonyms_EditProfile_PhoneNumber: String { return self._s[1656]! } + public var PasscodeSettings_UnlockWithTouchId: String { return self._s[1659]! } + public var TwoStepAuth_HintPlaceholder: String { return self._s[1660]! } public func PUSH_PINNED_INVOICE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1659]!, self._r[1659]!, [_1]) + return formatWithArgumentRanges(self._s[1661]!, self._r[1661]!, [_1]) } public func Passport_RequestHeader(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1660]!, self._r[1660]!, [_0]) - } - public var TwoFactorSetup_Done_Action: String { return self._s[1661]! } - public func VoiceOver_Chat_ContactOrganization(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1662]!, self._r[1662]!, [_0]) } - public var Wallet_Send_ErrorNotEnoughFundsText: String { return self._s[1663]! } - public var Watch_MessageView_ViewOnPhone: String { return self._s[1665]! } - public var Privacy_Calls_CustomShareHelp: String { return self._s[1666]! } - public var Wallet_Receive_CreateInvoiceInfo: String { return self._s[1668]! } - public var ChangePhoneNumberNumber_Title: String { return self._s[1669]! } - public var State_ConnectingToProxyInfo: String { return self._s[1670]! } - public var Conversation_SwipeToReplyHintTitle: String { return self._s[1671]! } - public var Message_VideoMessage: String { return self._s[1673]! } - public var ChannelInfo_DeleteChannel: String { return self._s[1674]! } - public var ContactInfo_PhoneLabelOther: String { return self._s[1675]! } - public var Channel_EditAdmin_CannotEdit: String { return self._s[1676]! } - public var Passport_DeleteAddressConfirmation: String { return self._s[1677]! } - public func Wallet_Time_PreciseDate_m9(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1678]!, self._r[1678]!, [_1, _2, _3]) + public var TwoFactorSetup_Done_Action: String { return self._s[1663]! } + public func VoiceOver_Chat_ContactOrganization(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1664]!, self._r[1664]!, [_0]) } - public var WallpaperPreview_SwipeBottomText: String { return self._s[1679]! } - public var Activity_RecordingAudio: String { return self._s[1680]! } - public var SettingsSearch_Synonyms_Watch: String { return self._s[1681]! } - public var PasscodeSettings_TryAgainIn1Minute: String { return self._s[1682]! } - public var Wallet_Info_Address: String { return self._s[1683]! } + public var Wallet_Send_ErrorNotEnoughFundsText: String { return self._s[1665]! } + public var Watch_MessageView_ViewOnPhone: String { return self._s[1667]! } + public var Privacy_Calls_CustomShareHelp: String { return self._s[1668]! } + public var Wallet_Receive_CreateInvoiceInfo: String { return self._s[1670]! } + public var ChangePhoneNumberNumber_Title: String { return self._s[1671]! } + public var State_ConnectingToProxyInfo: String { return self._s[1672]! } + public var Conversation_SwipeToReplyHintTitle: String { return self._s[1673]! } + public var Message_VideoMessage: String { return self._s[1675]! } + public var ChannelInfo_DeleteChannel: String { return self._s[1676]! } + public var ContactInfo_PhoneLabelOther: String { return self._s[1677]! } + public var Channel_EditAdmin_CannotEdit: String { return self._s[1678]! } + public var Passport_DeleteAddressConfirmation: String { return self._s[1679]! } + public func Wallet_Time_PreciseDate_m9(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1680]!, self._r[1680]!, [_1, _2, _3]) + } + public var WallpaperPreview_SwipeBottomText: String { return self._s[1681]! } + public var Activity_RecordingAudio: String { return self._s[1682]! } + public var SettingsSearch_Synonyms_Watch: String { return self._s[1683]! } + public var PasscodeSettings_TryAgainIn1Minute: String { return self._s[1684]! } + public var Wallet_Info_Address: String { return self._s[1685]! } public func Notification_ChangedGroupName(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1685]!, self._r[1685]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1687]!, self._r[1687]!, [_0, _1]) } public func EmptyGroupInfo_Line1(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1689]!, self._r[1689]!, [_0]) + return formatWithArgumentRanges(self._s[1691]!, self._r[1691]!, [_0]) } - public var Conversation_ApplyLocalization: String { return self._s[1690]! } - public var TwoFactorSetup_Intro_Action: String { return self._s[1691]! } - public var UserInfo_AddPhone: String { return self._s[1692]! } - public var Map_ShareLiveLocationHelp: String { return self._s[1693]! } + public var Conversation_ApplyLocalization: String { return self._s[1692]! } + public var TwoFactorSetup_Intro_Action: String { return self._s[1693]! } + public var UserInfo_AddPhone: String { return self._s[1694]! } + public var Map_ShareLiveLocationHelp: String { return self._s[1695]! } public func Passport_Identity_NativeNameGenericHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1694]!, self._r[1694]!, [_0]) + return formatWithArgumentRanges(self._s[1696]!, self._r[1696]!, [_0]) } - public var Passport_Scans: String { return self._s[1696]! } - public var BlockedUsers_Unblock: String { return self._s[1697]! } + public var Passport_Scans: String { return self._s[1698]! } + public var BlockedUsers_Unblock: String { return self._s[1699]! } public func PUSH_ENCRYPTION_REQUEST(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1698]!, self._r[1698]!, [_1]) + return formatWithArgumentRanges(self._s[1700]!, self._r[1700]!, [_1]) } - public var Channel_Management_LabelCreator: String { return self._s[1699]! } - public var Conversation_ReportSpamAndLeave: String { return self._s[1700]! } - public var SettingsSearch_Synonyms_EditProfile_Bio: String { return self._s[1701]! } - public var ChatList_UndoArchiveMultipleTitle: String { return self._s[1702]! } - public var Passport_Identity_NativeNameGenericTitle: String { return self._s[1703]! } + public var Channel_Management_LabelCreator: String { return self._s[1701]! } + public var Conversation_ReportSpamAndLeave: String { return self._s[1702]! } + public var SettingsSearch_Synonyms_EditProfile_Bio: String { return self._s[1703]! } + public var ChatList_UndoArchiveMultipleTitle: String { return self._s[1704]! } + public var Passport_Identity_NativeNameGenericTitle: String { return self._s[1705]! } public func Login_EmailPhoneBody(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1704]!, self._r[1704]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[1706]!, self._r[1706]!, [_0, _1, _2]) } - public var Login_PhoneNumberHelp: String { return self._s[1705]! } - public var LastSeen_ALongTimeAgo: String { return self._s[1706]! } - public var Channel_AdminLog_CanPinMessages: String { return self._s[1707]! } - public var ChannelIntro_CreateChannel: String { return self._s[1708]! } - public var Conversation_UnreadMessages: String { return self._s[1709]! } - public var SettingsSearch_Synonyms_Stickers_ArchivedPacks: String { return self._s[1710]! } - public var Channel_AdminLog_EmptyText: String { return self._s[1711]! } - public var Theme_Context_Apply: String { return self._s[1712]! } - public var Notification_GroupActivated: String { return self._s[1713]! } - public var NotificationSettings_ContactJoinedInfo: String { return self._s[1714]! } - public var Wallet_Intro_CreateWallet: String { return self._s[1715]! } + public var Login_PhoneNumberHelp: String { return self._s[1707]! } + public var LastSeen_ALongTimeAgo: String { return self._s[1708]! } + public var Channel_AdminLog_CanPinMessages: String { return self._s[1709]! } + public var ChannelIntro_CreateChannel: String { return self._s[1710]! } + public var Conversation_UnreadMessages: String { return self._s[1711]! } + public var SettingsSearch_Synonyms_Stickers_ArchivedPacks: String { return self._s[1712]! } + public var Channel_AdminLog_EmptyText: String { return self._s[1713]! } + public var Theme_Context_Apply: String { return self._s[1714]! } + public var Notification_GroupActivated: String { return self._s[1715]! } + public var NotificationSettings_ContactJoinedInfo: String { return self._s[1716]! } + public var Wallet_Intro_CreateWallet: String { return self._s[1717]! } public func Notification_PinnedContactMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1716]!, self._r[1716]!, [_0]) + return formatWithArgumentRanges(self._s[1718]!, self._r[1718]!, [_0]) } public func DownloadingStatus(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1717]!, self._r[1717]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1719]!, self._r[1719]!, [_0, _1]) } - public var GroupInfo_ConvertToSupergroup: String { return self._s[1719]! } + public var GroupInfo_ConvertToSupergroup: String { return self._s[1721]! } public func PrivacyPolicy_AgeVerificationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1720]!, self._r[1720]!, [_0]) + return formatWithArgumentRanges(self._s[1722]!, self._r[1722]!, [_0]) } - public var Undo_DeletedChannel: String { return self._s[1721]! } - public var CallFeedback_AddComment: String { return self._s[1722]! } + public var Undo_DeletedChannel: String { return self._s[1723]! } + public var CallFeedback_AddComment: String { return self._s[1724]! } public func Conversation_OpenBotLinkAllowMessages(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1723]!, self._r[1723]!, [_0]) - } - public var Document_TargetConfirmationFormat: String { return self._s[1724]! } - public func Call_StatusOngoing(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1725]!, self._r[1725]!, [_0]) } - public var LogoutOptions_SetPasscodeTitle: String { return self._s[1726]! } + public var Document_TargetConfirmationFormat: String { return self._s[1726]! } + public func Call_StatusOngoing(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1727]!, self._r[1727]!, [_0]) + } + public var LogoutOptions_SetPasscodeTitle: String { return self._s[1728]! } public func PUSH_CHAT_MESSAGE_GAME_SCORE(_ _1: String, _ _2: String, _ _3: String, _ _4: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1727]!, self._r[1727]!, [_1, _2, _3, _4]) + return formatWithArgumentRanges(self._s[1729]!, self._r[1729]!, [_1, _2, _3, _4]) } - public var Wallet_SecureStorageChanged_PasscodeText: String { return self._s[1728]! } - public var Theme_ErrorNotFound: String { return self._s[1729]! } - public var Contacts_SortByName: String { return self._s[1730]! } - public var SettingsSearch_Synonyms_Privacy_Forwards: String { return self._s[1731]! } + public var Wallet_SecureStorageChanged_PasscodeText: String { return self._s[1730]! } + public var Theme_ErrorNotFound: String { return self._s[1731]! } + public var Contacts_SortByName: String { return self._s[1732]! } + public var SettingsSearch_Synonyms_Privacy_Forwards: String { return self._s[1733]! } public func CHAT_MESSAGE_INVOICE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1733]!, self._r[1733]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1735]!, self._r[1735]!, [_1, _2, _3]) } - public var Notification_Exceptions_RemoveFromExceptions: String { return self._s[1734]! } - public var ScheduledMessages_EditTime: String { return self._s[1735]! } - public var Conversation_ClearSelfHistory: String { return self._s[1736]! } - public var Checkout_NewCard_PostcodePlaceholder: String { return self._s[1737]! } - public var PasscodeSettings_DoNotMatch: String { return self._s[1738]! } - public var Stickers_SuggestNone: String { return self._s[1739]! } - public var ChatSettings_Cache: String { return self._s[1740]! } - public var Settings_SaveIncomingPhotos: String { return self._s[1741]! } - public var Media_ShareThisPhoto: String { return self._s[1742]! } - public var Chat_SlowmodeTooltipPending: String { return self._s[1743]! } - public var InfoPlist_NSContactsUsageDescription: String { return self._s[1744]! } - public var Conversation_ContextMenuCopyLink: String { return self._s[1745]! } - public var PrivacyPolicy_AgeVerificationTitle: String { return self._s[1746]! } - public var SettingsSearch_Synonyms_Stickers_Masks: String { return self._s[1747]! } - public var TwoStepAuth_SetupPasswordEnterPasswordNew: String { return self._s[1748]! } - public var Appearance_ThemePreview_Chat_6_Text: String { return self._s[1749]! } + public var Notification_Exceptions_RemoveFromExceptions: String { return self._s[1736]! } + public var ScheduledMessages_EditTime: String { return self._s[1737]! } + public var Conversation_ClearSelfHistory: String { return self._s[1738]! } + public var Checkout_NewCard_PostcodePlaceholder: String { return self._s[1739]! } + public var PasscodeSettings_DoNotMatch: String { return self._s[1740]! } + public var Stickers_SuggestNone: String { return self._s[1741]! } + public var ChatSettings_Cache: String { return self._s[1742]! } + public var Settings_SaveIncomingPhotos: String { return self._s[1743]! } + public var Media_ShareThisPhoto: String { return self._s[1744]! } + public var Chat_SlowmodeTooltipPending: String { return self._s[1745]! } + public var InfoPlist_NSContactsUsageDescription: String { return self._s[1746]! } + public var Conversation_ContextMenuCopyLink: String { return self._s[1747]! } + public var PrivacyPolicy_AgeVerificationTitle: String { return self._s[1748]! } + public var SettingsSearch_Synonyms_Stickers_Masks: String { return self._s[1749]! } + public var TwoStepAuth_SetupPasswordEnterPasswordNew: String { return self._s[1750]! } + public var Appearance_ThemePreview_Chat_6_Text: String { return self._s[1751]! } public func Wallet_SecureStorageReset_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1750]!, self._r[1750]!, [_0]) + return formatWithArgumentRanges(self._s[1752]!, self._r[1752]!, [_0]) } - public var Permissions_CellularDataTitle_v0: String { return self._s[1751]! } - public var WallpaperSearch_ColorWhite: String { return self._s[1753]! } - public var Channel_AdminLog_DefaultRestrictionsUpdated: String { return self._s[1754]! } - public var Conversation_ErrorInaccessibleMessage: String { return self._s[1755]! } - public var Map_OpenIn: String { return self._s[1756]! } + public var Permissions_CellularDataTitle_v0: String { return self._s[1753]! } + public var WallpaperSearch_ColorWhite: String { return self._s[1755]! } + public var Channel_AdminLog_DefaultRestrictionsUpdated: String { return self._s[1756]! } + public var Conversation_ErrorInaccessibleMessage: String { return self._s[1757]! } + public var Map_OpenIn: String { return self._s[1758]! } + public var PeerInfo_ButtonCall: String { return self._s[1759]! } public func PUSH_PHONE_CALL_MISSED(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1759]!, self._r[1759]!, [_1]) + return formatWithArgumentRanges(self._s[1762]!, self._r[1762]!, [_1]) } public func ChannelInfo_AddParticipantConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1760]!, self._r[1760]!, [_0]) + return formatWithArgumentRanges(self._s[1763]!, self._r[1763]!, [_0]) } - public var GroupInfo_Permissions_SlowmodeHeader: String { return self._s[1761]! } - public var MessagePoll_LabelClosed: String { return self._s[1762]! } - public var GroupPermission_PermissionGloballyDisabled: String { return self._s[1764]! } - public var Wallet_Send_SendAnyway: String { return self._s[1765]! } - public var Passport_Identity_MiddleNamePlaceholder: String { return self._s[1766]! } - public var UserInfo_FirstNamePlaceholder: String { return self._s[1767]! } - public var PrivacyLastSeenSettings_WhoCanSeeMyTimestamp: String { return self._s[1768]! } - public var Map_SetThisPlace: String { return self._s[1769]! } - public var Login_SelectCountry_Title: String { return self._s[1770]! } - public var Channel_EditAdmin_PermissionBanUsers: String { return self._s[1771]! } + public var GroupInfo_Permissions_SlowmodeHeader: String { return self._s[1764]! } + public var MessagePoll_LabelClosed: String { return self._s[1765]! } + public var GroupPermission_PermissionGloballyDisabled: String { return self._s[1767]! } + public var Wallet_Send_SendAnyway: String { return self._s[1768]! } + public var Passport_Identity_MiddleNamePlaceholder: String { return self._s[1769]! } + public var UserInfo_FirstNamePlaceholder: String { return self._s[1770]! } + public var PrivacyLastSeenSettings_WhoCanSeeMyTimestamp: String { return self._s[1771]! } + public var Map_SetThisPlace: String { return self._s[1772]! } + public var Login_SelectCountry_Title: String { return self._s[1773]! } + public var Channel_EditAdmin_PermissionBanUsers: String { return self._s[1774]! } public func Conversation_OpenBotLinkLogin(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1772]!, self._r[1772]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1775]!, self._r[1775]!, [_1, _2]) } - public var Channel_AdminLog_ChangeInfo: String { return self._s[1773]! } - public var Watch_Suggestion_BRB: String { return self._s[1774]! } - public var Passport_Identity_EditIdentityCard: String { return self._s[1775]! } - public var Contacts_PermissionsTitle: String { return self._s[1776]! } - public var Conversation_RestrictedInline: String { return self._s[1777]! } - public var Appearance_RemoveThemeColor: String { return self._s[1779]! } - public var StickerPack_ViewPack: String { return self._s[1780]! } - public var Wallet_UnknownError: String { return self._s[1781]! } + public var Channel_AdminLog_ChangeInfo: String { return self._s[1776]! } + public var Watch_Suggestion_BRB: String { return self._s[1777]! } + public var Passport_Identity_EditIdentityCard: String { return self._s[1778]! } + public var Contacts_PermissionsTitle: String { return self._s[1779]! } + public var Conversation_RestrictedInline: String { return self._s[1780]! } + public var Appearance_RemoveThemeColor: String { return self._s[1782]! } + public var StickerPack_ViewPack: String { return self._s[1783]! } + public var Wallet_UnknownError: String { return self._s[1784]! } public func Update_AppVersion(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1782]!, self._r[1782]!, [_0]) + return formatWithArgumentRanges(self._s[1785]!, self._r[1785]!, [_0]) } - public var Compose_NewChannel: String { return self._s[1784]! } - public var ChatSettings_AutoDownloadSettings_TypePhoto: String { return self._s[1787]! } - public var MessagePoll_LabelQuiz: String { return self._s[1789]! } - public var Conversation_ReportSpamGroupConfirmation: String { return self._s[1790]! } - public var Channel_Info_Stickers: String { return self._s[1791]! } - public var AutoNightTheme_PreferredTheme: String { return self._s[1792]! } - public var PrivacyPolicy_AgeVerificationAgree: String { return self._s[1793]! } - public var Passport_DeletePersonalDetails: String { return self._s[1794]! } - public var LogoutOptions_AddAccountTitle: String { return self._s[1795]! } - public var Channel_DiscussionGroupInfo: String { return self._s[1796]! } - public var Group_EditAdmin_RankOwnerPlaceholder: String { return self._s[1797]! } - public var Conversation_SearchNoResults: String { return self._s[1800]! } - public var Wallet_Configuration_ApplyErrorTextURLInvalid: String { return self._s[1801]! } - public var MessagePoll_LabelAnonymous: String { return self._s[1802]! } - public var Channel_Members_AddAdminErrorNotAMember: String { return self._s[1803]! } - public var Login_Code: String { return self._s[1804]! } - public var EditTheme_Create_BottomInfo: String { return self._s[1805]! } - public var Watch_Suggestion_WhatsUp: String { return self._s[1806]! } - public var Weekday_ShortThursday: String { return self._s[1807]! } - public var Resolve_ErrorNotFound: String { return self._s[1809]! } - public var LastSeen_Offline: String { return self._s[1810]! } - public var PeopleNearby_NoMembers: String { return self._s[1811]! } - public var GroupPermission_AddMembersNotAvailable: String { return self._s[1812]! } - public var Privacy_Calls_AlwaysAllow_Title: String { return self._s[1813]! } - public var GroupInfo_Title: String { return self._s[1815]! } - public var NotificationsSound_Note: String { return self._s[1816]! } - public var Conversation_EditingMessagePanelTitle: String { return self._s[1817]! } - public var Watch_Message_Poll: String { return self._s[1818]! } - public var Privacy_Calls: String { return self._s[1819]! } + public var Compose_NewChannel: String { return self._s[1787]! } + public var ChatSettings_AutoDownloadSettings_TypePhoto: String { return self._s[1790]! } + public var MessagePoll_LabelQuiz: String { return self._s[1792]! } + public var Conversation_ReportSpamGroupConfirmation: String { return self._s[1793]! } + public var Channel_Info_Stickers: String { return self._s[1794]! } + public var AutoNightTheme_PreferredTheme: String { return self._s[1795]! } + public var PrivacyPolicy_AgeVerificationAgree: String { return self._s[1796]! } + public var Passport_DeletePersonalDetails: String { return self._s[1797]! } + public var LogoutOptions_AddAccountTitle: String { return self._s[1798]! } + public var Channel_DiscussionGroupInfo: String { return self._s[1799]! } + public var Group_EditAdmin_RankOwnerPlaceholder: String { return self._s[1800]! } + public var Conversation_SearchNoResults: String { return self._s[1803]! } + public var Wallet_Configuration_ApplyErrorTextURLInvalid: String { return self._s[1804]! } + public var MessagePoll_LabelAnonymous: String { return self._s[1805]! } + public var Channel_Members_AddAdminErrorNotAMember: String { return self._s[1806]! } + public var Login_Code: String { return self._s[1807]! } + public var EditTheme_Create_BottomInfo: String { return self._s[1808]! } + public var Watch_Suggestion_WhatsUp: String { return self._s[1809]! } + public var Weekday_ShortThursday: String { return self._s[1810]! } + public var Resolve_ErrorNotFound: String { return self._s[1812]! } + public var LastSeen_Offline: String { return self._s[1813]! } + public var PeopleNearby_NoMembers: String { return self._s[1814]! } + public var GroupPermission_AddMembersNotAvailable: String { return self._s[1815]! } + public var Privacy_Calls_AlwaysAllow_Title: String { return self._s[1816]! } + public var GroupInfo_Title: String { return self._s[1818]! } + public var NotificationsSound_Note: String { return self._s[1819]! } + public var Conversation_EditingMessagePanelTitle: String { return self._s[1820]! } + public var Watch_Message_Poll: String { return self._s[1821]! } + public var Privacy_Calls: String { return self._s[1822]! } public func Channel_AdminLog_MessageRankUsername(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1820]!, self._r[1820]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1823]!, self._r[1823]!, [_1, _2, _3]) } - public var Month_ShortAugust: String { return self._s[1821]! } - public var TwoStepAuth_SetPasswordHelp: String { return self._s[1822]! } - public var Notifications_Reset: String { return self._s[1823]! } - public var Conversation_Pin: String { return self._s[1824]! } - public var Passport_Language_lv: String { return self._s[1825]! } - public var Permissions_PeopleNearbyAllowInSettings_v0: String { return self._s[1826]! } - public var BlockedUsers_Info: String { return self._s[1827]! } - public var SettingsSearch_Synonyms_Data_AutoplayVideos: String { return self._s[1829]! } - public var Watch_Conversation_Unblock: String { return self._s[1831]! } + public var Month_ShortAugust: String { return self._s[1824]! } + public var TwoStepAuth_SetPasswordHelp: String { return self._s[1825]! } + public var Notifications_Reset: String { return self._s[1826]! } + public var Conversation_Pin: String { return self._s[1827]! } + public var Passport_Language_lv: String { return self._s[1828]! } + public var Permissions_PeopleNearbyAllowInSettings_v0: String { return self._s[1829]! } + public var BlockedUsers_Info: String { return self._s[1830]! } + public var SettingsSearch_Synonyms_Data_AutoplayVideos: String { return self._s[1832]! } + public var Watch_Conversation_Unblock: String { return self._s[1834]! } public func Time_MonthOfYear_m9(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1832]!, self._r[1832]!, [_0]) - } - public var CloudStorage_Title: String { return self._s[1833]! } - public var GroupInfo_DeleteAndExitConfirmation: String { return self._s[1834]! } - public func NetworkUsageSettings_WifiUsageSince(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1835]!, self._r[1835]!, [_0]) } - public var Channel_AdminLogFilter_AdminsTitle: String { return self._s[1836]! } - public var Watch_Suggestion_OnMyWay: String { return self._s[1837]! } - public var TwoStepAuth_RecoveryEmailTitle: String { return self._s[1838]! } - public var Passport_Address_EditBankStatement: String { return self._s[1839]! } - public func Channel_AdminLog_MessageChangedUnlinkedGroup(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1840]!, self._r[1840]!, [_1, _2]) + public var CloudStorage_Title: String { return self._s[1836]! } + public var GroupInfo_DeleteAndExitConfirmation: String { return self._s[1837]! } + public func NetworkUsageSettings_WifiUsageSince(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1838]!, self._r[1838]!, [_0]) } - public var ChatSettings_DownloadInBackgroundInfo: String { return self._s[1841]! } - public var ShareMenu_Comment: String { return self._s[1842]! } - public var Permissions_ContactsTitle_v0: String { return self._s[1843]! } - public var Notifications_PermissionsTitle: String { return self._s[1844]! } - public var GroupPermission_NoSendLinks: String { return self._s[1845]! } - public var Privacy_Forwards_NeverAllow_Title: String { return self._s[1846]! } - public var Wallet_SecureStorageChanged_ImportWallet: String { return self._s[1847]! } - public var Settings_Support: String { return self._s[1848]! } - public var Notifications_ChannelNotificationsSound: String { return self._s[1849]! } - public var SettingsSearch_Synonyms_Data_AutoDownloadReset: String { return self._s[1850]! } - public var Privacy_Forwards_Preview: String { return self._s[1851]! } - public var GroupPermission_ApplyAlertAction: String { return self._s[1852]! } - public var Watch_Stickers_StickerPacks: String { return self._s[1853]! } - public var Common_Select: String { return self._s[1855]! } - public var CheckoutInfo_ErrorEmailInvalid: String { return self._s[1856]! } - public var WallpaperSearch_ColorGray: String { return self._s[1859]! } - public var TwoFactorSetup_Password_PlaceholderPassword: String { return self._s[1860]! } - public var TwoFactorSetup_Hint_SkipAction: String { return self._s[1861]! } - public var ChatAdmins_AllMembersAreAdminsOffHelp: String { return self._s[1862]! } - public var PollResults_Title: String { return self._s[1863]! } - public var PasscodeSettings_AutoLock_IfAwayFor_5hours: String { return self._s[1864]! } - public var Appearance_PreviewReplyAuthor: String { return self._s[1865]! } - public var TwoStepAuth_RecoveryTitle: String { return self._s[1866]! } - public var Widget_AuthRequired: String { return self._s[1867]! } - public var Camera_FlashOn: String { return self._s[1868]! } - public var Conversation_ContextMenuLookUp: String { return self._s[1869]! } - public var Channel_Stickers_NotFoundHelp: String { return self._s[1870]! } - public var Watch_Suggestion_OK: String { return self._s[1871]! } + public var Channel_AdminLogFilter_AdminsTitle: String { return self._s[1839]! } + public var Watch_Suggestion_OnMyWay: String { return self._s[1840]! } + public var TwoStepAuth_RecoveryEmailTitle: String { return self._s[1841]! } + public var Passport_Address_EditBankStatement: String { return self._s[1842]! } + public func Channel_AdminLog_MessageChangedUnlinkedGroup(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1843]!, self._r[1843]!, [_1, _2]) + } + public var ChatSettings_DownloadInBackgroundInfo: String { return self._s[1844]! } + public var ShareMenu_Comment: String { return self._s[1845]! } + public var Permissions_ContactsTitle_v0: String { return self._s[1846]! } + public var Notifications_PermissionsTitle: String { return self._s[1847]! } + public var GroupPermission_NoSendLinks: String { return self._s[1848]! } + public var Privacy_Forwards_NeverAllow_Title: String { return self._s[1849]! } + public var Wallet_SecureStorageChanged_ImportWallet: String { return self._s[1850]! } + public var Settings_Support: String { return self._s[1851]! } + public var Notifications_ChannelNotificationsSound: String { return self._s[1852]! } + public var SettingsSearch_Synonyms_Data_AutoDownloadReset: String { return self._s[1853]! } + public var Privacy_Forwards_Preview: String { return self._s[1854]! } + public var GroupPermission_ApplyAlertAction: String { return self._s[1855]! } + public var Watch_Stickers_StickerPacks: String { return self._s[1856]! } + public var Common_Select: String { return self._s[1858]! } + public var CheckoutInfo_ErrorEmailInvalid: String { return self._s[1859]! } + public var WallpaperSearch_ColorGray: String { return self._s[1862]! } + public var TwoFactorSetup_Password_PlaceholderPassword: String { return self._s[1863]! } + public var TwoFactorSetup_Hint_SkipAction: String { return self._s[1864]! } + public var ChatAdmins_AllMembersAreAdminsOffHelp: String { return self._s[1865]! } + public var PollResults_Title: String { return self._s[1866]! } + public var PasscodeSettings_AutoLock_IfAwayFor_5hours: String { return self._s[1867]! } + public var Appearance_PreviewReplyAuthor: String { return self._s[1868]! } + public var TwoStepAuth_RecoveryTitle: String { return self._s[1869]! } + public var Widget_AuthRequired: String { return self._s[1870]! } + public var Camera_FlashOn: String { return self._s[1871]! } + public var Conversation_ContextMenuLookUp: String { return self._s[1872]! } + public var Channel_Stickers_NotFoundHelp: String { return self._s[1873]! } + public var Watch_Suggestion_OK: String { return self._s[1874]! } public func Username_LinkHint(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1873]!, self._r[1873]!, [_0]) + return formatWithArgumentRanges(self._s[1876]!, self._r[1876]!, [_0]) } public func Notification_PinnedLiveLocationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1875]!, self._r[1875]!, [_0]) + return formatWithArgumentRanges(self._s[1878]!, self._r[1878]!, [_0]) } - public var TextFormat_Strikethrough: String { return self._s[1876]! } - public var DialogList_AdLabel: String { return self._s[1877]! } - public var WatchRemote_NotificationText: String { return self._s[1878]! } - public var IntentsSettings_SuggestedChatsSavedMessages: String { return self._s[1879]! } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsAlert: String { return self._s[1880]! } - public var Conversation_ReportSpam: String { return self._s[1881]! } - public var SettingsSearch_Synonyms_Privacy_Data_TopPeers: String { return self._s[1882]! } - public var Settings_LogoutConfirmationTitle: String { return self._s[1884]! } - public var PhoneLabel_Title: String { return self._s[1885]! } - public var Passport_Address_EditRentalAgreement: String { return self._s[1886]! } - public var Settings_ChangePhoneNumber: String { return self._s[1887]! } - public var Notifications_ExceptionsTitle: String { return self._s[1888]! } - public var Notifications_AlertTones: String { return self._s[1889]! } - public var Call_ReportIncludeLogDescription: String { return self._s[1890]! } - public var SettingsSearch_Synonyms_Notifications_ResetAllNotifications: String { return self._s[1891]! } - public var AutoDownloadSettings_PrivateChats: String { return self._s[1892]! } - public var VoiceOver_Chat_Photo: String { return self._s[1894]! } - public var TwoStepAuth_AddHintTitle: String { return self._s[1895]! } - public var ReportPeer_ReasonOther: String { return self._s[1896]! } - public var ChatList_Context_JoinChannel: String { return self._s[1897]! } - public var KeyCommand_ScrollDown: String { return self._s[1899]! } - public var Conversation_ScheduleMessage_Title: String { return self._s[1900]! } + public var TextFormat_Strikethrough: String { return self._s[1879]! } + public var DialogList_AdLabel: String { return self._s[1880]! } + public var WatchRemote_NotificationText: String { return self._s[1881]! } + public var IntentsSettings_SuggestedChatsSavedMessages: String { return self._s[1882]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsAlert: String { return self._s[1883]! } + public var Conversation_ReportSpam: String { return self._s[1884]! } + public var SettingsSearch_Synonyms_Privacy_Data_TopPeers: String { return self._s[1885]! } + public var Settings_LogoutConfirmationTitle: String { return self._s[1887]! } + public var PhoneLabel_Title: String { return self._s[1888]! } + public var Passport_Address_EditRentalAgreement: String { return self._s[1889]! } + public var Settings_ChangePhoneNumber: String { return self._s[1890]! } + public var Notifications_ExceptionsTitle: String { return self._s[1891]! } + public var Notifications_AlertTones: String { return self._s[1892]! } + public var Call_ReportIncludeLogDescription: String { return self._s[1893]! } + public var SettingsSearch_Synonyms_Notifications_ResetAllNotifications: String { return self._s[1894]! } + public var AutoDownloadSettings_PrivateChats: String { return self._s[1895]! } + public var VoiceOver_Chat_Photo: String { return self._s[1897]! } + public var TwoStepAuth_AddHintTitle: String { return self._s[1898]! } + public var ReportPeer_ReasonOther: String { return self._s[1899]! } + public var ChatList_Context_JoinChannel: String { return self._s[1900]! } + public var KeyCommand_ScrollDown: String { return self._s[1902]! } + public var Conversation_ScheduleMessage_Title: String { return self._s[1903]! } public func Login_BannedPhoneSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1901]!, self._r[1901]!, [_0]) + return formatWithArgumentRanges(self._s[1904]!, self._r[1904]!, [_0]) } - public var NetworkUsageSettings_MediaVideoDataSection: String { return self._s[1902]! } - public var ChannelInfo_DeleteGroupConfirmation: String { return self._s[1903]! } - public var AuthSessions_LogOut: String { return self._s[1904]! } - public var Passport_Identity_TypeInternalPassport: String { return self._s[1905]! } - public var ChatSettings_AutoDownloadVoiceMessages: String { return self._s[1906]! } - public var Passport_Phone_Title: String { return self._s[1907]! } - public var ContactList_Context_StartSecretChat: String { return self._s[1908]! } - public var Settings_PhoneNumber: String { return self._s[1909]! } + public var NetworkUsageSettings_MediaVideoDataSection: String { return self._s[1905]! } + public var ChannelInfo_DeleteGroupConfirmation: String { return self._s[1906]! } + public var AuthSessions_LogOut: String { return self._s[1907]! } + public var Passport_Identity_TypeInternalPassport: String { return self._s[1908]! } + public var ChatSettings_AutoDownloadVoiceMessages: String { return self._s[1909]! } + public var Passport_Phone_Title: String { return self._s[1910]! } + public var ContactList_Context_StartSecretChat: String { return self._s[1911]! } + public var Settings_PhoneNumber: String { return self._s[1912]! } public func Conversation_ScheduleMessage_SendToday(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1910]!, self._r[1910]!, [_0]) + return formatWithArgumentRanges(self._s[1913]!, self._r[1913]!, [_0]) } - public var NotificationsSound_Alert: String { return self._s[1912]! } - public var Wallet_SecureStorageChanged_CreateWallet: String { return self._s[1913]! } - public var WebSearch_SearchNoResults: String { return self._s[1914]! } - public var Privacy_ProfilePhoto_AlwaysShareWith_Title: String { return self._s[1916]! } - public var Wallet_Configuration_SourceInfo: String { return self._s[1917]! } - public var LogoutOptions_AlternativeOptionsSection: String { return self._s[1918]! } - public var SettingsSearch_Synonyms_Passport: String { return self._s[1919]! } - public var PhotoEditor_CurvesTool: String { return self._s[1920]! } - public var Checkout_PaymentMethod: String { return self._s[1922]! } + public var NotificationsSound_Alert: String { return self._s[1915]! } + public var Wallet_SecureStorageChanged_CreateWallet: String { return self._s[1916]! } + public var WebSearch_SearchNoResults: String { return self._s[1917]! } + public var Privacy_ProfilePhoto_AlwaysShareWith_Title: String { return self._s[1919]! } + public var Wallet_Configuration_SourceInfo: String { return self._s[1920]! } + public var LogoutOptions_AlternativeOptionsSection: String { return self._s[1921]! } + public var SettingsSearch_Synonyms_Passport: String { return self._s[1922]! } + public var PhotoEditor_CurvesTool: String { return self._s[1923]! } + public var Checkout_PaymentMethod: String { return self._s[1925]! } public func PUSH_CHAT_ADD_YOU(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1923]!, self._r[1923]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1926]!, self._r[1926]!, [_1, _2]) } - public var Contacts_AccessDeniedError: String { return self._s[1924]! } - public var Camera_PhotoMode: String { return self._s[1927]! } - public var EditTheme_Expand_Preview_IncomingText: String { return self._s[1928]! } - public var Appearance_TextSize_Apply: String { return self._s[1929]! } - public var Passport_Address_AddUtilityBill: String { return self._s[1931]! } - public var CallSettings_OnMobile: String { return self._s[1932]! } - public var Tour_Text2: String { return self._s[1933]! } + public var Contacts_AccessDeniedError: String { return self._s[1927]! } + public var Camera_PhotoMode: String { return self._s[1930]! } + public var EditTheme_Expand_Preview_IncomingText: String { return self._s[1931]! } + public var Appearance_TextSize_Apply: String { return self._s[1932]! } + public var Passport_Address_AddUtilityBill: String { return self._s[1934]! } + public var CallSettings_OnMobile: String { return self._s[1935]! } + public var Tour_Text2: String { return self._s[1936]! } public func PUSH_CHAT_MESSAGE_ROUND(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1934]!, self._r[1934]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1937]!, self._r[1937]!, [_1, _2]) } - public var DialogList_EncryptionProcessing: String { return self._s[1936]! } - public var Permissions_Skip: String { return self._s[1937]! } - public var Wallet_Words_NotDoneOk: String { return self._s[1938]! } - public var SecretImage_Title: String { return self._s[1939]! } - public var Watch_MessageView_Title: String { return self._s[1940]! } - public var Channel_DiscussionGroupAdd: String { return self._s[1941]! } - public var AttachmentMenu_Poll: String { return self._s[1942]! } + public var DialogList_EncryptionProcessing: String { return self._s[1939]! } + public var Permissions_Skip: String { return self._s[1940]! } + public var Wallet_Words_NotDoneOk: String { return self._s[1941]! } + public var SecretImage_Title: String { return self._s[1942]! } + public var Watch_MessageView_Title: String { return self._s[1943]! } + public var Channel_DiscussionGroupAdd: String { return self._s[1944]! } + public var AttachmentMenu_Poll: String { return self._s[1945]! } public func Notification_GroupInviter(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1943]!, self._r[1943]!, [_0]) + return formatWithArgumentRanges(self._s[1946]!, self._r[1946]!, [_0]) } public func Channel_DiscussionGroup_PrivateChannelLink(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1944]!, self._r[1944]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1947]!, self._r[1947]!, [_1, _2]) } - public var Notification_CallCanceled: String { return self._s[1945]! } - public var WallpaperPreview_Title: String { return self._s[1946]! } - public var Privacy_PaymentsClear_PaymentInfo: String { return self._s[1947]! } - public var Settings_ProxyConnecting: String { return self._s[1948]! } - public var Settings_CheckPhoneNumberText: String { return self._s[1950]! } - public var VoiceOver_Chat_YourVideo: String { return self._s[1951]! } - public var Wallet_Intro_Title: String { return self._s[1952]! } - public var TwoFactorSetup_Password_Action: String { return self._s[1953]! } - public var Profile_MessageLifetime5s: String { return self._s[1954]! } - public var Username_InvalidCharacters: String { return self._s[1955]! } - public var VoiceOver_Media_PlaybackRateFast: String { return self._s[1956]! } - public var ScheduledMessages_ClearAll: String { return self._s[1957]! } - public var WallpaperPreview_CropBottomText: String { return self._s[1958]! } - public var AutoDownloadSettings_LimitBySize: String { return self._s[1959]! } - public var Settings_AddAccount: String { return self._s[1960]! } - public var Notification_CreatedChannel: String { return self._s[1963]! } + public var Notification_CallCanceled: String { return self._s[1948]! } + public var WallpaperPreview_Title: String { return self._s[1949]! } + public var Privacy_PaymentsClear_PaymentInfo: String { return self._s[1950]! } + public var Settings_ProxyConnecting: String { return self._s[1951]! } + public var Settings_CheckPhoneNumberText: String { return self._s[1953]! } + public var VoiceOver_Chat_YourVideo: String { return self._s[1954]! } + public var Wallet_Intro_Title: String { return self._s[1955]! } + public var TwoFactorSetup_Password_Action: String { return self._s[1956]! } + public var Profile_MessageLifetime5s: String { return self._s[1957]! } + public var Username_InvalidCharacters: String { return self._s[1958]! } + public var VoiceOver_Media_PlaybackRateFast: String { return self._s[1959]! } + public var ScheduledMessages_ClearAll: String { return self._s[1960]! } + public var WallpaperPreview_CropBottomText: String { return self._s[1961]! } + public var AutoDownloadSettings_LimitBySize: String { return self._s[1962]! } + public var Settings_AddAccount: String { return self._s[1963]! } + public var Notification_CreatedChannel: String { return self._s[1966]! } public func PUSH_CHAT_DELETE_MEMBER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1964]!, self._r[1964]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1967]!, self._r[1967]!, [_1, _2, _3]) } - public var Passcode_AppLockedAlert: String { return self._s[1966]! } - public var StickerPacksSettings_AnimatedStickersInfo: String { return self._s[1967]! } - public var VoiceOver_Media_PlaybackStop: String { return self._s[1968]! } - public var Contacts_TopSection: String { return self._s[1969]! } - public var ChatList_DeleteForEveryoneConfirmationAction: String { return self._s[1970]! } + public var Passcode_AppLockedAlert: String { return self._s[1969]! } + public var StickerPacksSettings_AnimatedStickersInfo: String { return self._s[1970]! } + public var VoiceOver_Media_PlaybackStop: String { return self._s[1971]! } + public var Contacts_TopSection: String { return self._s[1972]! } + public var ChatList_DeleteForEveryoneConfirmationAction: String { return self._s[1973]! } public func Conversation_SetReminder_RemindOn(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1971]!, self._r[1971]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1974]!, self._r[1974]!, [_0, _1]) } - public var Wallet_Info_Receive: String { return self._s[1972]! } - public var Wallet_Completed_ViewWallet: String { return self._s[1973]! } + public var Wallet_Info_Receive: String { return self._s[1975]! } + public var Wallet_Completed_ViewWallet: String { return self._s[1976]! } public func Time_MonthOfYear_m6(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1974]!, self._r[1974]!, [_0]) + return formatWithArgumentRanges(self._s[1977]!, self._r[1977]!, [_0]) } - public var ReportPeer_ReasonSpam: String { return self._s[1975]! } - public var UserInfo_TapToCall: String { return self._s[1976]! } - public var Conversation_ForwardAuthorHiddenTooltip: String { return self._s[1978]! } - public var AutoDownloadSettings_DataUsageCustom: String { return self._s[1979]! } - public var Common_Search: String { return self._s[1980]! } - public var ScheduledMessages_EmptyPlaceholder: String { return self._s[1981]! } + public var ReportPeer_ReasonSpam: String { return self._s[1978]! } + public var UserInfo_TapToCall: String { return self._s[1979]! } + public var Conversation_ForwardAuthorHiddenTooltip: String { return self._s[1981]! } + public var AutoDownloadSettings_DataUsageCustom: String { return self._s[1982]! } + public var Common_Search: String { return self._s[1983]! } + public var ScheduledMessages_EmptyPlaceholder: String { return self._s[1984]! } public func Channel_AdminLog_MessageChangedGroupGeoLocation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1982]!, self._r[1982]!, [_0]) + return formatWithArgumentRanges(self._s[1985]!, self._r[1985]!, [_0]) } - public var Wallet_Month_ShortJuly: String { return self._s[1983]! } - public var AuthSessions_IncompleteAttemptsInfo: String { return self._s[1985]! } - public var Message_InvoiceLabel: String { return self._s[1986]! } - public var Conversation_InputTextPlaceholder: String { return self._s[1987]! } - public var NetworkUsageSettings_MediaImageDataSection: String { return self._s[1988]! } + public var Wallet_Month_ShortJuly: String { return self._s[1986]! } + public var AuthSessions_IncompleteAttemptsInfo: String { return self._s[1988]! } + public var Message_InvoiceLabel: String { return self._s[1989]! } + public var Conversation_InputTextPlaceholder: String { return self._s[1990]! } + public var NetworkUsageSettings_MediaImageDataSection: String { return self._s[1991]! } public func Passport_Address_UploadOneOfScan(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1989]!, self._r[1989]!, [_0]) + return formatWithArgumentRanges(self._s[1992]!, self._r[1992]!, [_0]) } - public var IntentsSettings_Reset: String { return self._s[1990]! } - public var Conversation_Info: String { return self._s[1991]! } - public var Login_InfoDeletePhoto: String { return self._s[1992]! } - public var Passport_Language_vi: String { return self._s[1994]! } - public var UserInfo_ScamUserWarning: String { return self._s[1995]! } - public var Conversation_Search: String { return self._s[1996]! } - public var DialogList_DeleteBotConversationConfirmation: String { return self._s[1998]! } - public var ReportPeer_ReasonPornography: String { return self._s[1999]! } - public var AutoDownloadSettings_PhotosTitle: String { return self._s[2000]! } - public var Conversation_SendMessageErrorGroupRestricted: String { return self._s[2001]! } - public var Map_LiveLocationGroupDescription: String { return self._s[2002]! } - public var Channel_Setup_TypeHeader: String { return self._s[2003]! } - public var AuthSessions_LoggedIn: String { return self._s[2004]! } - public var Privacy_Forwards_AlwaysAllow_Title: String { return self._s[2005]! } - public var Login_SmsRequestState3: String { return self._s[2006]! } - public var Passport_Address_EditUtilityBill: String { return self._s[2007]! } - public var Appearance_ReduceMotionInfo: String { return self._s[2008]! } - public var Join_ChannelsTooMuch: String { return self._s[2009]! } - public var Channel_Edit_LinkItem: String { return self._s[2010]! } - public var Privacy_Calls_P2PNever: String { return self._s[2011]! } - public var Conversation_AddToReadingList: String { return self._s[2013]! } - public var Share_MultipleMessagesDisabled: String { return self._s[2014]! } - public var Message_Animation: String { return self._s[2015]! } - public var Conversation_DefaultRestrictedMedia: String { return self._s[2016]! } - public var Map_Unknown: String { return self._s[2017]! } - public var AutoDownloadSettings_LastDelimeter: String { return self._s[2018]! } + public var IntentsSettings_Reset: String { return self._s[1993]! } + public var Conversation_Info: String { return self._s[1994]! } + public var Login_InfoDeletePhoto: String { return self._s[1995]! } + public var Passport_Language_vi: String { return self._s[1997]! } + public var UserInfo_ScamUserWarning: String { return self._s[1998]! } + public var Conversation_Search: String { return self._s[1999]! } + public var DialogList_DeleteBotConversationConfirmation: String { return self._s[2001]! } + public var ReportPeer_ReasonPornography: String { return self._s[2002]! } + public var AutoDownloadSettings_PhotosTitle: String { return self._s[2003]! } + public var Conversation_SendMessageErrorGroupRestricted: String { return self._s[2004]! } + public var Map_LiveLocationGroupDescription: String { return self._s[2005]! } + public var Channel_Setup_TypeHeader: String { return self._s[2006]! } + public var AuthSessions_LoggedIn: String { return self._s[2007]! } + public var Privacy_Forwards_AlwaysAllow_Title: String { return self._s[2008]! } + public var Login_SmsRequestState3: String { return self._s[2009]! } + public var Passport_Address_EditUtilityBill: String { return self._s[2010]! } + public var Appearance_ReduceMotionInfo: String { return self._s[2011]! } + public var Join_ChannelsTooMuch: String { return self._s[2012]! } + public var Channel_Edit_LinkItem: String { return self._s[2013]! } + public var Privacy_Calls_P2PNever: String { return self._s[2014]! } + public var Conversation_AddToReadingList: String { return self._s[2016]! } + public var Share_MultipleMessagesDisabled: String { return self._s[2017]! } + public var Message_Animation: String { return self._s[2018]! } + public var Conversation_DefaultRestrictedMedia: String { return self._s[2019]! } + public var Map_Unknown: String { return self._s[2020]! } + public var AutoDownloadSettings_LastDelimeter: String { return self._s[2021]! } public func PUSH_PINNED_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2019]!, self._r[2019]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2022]!, self._r[2022]!, [_1, _2]) } public func Passport_FieldOneOf_Or(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2020]!, self._r[2020]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2023]!, self._r[2023]!, [_1, _2]) } - public var Call_StatusRequesting: String { return self._s[2021]! } - public var Conversation_SecretChatContextBotAlert: String { return self._s[2022]! } - public var SocksProxySetup_ProxyStatusChecking: String { return self._s[2023]! } + public var Call_StatusRequesting: String { return self._s[2024]! } + public var Conversation_SecretChatContextBotAlert: String { return self._s[2025]! } + public var SocksProxySetup_ProxyStatusChecking: String { return self._s[2026]! } public func PUSH_CHAT_MESSAGE_DOC(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2024]!, self._r[2024]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2027]!, self._r[2027]!, [_1, _2]) } public func Notification_PinnedLocationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2025]!, self._r[2025]!, [_0]) + return formatWithArgumentRanges(self._s[2028]!, self._r[2028]!, [_0]) } - public var Update_Skip: String { return self._s[2026]! } - public var Group_Username_RemoveExistingUsernamesInfo: String { return self._s[2027]! } - public var BlockedUsers_Title: String { return self._s[2028]! } - public var Weekday_Monday: String { return self._s[2029]! } + public var Update_Skip: String { return self._s[2029]! } + public var Group_Username_RemoveExistingUsernamesInfo: String { return self._s[2030]! } + public var BlockedUsers_Title: String { return self._s[2031]! } + public var Weekday_Monday: String { return self._s[2032]! } public func PUSH_CHANNEL_MESSAGE_AUDIO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2030]!, self._r[2030]!, [_1]) + return formatWithArgumentRanges(self._s[2033]!, self._r[2033]!, [_1]) } - public var Username_CheckingUsername: String { return self._s[2031]! } - public var NotificationsSound_Bell: String { return self._s[2032]! } - public var Conversation_SendMessageErrorFlood: String { return self._s[2033]! } - public var SettingsSearch_Synonyms_Notifications_DisplayNamesOnLockScreen: String { return self._s[2034]! } - public var ChannelMembers_ChannelAdminsTitle: String { return self._s[2035]! } - public var ChatSettings_Groups: String { return self._s[2036]! } - public var WallpaperPreview_PatternPaternDiscard: String { return self._s[2037]! } + public var Username_CheckingUsername: String { return self._s[2034]! } + public var NotificationsSound_Bell: String { return self._s[2035]! } + public var Conversation_SendMessageErrorFlood: String { return self._s[2036]! } + public var SettingsSearch_Synonyms_Notifications_DisplayNamesOnLockScreen: String { return self._s[2037]! } + public var ChannelMembers_ChannelAdminsTitle: String { return self._s[2038]! } + public var ChatSettings_Groups: String { return self._s[2039]! } + public var WallpaperPreview_PatternPaternDiscard: String { return self._s[2040]! } public func Conversation_SetReminder_RemindTomorrow(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2038]!, self._r[2038]!, [_0]) + return formatWithArgumentRanges(self._s[2041]!, self._r[2041]!, [_0]) } - public var Your_card_was_declined: String { return self._s[2039]! } - public var TwoStepAuth_EnterPasswordHelp: String { return self._s[2041]! } - public var Wallet_Month_ShortApril: String { return self._s[2042]! } - public var ChatList_Unmute: String { return self._s[2043]! } - public var AuthSessions_AddDevice_ScanTitle: String { return self._s[2044]! } - public var PhotoEditor_CurvesAll: String { return self._s[2045]! } - public var Weekday_ShortTuesday: String { return self._s[2046]! } - public var DialogList_Read: String { return self._s[2047]! } - public var Appearance_AppIconClassic: String { return self._s[2048]! } - public var ChannelMembers_WhoCanAddMembers_AllMembers: String { return self._s[2049]! } - public var Passport_Identity_Gender: String { return self._s[2050]! } + public var Your_card_was_declined: String { return self._s[2042]! } + public var TwoStepAuth_EnterPasswordHelp: String { return self._s[2044]! } + public var Wallet_Month_ShortApril: String { return self._s[2045]! } + public var ChatList_Unmute: String { return self._s[2046]! } + public var AuthSessions_AddDevice_ScanTitle: String { return self._s[2047]! } + public var PhotoEditor_CurvesAll: String { return self._s[2048]! } + public var Weekday_ShortTuesday: String { return self._s[2049]! } + public var DialogList_Read: String { return self._s[2050]! } + public var Appearance_AppIconClassic: String { return self._s[2051]! } + public var ChannelMembers_WhoCanAddMembers_AllMembers: String { return self._s[2052]! } + public var Passport_Identity_Gender: String { return self._s[2053]! } public func Target_ShareGameConfirmationPrivate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2051]!, self._r[2051]!, [_0]) + return formatWithArgumentRanges(self._s[2054]!, self._r[2054]!, [_0]) } - public var Target_SelectGroup: String { return self._s[2052]! } - public var Map_HomeAndWorkInfo: String { return self._s[2054]! } + public var Target_SelectGroup: String { return self._s[2055]! } + public var Map_HomeAndWorkInfo: String { return self._s[2057]! } public func DialogList_EncryptedChatStartedIncoming(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2055]!, self._r[2055]!, [_0]) + return formatWithArgumentRanges(self._s[2058]!, self._r[2058]!, [_0]) } - public var Passport_Language_en: String { return self._s[2056]! } - public var AutoDownloadSettings_AutodownloadPhotos: String { return self._s[2057]! } - public var Channel_Username_CreatePublicLinkHelp: String { return self._s[2058]! } - public var Login_CancelPhoneVerificationContinue: String { return self._s[2059]! } - public var ScheduledMessages_SendNow: String { return self._s[2060]! } - public var Checkout_NewCard_PaymentCard: String { return self._s[2062]! } - public var Login_InfoHelp: String { return self._s[2063]! } - public var Appearance_BubbleCorners_AdjustAdjacent: String { return self._s[2064]! } - public var Contacts_PermissionsSuppressWarningTitle: String { return self._s[2065]! } - public var SettingsSearch_Synonyms_Stickers_FeaturedPacks: String { return self._s[2066]! } + public var Passport_Language_en: String { return self._s[2059]! } + public var AutoDownloadSettings_AutodownloadPhotos: String { return self._s[2060]! } + public var Channel_Username_CreatePublicLinkHelp: String { return self._s[2061]! } + public var Login_CancelPhoneVerificationContinue: String { return self._s[2062]! } + public var ScheduledMessages_SendNow: String { return self._s[2063]! } + public var Checkout_NewCard_PaymentCard: String { return self._s[2065]! } + public var Login_InfoHelp: String { return self._s[2066]! } + public var Appearance_BubbleCorners_AdjustAdjacent: String { return self._s[2067]! } + public var Contacts_PermissionsSuppressWarningTitle: String { return self._s[2068]! } + public var SettingsSearch_Synonyms_Stickers_FeaturedPacks: String { return self._s[2069]! } public func Channel_AdminLog_MessageChangedLinkedChannel(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2067]!, self._r[2067]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2070]!, self._r[2070]!, [_1, _2]) } - public var SocksProxySetup_AddProxy: String { return self._s[2070]! } - public var CreatePoll_Title: String { return self._s[2071]! } - public var MessagePoll_QuizNoUsers: String { return self._s[2072]! } - public var Conversation_ViewTheme: String { return self._s[2073]! } - public var SettingsSearch_Synonyms_Privacy_Data_SecretChatLinkPreview: String { return self._s[2074]! } - public var PasscodeSettings_SimplePasscodeHelp: String { return self._s[2075]! } - public var TwoFactorSetup_Intro_Text: String { return self._s[2076]! } - public var UserInfo_GroupsInCommon: String { return self._s[2077]! } - public var TelegramWallet_Intro_TermsUrl: String { return self._s[2078]! } - public var Call_AudioRouteHide: String { return self._s[2079]! } + public var SocksProxySetup_AddProxy: String { return self._s[2073]! } + public var CreatePoll_Title: String { return self._s[2074]! } + public var MessagePoll_QuizNoUsers: String { return self._s[2075]! } + public var Conversation_ViewTheme: String { return self._s[2076]! } + public var SettingsSearch_Synonyms_Privacy_Data_SecretChatLinkPreview: String { return self._s[2077]! } + public var PasscodeSettings_SimplePasscodeHelp: String { return self._s[2078]! } + public var TwoFactorSetup_Intro_Text: String { return self._s[2079]! } + public var UserInfo_GroupsInCommon: String { return self._s[2080]! } + public var TelegramWallet_Intro_TermsUrl: String { return self._s[2081]! } + public var Call_AudioRouteHide: String { return self._s[2082]! } public func Wallet_Info_TransactionDateHeader(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2081]!, self._r[2081]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2084]!, self._r[2084]!, [_1, _2]) } - public var ContactInfo_PhoneLabelMobile: String { return self._s[2082]! } - public var IntentsSettings_SuggestedChatsInfo: String { return self._s[2083]! } - public var CreatePoll_QuizOptionsHeader: String { return self._s[2084]! } + public var ContactInfo_PhoneLabelMobile: String { return self._s[2085]! } + public var IntentsSettings_SuggestedChatsInfo: String { return self._s[2086]! } + public var CreatePoll_QuizOptionsHeader: String { return self._s[2087]! } public func ChatList_LeaveGroupConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2085]!, self._r[2085]!, [_0]) + return formatWithArgumentRanges(self._s[2088]!, self._r[2088]!, [_0]) } - public var TextFormat_Bold: String { return self._s[2086]! } - public var FastTwoStepSetup_EmailSection: String { return self._s[2087]! } - public var StickerPackActionInfo_AddedTitle: String { return self._s[2088]! } - public var Notifications_Title: String { return self._s[2089]! } - public var Group_Username_InvalidTooShort: String { return self._s[2090]! } - public var Channel_ErrorAddTooMuch: String { return self._s[2091]! } + public var TextFormat_Bold: String { return self._s[2089]! } + public var FastTwoStepSetup_EmailSection: String { return self._s[2090]! } + public var StickerPackActionInfo_AddedTitle: String { return self._s[2091]! } + public var Notifications_Title: String { return self._s[2092]! } + public var Group_Username_InvalidTooShort: String { return self._s[2093]! } + public var Channel_ErrorAddTooMuch: String { return self._s[2094]! } public func DialogList_MultipleTypingSuffix(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2092]!, self._r[2092]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[2095]!, self._r[2095]!, ["\(_0)"]) } - public var VoiceOver_DiscardPreparedContent: String { return self._s[2094]! } - public var Stickers_SuggestAdded: String { return self._s[2095]! } - public var Login_CountryCode: String { return self._s[2096]! } - public var ChatSettings_AutoPlayVideos: String { return self._s[2097]! } - public var Map_GetDirections: String { return self._s[2098]! } - public var Wallet_Receive_ShareInvoiceUrl: String { return self._s[2099]! } - public var Login_PhoneFloodError: String { return self._s[2100]! } + public var VoiceOver_DiscardPreparedContent: String { return self._s[2097]! } + public var Stickers_SuggestAdded: String { return self._s[2098]! } + public var Login_CountryCode: String { return self._s[2099]! } + public var ChatSettings_AutoPlayVideos: String { return self._s[2100]! } + public var Map_GetDirections: String { return self._s[2101]! } + public var Wallet_Receive_ShareInvoiceUrl: String { return self._s[2102]! } + public var Login_PhoneFloodError: String { return self._s[2103]! } public func Time_MonthOfYear_m3(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2101]!, self._r[2101]!, [_0]) + return formatWithArgumentRanges(self._s[2104]!, self._r[2104]!, [_0]) } public func Wallet_Time_PreciseDate_m10(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2102]!, self._r[2102]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2105]!, self._r[2105]!, [_1, _2, _3]) } - public var IntentsSettings_SuggestedChatsPrivateChats: String { return self._s[2103]! } - public var Settings_SetUsername: String { return self._s[2105]! } - public var Group_Location_ChangeLocation: String { return self._s[2106]! } - public var Notification_GroupInviterSelf: String { return self._s[2107]! } - public var InstantPage_TapToOpenLink: String { return self._s[2108]! } + public var IntentsSettings_SuggestedChatsPrivateChats: String { return self._s[2106]! } + public var Settings_SetUsername: String { return self._s[2108]! } + public var Group_Location_ChangeLocation: String { return self._s[2109]! } + public var Notification_GroupInviterSelf: String { return self._s[2110]! } + public var InstantPage_TapToOpenLink: String { return self._s[2111]! } public func Notification_ChannelInviter(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2109]!, self._r[2109]!, [_0]) + return formatWithArgumentRanges(self._s[2112]!, self._r[2112]!, [_0]) } - public var Watch_Suggestion_TalkLater: String { return self._s[2110]! } - public var SecretChat_Title: String { return self._s[2111]! } - public var Group_UpgradeNoticeText1: String { return self._s[2112]! } - public var AuthSessions_Title: String { return self._s[2113]! } + public var Watch_Suggestion_TalkLater: String { return self._s[2113]! } + public var SecretChat_Title: String { return self._s[2114]! } + public var Group_UpgradeNoticeText1: String { return self._s[2115]! } + public var AuthSessions_Title: String { return self._s[2116]! } public func TextFormat_AddLinkText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2114]!, self._r[2114]!, [_0]) + return formatWithArgumentRanges(self._s[2117]!, self._r[2117]!, [_0]) } - public var PhotoEditor_CropAuto: String { return self._s[2115]! } - public var Channel_About_Title: String { return self._s[2116]! } - public var Theme_ThemeChanged: String { return self._s[2117]! } - public var FastTwoStepSetup_EmailHelp: String { return self._s[2118]! } + public var PhotoEditor_CropAuto: String { return self._s[2118]! } + public var Channel_About_Title: String { return self._s[2119]! } + public var Theme_ThemeChanged: String { return self._s[2120]! } + public var FastTwoStepSetup_EmailHelp: String { return self._s[2121]! } public func Conversation_Bytes(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2120]!, self._r[2120]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[2123]!, self._r[2123]!, ["\(_0)"]) } - public var VoiceOver_MessageContextReport: String { return self._s[2121]! } - public var Conversation_PinMessageAlert_OnlyPin: String { return self._s[2123]! } - public var Group_Setup_HistoryVisibleHelp: String { return self._s[2124]! } + public var VoiceOver_MessageContextReport: String { return self._s[2124]! } + public var Conversation_PinMessageAlert_OnlyPin: String { return self._s[2126]! } + public var Group_Setup_HistoryVisibleHelp: String { return self._s[2127]! } public func PUSH_MESSAGE_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2125]!, self._r[2125]!, [_1]) + return formatWithArgumentRanges(self._s[2128]!, self._r[2128]!, [_1]) } public func SharedMedia_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2127]!, self._r[2127]!, [_0]) + return formatWithArgumentRanges(self._s[2130]!, self._r[2130]!, [_0]) } public func TwoStepAuth_RecoveryEmailUnavailable(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2128]!, self._r[2128]!, [_0]) + return formatWithArgumentRanges(self._s[2131]!, self._r[2131]!, [_0]) } - public var Privacy_PaymentsClearInfoHelp: String { return self._s[2129]! } - public var PeopleNearby_DiscoverDescription: String { return self._s[2131]! } - public var Presence_online: String { return self._s[2133]! } - public var PasscodeSettings_Title: String { return self._s[2134]! } - public var Passport_Identity_ExpiryDatePlaceholder: String { return self._s[2135]! } - public var Web_OpenExternal: String { return self._s[2136]! } - public var AutoDownloadSettings_AutoDownload: String { return self._s[2138]! } - public var Channel_OwnershipTransfer_EnterPasswordText: String { return self._s[2139]! } - public var LocalGroup_Title: String { return self._s[2140]! } + public var Privacy_PaymentsClearInfoHelp: String { return self._s[2132]! } + public var PeopleNearby_DiscoverDescription: String { return self._s[2134]! } + public var Presence_online: String { return self._s[2136]! } + public var PasscodeSettings_Title: String { return self._s[2137]! } + public var Passport_Identity_ExpiryDatePlaceholder: String { return self._s[2138]! } + public var Web_OpenExternal: String { return self._s[2139]! } + public var AutoDownloadSettings_AutoDownload: String { return self._s[2141]! } + public var Channel_OwnershipTransfer_EnterPasswordText: String { return self._s[2142]! } + public var LocalGroup_Title: String { return self._s[2143]! } public func AutoNightTheme_AutomaticHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2141]!, self._r[2141]!, [_0]) + return formatWithArgumentRanges(self._s[2144]!, self._r[2144]!, [_0]) } - public var FastTwoStepSetup_PasswordConfirmationPlaceholder: String { return self._s[2142]! } - public var Conversation_StopQuizConfirmation: String { return self._s[2143]! } - public var Map_YouAreHere: String { return self._s[2144]! } + public var FastTwoStepSetup_PasswordConfirmationPlaceholder: String { return self._s[2145]! } + public var Conversation_StopQuizConfirmation: String { return self._s[2146]! } + public var Map_YouAreHere: String { return self._s[2147]! } public func AuthSessions_Message(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2145]!, self._r[2145]!, [_0]) + return formatWithArgumentRanges(self._s[2148]!, self._r[2148]!, [_0]) } public func ChatList_DeleteChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2146]!, self._r[2146]!, [_0]) + return formatWithArgumentRanges(self._s[2149]!, self._r[2149]!, [_0]) } - public var Theme_Context_ChangeColors: String { return self._s[2147]! } - public var PrivacyLastSeenSettings_AlwaysShareWith: String { return self._s[2148]! } - public var Target_InviteToGroupErrorAlreadyInvited: String { return self._s[2149]! } + public var Theme_Context_ChangeColors: String { return self._s[2150]! } + public var PrivacyLastSeenSettings_AlwaysShareWith: String { return self._s[2151]! } + public var Target_InviteToGroupErrorAlreadyInvited: String { return self._s[2152]! } public func AuthSessions_AppUnofficial(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2150]!, self._r[2150]!, [_0]) + return formatWithArgumentRanges(self._s[2153]!, self._r[2153]!, [_0]) } public func DialogList_LiveLocationSharingTo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2151]!, self._r[2151]!, [_0]) - } - public var SocksProxySetup_Username: String { return self._s[2152]! } - public var Bot_Start: String { return self._s[2153]! } - public func Channel_AdminLog_EmptyFilterQueryText(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2154]!, self._r[2154]!, [_0]) } - public func Channel_AdminLog_MessagePinned(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2155]!, self._r[2155]!, [_0]) + public var SocksProxySetup_Username: String { return self._s[2155]! } + public var Bot_Start: String { return self._s[2156]! } + public func Channel_AdminLog_EmptyFilterQueryText(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2157]!, self._r[2157]!, [_0]) } - public var Contacts_SortByPresence: String { return self._s[2156]! } - public var AccentColor_Title: String { return self._s[2158]! } - public var Conversation_DiscardVoiceMessageTitle: String { return self._s[2159]! } + public func Channel_AdminLog_MessagePinned(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2158]!, self._r[2158]!, [_0]) + } + public var Contacts_SortByPresence: String { return self._s[2159]! } + public var AccentColor_Title: String { return self._s[2161]! } + public var Conversation_DiscardVoiceMessageTitle: String { return self._s[2162]! } public func PUSH_CHAT_CREATED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2160]!, self._r[2160]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2163]!, self._r[2163]!, [_1, _2]) } public func PrivacySettings_LastSeenContactsMinus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2161]!, self._r[2161]!, [_0]) + return formatWithArgumentRanges(self._s[2164]!, self._r[2164]!, [_0]) } public func Channel_AdminLog_MessageChangedLinkedGroup(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2162]!, self._r[2162]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2165]!, self._r[2165]!, [_1, _2]) } - public var Passport_Email_EnterOtherEmail: String { return self._s[2163]! } - public var Login_InfoAvatarPhoto: String { return self._s[2164]! } - public var Privacy_PaymentsClear_ShippingInfo: String { return self._s[2165]! } - public var Tour_Title4: String { return self._s[2166]! } - public var Passport_Identity_Translation: String { return self._s[2167]! } - public var SettingsSearch_Synonyms_Notifications_ContactJoined: String { return self._s[2168]! } - public var Login_TermsOfServiceLabel: String { return self._s[2170]! } - public var Passport_Language_it: String { return self._s[2171]! } - public var KeyCommand_JumpToNextUnreadChat: String { return self._s[2172]! } - public var Passport_Identity_SelfieHelp: String { return self._s[2173]! } - public var Conversation_ClearAll: String { return self._s[2175]! } - public var Wallet_Send_UninitializedText: String { return self._s[2177]! } - public var Channel_OwnershipTransfer_Title: String { return self._s[2178]! } - public var TwoStepAuth_FloodError: String { return self._s[2179]! } + public var Passport_Email_EnterOtherEmail: String { return self._s[2166]! } + public var Login_InfoAvatarPhoto: String { return self._s[2167]! } + public var Privacy_PaymentsClear_ShippingInfo: String { return self._s[2168]! } + public var Tour_Title4: String { return self._s[2169]! } + public var Passport_Identity_Translation: String { return self._s[2170]! } + public var SettingsSearch_Synonyms_Notifications_ContactJoined: String { return self._s[2171]! } + public var Login_TermsOfServiceLabel: String { return self._s[2173]! } + public var Passport_Language_it: String { return self._s[2174]! } + public var KeyCommand_JumpToNextUnreadChat: String { return self._s[2175]! } + public var Passport_Identity_SelfieHelp: String { return self._s[2176]! } + public var Conversation_ClearAll: String { return self._s[2178]! } + public var Wallet_Send_UninitializedText: String { return self._s[2180]! } + public var Channel_OwnershipTransfer_Title: String { return self._s[2181]! } + public var TwoStepAuth_FloodError: String { return self._s[2182]! } public func PUSH_CHANNEL_MESSAGE_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2180]!, self._r[2180]!, [_1]) + return formatWithArgumentRanges(self._s[2183]!, self._r[2183]!, [_1]) } - public var Paint_Delete: String { return self._s[2181]! } + public var Paint_Delete: String { return self._s[2184]! } public func Wallet_Sent_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2182]!, self._r[2182]!, [_0]) + return formatWithArgumentRanges(self._s[2185]!, self._r[2185]!, [_0]) } - public var Privacy_AddNewPeer: String { return self._s[2183]! } + public var Privacy_AddNewPeer: String { return self._s[2186]! } public func Channel_AdminLog_MessageRank(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2184]!, self._r[2184]!, [_1]) + return formatWithArgumentRanges(self._s[2187]!, self._r[2187]!, [_1]) } - public var LogoutOptions_SetPasscodeText: String { return self._s[2185]! } + public var LogoutOptions_SetPasscodeText: String { return self._s[2188]! } public func Passport_AcceptHelp(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2186]!, self._r[2186]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2189]!, self._r[2189]!, [_1, _2]) } - public var Message_PinnedAudioMessage: String { return self._s[2187]! } + public var Message_PinnedAudioMessage: String { return self._s[2190]! } public func Watch_Time_ShortTodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2188]!, self._r[2188]!, [_0]) + return formatWithArgumentRanges(self._s[2191]!, self._r[2191]!, [_0]) } - public var Notification_Mute1hMin: String { return self._s[2189]! } - public var Notifications_GroupNotificationsSound: String { return self._s[2190]! } - public var Wallet_Month_GenNovember: String { return self._s[2191]! } - public var SocksProxySetup_ShareProxyList: String { return self._s[2192]! } - public var Conversation_MessageEditedLabel: String { return self._s[2193]! } + public var Notification_Mute1hMin: String { return self._s[2192]! } + public var Notifications_GroupNotificationsSound: String { return self._s[2193]! } + public var Wallet_Month_GenNovember: String { return self._s[2194]! } + public var SocksProxySetup_ShareProxyList: String { return self._s[2195]! } + public var Conversation_MessageEditedLabel: String { return self._s[2196]! } public func ClearCache_Success(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2194]!, self._r[2194]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2197]!, self._r[2197]!, [_0, _1]) } - public var Notification_Exceptions_AlwaysOff: String { return self._s[2195]! } - public var Notification_Exceptions_NewException_MessagePreviewHeader: String { return self._s[2196]! } + public var Notification_Exceptions_AlwaysOff: String { return self._s[2198]! } + public var Notification_Exceptions_NewException_MessagePreviewHeader: String { return self._s[2199]! } public func Channel_AdminLog_MessageAdmin(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2197]!, self._r[2197]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[2200]!, self._r[2200]!, [_0, _1, _2]) } - public var NetworkUsageSettings_ResetStats: String { return self._s[2198]! } + public var NetworkUsageSettings_ResetStats: String { return self._s[2201]! } public func PUSH_MESSAGE_GEOLIVE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2199]!, self._r[2199]!, [_1]) + return formatWithArgumentRanges(self._s[2202]!, self._r[2202]!, [_1]) } - public var AccessDenied_LocationTracking: String { return self._s[2200]! } - public var Month_GenOctober: String { return self._s[2201]! } - public var GroupInfo_InviteLink_RevokeAlert_Revoke: String { return self._s[2202]! } - public var EnterPasscode_EnterPasscode: String { return self._s[2203]! } - public var MediaPicker_TimerTooltip: String { return self._s[2205]! } - public var SharedMedia_TitleAll: String { return self._s[2206]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsExceptions: String { return self._s[2209]! } - public var Conversation_RestrictedMedia: String { return self._s[2210]! } - public var AccessDenied_PhotosRestricted: String { return self._s[2211]! } - public var Privacy_Forwards_WhoCanForward: String { return self._s[2213]! } - public var ChangePhoneNumberCode_Called: String { return self._s[2214]! } + public var AccessDenied_LocationTracking: String { return self._s[2203]! } + public var Month_GenOctober: String { return self._s[2204]! } + public var GroupInfo_InviteLink_RevokeAlert_Revoke: String { return self._s[2205]! } + public var EnterPasscode_EnterPasscode: String { return self._s[2206]! } + public var MediaPicker_TimerTooltip: String { return self._s[2208]! } + public var SharedMedia_TitleAll: String { return self._s[2209]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsExceptions: String { return self._s[2212]! } + public var Conversation_RestrictedMedia: String { return self._s[2213]! } + public var AccessDenied_PhotosRestricted: String { return self._s[2214]! } + public var Privacy_Forwards_WhoCanForward: String { return self._s[2216]! } + public var ChangePhoneNumberCode_Called: String { return self._s[2217]! } public func Notification_PinnedDocumentMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2215]!, self._r[2215]!, [_0]) + return formatWithArgumentRanges(self._s[2218]!, self._r[2218]!, [_0]) } - public var Conversation_SavedMessages: String { return self._s[2218]! } - public var Your_cards_expiration_month_is_invalid: String { return self._s[2220]! } - public var FastTwoStepSetup_PasswordPlaceholder: String { return self._s[2221]! } + public var Conversation_SavedMessages: String { return self._s[2221]! } + public var Your_cards_expiration_month_is_invalid: String { return self._s[2223]! } + public var FastTwoStepSetup_PasswordPlaceholder: String { return self._s[2224]! } public func Target_ShareGameConfirmationGroup(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2223]!, self._r[2223]!, [_0]) + return formatWithArgumentRanges(self._s[2226]!, self._r[2226]!, [_0]) } - public var VoiceOver_Chat_YourMessage: String { return self._s[2224]! } + public var VoiceOver_Chat_YourMessage: String { return self._s[2227]! } public func VoiceOver_Chat_Title(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2225]!, self._r[2225]!, [_0]) + return formatWithArgumentRanges(self._s[2228]!, self._r[2228]!, [_0]) } - public var ReportPeer_AlertSuccess: String { return self._s[2226]! } - public var PhotoEditor_CropAspectRatioOriginal: String { return self._s[2227]! } + public var ReportPeer_AlertSuccess: String { return self._s[2229]! } + public var PhotoEditor_CropAspectRatioOriginal: String { return self._s[2230]! } public func InstantPage_RelatedArticleAuthorAndDateTitle(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2228]!, self._r[2228]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2231]!, self._r[2231]!, [_1, _2]) } - public var Checkout_PasswordEntry_Title: String { return self._s[2229]! } - public var PhotoEditor_FadeTool: String { return self._s[2230]! } - public var Privacy_ContactsReset: String { return self._s[2231]! } + public var Checkout_PasswordEntry_Title: String { return self._s[2232]! } + public var PhotoEditor_FadeTool: String { return self._s[2233]! } + public var Privacy_ContactsReset: String { return self._s[2234]! } public func Channel_AdminLog_MessageRestrictedUntil(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2233]!, self._r[2233]!, [_0]) + return formatWithArgumentRanges(self._s[2236]!, self._r[2236]!, [_0]) } - public var Message_PinnedVideoMessage: String { return self._s[2234]! } - public var ChatList_Mute: String { return self._s[2235]! } + public var Message_PinnedVideoMessage: String { return self._s[2237]! } + public var ChatList_Mute: String { return self._s[2238]! } public func Wallet_Time_PreciseDate_m5(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2236]!, self._r[2236]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2239]!, self._r[2239]!, [_1, _2, _3]) } - public var Permissions_CellularDataText_v0: String { return self._s[2237]! } - public var Conversation_PinnedQuiz: String { return self._s[2239]! } - public var ShareMenu_SelectChats: String { return self._s[2241]! } - public var ChatList_Context_Unarchive: String { return self._s[2242]! } - public var MusicPlayer_VoiceNote: String { return self._s[2243]! } - public var Conversation_RestrictedText: String { return self._s[2244]! } - public var SettingsSearch_Synonyms_Privacy_Data_DeleteDrafts: String { return self._s[2245]! } - public var Wallet_Month_GenApril: String { return self._s[2246]! } - public var Wallet_Month_ShortMarch: String { return self._s[2247]! } - public var TwoStepAuth_DisableSuccess: String { return self._s[2248]! } - public var Cache_Videos: String { return self._s[2249]! } - public var PrivacySettings_PhoneNumber: String { return self._s[2250]! } - public var Wallet_Month_GenFebruary: String { return self._s[2251]! } - public var FeatureDisabled_Oops: String { return self._s[2253]! } - public var Passport_Address_PostcodePlaceholder: String { return self._s[2254]! } + public var Permissions_CellularDataText_v0: String { return self._s[2240]! } + public var Conversation_PinnedQuiz: String { return self._s[2242]! } + public var ShareMenu_SelectChats: String { return self._s[2244]! } + public var ChatList_Context_Unarchive: String { return self._s[2245]! } + public var MusicPlayer_VoiceNote: String { return self._s[2246]! } + public var Conversation_RestrictedText: String { return self._s[2247]! } + public var SettingsSearch_Synonyms_Privacy_Data_DeleteDrafts: String { return self._s[2248]! } + public var Wallet_Month_GenApril: String { return self._s[2249]! } + public var Wallet_Month_ShortMarch: String { return self._s[2250]! } + public var TwoStepAuth_DisableSuccess: String { return self._s[2251]! } + public var Cache_Videos: String { return self._s[2252]! } + public var PrivacySettings_PhoneNumber: String { return self._s[2253]! } + public var Wallet_Month_GenFebruary: String { return self._s[2254]! } + public var FeatureDisabled_Oops: String { return self._s[2256]! } + public var Passport_Address_PostcodePlaceholder: String { return self._s[2257]! } public func AddContact_StatusSuccess(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2255]!, self._r[2255]!, [_0]) + return formatWithArgumentRanges(self._s[2258]!, self._r[2258]!, [_0]) } - public var Stickers_GroupStickersHelp: String { return self._s[2257]! } - public var GroupPermission_NoSendPolls: String { return self._s[2258]! } - public var Wallet_Qr_ScanCode: String { return self._s[2259]! } - public var Message_VideoExpired: String { return self._s[2261]! } - public var GroupInfo_GroupHistoryVisible: String { return self._s[2262]! } - public var Notifications_Badge: String { return self._s[2263]! } - public var Wallet_Receive_AddressCopied: String { return self._s[2264]! } - public var CreatePoll_OptionPlaceholder: String { return self._s[2265]! } - public var Username_InvalidTooShort: String { return self._s[2266]! } - public var EnterPasscode_EnterNewPasscodeChange: String { return self._s[2267]! } - public var Channel_AdminLog_PinMessages: String { return self._s[2268]! } - public var ArchivedChats_IntroTitle3: String { return self._s[2269]! } + public var Stickers_GroupStickersHelp: String { return self._s[2260]! } + public var GroupPermission_NoSendPolls: String { return self._s[2261]! } + public var Wallet_Qr_ScanCode: String { return self._s[2262]! } + public var Message_VideoExpired: String { return self._s[2264]! } + public var GroupInfo_GroupHistoryVisible: String { return self._s[2265]! } + public var Notifications_Badge: String { return self._s[2266]! } + public var Wallet_Receive_AddressCopied: String { return self._s[2267]! } + public var CreatePoll_OptionPlaceholder: String { return self._s[2268]! } + public var Username_InvalidTooShort: String { return self._s[2269]! } + public var EnterPasscode_EnterNewPasscodeChange: String { return self._s[2270]! } + public var Channel_AdminLog_PinMessages: String { return self._s[2271]! } + public var ArchivedChats_IntroTitle3: String { return self._s[2272]! } public func Notification_MessageLifetimeRemoved(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2270]!, self._r[2270]!, [_1]) + return formatWithArgumentRanges(self._s[2273]!, self._r[2273]!, [_1]) } - public var Permissions_SiriAllowInSettings_v0: String { return self._s[2271]! } - public var Conversation_DefaultRestrictedText: String { return self._s[2272]! } - public var SharedMedia_CategoryDocs: String { return self._s[2275]! } + public var Permissions_SiriAllowInSettings_v0: String { return self._s[2274]! } + public var Conversation_DefaultRestrictedText: String { return self._s[2275]! } + public var SharedMedia_CategoryDocs: String { return self._s[2278]! } public func PUSH_MESSAGE_CONTACT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2276]!, self._r[2276]!, [_1]) + return formatWithArgumentRanges(self._s[2279]!, self._r[2279]!, [_1]) } - public var Wallet_Send_UninitializedTitle: String { return self._s[2277]! } - public var StickerPackActionInfo_ArchivedTitle: String { return self._s[2278]! } - public var Privacy_Forwards_NeverLink: String { return self._s[2280]! } + public var Wallet_Send_UninitializedTitle: String { return self._s[2280]! } + public var StickerPackActionInfo_ArchivedTitle: String { return self._s[2281]! } + public var Privacy_Forwards_NeverLink: String { return self._s[2283]! } public func Notification_MessageLifetimeChangedOutgoing(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2281]!, self._r[2281]!, [_1]) + return formatWithArgumentRanges(self._s[2284]!, self._r[2284]!, [_1]) } - public var CheckoutInfo_ErrorShippingNotAvailable: String { return self._s[2282]! } + public var CheckoutInfo_ErrorShippingNotAvailable: String { return self._s[2285]! } public func Time_MonthOfYear_m12(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2283]!, self._r[2283]!, [_0]) + return formatWithArgumentRanges(self._s[2286]!, self._r[2286]!, [_0]) } - public var ChatSettings_PrivateChats: String { return self._s[2284]! } - public var SettingsSearch_Synonyms_EditProfile_Logout: String { return self._s[2285]! } - public var Conversation_PrivateMessageLinkCopied: String { return self._s[2286]! } - public var Channel_UpdatePhotoItem: String { return self._s[2287]! } - public var GroupInfo_LeftStatus: String { return self._s[2288]! } - public var Watch_MessageView_Forward: String { return self._s[2290]! } - public var ReportPeer_ReasonChildAbuse: String { return self._s[2291]! } - public var Cache_ClearEmpty: String { return self._s[2293]! } - public var Localization_LanguageName: String { return self._s[2294]! } - public var Wallet_AccessDenied_Title: String { return self._s[2295]! } - public var WebSearch_GIFs: String { return self._s[2296]! } - public var Notifications_DisplayNamesOnLockScreenInfoWithLink: String { return self._s[2297]! } - public var Wallet_AccessDenied_Settings: String { return self._s[2298]! } - public var Username_InvalidStartsWithNumber: String { return self._s[2299]! } - public var Common_Back: String { return self._s[2300]! } - public var GroupInfo_Permissions_EditingDisabled: String { return self._s[2301]! } - public var Passport_Identity_DateOfBirthPlaceholder: String { return self._s[2302]! } - public var Wallet_Send_Send: String { return self._s[2303]! } + public var ChatSettings_PrivateChats: String { return self._s[2287]! } + public var SettingsSearch_Synonyms_EditProfile_Logout: String { return self._s[2288]! } + public var Conversation_PrivateMessageLinkCopied: String { return self._s[2289]! } + public var Channel_UpdatePhotoItem: String { return self._s[2290]! } + public var GroupInfo_LeftStatus: String { return self._s[2291]! } + public var Watch_MessageView_Forward: String { return self._s[2293]! } + public var ReportPeer_ReasonChildAbuse: String { return self._s[2294]! } + public var Cache_ClearEmpty: String { return self._s[2296]! } + public var Localization_LanguageName: String { return self._s[2297]! } + public var Wallet_AccessDenied_Title: String { return self._s[2298]! } + public var WebSearch_GIFs: String { return self._s[2299]! } + public var Notifications_DisplayNamesOnLockScreenInfoWithLink: String { return self._s[2300]! } + public var Wallet_AccessDenied_Settings: String { return self._s[2301]! } + public var Username_InvalidStartsWithNumber: String { return self._s[2302]! } + public var Common_Back: String { return self._s[2303]! } + public var GroupInfo_Permissions_EditingDisabled: String { return self._s[2304]! } + public var Passport_Identity_DateOfBirthPlaceholder: String { return self._s[2305]! } + public var Wallet_Send_Send: String { return self._s[2306]! } public func PUSH_CHANNEL_MESSAGE_STICKER(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2305]!, self._r[2305]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2308]!, self._r[2308]!, [_1, _2]) } - public var Wallet_Info_RefreshErrorTitle: String { return self._s[2306]! } - public var Wallet_Month_GenJune: String { return self._s[2307]! } - public var Passport_Email_Help: String { return self._s[2308]! } - public var Watch_Conversation_Reply: String { return self._s[2310]! } - public var Conversation_EditingMessageMediaChange: String { return self._s[2313]! } - public var Passport_Identity_IssueDatePlaceholder: String { return self._s[2314]! } - public var Channel_BanUser_Unban: String { return self._s[2316]! } - public var Channel_EditAdmin_PermissionPostMessages: String { return self._s[2317]! } - public var Group_Username_CreatePublicLinkHelp: String { return self._s[2318]! } - public var TwoStepAuth_ConfirmEmailCodePlaceholder: String { return self._s[2320]! } - public var Wallet_Send_AddressHeader: String { return self._s[2321]! } - public var Passport_Identity_Name: String { return self._s[2322]! } + public var Wallet_Info_RefreshErrorTitle: String { return self._s[2309]! } + public var Wallet_Month_GenJune: String { return self._s[2310]! } + public var Passport_Email_Help: String { return self._s[2311]! } + public var Watch_Conversation_Reply: String { return self._s[2313]! } + public var Conversation_EditingMessageMediaChange: String { return self._s[2316]! } + public var Passport_Identity_IssueDatePlaceholder: String { return self._s[2317]! } + public var Channel_BanUser_Unban: String { return self._s[2319]! } + public var Channel_EditAdmin_PermissionPostMessages: String { return self._s[2320]! } + public var Group_Username_CreatePublicLinkHelp: String { return self._s[2321]! } + public var TwoStepAuth_ConfirmEmailCodePlaceholder: String { return self._s[2323]! } + public var Wallet_Send_AddressHeader: String { return self._s[2324]! } + public var Passport_Identity_Name: String { return self._s[2325]! } public func Channel_DiscussionGroup_HeaderGroupSet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2323]!, self._r[2323]!, [_0]) + return formatWithArgumentRanges(self._s[2326]!, self._r[2326]!, [_0]) } - public var GroupRemoved_ViewUserInfo: String { return self._s[2324]! } - public var Conversation_BlockUser: String { return self._s[2325]! } - public var Month_GenJanuary: String { return self._s[2326]! } - public var ChatSettings_TextSize: String { return self._s[2327]! } - public var Notification_PassportValuePhone: String { return self._s[2328]! } - public var MediaPlayer_UnknownArtist: String { return self._s[2329]! } - public var Passport_Language_ne: String { return self._s[2330]! } - public var Notification_CallBack: String { return self._s[2331]! } - public var Wallet_SecureStorageReset_BiometryTouchId: String { return self._s[2332]! } - public var TwoStepAuth_EmailHelp: String { return self._s[2333]! } + public var GroupRemoved_ViewUserInfo: String { return self._s[2327]! } + public var Conversation_BlockUser: String { return self._s[2328]! } + public var Month_GenJanuary: String { return self._s[2329]! } + public var ChatSettings_TextSize: String { return self._s[2330]! } + public var Notification_PassportValuePhone: String { return self._s[2331]! } + public var MediaPlayer_UnknownArtist: String { return self._s[2332]! } + public var Passport_Language_ne: String { return self._s[2333]! } + public var Notification_CallBack: String { return self._s[2334]! } + public var Wallet_SecureStorageReset_BiometryTouchId: String { return self._s[2335]! } + public var TwoStepAuth_EmailHelp: String { return self._s[2336]! } public func Time_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2334]!, self._r[2334]!, [_0]) + return formatWithArgumentRanges(self._s[2337]!, self._r[2337]!, [_0]) } - public var Channel_Info_Management: String { return self._s[2335]! } - public var Passport_FieldIdentityUploadHelp: String { return self._s[2336]! } - public var Stickers_FrequentlyUsed: String { return self._s[2337]! } - public var Channel_BanUser_PermissionSendMessages: String { return self._s[2338]! } - public var Passport_Address_OneOfTypeUtilityBill: String { return self._s[2340]! } + public var Channel_Info_Management: String { return self._s[2338]! } + public var Passport_FieldIdentityUploadHelp: String { return self._s[2339]! } + public var Stickers_FrequentlyUsed: String { return self._s[2340]! } + public var Channel_BanUser_PermissionSendMessages: String { return self._s[2341]! } + public var Passport_Address_OneOfTypeUtilityBill: String { return self._s[2343]! } public func LOCAL_CHANNEL_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2341]!, self._r[2341]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[2344]!, self._r[2344]!, [_1, "\(_2)"]) } - public var TwoFactorSetup_Password_Title: String { return self._s[2342]! } - public var Passport_Address_EditResidentialAddress: String { return self._s[2343]! } - public var PrivacyPolicy_DeclineTitle: String { return self._s[2344]! } - public var CreatePoll_TextHeader: String { return self._s[2345]! } + public var TwoFactorSetup_Password_Title: String { return self._s[2345]! } + public var Passport_Address_EditResidentialAddress: String { return self._s[2346]! } + public var PrivacyPolicy_DeclineTitle: String { return self._s[2347]! } + public var CreatePoll_TextHeader: String { return self._s[2348]! } public func Checkout_SavePasswordTimeoutAndTouchId(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2346]!, self._r[2346]!, [_0]) + return formatWithArgumentRanges(self._s[2349]!, self._r[2349]!, [_0]) } - public var PhotoEditor_QualityMedium: String { return self._s[2347]! } - public var InfoPlist_NSMicrophoneUsageDescription: String { return self._s[2348]! } - public var Conversation_StatusKickedFromChannel: String { return self._s[2350]! } - public var CheckoutInfo_ReceiverInfoName: String { return self._s[2351]! } - public var Group_ErrorSendRestrictedStickers: String { return self._s[2352]! } + public var PhotoEditor_QualityMedium: String { return self._s[2350]! } + public var InfoPlist_NSMicrophoneUsageDescription: String { return self._s[2351]! } + public var Conversation_StatusKickedFromChannel: String { return self._s[2353]! } + public var CheckoutInfo_ReceiverInfoName: String { return self._s[2354]! } + public var Group_ErrorSendRestrictedStickers: String { return self._s[2355]! } public func Conversation_RestrictedInlineTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2353]!, self._r[2353]!, [_0]) + return formatWithArgumentRanges(self._s[2356]!, self._r[2356]!, [_0]) } public func Channel_AdminLog_MessageTransferedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2354]!, self._r[2354]!, [_1]) + return formatWithArgumentRanges(self._s[2357]!, self._r[2357]!, [_1]) } - public var LogoutOptions_LogOutWalletInfo: String { return self._s[2355]! } - public var TwoFactorSetup_Email_SkipConfirmationTitle: String { return self._s[2356]! } - public var Conversation_LinkDialogOpen: String { return self._s[2358]! } - public var TwoFactorSetup_Hint_Title: String { return self._s[2359]! } - public var VoiceOver_Chat_PollNoVotes: String { return self._s[2360]! } - public var Settings_Username: String { return self._s[2362]! } - public var Conversation_Block: String { return self._s[2364]! } - public var Wallpaper_Wallpaper: String { return self._s[2365]! } - public var SocksProxySetup_UseProxy: String { return self._s[2367]! } - public var Wallet_Send_Confirmation: String { return self._s[2368]! } - public var EditTheme_UploadEditedTheme: String { return self._s[2369]! } - public var UserInfo_ShareMyContactInfo: String { return self._s[2370]! } - public var MessageTimer_Forever: String { return self._s[2371]! } - public var Privacy_Calls_WhoCanCallMe: String { return self._s[2372]! } - public var PhotoEditor_DiscardChanges: String { return self._s[2373]! } - public var AuthSessions_TerminateOtherSessionsHelp: String { return self._s[2374]! } - public var Passport_Language_da: String { return self._s[2375]! } - public var SocksProxySetup_PortPlaceholder: String { return self._s[2376]! } + public var LogoutOptions_LogOutWalletInfo: String { return self._s[2358]! } + public var TwoFactorSetup_Email_SkipConfirmationTitle: String { return self._s[2359]! } + public var Conversation_LinkDialogOpen: String { return self._s[2361]! } + public var TwoFactorSetup_Hint_Title: String { return self._s[2362]! } + public var VoiceOver_Chat_PollNoVotes: String { return self._s[2363]! } + public var Settings_Username: String { return self._s[2365]! } + public var Conversation_Block: String { return self._s[2367]! } + public var Wallpaper_Wallpaper: String { return self._s[2368]! } + public var SocksProxySetup_UseProxy: String { return self._s[2370]! } + public var Wallet_Send_Confirmation: String { return self._s[2371]! } + public var EditTheme_UploadEditedTheme: String { return self._s[2372]! } + public var UserInfo_ShareMyContactInfo: String { return self._s[2373]! } + public var MessageTimer_Forever: String { return self._s[2374]! } + public var Privacy_Calls_WhoCanCallMe: String { return self._s[2375]! } + public var PhotoEditor_DiscardChanges: String { return self._s[2376]! } + public var AuthSessions_TerminateOtherSessionsHelp: String { return self._s[2377]! } + public var Passport_Language_da: String { return self._s[2378]! } + public var SocksProxySetup_PortPlaceholder: String { return self._s[2379]! } public func SecretGIF_NotViewedYet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2377]!, self._r[2377]!, [_0]) - } - public var Passport_Address_EditPassportRegistration: String { return self._s[2378]! } - public func Channel_AdminLog_MessageChangedGroupAbout(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2380]!, self._r[2380]!, [_0]) } - public var Settings_AddDevice: String { return self._s[2381]! } - public var Passport_Identity_ResidenceCountryPlaceholder: String { return self._s[2383]! } - public var AuthSessions_AddDeviceIntro_Text1: String { return self._s[2384]! } - public var Conversation_SearchByName_Prefix: String { return self._s[2385]! } - public var Conversation_PinnedPoll: String { return self._s[2386]! } - public var AuthSessions_AddDeviceIntro_Text2: String { return self._s[2387]! } - public var Conversation_EmptyGifPanelPlaceholder: String { return self._s[2388]! } - public var AuthSessions_AddDeviceIntro_Text3: String { return self._s[2389]! } + public var Passport_Address_EditPassportRegistration: String { return self._s[2381]! } + public func Channel_AdminLog_MessageChangedGroupAbout(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2383]!, self._r[2383]!, [_0]) + } + public var Settings_AddDevice: String { return self._s[2384]! } + public var Passport_Identity_ResidenceCountryPlaceholder: String { return self._s[2386]! } + public var AuthSessions_AddDeviceIntro_Text1: String { return self._s[2387]! } + public var Conversation_SearchByName_Prefix: String { return self._s[2388]! } + public var Conversation_PinnedPoll: String { return self._s[2389]! } + public var AuthSessions_AddDeviceIntro_Text2: String { return self._s[2390]! } + public var Conversation_EmptyGifPanelPlaceholder: String { return self._s[2391]! } + public var AuthSessions_AddDeviceIntro_Text3: String { return self._s[2392]! } public func PUSH_ENCRYPTION_ACCEPT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2390]!, self._r[2390]!, [_1]) + return formatWithArgumentRanges(self._s[2393]!, self._r[2393]!, [_1]) } - public var WallpaperSearch_ColorPurple: String { return self._s[2391]! } - public var Cache_ByPeerHeader: String { return self._s[2392]! } + public var WallpaperSearch_ColorPurple: String { return self._s[2394]! } + public var Cache_ByPeerHeader: String { return self._s[2395]! } public func Conversation_EncryptedPlaceholderTitleIncoming(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2393]!, self._r[2393]!, [_0]) + return formatWithArgumentRanges(self._s[2396]!, self._r[2396]!, [_0]) } - public var ChatSettings_AutoDownloadDocuments: String { return self._s[2394]! } - public var Appearance_ThemePreview_Chat_3_Text: String { return self._s[2397]! } - public var Wallet_Completed_Title: String { return self._s[2398]! } - public var Notification_PinnedMessage: String { return self._s[2399]! } - public var TwoFactorSetup_EmailVerification_Placeholder: String { return self._s[2400]! } - public var VoiceOver_Chat_RecordModeVideoMessage: String { return self._s[2402]! } - public var Contacts_SortBy: String { return self._s[2403]! } + public var ChatSettings_AutoDownloadDocuments: String { return self._s[2397]! } + public var Appearance_ThemePreview_Chat_3_Text: String { return self._s[2400]! } + public var Wallet_Completed_Title: String { return self._s[2401]! } + public var Notification_PinnedMessage: String { return self._s[2402]! } + public var TwoFactorSetup_EmailVerification_Placeholder: String { return self._s[2403]! } + public var VoiceOver_Chat_RecordModeVideoMessage: String { return self._s[2405]! } + public var Contacts_SortBy: String { return self._s[2406]! } public func PUSH_CHANNEL_MESSAGE_NOTEXT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2404]!, self._r[2404]!, [_1]) + return formatWithArgumentRanges(self._s[2407]!, self._r[2407]!, [_1]) } - public var Appearance_ColorThemeNight: String { return self._s[2406]! } + public var Appearance_ColorThemeNight: String { return self._s[2409]! } public func PUSH_MESSAGE_GAME(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2407]!, self._r[2407]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2410]!, self._r[2410]!, [_1, _2]) } - public var Call_EncryptionKey_Title: String { return self._s[2408]! } - public var Watch_UserInfo_Service: String { return self._s[2409]! } - public var SettingsSearch_Synonyms_Data_SaveEditedPhotos: String { return self._s[2411]! } - public var Conversation_Unpin: String { return self._s[2413]! } - public var CancelResetAccount_Title: String { return self._s[2414]! } - public var Map_LiveLocationFor15Minutes: String { return self._s[2415]! } + public var Call_EncryptionKey_Title: String { return self._s[2411]! } + public var Watch_UserInfo_Service: String { return self._s[2412]! } + public var SettingsSearch_Synonyms_Data_SaveEditedPhotos: String { return self._s[2414]! } + public var Conversation_Unpin: String { return self._s[2416]! } + public var CancelResetAccount_Title: String { return self._s[2417]! } + public var Map_LiveLocationFor15Minutes: String { return self._s[2418]! } public func Time_PreciseDate_m8(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2417]!, self._r[2417]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2420]!, self._r[2420]!, [_1, _2, _3]) } - public var Group_Members_AddMemberBotErrorNotAllowed: String { return self._s[2418]! } - public var Appearance_BubbleCorners_Title: String { return self._s[2419]! } - public var CallSettings_Title: String { return self._s[2420]! } - public var SettingsSearch_Synonyms_Appearance_ChatBackground: String { return self._s[2421]! } - public var PasscodeSettings_EncryptDataHelp: String { return self._s[2423]! } - public var AutoDownloadSettings_Contacts: String { return self._s[2424]! } + public var Group_Members_AddMemberBotErrorNotAllowed: String { return self._s[2421]! } + public var Appearance_BubbleCorners_Title: String { return self._s[2422]! } + public var CallSettings_Title: String { return self._s[2423]! } + public var SettingsSearch_Synonyms_Appearance_ChatBackground: String { return self._s[2424]! } + public var PasscodeSettings_EncryptDataHelp: String { return self._s[2426]! } + public var AutoDownloadSettings_Contacts: String { return self._s[2427]! } public func Channel_AdminLog_MessageRankName(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2425]!, self._r[2425]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2428]!, self._r[2428]!, [_1, _2]) } - public var Passport_Identity_DocumentDetails: String { return self._s[2426]! } - public var LoginPassword_PasswordHelp: String { return self._s[2427]! } - public var SettingsSearch_Synonyms_Data_AutoDownloadUsingWifi: String { return self._s[2428]! } - public var PrivacyLastSeenSettings_CustomShareSettings_Delete: String { return self._s[2429]! } - public var ChatContextMenu_TextSelectionTip: String { return self._s[2430]! } - public var Checkout_TotalPaidAmount: String { return self._s[2431]! } + public var Passport_Identity_DocumentDetails: String { return self._s[2429]! } + public var LoginPassword_PasswordHelp: String { return self._s[2430]! } + public var SettingsSearch_Synonyms_Data_AutoDownloadUsingWifi: String { return self._s[2431]! } + public var PrivacyLastSeenSettings_CustomShareSettings_Delete: String { return self._s[2432]! } + public var ChatContextMenu_TextSelectionTip: String { return self._s[2433]! } + public var Checkout_TotalPaidAmount: String { return self._s[2434]! } public func FileSize_KB(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2432]!, self._r[2432]!, [_0]) + return formatWithArgumentRanges(self._s[2435]!, self._r[2435]!, [_0]) } - public var ChatState_Updating: String { return self._s[2433]! } - public var PasscodeSettings_ChangePasscode: String { return self._s[2434]! } - public var Conversation_SecretLinkPreviewAlert: String { return self._s[2436]! } - public var Privacy_SecretChatsLinkPreviews: String { return self._s[2437]! } + public var ChatState_Updating: String { return self._s[2436]! } + public var PasscodeSettings_ChangePasscode: String { return self._s[2437]! } + public var Conversation_SecretLinkPreviewAlert: String { return self._s[2439]! } + public var Privacy_SecretChatsLinkPreviews: String { return self._s[2440]! } public func PUSH_CHANNEL_MESSAGE_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2438]!, self._r[2438]!, [_1]) + return formatWithArgumentRanges(self._s[2441]!, self._r[2441]!, [_1]) } - public var VoiceOver_Chat_ReplyToYourMessage: String { return self._s[2439]! } - public var Contacts_InviteFriends: String { return self._s[2441]! } - public var Map_ChooseLocationTitle: String { return self._s[2442]! } - public var Conversation_StopPoll: String { return self._s[2444]! } + public var VoiceOver_Chat_ReplyToYourMessage: String { return self._s[2442]! } + public var Contacts_InviteFriends: String { return self._s[2444]! } + public var Map_ChooseLocationTitle: String { return self._s[2445]! } + public var Conversation_StopPoll: String { return self._s[2447]! } public func WebSearch_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2445]!, self._r[2445]!, [_0]) + return formatWithArgumentRanges(self._s[2448]!, self._r[2448]!, [_0]) } - public var Call_Camera: String { return self._s[2446]! } - public var LogoutOptions_ChangePhoneNumberTitle: String { return self._s[2447]! } - public var AppWallet_Intro_Text: String { return self._s[2448]! } - public var Appearance_BubbleCornersSetting: String { return self._s[2449]! } - public var Calls_RatingFeedback: String { return self._s[2450]! } - public var GroupInfo_BroadcastListNamePlaceholder: String { return self._s[2452]! } - public var Wallet_Alert_OK: String { return self._s[2453]! } - public var NotificationsSound_Pulse: String { return self._s[2454]! } - public var Watch_LastSeen_Lately: String { return self._s[2455]! } - public var ReportGroupLocation_Report: String { return self._s[2458]! } - public var Widget_NoUsers: String { return self._s[2459]! } - public var Conversation_UnvotePoll: String { return self._s[2460]! } - public var SettingsSearch_Synonyms_Privacy_ProfilePhoto: String { return self._s[2462]! } - public var Privacy_ProfilePhoto_WhoCanSeeMyPhoto: String { return self._s[2463]! } - public var NotificationsSound_Circles: String { return self._s[2464]! } - public var PrivacyLastSeenSettings_AlwaysShareWith_Title: String { return self._s[2467]! } - public var Wallet_Settings_DeleteWallet: String { return self._s[2468]! } - public var TwoStepAuth_RecoveryCodeExpired: String { return self._s[2469]! } - public var Proxy_TooltipUnavailable: String { return self._s[2470]! } - public var Passport_Identity_CountryPlaceholder: String { return self._s[2472]! } - public var GroupInfo_Permissions_SlowmodeInfo: String { return self._s[2474]! } - public var Conversation_FileDropbox: String { return self._s[2475]! } - public var Notifications_ExceptionsUnmuted: String { return self._s[2476]! } - public var Tour_Text3: String { return self._s[2478]! } - public var Login_ResetAccountProtected_Title: String { return self._s[2480]! } - public var GroupPermission_NoSendMessages: String { return self._s[2481]! } - public var WallpaperSearch_ColorTitle: String { return self._s[2482]! } - public var ChatAdmins_AllMembersAreAdminsOnHelp: String { return self._s[2483]! } + public var Call_Camera: String { return self._s[2449]! } + public var LogoutOptions_ChangePhoneNumberTitle: String { return self._s[2450]! } + public var AppWallet_Intro_Text: String { return self._s[2451]! } + public var Appearance_BubbleCornersSetting: String { return self._s[2452]! } + public var Calls_RatingFeedback: String { return self._s[2453]! } + public var GroupInfo_BroadcastListNamePlaceholder: String { return self._s[2455]! } + public var Wallet_Alert_OK: String { return self._s[2456]! } + public var NotificationsSound_Pulse: String { return self._s[2457]! } + public var Watch_LastSeen_Lately: String { return self._s[2458]! } + public var ReportGroupLocation_Report: String { return self._s[2461]! } + public var Widget_NoUsers: String { return self._s[2462]! } + public var Conversation_UnvotePoll: String { return self._s[2463]! } + public var SettingsSearch_Synonyms_Privacy_ProfilePhoto: String { return self._s[2465]! } + public var Privacy_ProfilePhoto_WhoCanSeeMyPhoto: String { return self._s[2466]! } + public var NotificationsSound_Circles: String { return self._s[2467]! } + public var PrivacyLastSeenSettings_AlwaysShareWith_Title: String { return self._s[2470]! } + public var Wallet_Settings_DeleteWallet: String { return self._s[2471]! } + public var TwoStepAuth_RecoveryCodeExpired: String { return self._s[2472]! } + public var Proxy_TooltipUnavailable: String { return self._s[2473]! } + public var Passport_Identity_CountryPlaceholder: String { return self._s[2475]! } + public var GroupInfo_Permissions_SlowmodeInfo: String { return self._s[2477]! } + public var Conversation_FileDropbox: String { return self._s[2478]! } + public var Notifications_ExceptionsUnmuted: String { return self._s[2479]! } + public var Tour_Text3: String { return self._s[2481]! } + public var Login_ResetAccountProtected_Title: String { return self._s[2483]! } + public var GroupPermission_NoSendMessages: String { return self._s[2484]! } + public var WallpaperSearch_ColorTitle: String { return self._s[2485]! } + public var ChatAdmins_AllMembersAreAdminsOnHelp: String { return self._s[2486]! } public func Conversation_LiveLocationYouAnd(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2485]!, self._r[2485]!, [_0]) + return formatWithArgumentRanges(self._s[2488]!, self._r[2488]!, [_0]) } - public var GroupInfo_AddParticipantTitle: String { return self._s[2486]! } - public var Checkout_ShippingOption_Title: String { return self._s[2487]! } - public var ChatSettings_AutoDownloadTitle: String { return self._s[2488]! } + public var GroupInfo_AddParticipantTitle: String { return self._s[2489]! } + public var Checkout_ShippingOption_Title: String { return self._s[2490]! } + public var ChatSettings_AutoDownloadTitle: String { return self._s[2491]! } public func DialogList_SingleTypingSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2489]!, self._r[2489]!, [_0]) + return formatWithArgumentRanges(self._s[2492]!, self._r[2492]!, [_0]) } public func ChatSettings_AutoDownloadSettings_TypeVideo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2490]!, self._r[2490]!, [_0]) + return formatWithArgumentRanges(self._s[2493]!, self._r[2493]!, [_0]) } - public var Channel_Management_LabelAdministrator: String { return self._s[2491]! } - public var EditTheme_FileReadError: String { return self._s[2492]! } - public var OwnershipTransfer_ComeBackLater: String { return self._s[2493]! } - public var PrivacyLastSeenSettings_NeverShareWith_Placeholder: String { return self._s[2494]! } - public var AutoDownloadSettings_Photos: String { return self._s[2496]! } - public var Appearance_PreviewIncomingText: String { return self._s[2497]! } - public var ChatList_Context_MarkAllAsRead: String { return self._s[2498]! } - public var ChannelInfo_ConfirmLeave: String { return self._s[2499]! } - public var MediaPicker_MomentsDateRangeSameMonthYearFormat: String { return self._s[2500]! } - public var Passport_Identity_DocumentNumberPlaceholder: String { return self._s[2501]! } - public var Channel_AdminLogFilter_EventsNewMembers: String { return self._s[2502]! } - public var PasscodeSettings_AutoLock_IfAwayFor_5minutes: String { return self._s[2503]! } - public var GroupInfo_SetGroupPhotoStop: String { return self._s[2504]! } - public var Notification_SecretChatScreenshot: String { return self._s[2505]! } - public var AccessDenied_Wallpapers: String { return self._s[2506]! } - public var ChatList_Context_Mute: String { return self._s[2508]! } - public var Passport_Address_City: String { return self._s[2509]! } - public var InfoPlist_NSPhotoLibraryAddUsageDescription: String { return self._s[2510]! } - public var Appearance_ThemeCarouselClassic: String { return self._s[2511]! } - public var SocksProxySetup_SecretPlaceholder: String { return self._s[2512]! } - public var AccessDenied_LocationDisabled: String { return self._s[2513]! } - public var Group_Location_Title: String { return self._s[2514]! } - public var SocksProxySetup_HostnamePlaceholder: String { return self._s[2516]! } - public var GroupInfo_Sound: String { return self._s[2517]! } - public var SettingsSearch_Synonyms_ChatSettings_OpenLinksIn: String { return self._s[2518]! } - public var ChannelInfo_ScamChannelWarning: String { return self._s[2519]! } - public var Stickers_RemoveFromFavorites: String { return self._s[2520]! } - public var Contacts_Title: String { return self._s[2521]! } - public var EditTheme_ThemeTemplateAlertText: String { return self._s[2522]! } - public var Passport_Language_fr: String { return self._s[2523]! } - public var TwoFactorSetup_EmailVerification_Action: String { return self._s[2524]! } - public var Notifications_ResetAllNotifications: String { return self._s[2525]! } - public var IntentsSettings_SuggestedChats: String { return self._s[2527]! } - public var PrivacySettings_SecurityTitle: String { return self._s[2529]! } - public var Checkout_NewCard_Title: String { return self._s[2530]! } - public var Login_HaveNotReceivedCodeInternal: String { return self._s[2531]! } - public var Conversation_ForwardChats: String { return self._s[2532]! } - public var Wallet_SecureStorageReset_PasscodeText: String { return self._s[2534]! } - public var PasscodeSettings_4DigitCode: String { return self._s[2535]! } - public var Settings_FAQ: String { return self._s[2537]! } - public var AutoDownloadSettings_DocumentsTitle: String { return self._s[2538]! } - public var Conversation_ContextMenuForward: String { return self._s[2539]! } - public var VoiceOver_Chat_YourPhoto: String { return self._s[2542]! } - public var PrivacyPolicy_Title: String { return self._s[2545]! } - public var Notifications_TextTone: String { return self._s[2546]! } - public var Profile_CreateNewContact: String { return self._s[2547]! } - public var PrivacyPhoneNumberSettings_WhoCanSeeMyPhoneNumber: String { return self._s[2548]! } - public var TwoFactorSetup_EmailVerification_Title: String { return self._s[2550]! } - public var Call_Speaker: String { return self._s[2551]! } - public var AutoNightTheme_AutomaticSection: String { return self._s[2552]! } - public var Channel_OwnershipTransfer_EnterPassword: String { return self._s[2554]! } - public var Channel_Username_InvalidCharacters: String { return self._s[2555]! } + public var Channel_Management_LabelAdministrator: String { return self._s[2494]! } + public var EditTheme_FileReadError: String { return self._s[2495]! } + public var OwnershipTransfer_ComeBackLater: String { return self._s[2496]! } + public var PrivacyLastSeenSettings_NeverShareWith_Placeholder: String { return self._s[2497]! } + public var AutoDownloadSettings_Photos: String { return self._s[2499]! } + public var Appearance_PreviewIncomingText: String { return self._s[2500]! } + public var ChatList_Context_MarkAllAsRead: String { return self._s[2501]! } + public var ChannelInfo_ConfirmLeave: String { return self._s[2502]! } + public var MediaPicker_MomentsDateRangeSameMonthYearFormat: String { return self._s[2503]! } + public var Passport_Identity_DocumentNumberPlaceholder: String { return self._s[2504]! } + public var Channel_AdminLogFilter_EventsNewMembers: String { return self._s[2505]! } + public var PasscodeSettings_AutoLock_IfAwayFor_5minutes: String { return self._s[2506]! } + public var GroupInfo_SetGroupPhotoStop: String { return self._s[2507]! } + public var Notification_SecretChatScreenshot: String { return self._s[2508]! } + public var AccessDenied_Wallpapers: String { return self._s[2509]! } + public var ChatList_Context_Mute: String { return self._s[2511]! } + public var Passport_Address_City: String { return self._s[2512]! } + public var InfoPlist_NSPhotoLibraryAddUsageDescription: String { return self._s[2513]! } + public var Appearance_ThemeCarouselClassic: String { return self._s[2514]! } + public var SocksProxySetup_SecretPlaceholder: String { return self._s[2515]! } + public var AccessDenied_LocationDisabled: String { return self._s[2516]! } + public var Group_Location_Title: String { return self._s[2517]! } + public var SocksProxySetup_HostnamePlaceholder: String { return self._s[2519]! } + public var GroupInfo_Sound: String { return self._s[2520]! } + public var SettingsSearch_Synonyms_ChatSettings_OpenLinksIn: String { return self._s[2521]! } + public var ChannelInfo_ScamChannelWarning: String { return self._s[2522]! } + public var Stickers_RemoveFromFavorites: String { return self._s[2523]! } + public var Contacts_Title: String { return self._s[2524]! } + public var EditTheme_ThemeTemplateAlertText: String { return self._s[2525]! } + public var Passport_Language_fr: String { return self._s[2526]! } + public var TwoFactorSetup_EmailVerification_Action: String { return self._s[2527]! } + public var Notifications_ResetAllNotifications: String { return self._s[2528]! } + public var IntentsSettings_SuggestedChats: String { return self._s[2530]! } + public var PrivacySettings_SecurityTitle: String { return self._s[2532]! } + public var Checkout_NewCard_Title: String { return self._s[2533]! } + public var Login_HaveNotReceivedCodeInternal: String { return self._s[2534]! } + public var Conversation_ForwardChats: String { return self._s[2535]! } + public var Wallet_SecureStorageReset_PasscodeText: String { return self._s[2537]! } + public var PasscodeSettings_4DigitCode: String { return self._s[2538]! } + public var Settings_FAQ: String { return self._s[2540]! } + public var AutoDownloadSettings_DocumentsTitle: String { return self._s[2541]! } + public var Conversation_ContextMenuForward: String { return self._s[2542]! } + public var VoiceOver_Chat_YourPhoto: String { return self._s[2545]! } + public var PrivacyPolicy_Title: String { return self._s[2548]! } + public var Notifications_TextTone: String { return self._s[2549]! } + public var Profile_CreateNewContact: String { return self._s[2550]! } + public var PrivacyPhoneNumberSettings_WhoCanSeeMyPhoneNumber: String { return self._s[2551]! } + public var TwoFactorSetup_EmailVerification_Title: String { return self._s[2553]! } + public var Call_Speaker: String { return self._s[2554]! } + public var AutoNightTheme_AutomaticSection: String { return self._s[2555]! } + public var Channel_OwnershipTransfer_EnterPassword: String { return self._s[2557]! } + public var Channel_Username_InvalidCharacters: String { return self._s[2558]! } public func Channel_AdminLog_MessageChangedChannelUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2556]!, self._r[2556]!, [_0]) + return formatWithArgumentRanges(self._s[2559]!, self._r[2559]!, [_0]) } - public var AutoDownloadSettings_AutodownloadFiles: String { return self._s[2557]! } - public var PrivacySettings_LastSeenTitle: String { return self._s[2558]! } - public var Channel_AdminLog_CanInviteUsers: String { return self._s[2559]! } - public var SettingsSearch_Synonyms_Privacy_Data_ClearPaymentsInfo: String { return self._s[2560]! } - public var OwnershipTransfer_SecurityCheck: String { return self._s[2561]! } - public var Conversation_MessageDeliveryFailed: String { return self._s[2562]! } - public var Watch_ChatList_NoConversationsText: String { return self._s[2563]! } - public var Bot_Unblock: String { return self._s[2564]! } - public var TextFormat_Italic: String { return self._s[2565]! } - public var WallpaperSearch_ColorPink: String { return self._s[2566]! } - public var Settings_About_Help: String { return self._s[2568]! } - public var SearchImages_Title: String { return self._s[2569]! } - public var Weekday_Wednesday: String { return self._s[2570]! } - public var Conversation_ClousStorageInfo_Description1: String { return self._s[2571]! } - public var ExplicitContent_AlertTitle: String { return self._s[2572]! } + public var AutoDownloadSettings_AutodownloadFiles: String { return self._s[2560]! } + public var PrivacySettings_LastSeenTitle: String { return self._s[2561]! } + public var Channel_AdminLog_CanInviteUsers: String { return self._s[2562]! } + public var SettingsSearch_Synonyms_Privacy_Data_ClearPaymentsInfo: String { return self._s[2563]! } + public var OwnershipTransfer_SecurityCheck: String { return self._s[2564]! } + public var Conversation_MessageDeliveryFailed: String { return self._s[2565]! } + public var Watch_ChatList_NoConversationsText: String { return self._s[2566]! } + public var Bot_Unblock: String { return self._s[2567]! } + public var TextFormat_Italic: String { return self._s[2568]! } + public var WallpaperSearch_ColorPink: String { return self._s[2569]! } + public var Settings_About_Help: String { return self._s[2571]! } + public var SearchImages_Title: String { return self._s[2572]! } + public var Weekday_Wednesday: String { return self._s[2573]! } + public var Conversation_ClousStorageInfo_Description1: String { return self._s[2574]! } + public var ExplicitContent_AlertTitle: String { return self._s[2575]! } public func Time_PreciseDate_m5(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2573]!, self._r[2573]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2576]!, self._r[2576]!, [_1, _2, _3]) } - public var Channel_DiscussionGroup_Create: String { return self._s[2574]! } - public var Weekday_Thursday: String { return self._s[2575]! } - public var Channel_BanUser_PermissionChangeGroupInfo: String { return self._s[2576]! } - public var Channel_Members_AddMembersHelp: String { return self._s[2577]! } + public var Channel_DiscussionGroup_Create: String { return self._s[2577]! } + public var Weekday_Thursday: String { return self._s[2578]! } + public var Channel_BanUser_PermissionChangeGroupInfo: String { return self._s[2579]! } + public var Channel_Members_AddMembersHelp: String { return self._s[2580]! } public func Checkout_SavePasswordTimeout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2578]!, self._r[2578]!, [_0]) + return formatWithArgumentRanges(self._s[2581]!, self._r[2581]!, [_0]) } - public var Channel_DiscussionGroup_LinkGroup: String { return self._s[2579]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsVibrate: String { return self._s[2580]! } - public var Passport_RequestedInformation: String { return self._s[2581]! } - public var Login_PhoneAndCountryHelp: String { return self._s[2582]! } - public var Conversation_EncryptionProcessing: String { return self._s[2584]! } - public var Notifications_PermissionsSuppressWarningTitle: String { return self._s[2585]! } - public var PhotoEditor_EnhanceTool: String { return self._s[2587]! } - public var Channel_Setup_Title: String { return self._s[2588]! } - public var Conversation_SearchPlaceholder: String { return self._s[2589]! } - public var OldChannels_GroupEmptyFormat: String { return self._s[2590]! } - public var AccessDenied_LocationAlwaysDenied: String { return self._s[2591]! } - public var Checkout_ErrorGeneric: String { return self._s[2592]! } - public var Passport_Language_hu: String { return self._s[2593]! } - public var GroupPermission_EditingDisabled: String { return self._s[2594]! } - public var Wallet_Month_ShortSeptember: String { return self._s[2596]! } + public var Channel_DiscussionGroup_LinkGroup: String { return self._s[2582]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsVibrate: String { return self._s[2583]! } + public var Passport_RequestedInformation: String { return self._s[2584]! } + public var Login_PhoneAndCountryHelp: String { return self._s[2585]! } + public var Conversation_EncryptionProcessing: String { return self._s[2587]! } + public var Notifications_PermissionsSuppressWarningTitle: String { return self._s[2588]! } + public var PhotoEditor_EnhanceTool: String { return self._s[2590]! } + public var Channel_Setup_Title: String { return self._s[2591]! } + public var Conversation_SearchPlaceholder: String { return self._s[2592]! } + public var OldChannels_GroupEmptyFormat: String { return self._s[2593]! } + public var AccessDenied_LocationAlwaysDenied: String { return self._s[2594]! } + public var Checkout_ErrorGeneric: String { return self._s[2595]! } + public var Passport_Language_hu: String { return self._s[2596]! } + public var GroupPermission_EditingDisabled: String { return self._s[2597]! } + public var Wallet_Month_ShortSeptember: String { return self._s[2599]! } public func Passport_Identity_UploadOneOfScan(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2597]!, self._r[2597]!, [_0]) + return formatWithArgumentRanges(self._s[2600]!, self._r[2600]!, [_0]) } public func PUSH_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2600]!, self._r[2600]!, [_1]) + return formatWithArgumentRanges(self._s[2603]!, self._r[2603]!, [_1]) } - public var ChatList_DeleteSavedMessagesConfirmationTitle: String { return self._s[2601]! } + public var ChatList_DeleteSavedMessagesConfirmationTitle: String { return self._s[2604]! } public func UserInfo_BlockConfirmationTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2602]!, self._r[2602]!, [_0]) + return formatWithArgumentRanges(self._s[2605]!, self._r[2605]!, [_0]) } - public var Conversation_CloudStorageInfo_Title: String { return self._s[2603]! } - public var Group_Location_Info: String { return self._s[2604]! } - public var PhotoEditor_CropAspectRatioSquare: String { return self._s[2605]! } - public var Permissions_PeopleNearbyAllow_v0: String { return self._s[2606]! } + public var Conversation_CloudStorageInfo_Title: String { return self._s[2606]! } + public var Group_Location_Info: String { return self._s[2607]! } + public var PhotoEditor_CropAspectRatioSquare: String { return self._s[2608]! } + public var Permissions_PeopleNearbyAllow_v0: String { return self._s[2609]! } public func Notification_Exceptions_MutedUntil(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2607]!, self._r[2607]!, [_0]) + return formatWithArgumentRanges(self._s[2610]!, self._r[2610]!, [_0]) } - public var Conversation_ClearPrivateHistory: String { return self._s[2608]! } - public var ContactInfo_PhoneLabelHome: String { return self._s[2609]! } - public var Appearance_RemoveThemeConfirmation: String { return self._s[2610]! } - public var PrivacySettings_LastSeenContacts: String { return self._s[2611]! } + public var Conversation_ClearPrivateHistory: String { return self._s[2611]! } + public var ContactInfo_PhoneLabelHome: String { return self._s[2612]! } + public var Appearance_RemoveThemeConfirmation: String { return self._s[2613]! } + public var PrivacySettings_LastSeenContacts: String { return self._s[2614]! } public func ChangePhone_ErrorOccupied(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2612]!, self._r[2612]!, [_0]) + return formatWithArgumentRanges(self._s[2615]!, self._r[2615]!, [_0]) } public func Notification_PinnedQuizMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2613]!, self._r[2613]!, [_0]) + return formatWithArgumentRanges(self._s[2616]!, self._r[2616]!, [_0]) } - public var Passport_Language_cs: String { return self._s[2614]! } - public var Message_PinnedAnimationMessage: String { return self._s[2616]! } - public var Passport_Identity_ReverseSideHelp: String { return self._s[2618]! } - public var SettingsSearch_Synonyms_Data_Storage_Title: String { return self._s[2619]! } - public var Wallet_Info_TransactionTo: String { return self._s[2621]! } - public var ChatList_DeleteForEveryoneConfirmationText: String { return self._s[2622]! } - public var SettingsSearch_Synonyms_Privacy_PasscodeAndTouchId: String { return self._s[2623]! } - public var Embed_PlayingInPIP: String { return self._s[2624]! } - public var Appearance_ThemePreview_Chat_3_TextWithLink: String { return self._s[2625]! } - public var AutoNightTheme_ScheduleSection: String { return self._s[2626]! } + public var Passport_Language_cs: String { return self._s[2617]! } + public var Message_PinnedAnimationMessage: String { return self._s[2619]! } + public var Passport_Identity_ReverseSideHelp: String { return self._s[2621]! } + public var SettingsSearch_Synonyms_Data_Storage_Title: String { return self._s[2622]! } + public var Wallet_Info_TransactionTo: String { return self._s[2624]! } + public var ChatList_DeleteForEveryoneConfirmationText: String { return self._s[2625]! } + public var SettingsSearch_Synonyms_Privacy_PasscodeAndTouchId: String { return self._s[2626]! } + public var Embed_PlayingInPIP: String { return self._s[2627]! } + public var Appearance_ThemePreview_Chat_3_TextWithLink: String { return self._s[2628]! } + public var AutoNightTheme_ScheduleSection: String { return self._s[2629]! } public func Call_EmojiDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2627]!, self._r[2627]!, [_0]) + return formatWithArgumentRanges(self._s[2630]!, self._r[2630]!, [_0]) } - public var MediaPicker_LivePhotoDescription: String { return self._s[2628]! } + public var MediaPicker_LivePhotoDescription: String { return self._s[2631]! } public func Channel_AdminLog_MessageRestrictedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2629]!, self._r[2629]!, [_1]) + return formatWithArgumentRanges(self._s[2632]!, self._r[2632]!, [_1]) } - public var Notification_PaymentSent: String { return self._s[2630]! } - public var PhotoEditor_CurvesGreen: String { return self._s[2631]! } - public var Notification_Exceptions_PreviewAlwaysOff: String { return self._s[2632]! } - public var AutoNightTheme_System: String { return self._s[2633]! } - public var SaveIncomingPhotosSettings_Title: String { return self._s[2634]! } - public var CreatePoll_QuizTitle: String { return self._s[2635]! } - public var NotificationSettings_ShowNotificationsAllAccounts: String { return self._s[2636]! } - public var VoiceOver_Chat_PagePreview: String { return self._s[2637]! } + public var Notification_PaymentSent: String { return self._s[2633]! } + public var PhotoEditor_CurvesGreen: String { return self._s[2634]! } + public var Notification_Exceptions_PreviewAlwaysOff: String { return self._s[2635]! } + public var AutoNightTheme_System: String { return self._s[2636]! } + public var SaveIncomingPhotosSettings_Title: String { return self._s[2637]! } + public var CreatePoll_QuizTitle: String { return self._s[2638]! } + public var NotificationSettings_ShowNotificationsAllAccounts: String { return self._s[2639]! } + public var VoiceOver_Chat_PagePreview: String { return self._s[2640]! } public func PUSH_MESSAGE_SCREENSHOT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2640]!, self._r[2640]!, [_1]) + return formatWithArgumentRanges(self._s[2643]!, self._r[2643]!, [_1]) } public func PUSH_MESSAGE_PHOTO_SECRET(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2641]!, self._r[2641]!, [_1]) + return formatWithArgumentRanges(self._s[2644]!, self._r[2644]!, [_1]) } public func ApplyLanguage_UnsufficientDataText(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2642]!, self._r[2642]!, [_1]) + return formatWithArgumentRanges(self._s[2645]!, self._r[2645]!, [_1]) } - public var NetworkUsageSettings_CallDataSection: String { return self._s[2644]! } - public var PasscodeSettings_HelpTop: String { return self._s[2645]! } - public var Conversation_WalletRequiredTitle: String { return self._s[2646]! } - public var Group_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[2647]! } - public var Passport_Address_TypeRentalAgreement: String { return self._s[2648]! } - public var EditTheme_ShortLink: String { return self._s[2649]! } - public var Theme_Colors_ColorWallpaperWarning: String { return self._s[2650]! } - public var ProxyServer_VoiceOver_Active: String { return self._s[2651]! } - public var ReportPeer_ReasonOther_Placeholder: String { return self._s[2652]! } - public var CheckoutInfo_ErrorPhoneInvalid: String { return self._s[2653]! } - public var Call_Accept: String { return self._s[2655]! } - public var GroupRemoved_RemoveInfo: String { return self._s[2656]! } - public var Month_GenMarch: String { return self._s[2658]! } - public var PhotoEditor_ShadowsTool: String { return self._s[2659]! } - public var LoginPassword_Title: String { return self._s[2660]! } - public var Call_End: String { return self._s[2661]! } - public var Watch_Conversation_GroupInfo: String { return self._s[2662]! } - public var VoiceOver_Chat_Contact: String { return self._s[2663]! } - public var EditTheme_Create_Preview_IncomingText: String { return self._s[2664]! } - public var CallSettings_Always: String { return self._s[2665]! } - public var CallFeedback_Success: String { return self._s[2666]! } - public var TwoStepAuth_SetupHint: String { return self._s[2667]! } + public var NetworkUsageSettings_CallDataSection: String { return self._s[2647]! } + public var PasscodeSettings_HelpTop: String { return self._s[2648]! } + public var Conversation_WalletRequiredTitle: String { return self._s[2649]! } + public var Group_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[2650]! } + public var Passport_Address_TypeRentalAgreement: String { return self._s[2651]! } + public var EditTheme_ShortLink: String { return self._s[2652]! } + public var Theme_Colors_ColorWallpaperWarning: String { return self._s[2653]! } + public var ProxyServer_VoiceOver_Active: String { return self._s[2654]! } + public var ReportPeer_ReasonOther_Placeholder: String { return self._s[2655]! } + public var CheckoutInfo_ErrorPhoneInvalid: String { return self._s[2656]! } + public var Call_Accept: String { return self._s[2658]! } + public var GroupRemoved_RemoveInfo: String { return self._s[2659]! } + public var Month_GenMarch: String { return self._s[2661]! } + public var PhotoEditor_ShadowsTool: String { return self._s[2662]! } + public var LoginPassword_Title: String { return self._s[2663]! } + public var Call_End: String { return self._s[2664]! } + public var Watch_Conversation_GroupInfo: String { return self._s[2665]! } + public var VoiceOver_Chat_Contact: String { return self._s[2666]! } + public var EditTheme_Create_Preview_IncomingText: String { return self._s[2667]! } + public var CallSettings_Always: String { return self._s[2668]! } + public var CallFeedback_Success: String { return self._s[2669]! } + public var TwoStepAuth_SetupHint: String { return self._s[2670]! } public func AddContact_ContactWillBeSharedAfterMutual(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2668]!, self._r[2668]!, [_1]) + return formatWithArgumentRanges(self._s[2671]!, self._r[2671]!, [_1]) } - public var ConversationProfile_UsersTooMuchError: String { return self._s[2669]! } - public var Login_PhoneTitle: String { return self._s[2670]! } - public var Passport_FieldPhoneHelp: String { return self._s[2671]! } - public var Weekday_ShortSunday: String { return self._s[2672]! } - public var Passport_InfoFAQ_URL: String { return self._s[2673]! } - public var ContactInfo_Job: String { return self._s[2675]! } - public var UserInfo_InviteBotToGroup: String { return self._s[2676]! } - public var Appearance_ThemeCarouselNightBlue: String { return self._s[2677]! } - public var CreatePoll_QuizTip: String { return self._s[2678]! } - public var TwoFactorSetup_Email_Text: String { return self._s[2679]! } - public var TwoStepAuth_PasswordRemovePassportConfirmation: String { return self._s[2680]! } - public var Invite_ChannelsTooMuch: String { return self._s[2681]! } - public var Wallet_Send_ConfirmationConfirm: String { return self._s[2682]! } - public var Wallet_TransactionInfo_OtherFeeInfo: String { return self._s[2683]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsPreview: String { return self._s[2684]! } - public var Wallet_Receive_AmountText: String { return self._s[2685]! } - public var Passport_DeletePersonalDetailsConfirmation: String { return self._s[2686]! } - public var CallFeedback_ReasonNoise: String { return self._s[2687]! } - public var Appearance_AppIconDefault: String { return self._s[2689]! } - public var Passport_Identity_AddInternalPassport: String { return self._s[2690]! } - public var MediaPicker_AddCaption: String { return self._s[2691]! } - public var CallSettings_TabIconDescription: String { return self._s[2692]! } + public var ConversationProfile_UsersTooMuchError: String { return self._s[2672]! } + public var PeerInfo_ButtonAddMember: String { return self._s[2673]! } + public var Login_PhoneTitle: String { return self._s[2674]! } + public var Passport_FieldPhoneHelp: String { return self._s[2675]! } + public var Weekday_ShortSunday: String { return self._s[2676]! } + public var Passport_InfoFAQ_URL: String { return self._s[2677]! } + public var ContactInfo_Job: String { return self._s[2679]! } + public var UserInfo_InviteBotToGroup: String { return self._s[2680]! } + public var Appearance_ThemeCarouselNightBlue: String { return self._s[2681]! } + public var CreatePoll_QuizTip: String { return self._s[2682]! } + public var TwoFactorSetup_Email_Text: String { return self._s[2683]! } + public var TwoStepAuth_PasswordRemovePassportConfirmation: String { return self._s[2684]! } + public var Invite_ChannelsTooMuch: String { return self._s[2685]! } + public var Wallet_Send_ConfirmationConfirm: String { return self._s[2686]! } + public var Wallet_TransactionInfo_OtherFeeInfo: String { return self._s[2687]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsPreview: String { return self._s[2688]! } + public var Wallet_Receive_AmountText: String { return self._s[2689]! } + public var Passport_DeletePersonalDetailsConfirmation: String { return self._s[2690]! } + public var CallFeedback_ReasonNoise: String { return self._s[2691]! } + public var Appearance_AppIconDefault: String { return self._s[2693]! } + public var Passport_Identity_AddInternalPassport: String { return self._s[2694]! } + public var MediaPicker_AddCaption: String { return self._s[2695]! } + public var CallSettings_TabIconDescription: String { return self._s[2696]! } public func VoiceOver_Chat_Caption(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2693]!, self._r[2693]!, [_0]) + return formatWithArgumentRanges(self._s[2697]!, self._r[2697]!, [_0]) } - public var IntentsSettings_SuggestedChatsGroups: String { return self._s[2694]! } + public var IntentsSettings_SuggestedChatsGroups: String { return self._s[2698]! } public func Map_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2695]!, self._r[2695]!, [_0]) + return formatWithArgumentRanges(self._s[2699]!, self._r[2699]!, [_0]) } - public var ChatList_UndoArchiveHiddenTitle: String { return self._s[2696]! } - public var Privacy_GroupsAndChannels_AlwaysAllow: String { return self._s[2697]! } - public var Passport_Identity_TypePersonalDetails: String { return self._s[2698]! } - public var DialogList_SearchSectionRecent: String { return self._s[2699]! } - public var PrivacyPolicy_DeclineMessage: String { return self._s[2700]! } - public var CreatePoll_Anonymous: String { return self._s[2701]! } - public var LogoutOptions_ClearCacheText: String { return self._s[2704]! } - public var LastSeen_WithinAWeek: String { return self._s[2705]! } - public var ChannelMembers_GroupAdminsTitle: String { return self._s[2706]! } - public var Conversation_CloudStorage_ChatStatus: String { return self._s[2708]! } - public var VoiceOver_Media_PlaybackRateNormal: String { return self._s[2709]! } + public var ChatList_UndoArchiveHiddenTitle: String { return self._s[2700]! } + public var Privacy_GroupsAndChannels_AlwaysAllow: String { return self._s[2701]! } + public var Passport_Identity_TypePersonalDetails: String { return self._s[2702]! } + public var DialogList_SearchSectionRecent: String { return self._s[2703]! } + public var PrivacyPolicy_DeclineMessage: String { return self._s[2704]! } + public var CreatePoll_Anonymous: String { return self._s[2705]! } + public var LogoutOptions_ClearCacheText: String { return self._s[2708]! } + public var LastSeen_WithinAWeek: String { return self._s[2709]! } + public var ChannelMembers_GroupAdminsTitle: String { return self._s[2710]! } + public var Conversation_CloudStorage_ChatStatus: String { return self._s[2712]! } + public var VoiceOver_Media_PlaybackRateNormal: String { return self._s[2713]! } public func AddContact_SharedContactExceptionInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2710]!, self._r[2710]!, [_0]) + return formatWithArgumentRanges(self._s[2714]!, self._r[2714]!, [_0]) } - public var Passport_Address_TypeResidentialAddress: String { return self._s[2711]! } - public var Conversation_StatusLeftGroup: String { return self._s[2712]! } - public var SocksProxySetup_ProxyDetailsTitle: String { return self._s[2713]! } - public var SettingsSearch_Synonyms_Calls_Title: String { return self._s[2715]! } - public var GroupPermission_AddSuccess: String { return self._s[2716]! } - public var PhotoEditor_BlurToolRadial: String { return self._s[2718]! } - public var Conversation_ContextMenuCopy: String { return self._s[2719]! } - public var AccessDenied_CallMicrophone: String { return self._s[2720]! } + public var Passport_Address_TypeResidentialAddress: String { return self._s[2715]! } + public var Conversation_StatusLeftGroup: String { return self._s[2716]! } + public var SocksProxySetup_ProxyDetailsTitle: String { return self._s[2717]! } + public var SettingsSearch_Synonyms_Calls_Title: String { return self._s[2719]! } + public var GroupPermission_AddSuccess: String { return self._s[2720]! } + public var PhotoEditor_BlurToolRadial: String { return self._s[2722]! } + public var Conversation_ContextMenuCopy: String { return self._s[2723]! } + public var AccessDenied_CallMicrophone: String { return self._s[2724]! } public func Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2721]!, self._r[2721]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2725]!, self._r[2725]!, [_1, _2, _3]) } - public var Login_InvalidFirstNameError: String { return self._s[2722]! } - public var Notifications_Badge_CountUnreadMessages_InfoOn: String { return self._s[2723]! } - public var Checkout_PaymentMethod_New: String { return self._s[2724]! } - public var ShareMenu_CopyShareLinkGame: String { return self._s[2725]! } - public var PhotoEditor_QualityTool: String { return self._s[2726]! } - public var Login_SendCodeViaSms: String { return self._s[2727]! } - public var SettingsSearch_Synonyms_Privacy_DeleteAccountIfAwayFor: String { return self._s[2728]! } - public var Chat_SlowmodeAttachmentLimitReached: String { return self._s[2729]! } - public var Wallet_Receive_CopyAddress: String { return self._s[2730]! } - public var Login_EmailNotConfiguredError: String { return self._s[2731]! } - public var SocksProxySetup_Status: String { return self._s[2732]! } - public var Conversation_ScheduleMessage_SendWhenOnline: String { return self._s[2733]! } - public var PrivacyPolicy_Accept: String { return self._s[2734]! } - public var Notifications_ExceptionsMessagePlaceholder: String { return self._s[2735]! } - public var Appearance_AppIconClassicX: String { return self._s[2736]! } + public var Login_InvalidFirstNameError: String { return self._s[2726]! } + public var Notifications_Badge_CountUnreadMessages_InfoOn: String { return self._s[2727]! } + public var Checkout_PaymentMethod_New: String { return self._s[2728]! } + public var ShareMenu_CopyShareLinkGame: String { return self._s[2729]! } + public var PhotoEditor_QualityTool: String { return self._s[2730]! } + public var Login_SendCodeViaSms: String { return self._s[2731]! } + public var SettingsSearch_Synonyms_Privacy_DeleteAccountIfAwayFor: String { return self._s[2732]! } + public var Chat_SlowmodeAttachmentLimitReached: String { return self._s[2733]! } + public var Wallet_Receive_CopyAddress: String { return self._s[2734]! } + public var Login_EmailNotConfiguredError: String { return self._s[2735]! } + public var SocksProxySetup_Status: String { return self._s[2736]! } + public var Conversation_ScheduleMessage_SendWhenOnline: String { return self._s[2737]! } + public var PrivacyPolicy_Accept: String { return self._s[2738]! } + public var Notifications_ExceptionsMessagePlaceholder: String { return self._s[2739]! } + public var Appearance_AppIconClassicX: String { return self._s[2740]! } public func PUSH_CHAT_MESSAGE_TEXT(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2737]!, self._r[2737]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2741]!, self._r[2741]!, [_1, _2, _3]) } - public var OwnershipTransfer_SecurityRequirements: String { return self._s[2738]! } - public var InfoPlist_NSLocationAlwaysUsageDescription: String { return self._s[2740]! } - public var AutoNightTheme_Automatic: String { return self._s[2741]! } - public var Channel_Username_InvalidStartsWithNumber: String { return self._s[2742]! } - public var Privacy_ContactsSyncHelp: String { return self._s[2743]! } - public var Cache_Help: String { return self._s[2744]! } - public var Group_ErrorAccessDenied: String { return self._s[2745]! } - public var Passport_Language_fa: String { return self._s[2746]! } - public var Wallet_Intro_Text: String { return self._s[2747]! } - public var Login_ResetAccountProtected_TimerTitle: String { return self._s[2748]! } - public var VoiceOver_Chat_YourVideoMessage: String { return self._s[2749]! } - public var PrivacySettings_LastSeen: String { return self._s[2750]! } + public var OwnershipTransfer_SecurityRequirements: String { return self._s[2742]! } + public var InfoPlist_NSLocationAlwaysUsageDescription: String { return self._s[2744]! } + public var AutoNightTheme_Automatic: String { return self._s[2745]! } + public var Channel_Username_InvalidStartsWithNumber: String { return self._s[2746]! } + public var Privacy_ContactsSyncHelp: String { return self._s[2747]! } + public var Cache_Help: String { return self._s[2748]! } + public var Group_ErrorAccessDenied: String { return self._s[2749]! } + public var Passport_Language_fa: String { return self._s[2750]! } + public var Wallet_Intro_Text: String { return self._s[2751]! } + public var Login_ResetAccountProtected_TimerTitle: String { return self._s[2752]! } + public var VoiceOver_Chat_YourVideoMessage: String { return self._s[2753]! } + public var PrivacySettings_LastSeen: String { return self._s[2754]! } public func DialogList_MultipleTyping(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2751]!, self._r[2751]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2755]!, self._r[2755]!, [_0, _1]) } - public var Wallet_Configuration_Apply: String { return self._s[2755]! } - public var Preview_SaveGif: String { return self._s[2756]! } - public var SettingsSearch_Synonyms_Privacy_TwoStepAuth: String { return self._s[2757]! } - public var Profile_About: String { return self._s[2758]! } - public var Channel_About_Placeholder: String { return self._s[2759]! } - public var Login_InfoTitle: String { return self._s[2760]! } + public var Wallet_Configuration_Apply: String { return self._s[2759]! } + public var Preview_SaveGif: String { return self._s[2760]! } + public var SettingsSearch_Synonyms_Privacy_TwoStepAuth: String { return self._s[2761]! } + public var Profile_About: String { return self._s[2762]! } + public var Channel_About_Placeholder: String { return self._s[2763]! } + public var Login_InfoTitle: String { return self._s[2764]! } public func TwoStepAuth_SetupPendingEmail(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2761]!, self._r[2761]!, [_0]) + return formatWithArgumentRanges(self._s[2765]!, self._r[2765]!, [_0]) } - public var EditTheme_Expand_Preview_IncomingReplyText: String { return self._s[2762]! } - public var Watch_Suggestion_CantTalk: String { return self._s[2764]! } - public var ContactInfo_Title: String { return self._s[2765]! } - public var Media_ShareThisVideo: String { return self._s[2766]! } - public var Weekday_ShortFriday: String { return self._s[2767]! } - public var AccessDenied_Contacts: String { return self._s[2769]! } - public var Notification_CallIncomingShort: String { return self._s[2770]! } - public var Group_Setup_TypePublic: String { return self._s[2771]! } - public var Notifications_MessageNotificationsExceptions: String { return self._s[2772]! } - public var Notifications_Badge_IncludeChannels: String { return self._s[2773]! } - public var Notifications_MessageNotificationsPreview: String { return self._s[2776]! } - public var ConversationProfile_ErrorCreatingConversation: String { return self._s[2777]! } - public var Group_ErrorAddTooMuchBots: String { return self._s[2778]! } - public var Privacy_GroupsAndChannels_CustomShareHelp: String { return self._s[2779]! } - public var Permissions_CellularDataAllowInSettings_v0: String { return self._s[2780]! } + public var EditTheme_Expand_Preview_IncomingReplyText: String { return self._s[2766]! } + public var Watch_Suggestion_CantTalk: String { return self._s[2768]! } + public var ContactInfo_Title: String { return self._s[2769]! } + public var Media_ShareThisVideo: String { return self._s[2770]! } + public var Weekday_ShortFriday: String { return self._s[2771]! } + public var AccessDenied_Contacts: String { return self._s[2773]! } + public var Notification_CallIncomingShort: String { return self._s[2774]! } + public var Group_Setup_TypePublic: String { return self._s[2775]! } + public var Notifications_MessageNotificationsExceptions: String { return self._s[2776]! } + public var Notifications_Badge_IncludeChannels: String { return self._s[2777]! } + public var Notifications_MessageNotificationsPreview: String { return self._s[2780]! } + public var ConversationProfile_ErrorCreatingConversation: String { return self._s[2781]! } + public var Group_ErrorAddTooMuchBots: String { return self._s[2782]! } + public var Privacy_GroupsAndChannels_CustomShareHelp: String { return self._s[2783]! } + public var Permissions_CellularDataAllowInSettings_v0: String { return self._s[2784]! } public func Wallet_SecureStorageChanged_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2781]!, self._r[2781]!, [_0]) + return formatWithArgumentRanges(self._s[2785]!, self._r[2785]!, [_0]) } - public var DialogList_Typing: String { return self._s[2782]! } - public var CallFeedback_IncludeLogs: String { return self._s[2784]! } - public var Checkout_Phone: String { return self._s[2786]! } - public var Login_InfoFirstNamePlaceholder: String { return self._s[2789]! } - public var Privacy_Calls_Integration: String { return self._s[2790]! } - public var Notifications_PermissionsAllow: String { return self._s[2791]! } - public var TwoStepAuth_AddHintDescription: String { return self._s[2796]! } - public var Settings_ChatSettings: String { return self._s[2797]! } - public var Conversation_SendingOptionsTooltip: String { return self._s[2798]! } + public var DialogList_Typing: String { return self._s[2786]! } + public var CallFeedback_IncludeLogs: String { return self._s[2788]! } + public var Checkout_Phone: String { return self._s[2790]! } + public var Login_InfoFirstNamePlaceholder: String { return self._s[2793]! } + public var Privacy_Calls_Integration: String { return self._s[2794]! } + public var Notifications_PermissionsAllow: String { return self._s[2795]! } + public var TwoStepAuth_AddHintDescription: String { return self._s[2800]! } + public var Settings_ChatSettings: String { return self._s[2801]! } + public var Conversation_SendingOptionsTooltip: String { return self._s[2802]! } public func UserInfo_StartSecretChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2800]!, self._r[2800]!, [_0]) - } - public func Channel_AdminLog_MessageInvitedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2801]!, self._r[2801]!, [_1, _2]) - } - public var GroupRemoved_DeleteUser: String { return self._s[2803]! } - public func Channel_AdminLog_PollStopped(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2804]!, self._r[2804]!, [_0]) } + public func Channel_AdminLog_MessageInvitedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2805]!, self._r[2805]!, [_1, _2]) + } + public var GroupRemoved_DeleteUser: String { return self._s[2807]! } + public func Channel_AdminLog_PollStopped(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2808]!, self._r[2808]!, [_0]) + } public func PUSH_MESSAGE_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2805]!, self._r[2805]!, [_1]) + return formatWithArgumentRanges(self._s[2809]!, self._r[2809]!, [_1]) } - public var Login_ContinueWithLocalization: String { return self._s[2806]! } - public var Watch_Message_ForwardedFrom: String { return self._s[2807]! } - public var TwoStepAuth_EnterEmailCode: String { return self._s[2809]! } - public var Conversation_Unblock: String { return self._s[2810]! } - public var PrivacySettings_DataSettings: String { return self._s[2811]! } - public var WallpaperPreview_PatternPaternApply: String { return self._s[2812]! } - public var Group_PublicLink_Info: String { return self._s[2813]! } + public var Login_ContinueWithLocalization: String { return self._s[2810]! } + public var Watch_Message_ForwardedFrom: String { return self._s[2811]! } + public var TwoStepAuth_EnterEmailCode: String { return self._s[2813]! } + public var Conversation_Unblock: String { return self._s[2814]! } + public var PrivacySettings_DataSettings: String { return self._s[2815]! } + public var WallpaperPreview_PatternPaternApply: String { return self._s[2816]! } + public var Group_PublicLink_Info: String { return self._s[2817]! } public func Wallet_Time_PreciseDate_m1(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2814]!, self._r[2814]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2818]!, self._r[2818]!, [_1, _2, _3]) } - public var Notifications_InAppNotificationsVibrate: String { return self._s[2815]! } + public var Notifications_InAppNotificationsVibrate: String { return self._s[2819]! } public func Privacy_GroupsAndChannels_InviteToChannelError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2816]!, self._r[2816]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2820]!, self._r[2820]!, [_0, _1]) } - public var OldChannels_ChannelsHeader: String { return self._s[2818]! } - public var Wallet_RestoreFailed_CreateWallet: String { return self._s[2819]! } - public var PrivacySettings_Passcode: String { return self._s[2821]! } - public var Call_Mute: String { return self._s[2822]! } - public var Wallet_Weekday_Yesterday: String { return self._s[2823]! } - public var Passport_Language_dz: String { return self._s[2824]! } - public var Wallet_Receive_AmountHeader: String { return self._s[2825]! } - public var Wallet_TransactionInfo_OtherFeeInfoUrl: String { return self._s[2826]! } - public var Passport_Language_tk: String { return self._s[2827]! } + public var OldChannels_ChannelsHeader: String { return self._s[2822]! } + public var Wallet_RestoreFailed_CreateWallet: String { return self._s[2823]! } + public var PrivacySettings_Passcode: String { return self._s[2825]! } + public var Call_Mute: String { return self._s[2826]! } + public var Wallet_Weekday_Yesterday: String { return self._s[2827]! } + public var Passport_Language_dz: String { return self._s[2828]! } + public var Wallet_Receive_AmountHeader: String { return self._s[2829]! } + public var Wallet_TransactionInfo_OtherFeeInfoUrl: String { return self._s[2830]! } + public var Passport_Language_tk: String { return self._s[2831]! } public func Login_EmailCodeSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2828]!, self._r[2828]!, [_0]) + return formatWithArgumentRanges(self._s[2832]!, self._r[2832]!, [_0]) } - public var Settings_Search: String { return self._s[2829]! } - public var Wallet_Month_ShortFebruary: String { return self._s[2830]! } - public var InfoPlist_NSPhotoLibraryUsageDescription: String { return self._s[2831]! } - public var Wallet_Configuration_SourceJSON: String { return self._s[2832]! } - public var Conversation_ContextMenuReply: String { return self._s[2833]! } - public var WallpaperSearch_ColorBrown: String { return self._s[2834]! } - public var Chat_AttachmentMultipleForwardDisabled: String { return self._s[2835]! } - public var Tour_Title1: String { return self._s[2836]! } - public var Wallet_Alert_Cancel: String { return self._s[2837]! } - public var Conversation_ClearGroupHistory: String { return self._s[2839]! } - public var Wallet_TransactionInfo_RecipientHeader: String { return self._s[2840]! } - public var WallpaperPreview_Motion: String { return self._s[2841]! } + public var Settings_Search: String { return self._s[2833]! } + public var Wallet_Month_ShortFebruary: String { return self._s[2834]! } + public var InfoPlist_NSPhotoLibraryUsageDescription: String { return self._s[2835]! } + public var Wallet_Configuration_SourceJSON: String { return self._s[2836]! } + public var Conversation_ContextMenuReply: String { return self._s[2837]! } + public var WallpaperSearch_ColorBrown: String { return self._s[2838]! } + public var Chat_AttachmentMultipleForwardDisabled: String { return self._s[2839]! } + public var Tour_Title1: String { return self._s[2840]! } + public var Wallet_Alert_Cancel: String { return self._s[2841]! } + public var Conversation_ClearGroupHistory: String { return self._s[2843]! } + public var Wallet_TransactionInfo_RecipientHeader: String { return self._s[2844]! } + public var WallpaperPreview_Motion: String { return self._s[2845]! } public func Checkout_PasswordEntry_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2842]!, self._r[2842]!, [_0]) + return formatWithArgumentRanges(self._s[2846]!, self._r[2846]!, [_0]) } - public var Wallet_Configuration_ApplyErrorTextJSONInvalidData: String { return self._s[2843]! } - public var Call_RateCall: String { return self._s[2844]! } - public var Channel_AdminLog_BanSendStickersAndGifs: String { return self._s[2845]! } - public var Passport_PasswordCompleteSetup: String { return self._s[2846]! } - public var Conversation_InputTextSilentBroadcastPlaceholder: String { return self._s[2847]! } - public var UserInfo_LastNamePlaceholder: String { return self._s[2849]! } + public var Wallet_Configuration_ApplyErrorTextJSONInvalidData: String { return self._s[2847]! } + public var Call_RateCall: String { return self._s[2848]! } + public var Channel_AdminLog_BanSendStickersAndGifs: String { return self._s[2849]! } + public var Passport_PasswordCompleteSetup: String { return self._s[2850]! } + public var Conversation_InputTextSilentBroadcastPlaceholder: String { return self._s[2851]! } + public var UserInfo_LastNamePlaceholder: String { return self._s[2853]! } public func Login_WillCallYou(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2851]!, self._r[2851]!, [_0]) + return formatWithArgumentRanges(self._s[2855]!, self._r[2855]!, [_0]) } - public var Compose_Create: String { return self._s[2852]! } - public var Contacts_InviteToTelegram: String { return self._s[2853]! } - public var GroupInfo_Notifications: String { return self._s[2854]! } - public var ChatList_DeleteSavedMessagesConfirmationAction: String { return self._s[2856]! } - public var Message_PinnedLiveLocationMessage: String { return self._s[2857]! } - public var Month_GenApril: String { return self._s[2858]! } - public var Appearance_AutoNightTheme: String { return self._s[2859]! } - public var ChatSettings_AutomaticAudioDownload: String { return self._s[2861]! } - public var Login_CodeSentSms: String { return self._s[2863]! } + public var Compose_Create: String { return self._s[2856]! } + public var Contacts_InviteToTelegram: String { return self._s[2857]! } + public var GroupInfo_Notifications: String { return self._s[2858]! } + public var ChatList_DeleteSavedMessagesConfirmationAction: String { return self._s[2860]! } + public var Message_PinnedLiveLocationMessage: String { return self._s[2861]! } + public var Month_GenApril: String { return self._s[2862]! } + public var Appearance_AutoNightTheme: String { return self._s[2863]! } + public var ChatSettings_AutomaticAudioDownload: String { return self._s[2865]! } + public var Login_CodeSentSms: String { return self._s[2867]! } public func UserInfo_UnblockConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2864]!, self._r[2864]!, [_0]) + return formatWithArgumentRanges(self._s[2868]!, self._r[2868]!, [_0]) } - public var EmptyGroupInfo_Line3: String { return self._s[2865]! } - public var LogoutOptions_ContactSupportText: String { return self._s[2866]! } - public var Passport_Language_hr: String { return self._s[2867]! } - public var Common_ActionNotAllowedError: String { return self._s[2868]! } + public var EmptyGroupInfo_Line3: String { return self._s[2869]! } + public var LogoutOptions_ContactSupportText: String { return self._s[2870]! } + public var Passport_Language_hr: String { return self._s[2871]! } + public var Common_ActionNotAllowedError: String { return self._s[2872]! } public func Channel_AdminLog_MessageRestrictedNewSetting(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2869]!, self._r[2869]!, [_0]) + return formatWithArgumentRanges(self._s[2873]!, self._r[2873]!, [_0]) } - public var GroupInfo_InviteLink_CopyLink: String { return self._s[2870]! } - public var Wallet_Info_TransactionFrom: String { return self._s[2871]! } - public var Wallet_Send_ErrorDecryptionFailed: String { return self._s[2872]! } - public var Conversation_InputTextBroadcastPlaceholder: String { return self._s[2873]! } - public var Privacy_SecretChatsTitle: String { return self._s[2874]! } - public var Notification_SecretChatMessageScreenshotSelf: String { return self._s[2876]! } - public var GroupInfo_AddUserLeftError: String { return self._s[2877]! } - public var AutoDownloadSettings_TypePrivateChats: String { return self._s[2878]! } - public var LogoutOptions_ContactSupportTitle: String { return self._s[2879]! } - public var Appearance_ThemePreview_Chat_7_Text: String { return self._s[2880]! } - public var Channel_AddBotErrorHaveRights: String { return self._s[2881]! } - public var Preview_DeleteGif: String { return self._s[2882]! } - public var GroupInfo_Permissions_Exceptions: String { return self._s[2883]! } - public var Group_ErrorNotMutualContact: String { return self._s[2884]! } - public var Notification_MessageLifetime5s: String { return self._s[2885]! } - public var Wallet_Send_OwnAddressAlertText: String { return self._s[2886]! } - public var OldChannels_ChannelFormat: String { return self._s[2887]! } + public var GroupInfo_InviteLink_CopyLink: String { return self._s[2874]! } + public var Wallet_Info_TransactionFrom: String { return self._s[2875]! } + public var Wallet_Send_ErrorDecryptionFailed: String { return self._s[2876]! } + public var Conversation_InputTextBroadcastPlaceholder: String { return self._s[2877]! } + public var Privacy_SecretChatsTitle: String { return self._s[2878]! } + public var Notification_SecretChatMessageScreenshotSelf: String { return self._s[2880]! } + public var GroupInfo_AddUserLeftError: String { return self._s[2881]! } + public var AutoDownloadSettings_TypePrivateChats: String { return self._s[2882]! } + public var LogoutOptions_ContactSupportTitle: String { return self._s[2883]! } + public var Appearance_ThemePreview_Chat_7_Text: String { return self._s[2884]! } + public var Channel_AddBotErrorHaveRights: String { return self._s[2885]! } + public var Preview_DeleteGif: String { return self._s[2886]! } + public var GroupInfo_Permissions_Exceptions: String { return self._s[2887]! } + public var Group_ErrorNotMutualContact: String { return self._s[2888]! } + public var Notification_MessageLifetime5s: String { return self._s[2889]! } + public var Wallet_Send_OwnAddressAlertText: String { return self._s[2890]! } + public var OldChannels_ChannelFormat: String { return self._s[2891]! } public func Watch_LastSeen_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2888]!, self._r[2888]!, [_0]) + return formatWithArgumentRanges(self._s[2892]!, self._r[2892]!, [_0]) } - public var VoiceOver_Chat_Video: String { return self._s[2889]! } - public var Channel_OwnershipTransfer_ErrorPublicChannelsTooMuch: String { return self._s[2891]! } - public var ReportSpam_DeleteThisChat: String { return self._s[2892]! } - public var Passport_Address_AddBankStatement: String { return self._s[2893]! } - public var Notification_CallIncoming: String { return self._s[2894]! } - public var Wallet_Words_NotDoneTitle: String { return self._s[2895]! } - public var Compose_NewGroupTitle: String { return self._s[2896]! } - public var TwoStepAuth_RecoveryCodeHelp: String { return self._s[2898]! } - public var Passport_Address_Postcode: String { return self._s[2900]! } + public var VoiceOver_Chat_Video: String { return self._s[2893]! } + public var Channel_OwnershipTransfer_ErrorPublicChannelsTooMuch: String { return self._s[2895]! } + public var ReportSpam_DeleteThisChat: String { return self._s[2896]! } + public var Passport_Address_AddBankStatement: String { return self._s[2897]! } + public var Notification_CallIncoming: String { return self._s[2898]! } + public var Wallet_Words_NotDoneTitle: String { return self._s[2899]! } + public var Compose_NewGroupTitle: String { return self._s[2900]! } + public var TwoStepAuth_RecoveryCodeHelp: String { return self._s[2902]! } + public var Passport_Address_Postcode: String { return self._s[2904]! } public func LastSeen_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2901]!, self._r[2901]!, [_0]) + return formatWithArgumentRanges(self._s[2905]!, self._r[2905]!, [_0]) } - public var Checkout_NewCard_SaveInfoHelp: String { return self._s[2902]! } - public var Wallet_Month_ShortOctober: String { return self._s[2903]! } - public var VoiceOver_Chat_YourMusic: String { return self._s[2904]! } - public var WallpaperColors_Title: String { return self._s[2905]! } - public var SocksProxySetup_ShareQRCodeInfo: String { return self._s[2906]! } - public var VoiceOver_MessageContextForward: String { return self._s[2907]! } - public var GroupPermission_Duration: String { return self._s[2908]! } + public var Checkout_NewCard_SaveInfoHelp: String { return self._s[2906]! } + public var Wallet_Month_ShortOctober: String { return self._s[2907]! } + public var VoiceOver_Chat_YourMusic: String { return self._s[2908]! } + public var WallpaperColors_Title: String { return self._s[2909]! } + public var SocksProxySetup_ShareQRCodeInfo: String { return self._s[2910]! } + public var VoiceOver_MessageContextForward: String { return self._s[2911]! } + public var GroupPermission_Duration: String { return self._s[2912]! } public func Cache_Clear(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2909]!, self._r[2909]!, [_0]) + return formatWithArgumentRanges(self._s[2913]!, self._r[2913]!, [_0]) } - public var Bot_GroupStatusDoesNotReadHistory: String { return self._s[2910]! } - public var Username_Placeholder: String { return self._s[2911]! } - public var CallFeedback_WhatWentWrong: String { return self._s[2912]! } - public var Passport_FieldAddressUploadHelp: String { return self._s[2913]! } - public var Permissions_NotificationsAllowInSettings_v0: String { return self._s[2914]! } + public var Bot_GroupStatusDoesNotReadHistory: String { return self._s[2914]! } + public var Username_Placeholder: String { return self._s[2915]! } + public var CallFeedback_WhatWentWrong: String { return self._s[2916]! } + public var Passport_FieldAddressUploadHelp: String { return self._s[2917]! } + public var Permissions_NotificationsAllowInSettings_v0: String { return self._s[2918]! } public func Channel_AdminLog_MessageChangedUnlinkedChannel(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2916]!, self._r[2916]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2920]!, self._r[2920]!, [_1, _2]) } - public var Passport_PasswordDescription: String { return self._s[2917]! } - public var Channel_MessagePhotoUpdated: String { return self._s[2918]! } - public var MediaPicker_TapToUngroupDescription: String { return self._s[2919]! } - public var SettingsSearch_Synonyms_Notifications_BadgeCountUnreadMessages: String { return self._s[2920]! } - public var AttachmentMenu_PhotoOrVideo: String { return self._s[2921]! } - public var Conversation_ContextMenuMore: String { return self._s[2922]! } - public var Privacy_PaymentsClearInfo: String { return self._s[2923]! } - public var CallSettings_TabIcon: String { return self._s[2924]! } - public var KeyCommand_Find: String { return self._s[2925]! } - public var ClearCache_FreeSpaceDescription: String { return self._s[2926]! } - public var Appearance_ThemePreview_ChatList_7_Text: String { return self._s[2927]! } - public var EditTheme_Edit_Preview_IncomingText: String { return self._s[2928]! } - public var Message_PinnedGame: String { return self._s[2929]! } - public var VoiceOver_Chat_ForwardedFromYou: String { return self._s[2930]! } - public var Notifications_Badge_CountUnreadMessages_InfoOff: String { return self._s[2932]! } - public var Login_CallRequestState2: String { return self._s[2934]! } - public var CheckoutInfo_ReceiverInfoNamePlaceholder: String { return self._s[2936]! } + public var Passport_PasswordDescription: String { return self._s[2921]! } + public var Channel_MessagePhotoUpdated: String { return self._s[2922]! } + public var MediaPicker_TapToUngroupDescription: String { return self._s[2923]! } + public var SettingsSearch_Synonyms_Notifications_BadgeCountUnreadMessages: String { return self._s[2924]! } + public var AttachmentMenu_PhotoOrVideo: String { return self._s[2925]! } + public var Conversation_ContextMenuMore: String { return self._s[2926]! } + public var Privacy_PaymentsClearInfo: String { return self._s[2927]! } + public var CallSettings_TabIcon: String { return self._s[2928]! } + public var KeyCommand_Find: String { return self._s[2929]! } + public var ClearCache_FreeSpaceDescription: String { return self._s[2930]! } + public var Appearance_ThemePreview_ChatList_7_Text: String { return self._s[2931]! } + public var EditTheme_Edit_Preview_IncomingText: String { return self._s[2932]! } + public var Message_PinnedGame: String { return self._s[2933]! } + public var VoiceOver_Chat_ForwardedFromYou: String { return self._s[2934]! } + public var Notifications_Badge_CountUnreadMessages_InfoOff: String { return self._s[2936]! } + public var Login_CallRequestState2: String { return self._s[2938]! } + public var CheckoutInfo_ReceiverInfoNamePlaceholder: String { return self._s[2940]! } public func VoiceOver_Chat_PhotoFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2937]!, self._r[2937]!, [_0]) + return formatWithArgumentRanges(self._s[2941]!, self._r[2941]!, [_0]) } public func Checkout_PayPrice(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2939]!, self._r[2939]!, [_0]) - } - public var AuthSessions_AddDevice: String { return self._s[2940]! } - public var WallpaperPreview_Blurred: String { return self._s[2941]! } - public var Conversation_InstantPagePreview: String { return self._s[2942]! } - public func DialogList_SingleUploadingVideoSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2943]!, self._r[2943]!, [_0]) } - public var SecretTimer_VideoDescription: String { return self._s[2946]! } - public var WallpaperSearch_ColorRed: String { return self._s[2947]! } - public var GroupPermission_NoPinMessages: String { return self._s[2948]! } - public var Passport_Language_es: String { return self._s[2949]! } - public var Permissions_ContactsAllow_v0: String { return self._s[2951]! } - public var Conversation_EditingMessageMediaEditCurrentVideo: String { return self._s[2952]! } + public var AuthSessions_AddDevice: String { return self._s[2944]! } + public var WallpaperPreview_Blurred: String { return self._s[2945]! } + public var Conversation_InstantPagePreview: String { return self._s[2946]! } + public var PeerInfo_ButtonUnmute: String { return self._s[2947]! } + public func DialogList_SingleUploadingVideoSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2948]!, self._r[2948]!, [_0]) + } + public var SecretTimer_VideoDescription: String { return self._s[2951]! } + public var WallpaperSearch_ColorRed: String { return self._s[2952]! } + public var GroupPermission_NoPinMessages: String { return self._s[2953]! } + public var Passport_Language_es: String { return self._s[2954]! } + public var Permissions_ContactsAllow_v0: String { return self._s[2956]! } + public var Conversation_EditingMessageMediaEditCurrentVideo: String { return self._s[2957]! } public func PUSH_CHAT_MESSAGE_CONTACT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2953]!, self._r[2953]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2958]!, self._r[2958]!, [_1, _2]) } - public var Privacy_Forwards_CustomHelp: String { return self._s[2954]! } - public var WebPreview_GettingLinkInfo: String { return self._s[2955]! } - public var Watch_UserInfo_Unmute: String { return self._s[2956]! } - public var GroupInfo_ChannelListNamePlaceholder: String { return self._s[2957]! } - public var AccessDenied_CameraRestricted: String { return self._s[2959]! } + public var Privacy_Forwards_CustomHelp: String { return self._s[2959]! } + public var WebPreview_GettingLinkInfo: String { return self._s[2960]! } + public var Watch_UserInfo_Unmute: String { return self._s[2961]! } + public var GroupInfo_ChannelListNamePlaceholder: String { return self._s[2962]! } + public var AccessDenied_CameraRestricted: String { return self._s[2964]! } public func Conversation_Kilobytes(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2960]!, self._r[2960]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[2965]!, self._r[2965]!, ["\(_0)"]) } - public var ChatList_ReadAll: String { return self._s[2962]! } - public var Settings_CopyUsername: String { return self._s[2963]! } - public var Contacts_SearchLabel: String { return self._s[2964]! } - public var Map_OpenInYandexNavigator: String { return self._s[2966]! } - public var PasscodeSettings_EncryptData: String { return self._s[2967]! } - public var Settings_Wallet: String { return self._s[2968]! } - public var Group_ErrorSupergroupConversionNotPossible: String { return self._s[2969]! } - public var WallpaperSearch_ColorPrefix: String { return self._s[2970]! } - public var Notifications_GroupNotificationsPreview: String { return self._s[2971]! } - public var DialogList_AdNoticeAlert: String { return self._s[2972]! } - public var Wallet_Month_GenMay: String { return self._s[2974]! } - public var CheckoutInfo_ShippingInfoAddress1: String { return self._s[2975]! } - public var CheckoutInfo_ShippingInfoAddress2: String { return self._s[2976]! } - public var Localization_LanguageCustom: String { return self._s[2977]! } - public var Passport_Identity_TypeDriversLicenseUploadScan: String { return self._s[2978]! } - public var CallFeedback_Title: String { return self._s[2979]! } - public var VoiceOver_Chat_RecordPreviewVoiceMessage: String { return self._s[2982]! } - public var Passport_Address_OneOfTypePassportRegistration: String { return self._s[2983]! } - public var Wallet_Intro_CreateErrorTitle: String { return self._s[2984]! } - public var Conversation_InfoGroup: String { return self._s[2985]! } - public var Compose_NewMessage: String { return self._s[2986]! } - public var FastTwoStepSetup_HintPlaceholder: String { return self._s[2987]! } - public var ChatSettings_AutoDownloadVideoMessages: String { return self._s[2988]! } - public var Wallet_SecureStorageReset_BiometryFaceId: String { return self._s[2989]! } - public var Channel_DiscussionGroup_UnlinkChannel: String { return self._s[2990]! } + public var ChatList_ReadAll: String { return self._s[2967]! } + public var Settings_CopyUsername: String { return self._s[2968]! } + public var Contacts_SearchLabel: String { return self._s[2969]! } + public var Map_OpenInYandexNavigator: String { return self._s[2971]! } + public var PasscodeSettings_EncryptData: String { return self._s[2972]! } + public var Settings_Wallet: String { return self._s[2973]! } + public var Group_ErrorSupergroupConversionNotPossible: String { return self._s[2974]! } + public var WallpaperSearch_ColorPrefix: String { return self._s[2975]! } + public var Notifications_GroupNotificationsPreview: String { return self._s[2976]! } + public var DialogList_AdNoticeAlert: String { return self._s[2977]! } + public var Wallet_Month_GenMay: String { return self._s[2979]! } + public var CheckoutInfo_ShippingInfoAddress1: String { return self._s[2980]! } + public var CheckoutInfo_ShippingInfoAddress2: String { return self._s[2981]! } + public var Localization_LanguageCustom: String { return self._s[2982]! } + public var Passport_Identity_TypeDriversLicenseUploadScan: String { return self._s[2983]! } + public var CallFeedback_Title: String { return self._s[2984]! } + public var VoiceOver_Chat_RecordPreviewVoiceMessage: String { return self._s[2987]! } + public var Passport_Address_OneOfTypePassportRegistration: String { return self._s[2988]! } + public var Wallet_Intro_CreateErrorTitle: String { return self._s[2989]! } + public var Conversation_InfoGroup: String { return self._s[2990]! } + public var Compose_NewMessage: String { return self._s[2991]! } + public var FastTwoStepSetup_HintPlaceholder: String { return self._s[2992]! } + public var ChatSettings_AutoDownloadVideoMessages: String { return self._s[2993]! } + public var Wallet_SecureStorageReset_BiometryFaceId: String { return self._s[2994]! } + public var Channel_DiscussionGroup_UnlinkChannel: String { return self._s[2995]! } public func Passport_Scans_ScanIndex(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2991]!, self._r[2991]!, [_0]) + return formatWithArgumentRanges(self._s[2996]!, self._r[2996]!, [_0]) } - public var Channel_AdminLog_CanDeleteMessages: String { return self._s[2992]! } - public var Login_CancelSignUpConfirmation: String { return self._s[2993]! } - public var ChangePhoneNumberCode_Help: String { return self._s[2994]! } - public var PrivacySettings_DeleteAccountHelp: String { return self._s[2995]! } - public var Channel_BlackList_Title: String { return self._s[2996]! } - public var UserInfo_PhoneCall: String { return self._s[2997]! } - public var Passport_Address_OneOfTypeBankStatement: String { return self._s[2999]! } - public var Wallet_Month_ShortJanuary: String { return self._s[3000]! } - public var State_connecting: String { return self._s[3001]! } - public var Appearance_ThemePreview_ChatList_6_Text: String { return self._s[3002]! } - public var Wallet_Month_GenMarch: String { return self._s[3003]! } - public var EditTheme_Expand_BottomInfo: String { return self._s[3004]! } - public var AuthSessions_AddedDeviceTerminate: String { return self._s[3005]! } + public var Channel_AdminLog_CanDeleteMessages: String { return self._s[2997]! } + public var Login_CancelSignUpConfirmation: String { return self._s[2998]! } + public var ChangePhoneNumberCode_Help: String { return self._s[2999]! } + public var PrivacySettings_DeleteAccountHelp: String { return self._s[3000]! } + public var Channel_BlackList_Title: String { return self._s[3001]! } + public var UserInfo_PhoneCall: String { return self._s[3002]! } + public var Passport_Address_OneOfTypeBankStatement: String { return self._s[3004]! } + public var Wallet_Month_ShortJanuary: String { return self._s[3005]! } + public var State_connecting: String { return self._s[3006]! } + public var Appearance_ThemePreview_ChatList_6_Text: String { return self._s[3007]! } + public var Wallet_Month_GenMarch: String { return self._s[3008]! } + public var EditTheme_Expand_BottomInfo: String { return self._s[3009]! } + public var AuthSessions_AddedDeviceTerminate: String { return self._s[3010]! } public func LastSeen_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3006]!, self._r[3006]!, [_0]) + return formatWithArgumentRanges(self._s[3011]!, self._r[3011]!, [_0]) } public func DialogList_SingleRecordingAudioSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3007]!, self._r[3007]!, [_0]) + return formatWithArgumentRanges(self._s[3012]!, self._r[3012]!, [_0]) } - public var Notifications_GroupNotifications: String { return self._s[3008]! } - public var Conversation_SendMessageErrorTooMuchScheduled: String { return self._s[3009]! } - public var Passport_Identity_EditPassport: String { return self._s[3010]! } - public var EnterPasscode_RepeatNewPasscode: String { return self._s[3012]! } - public var Localization_EnglishLanguageName: String { return self._s[3013]! } - public var Share_AuthDescription: String { return self._s[3014]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsAlert: String { return self._s[3015]! } - public var Passport_Identity_Surname: String { return self._s[3016]! } - public var Compose_TokenListPlaceholder: String { return self._s[3017]! } - public var Wallet_AccessDenied_Camera: String { return self._s[3018]! } - public var Passport_Identity_OneOfTypePassport: String { return self._s[3019]! } - public var Settings_AboutEmpty: String { return self._s[3020]! } - public var Conversation_Unmute: String { return self._s[3021]! } - public var CreateGroup_ChannelsTooMuch: String { return self._s[3023]! } - public var Wallet_Sending_Text: String { return self._s[3024]! } + public var Notifications_GroupNotifications: String { return self._s[3013]! } + public var Conversation_SendMessageErrorTooMuchScheduled: String { return self._s[3014]! } + public var Passport_Identity_EditPassport: String { return self._s[3015]! } + public var EnterPasscode_RepeatNewPasscode: String { return self._s[3017]! } + public var Localization_EnglishLanguageName: String { return self._s[3018]! } + public var Share_AuthDescription: String { return self._s[3019]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsAlert: String { return self._s[3020]! } + public var Passport_Identity_Surname: String { return self._s[3021]! } + public var Compose_TokenListPlaceholder: String { return self._s[3022]! } + public var Wallet_AccessDenied_Camera: String { return self._s[3023]! } + public var Passport_Identity_OneOfTypePassport: String { return self._s[3024]! } + public var Settings_AboutEmpty: String { return self._s[3025]! } + public var Conversation_Unmute: String { return self._s[3026]! } + public var CreateGroup_ChannelsTooMuch: String { return self._s[3028]! } + public var Wallet_Sending_Text: String { return self._s[3029]! } public func PUSH_CONTACT_JOINED(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3025]!, self._r[3025]!, [_1]) + return formatWithArgumentRanges(self._s[3030]!, self._r[3030]!, [_1]) } - public var Login_CodeSentCall: String { return self._s[3026]! } - public var ContactInfo_PhoneLabelHomeFax: String { return self._s[3028]! } - public var ChatSettings_Appearance: String { return self._s[3029]! } - public var ClearCache_StorageUsage: String { return self._s[3030]! } - public var Appearance_PickAccentColor: String { return self._s[3031]! } + public var Login_CodeSentCall: String { return self._s[3031]! } + public var ContactInfo_PhoneLabelHomeFax: String { return self._s[3033]! } + public var ChatSettings_Appearance: String { return self._s[3034]! } + public var ClearCache_StorageUsage: String { return self._s[3035]! } + public var Appearance_PickAccentColor: String { return self._s[3036]! } public func PUSH_CHAT_MESSAGE_NOTEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3032]!, self._r[3032]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3037]!, self._r[3037]!, [_1, _2]) } public func PUSH_MESSAGE_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3033]!, self._r[3033]!, [_1]) + return formatWithArgumentRanges(self._s[3038]!, self._r[3038]!, [_1]) } - public var Notification_CallMissed: String { return self._s[3034]! } - public var SettingsSearch_Synonyms_Appearance_ChatBackground_Custom: String { return self._s[3035]! } - public var Channel_AdminLogFilter_EventsInfo: String { return self._s[3036]! } - public var Wallet_Month_GenOctober: String { return self._s[3038]! } - public var ChatAdmins_AdminLabel: String { return self._s[3039]! } - public var KeyCommand_JumpToNextChat: String { return self._s[3040]! } - public var Conversation_StopPollConfirmationTitle: String { return self._s[3042]! } - public var ChangePhoneNumberCode_CodePlaceholder: String { return self._s[3043]! } - public var Month_GenJune: String { return self._s[3044]! } - public var IntentsSettings_MainAccountInfo: String { return self._s[3045]! } - public var Watch_Location_Current: String { return self._s[3046]! } - public var Wallet_Receive_CopyInvoiceUrl: String { return self._s[3047]! } - public var Conversation_TitleMute: String { return self._s[3048]! } - public var Map_PlacesInThisArea: String { return self._s[3049]! } + public var Notification_CallMissed: String { return self._s[3039]! } + public var SettingsSearch_Synonyms_Appearance_ChatBackground_Custom: String { return self._s[3040]! } + public var Channel_AdminLogFilter_EventsInfo: String { return self._s[3041]! } + public var Wallet_Month_GenOctober: String { return self._s[3043]! } + public var ChatAdmins_AdminLabel: String { return self._s[3044]! } + public var KeyCommand_JumpToNextChat: String { return self._s[3045]! } + public var Conversation_StopPollConfirmationTitle: String { return self._s[3047]! } + public var ChangePhoneNumberCode_CodePlaceholder: String { return self._s[3048]! } + public var Month_GenJune: String { return self._s[3049]! } + public var IntentsSettings_MainAccountInfo: String { return self._s[3050]! } + public var Watch_Location_Current: String { return self._s[3051]! } + public var Wallet_Receive_CopyInvoiceUrl: String { return self._s[3052]! } + public var Conversation_TitleMute: String { return self._s[3053]! } + public var Map_PlacesInThisArea: String { return self._s[3054]! } public func PUSH_CHANNEL_MESSAGE_ROUND(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3050]!, self._r[3050]!, [_1]) + return formatWithArgumentRanges(self._s[3055]!, self._r[3055]!, [_1]) } - public var GroupInfo_DeleteAndExit: String { return self._s[3051]! } + public var GroupInfo_DeleteAndExit: String { return self._s[3056]! } public func Conversation_Moderate_DeleteAllMessages(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3052]!, self._r[3052]!, [_0]) - } - public var Call_ReportPlaceholder: String { return self._s[3053]! } - public var Chat_SlowmodeSendError: String { return self._s[3054]! } - public var MaskStickerSettings_Info: String { return self._s[3055]! } - public var EditTheme_Expand_TopInfo: String { return self._s[3056]! } - public func GroupInfo_AddParticipantConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3057]!, self._r[3057]!, [_0]) } - public var Checkout_NewCard_PostcodeTitle: String { return self._s[3058]! } - public var Passport_Address_RegionPlaceholder: String { return self._s[3060]! } - public var Contacts_ShareTelegram: String { return self._s[3061]! } - public var EnterPasscode_EnterNewPasscodeNew: String { return self._s[3062]! } - public var Map_AddressOnMap: String { return self._s[3063]! } - public var Channel_ErrorAccessDenied: String { return self._s[3064]! } - public var UserInfo_ScamBotWarning: String { return self._s[3066]! } - public var Stickers_GroupChooseStickerPack: String { return self._s[3067]! } - public var Call_ConnectionErrorTitle: String { return self._s[3068]! } - public var UserInfo_NotificationsEnable: String { return self._s[3069]! } - public var ArchivedChats_IntroText1: String { return self._s[3070]! } - public var Tour_Text4: String { return self._s[3073]! } - public var WallpaperSearch_Recent: String { return self._s[3074]! } - public var GroupInfo_ScamGroupWarning: String { return self._s[3075]! } - public var PeopleNearby_MakeVisibleTitle: String { return self._s[3076]! } - public var Profile_MessageLifetime2s: String { return self._s[3078]! } - public var Appearance_ThemePreview_ChatList_5_Text: String { return self._s[3079]! } - public var Notification_MessageLifetime2s: String { return self._s[3080]! } - public func Time_PreciseDate_m10(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3081]!, self._r[3081]!, [_1, _2, _3]) + public var Call_ReportPlaceholder: String { return self._s[3058]! } + public var Chat_SlowmodeSendError: String { return self._s[3059]! } + public var MaskStickerSettings_Info: String { return self._s[3060]! } + public var EditTheme_Expand_TopInfo: String { return self._s[3061]! } + public func GroupInfo_AddParticipantConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3062]!, self._r[3062]!, [_0]) } - public var Cache_ClearCache: String { return self._s[3082]! } - public var AutoNightTheme_UpdateLocation: String { return self._s[3083]! } - public var Permissions_NotificationsUnreachableText_v0: String { return self._s[3084]! } + public var Checkout_NewCard_PostcodeTitle: String { return self._s[3063]! } + public var Passport_Address_RegionPlaceholder: String { return self._s[3065]! } + public var Contacts_ShareTelegram: String { return self._s[3066]! } + public var EnterPasscode_EnterNewPasscodeNew: String { return self._s[3067]! } + public var Map_AddressOnMap: String { return self._s[3068]! } + public var Channel_ErrorAccessDenied: String { return self._s[3069]! } + public var UserInfo_ScamBotWarning: String { return self._s[3071]! } + public var Stickers_GroupChooseStickerPack: String { return self._s[3072]! } + public var Call_ConnectionErrorTitle: String { return self._s[3073]! } + public var UserInfo_NotificationsEnable: String { return self._s[3074]! } + public var ArchivedChats_IntroText1: String { return self._s[3075]! } + public var Tour_Text4: String { return self._s[3078]! } + public var WallpaperSearch_Recent: String { return self._s[3079]! } + public var GroupInfo_ScamGroupWarning: String { return self._s[3080]! } + public var PeopleNearby_MakeVisibleTitle: String { return self._s[3081]! } + public var Profile_MessageLifetime2s: String { return self._s[3083]! } + public var Appearance_ThemePreview_ChatList_5_Text: String { return self._s[3084]! } + public var Notification_MessageLifetime2s: String { return self._s[3085]! } + public func Time_PreciseDate_m10(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3086]!, self._r[3086]!, [_1, _2, _3]) + } + public var Cache_ClearCache: String { return self._s[3087]! } + public var AutoNightTheme_UpdateLocation: String { return self._s[3088]! } + public var Permissions_NotificationsUnreachableText_v0: String { return self._s[3089]! } public func Channel_AdminLog_MessageChangedGroupUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3088]!, self._r[3088]!, [_0]) + return formatWithArgumentRanges(self._s[3093]!, self._r[3093]!, [_0]) } public func Conversation_ShareMyPhoneNumber_StatusSuccess(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3090]!, self._r[3090]!, [_0]) + return formatWithArgumentRanges(self._s[3095]!, self._r[3095]!, [_0]) } - public var LocalGroup_Text: String { return self._s[3091]! } - public var Channel_AdminLog_EmptyFilterTitle: String { return self._s[3092]! } - public var SocksProxySetup_TypeSocks: String { return self._s[3093]! } - public var ChatList_UnarchiveAction: String { return self._s[3094]! } - public var AutoNightTheme_Title: String { return self._s[3095]! } - public var InstantPage_FeedbackButton: String { return self._s[3096]! } - public var Passport_FieldAddress: String { return self._s[3097]! } + public var LocalGroup_Text: String { return self._s[3096]! } + public var Channel_AdminLog_EmptyFilterTitle: String { return self._s[3097]! } + public var SocksProxySetup_TypeSocks: String { return self._s[3098]! } + public var ChatList_UnarchiveAction: String { return self._s[3099]! } + public var AutoNightTheme_Title: String { return self._s[3100]! } + public var InstantPage_FeedbackButton: String { return self._s[3101]! } + public var Passport_FieldAddress: String { return self._s[3102]! } public func Channel_AdminLog_SetSlowmode(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3098]!, self._r[3098]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3103]!, self._r[3103]!, [_1, _2]) } - public var Month_ShortMarch: String { return self._s[3099]! } + public var Month_ShortMarch: String { return self._s[3104]! } public func PUSH_MESSAGE_INVOICE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3100]!, self._r[3100]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3105]!, self._r[3105]!, [_1, _2]) } - public var SocksProxySetup_UsernamePlaceholder: String { return self._s[3101]! } - public var Conversation_ShareInlineBotLocationConfirmation: String { return self._s[3102]! } - public var Passport_FloodError: String { return self._s[3103]! } - public var SecretGif_Title: String { return self._s[3104]! } - public var NotificationSettings_ShowNotificationsAllAccountsInfoOn: String { return self._s[3105]! } - public var ChatList_Context_UnhideArchive: String { return self._s[3106]! } - public var Passport_Language_th: String { return self._s[3108]! } - public var Passport_Address_Address: String { return self._s[3109]! } - public var Login_InvalidLastNameError: String { return self._s[3110]! } - public var Notifications_InAppNotificationsPreview: String { return self._s[3111]! } - public var Notifications_PermissionsUnreachableTitle: String { return self._s[3112]! } - public var ChatList_Context_Archive: String { return self._s[3113]! } - public var SettingsSearch_FAQ: String { return self._s[3114]! } - public var ShareMenu_Send: String { return self._s[3115]! } - public var ChatState_Connecting: String { return self._s[3116]! } - public var WallpaperSearch_ColorYellow: String { return self._s[3118]! } - public var Month_GenNovember: String { return self._s[3120]! } - public var SettingsSearch_Synonyms_Appearance_LargeEmoji: String { return self._s[3122]! } + public var SocksProxySetup_UsernamePlaceholder: String { return self._s[3106]! } + public var Conversation_ShareInlineBotLocationConfirmation: String { return self._s[3107]! } + public var Passport_FloodError: String { return self._s[3108]! } + public var SecretGif_Title: String { return self._s[3109]! } + public var NotificationSettings_ShowNotificationsAllAccountsInfoOn: String { return self._s[3110]! } + public var ChatList_Context_UnhideArchive: String { return self._s[3111]! } + public var Passport_Language_th: String { return self._s[3113]! } + public var Passport_Address_Address: String { return self._s[3114]! } + public var Login_InvalidLastNameError: String { return self._s[3115]! } + public var Notifications_InAppNotificationsPreview: String { return self._s[3116]! } + public var Notifications_PermissionsUnreachableTitle: String { return self._s[3117]! } + public var ChatList_Context_Archive: String { return self._s[3118]! } + public var SettingsSearch_FAQ: String { return self._s[3119]! } + public var ShareMenu_Send: String { return self._s[3120]! } + public var ChatState_Connecting: String { return self._s[3121]! } + public var WallpaperSearch_ColorYellow: String { return self._s[3123]! } + public var Month_GenNovember: String { return self._s[3125]! } + public var SettingsSearch_Synonyms_Appearance_LargeEmoji: String { return self._s[3127]! } public func Conversation_ShareMyPhoneNumberConfirmation(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3123]!, self._r[3123]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3128]!, self._r[3128]!, [_1, _2]) } - public var Conversation_SwipeToReplyHintText: String { return self._s[3124]! } - public var Checkout_Email: String { return self._s[3125]! } - public var NotificationsSound_Tritone: String { return self._s[3126]! } - public var StickerPacksSettings_ManagingHelp: String { return self._s[3128]! } - public var Wallet_ContextMenuCopy: String { return self._s[3130]! } + public var Conversation_SwipeToReplyHintText: String { return self._s[3129]! } + public var Checkout_Email: String { return self._s[3130]! } + public var NotificationsSound_Tritone: String { return self._s[3131]! } + public var StickerPacksSettings_ManagingHelp: String { return self._s[3133]! } + public var Wallet_ContextMenuCopy: String { return self._s[3135]! } public func Wallet_Time_PreciseDate_m6(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3132]!, self._r[3132]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3137]!, self._r[3137]!, [_1, _2, _3]) } - public var Appearance_TextSize_Automatic: String { return self._s[3133]! } + public var Appearance_TextSize_Automatic: String { return self._s[3138]! } public func PUSH_PINNED_ROUND(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3134]!, self._r[3134]!, [_1]) + return formatWithArgumentRanges(self._s[3139]!, self._r[3139]!, [_1]) } public func StickerPackActionInfo_AddedText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3135]!, self._r[3135]!, [_0]) + return formatWithArgumentRanges(self._s[3140]!, self._r[3140]!, [_0]) } - public var ChangePhoneNumberNumber_Help: String { return self._s[3136]! } + public var ChangePhoneNumberNumber_Help: String { return self._s[3141]! } public func Checkout_LiabilityAlert(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3137]!, self._r[3137]!, [_1, _1, _1, _2]) + return formatWithArgumentRanges(self._s[3142]!, self._r[3142]!, [_1, _1, _1, _2]) } - public var ChatList_UndoArchiveTitle: String { return self._s[3138]! } - public var Notification_Exceptions_Add: String { return self._s[3139]! } - public var DialogList_You: String { return self._s[3140]! } - public var MediaPicker_Send: String { return self._s[3143]! } - public var SettingsSearch_Synonyms_Stickers_Title: String { return self._s[3144]! } - public var Appearance_ThemePreview_ChatList_4_Text: String { return self._s[3145]! } - public var Call_AudioRouteSpeaker: String { return self._s[3146]! } - public var Watch_UserInfo_Title: String { return self._s[3147]! } - public var VoiceOver_Chat_PollFinalResults: String { return self._s[3148]! } - public var Appearance_AccentColor: String { return self._s[3150]! } + public var ChatList_UndoArchiveTitle: String { return self._s[3143]! } + public var Notification_Exceptions_Add: String { return self._s[3144]! } + public var DialogList_You: String { return self._s[3145]! } + public var MediaPicker_Send: String { return self._s[3148]! } + public var SettingsSearch_Synonyms_Stickers_Title: String { return self._s[3149]! } + public var Appearance_ThemePreview_ChatList_4_Text: String { return self._s[3150]! } + public var Call_AudioRouteSpeaker: String { return self._s[3151]! } + public var Watch_UserInfo_Title: String { return self._s[3152]! } + public var VoiceOver_Chat_PollFinalResults: String { return self._s[3153]! } + public var Appearance_AccentColor: String { return self._s[3155]! } public func Login_EmailPhoneSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3151]!, self._r[3151]!, [_0]) + return formatWithArgumentRanges(self._s[3156]!, self._r[3156]!, [_0]) } - public var Permissions_ContactsAllowInSettings_v0: String { return self._s[3152]! } + public var Permissions_ContactsAllowInSettings_v0: String { return self._s[3157]! } public func PUSH_CHANNEL_MESSAGE_GAME(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3153]!, self._r[3153]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3158]!, self._r[3158]!, [_1, _2]) } - public var Conversation_ClousStorageInfo_Description2: String { return self._s[3154]! } - public var WebSearch_RecentClearConfirmation: String { return self._s[3155]! } - public var Notification_CallOutgoing: String { return self._s[3156]! } - public var PrivacySettings_PasscodeAndFaceId: String { return self._s[3157]! } - public var Channel_DiscussionGroup_MakeHistoryPublic: String { return self._s[3158]! } - public var Call_RecordingDisabledMessage: String { return self._s[3159]! } - public var Message_Game: String { return self._s[3160]! } - public var Conversation_PressVolumeButtonForSound: String { return self._s[3161]! } - public var PrivacyLastSeenSettings_CustomHelp: String { return self._s[3162]! } - public var Channel_DiscussionGroup_PrivateGroup: String { return self._s[3163]! } - public var Channel_EditAdmin_PermissionAddAdmins: String { return self._s[3164]! } - public var Date_DialogDateFormat: String { return self._s[3166]! } - public var WallpaperColors_SetCustomColor: String { return self._s[3167]! } - public var Notifications_InAppNotifications: String { return self._s[3168]! } + public var Conversation_ClousStorageInfo_Description2: String { return self._s[3159]! } + public var WebSearch_RecentClearConfirmation: String { return self._s[3160]! } + public var Notification_CallOutgoing: String { return self._s[3161]! } + public var PrivacySettings_PasscodeAndFaceId: String { return self._s[3162]! } + public var Channel_DiscussionGroup_MakeHistoryPublic: String { return self._s[3163]! } + public var Call_RecordingDisabledMessage: String { return self._s[3164]! } + public var Message_Game: String { return self._s[3165]! } + public var Conversation_PressVolumeButtonForSound: String { return self._s[3166]! } + public var PrivacyLastSeenSettings_CustomHelp: String { return self._s[3167]! } + public var Channel_DiscussionGroup_PrivateGroup: String { return self._s[3168]! } + public var Channel_EditAdmin_PermissionAddAdmins: String { return self._s[3169]! } + public var Date_DialogDateFormat: String { return self._s[3171]! } + public var WallpaperColors_SetCustomColor: String { return self._s[3172]! } + public var Notifications_InAppNotifications: String { return self._s[3173]! } public func Channel_Management_RemovedBy(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3169]!, self._r[3169]!, [_0]) + return formatWithArgumentRanges(self._s[3174]!, self._r[3174]!, [_0]) } public func Settings_ApplyProxyAlert(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3170]!, self._r[3170]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3175]!, self._r[3175]!, [_1, _2]) } - public var NewContact_Title: String { return self._s[3171]! } + public var NewContact_Title: String { return self._s[3176]! } public func AutoDownloadSettings_UpToForAll(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3172]!, self._r[3172]!, [_0]) + return formatWithArgumentRanges(self._s[3177]!, self._r[3177]!, [_0]) } - public var Conversation_ViewContactDetails: String { return self._s[3173]! } + public var Conversation_ViewContactDetails: String { return self._s[3178]! } public func PUSH_CHANNEL_MESSAGE_CONTACT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3175]!, self._r[3175]!, [_1]) + return formatWithArgumentRanges(self._s[3180]!, self._r[3180]!, [_1]) } - public var Checkout_NewCard_CardholderNameTitle: String { return self._s[3176]! } - public var Passport_Identity_ExpiryDateNone: String { return self._s[3177]! } - public var PrivacySettings_Title: String { return self._s[3178]! } - public var Conversation_SilentBroadcastTooltipOff: String { return self._s[3181]! } - public var GroupRemoved_UsersSectionTitle: String { return self._s[3182]! } - public var VoiceOver_Chat_ContactEmail: String { return self._s[3183]! } - public var Contacts_PhoneNumber: String { return self._s[3184]! } - public var TwoFactorSetup_Password_PlaceholderConfirmPassword: String { return self._s[3186]! } - public var Map_ShowPlaces: String { return self._s[3187]! } - public var ChatAdmins_Title: String { return self._s[3188]! } - public var InstantPage_Reference: String { return self._s[3190]! } - public var Wallet_Info_Updating: String { return self._s[3191]! } - public var ReportGroupLocation_Text: String { return self._s[3192]! } + public var Checkout_NewCard_CardholderNameTitle: String { return self._s[3181]! } + public var Passport_Identity_ExpiryDateNone: String { return self._s[3182]! } + public var PrivacySettings_Title: String { return self._s[3183]! } + public var Conversation_SilentBroadcastTooltipOff: String { return self._s[3186]! } + public var GroupRemoved_UsersSectionTitle: String { return self._s[3187]! } + public var VoiceOver_Chat_ContactEmail: String { return self._s[3188]! } + public var Contacts_PhoneNumber: String { return self._s[3189]! } + public var PeerInfo_ButtonMute: String { return self._s[3190]! } + public var TwoFactorSetup_Password_PlaceholderConfirmPassword: String { return self._s[3192]! } + public var Map_ShowPlaces: String { return self._s[3193]! } + public var ChatAdmins_Title: String { return self._s[3194]! } + public var InstantPage_Reference: String { return self._s[3196]! } + public var Wallet_Info_Updating: String { return self._s[3197]! } + public var ReportGroupLocation_Text: String { return self._s[3198]! } public func PUSH_CHAT_MESSAGE_FWD(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3193]!, self._r[3193]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3199]!, self._r[3199]!, [_1, _2]) } - public var Camera_FlashOff: String { return self._s[3194]! } - public var Watch_UserInfo_Block: String { return self._s[3195]! } - public var ChatSettings_Stickers: String { return self._s[3196]! } - public var ChatSettings_DownloadInBackground: String { return self._s[3197]! } - public var Appearance_ThemeCarouselTintedNight: String { return self._s[3198]! } + public var Camera_FlashOff: String { return self._s[3200]! } + public var Watch_UserInfo_Block: String { return self._s[3201]! } + public var ChatSettings_Stickers: String { return self._s[3202]! } + public var ChatSettings_DownloadInBackground: String { return self._s[3203]! } + public var Appearance_ThemeCarouselTintedNight: String { return self._s[3204]! } public func UserInfo_BlockConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3199]!, self._r[3199]!, [_0]) + return formatWithArgumentRanges(self._s[3205]!, self._r[3205]!, [_0]) } - public var Settings_ViewPhoto: String { return self._s[3200]! } - public var Login_CheckOtherSessionMessages: String { return self._s[3201]! } - public var AutoDownloadSettings_Cellular: String { return self._s[3202]! } - public var Wallet_Created_ExportErrorTitle: String { return self._s[3203]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsExceptions: String { return self._s[3204]! } - public var VoiceOver_MessageContextShare: String { return self._s[3205]! } + public var Settings_ViewPhoto: String { return self._s[3206]! } + public var Login_CheckOtherSessionMessages: String { return self._s[3207]! } + public var AutoDownloadSettings_Cellular: String { return self._s[3208]! } + public var Wallet_Created_ExportErrorTitle: String { return self._s[3209]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsExceptions: String { return self._s[3210]! } + public var VoiceOver_MessageContextShare: String { return self._s[3211]! } public func Target_InviteToGroupConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3207]!, self._r[3207]!, [_0]) + return formatWithArgumentRanges(self._s[3213]!, self._r[3213]!, [_0]) } - public var Privacy_DeleteDrafts: String { return self._s[3208]! } - public var Wallpaper_SetCustomBackgroundInfo: String { return self._s[3209]! } + public var Privacy_DeleteDrafts: String { return self._s[3214]! } + public var Wallpaper_SetCustomBackgroundInfo: String { return self._s[3215]! } public func LastSeen_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3210]!, self._r[3210]!, [_0]) + return formatWithArgumentRanges(self._s[3216]!, self._r[3216]!, [_0]) } - public var DialogList_SavedMessagesHelp: String { return self._s[3211]! } - public var Wallet_SecureStorageNotAvailable_Title: String { return self._s[3212]! } - public var DialogList_SavedMessages: String { return self._s[3213]! } - public var GroupInfo_UpgradeButton: String { return self._s[3214]! } - public var Appearance_ThemePreview_ChatList_3_Text: String { return self._s[3216]! } - public var DialogList_Pin: String { return self._s[3217]! } + public var DialogList_SavedMessagesHelp: String { return self._s[3217]! } + public var Wallet_SecureStorageNotAvailable_Title: String { return self._s[3218]! } + public var DialogList_SavedMessages: String { return self._s[3219]! } + public var GroupInfo_UpgradeButton: String { return self._s[3220]! } + public var Appearance_ThemePreview_ChatList_3_Text: String { return self._s[3222]! } + public var DialogList_Pin: String { return self._s[3223]! } public func ForwardedAuthors2(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3218]!, self._r[3218]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3224]!, self._r[3224]!, [_0, _1]) } public func Login_PhoneGenericEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3219]!, self._r[3219]!, [_0]) + return formatWithArgumentRanges(self._s[3225]!, self._r[3225]!, [_0]) } - public var Notification_Exceptions_AlwaysOn: String { return self._s[3220]! } - public var UserInfo_NotificationsDisable: String { return self._s[3221]! } - public var Conversation_ContextMenuCancelEditing: String { return self._s[3222]! } - public var Paint_Outlined: String { return self._s[3223]! } - public var Activity_PlayingGame: String { return self._s[3224]! } - public var SearchImages_NoImagesFound: String { return self._s[3225]! } - public var SocksProxySetup_ProxyType: String { return self._s[3226]! } - public var AppleWatch_ReplyPresetsHelp: String { return self._s[3228]! } - public var Conversation_ContextMenuCancelSending: String { return self._s[3229]! } - public var Settings_AppLanguage: String { return self._s[3230]! } - public var TwoStepAuth_ResetAccountHelp: String { return self._s[3231]! } - public var Common_ChoosePhoto: String { return self._s[3232]! } - public var AuthSessions_AddDevice_InvalidQRCode: String { return self._s[3233]! } - public var CallFeedback_ReasonEcho: String { return self._s[3234]! } + public var Notification_Exceptions_AlwaysOn: String { return self._s[3226]! } + public var UserInfo_NotificationsDisable: String { return self._s[3227]! } + public var Conversation_ContextMenuCancelEditing: String { return self._s[3228]! } + public var Paint_Outlined: String { return self._s[3229]! } + public var Activity_PlayingGame: String { return self._s[3230]! } + public var SearchImages_NoImagesFound: String { return self._s[3231]! } + public var SocksProxySetup_ProxyType: String { return self._s[3232]! } + public var AppleWatch_ReplyPresetsHelp: String { return self._s[3234]! } + public var Conversation_ContextMenuCancelSending: String { return self._s[3235]! } + public var Settings_AppLanguage: String { return self._s[3236]! } + public var TwoStepAuth_ResetAccountHelp: String { return self._s[3237]! } + public var Common_ChoosePhoto: String { return self._s[3238]! } + public var AuthSessions_AddDevice_InvalidQRCode: String { return self._s[3239]! } + public var CallFeedback_ReasonEcho: String { return self._s[3240]! } public func PUSH_PINNED_AUDIO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3235]!, self._r[3235]!, [_1]) + return formatWithArgumentRanges(self._s[3241]!, self._r[3241]!, [_1]) } - public var Privacy_Calls_AlwaysAllow: String { return self._s[3236]! } - public var PollResults_Collapse: String { return self._s[3237]! } - public var Activity_UploadingVideo: String { return self._s[3238]! } - public var Conversation_WalletRequiredNotNow: String { return self._s[3239]! } - public var ChannelInfo_DeleteChannelConfirmation: String { return self._s[3240]! } - public var NetworkUsageSettings_Wifi: String { return self._s[3241]! } - public var VoiceOver_Editing_ClearText: String { return self._s[3242]! } - public var PUSH_SENDER_YOU: String { return self._s[3243]! } - public var Channel_BanUser_PermissionReadMessages: String { return self._s[3244]! } - public var Checkout_PayWithTouchId: String { return self._s[3245]! } - public var Wallpaper_ResetWallpapersConfirmation: String { return self._s[3246]! } + public var Privacy_Calls_AlwaysAllow: String { return self._s[3242]! } + public var PollResults_Collapse: String { return self._s[3243]! } + public var Activity_UploadingVideo: String { return self._s[3244]! } + public var Conversation_WalletRequiredNotNow: String { return self._s[3245]! } + public var ChannelInfo_DeleteChannelConfirmation: String { return self._s[3246]! } + public var NetworkUsageSettings_Wifi: String { return self._s[3247]! } + public var VoiceOver_Editing_ClearText: String { return self._s[3248]! } + public var PUSH_SENDER_YOU: String { return self._s[3249]! } + public var Channel_BanUser_PermissionReadMessages: String { return self._s[3250]! } + public var Checkout_PayWithTouchId: String { return self._s[3251]! } + public var Wallpaper_ResetWallpapersConfirmation: String { return self._s[3252]! } public func PUSH_LOCKED_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3248]!, self._r[3248]!, [_1]) + return formatWithArgumentRanges(self._s[3254]!, self._r[3254]!, [_1]) } - public var Notifications_ExceptionsNone: String { return self._s[3249]! } + public var Notifications_ExceptionsNone: String { return self._s[3255]! } public func Message_ForwardedMessageShort(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3250]!, self._r[3250]!, [_0]) + return formatWithArgumentRanges(self._s[3256]!, self._r[3256]!, [_0]) } public func PUSH_PINNED_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3251]!, self._r[3251]!, [_1]) + return formatWithArgumentRanges(self._s[3257]!, self._r[3257]!, [_1]) } - public var AuthSessions_IncompleteAttempts: String { return self._s[3253]! } - public var Passport_Address_Region: String { return self._s[3256]! } - public var ChatList_DeleteChat: String { return self._s[3257]! } - public var LogoutOptions_ClearCacheTitle: String { return self._s[3258]! } - public var PhotoEditor_TiltShift: String { return self._s[3259]! } - public var Settings_FAQ_URL: String { return self._s[3260]! } - public var TwoFactorSetup_EmailVerification_ChangeAction: String { return self._s[3261]! } - public var Passport_Language_sl: String { return self._s[3262]! } - public var Settings_PrivacySettings: String { return self._s[3264]! } - public var SharedMedia_TitleLink: String { return self._s[3265]! } - public var Passport_Identity_TypePassportUploadScan: String { return self._s[3266]! } - public var Settings_SetProfilePhoto: String { return self._s[3267]! } - public var Channel_About_Help: String { return self._s[3268]! } - public var Contacts_PermissionsEnable: String { return self._s[3269]! } - public var Wallet_Sending_Title: String { return self._s[3270]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsAlert: String { return self._s[3271]! } - public var AttachmentMenu_SendAsFiles: String { return self._s[3272]! } - public var CallFeedback_ReasonInterruption: String { return self._s[3274]! } - public var Passport_Address_AddTemporaryRegistration: String { return self._s[3275]! } - public var AutoDownloadSettings_AutodownloadVideos: String { return self._s[3276]! } - public var ChatSettings_AutoDownloadSettings_Delimeter: String { return self._s[3277]! } - public var OldChannels_Title: String { return self._s[3278]! } - public var PrivacySettings_DeleteAccountTitle: String { return self._s[3279]! } - public var AccessDenied_VideoMessageCamera: String { return self._s[3281]! } - public var Map_OpenInYandexMaps: String { return self._s[3283]! } - public var CreateGroup_ErrorLocatedGroupsTooMuch: String { return self._s[3284]! } - public var VoiceOver_MessageContextReply: String { return self._s[3285]! } - public var PhotoEditor_SaturationTool: String { return self._s[3287]! } + public var AuthSessions_IncompleteAttempts: String { return self._s[3259]! } + public var Passport_Address_Region: String { return self._s[3262]! } + public var ChatList_DeleteChat: String { return self._s[3263]! } + public var LogoutOptions_ClearCacheTitle: String { return self._s[3264]! } + public var PhotoEditor_TiltShift: String { return self._s[3265]! } + public var Settings_FAQ_URL: String { return self._s[3266]! } + public var TwoFactorSetup_EmailVerification_ChangeAction: String { return self._s[3267]! } + public var Passport_Language_sl: String { return self._s[3268]! } + public var Settings_PrivacySettings: String { return self._s[3270]! } + public var SharedMedia_TitleLink: String { return self._s[3271]! } + public var Passport_Identity_TypePassportUploadScan: String { return self._s[3272]! } + public var Settings_SetProfilePhoto: String { return self._s[3273]! } + public var Channel_About_Help: String { return self._s[3274]! } + public var Contacts_PermissionsEnable: String { return self._s[3275]! } + public var Wallet_Sending_Title: String { return self._s[3276]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsAlert: String { return self._s[3277]! } + public var AttachmentMenu_SendAsFiles: String { return self._s[3278]! } + public var CallFeedback_ReasonInterruption: String { return self._s[3280]! } + public var Passport_Address_AddTemporaryRegistration: String { return self._s[3281]! } + public var AutoDownloadSettings_AutodownloadVideos: String { return self._s[3282]! } + public var ChatSettings_AutoDownloadSettings_Delimeter: String { return self._s[3283]! } + public var OldChannels_Title: String { return self._s[3284]! } + public var PrivacySettings_DeleteAccountTitle: String { return self._s[3285]! } + public var AccessDenied_VideoMessageCamera: String { return self._s[3287]! } + public var Map_OpenInYandexMaps: String { return self._s[3289]! } + public var CreateGroup_ErrorLocatedGroupsTooMuch: String { return self._s[3290]! } + public var VoiceOver_MessageContextReply: String { return self._s[3291]! } + public var PhotoEditor_SaturationTool: String { return self._s[3293]! } public func PUSH_MESSAGE_STICKER(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3288]!, self._r[3288]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3294]!, self._r[3294]!, [_1, _2]) } - public var PrivacyPhoneNumberSettings_CustomHelp: String { return self._s[3289]! } - public var Notification_Exceptions_NewException_NotificationHeader: String { return self._s[3290]! } - public var Group_OwnershipTransfer_ErrorLocatedGroupsTooMuch: String { return self._s[3291]! } + public var PrivacyPhoneNumberSettings_CustomHelp: String { return self._s[3295]! } + public var Notification_Exceptions_NewException_NotificationHeader: String { return self._s[3296]! } + public var Group_OwnershipTransfer_ErrorLocatedGroupsTooMuch: String { return self._s[3297]! } public func LOCAL_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3292]!, self._r[3292]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[3298]!, self._r[3298]!, [_1, "\(_2)"]) } - public var Appearance_ThemePreview_ChatList_2_Text: String { return self._s[3293]! } - public var Channel_Username_InvalidTooShort: String { return self._s[3295]! } - public var SettingsSearch_Synonyms_Wallet: String { return self._s[3296]! } + public var Appearance_ThemePreview_ChatList_2_Text: String { return self._s[3299]! } + public var Channel_Username_InvalidTooShort: String { return self._s[3301]! } + public var SettingsSearch_Synonyms_Wallet: String { return self._s[3302]! } public func Group_OwnershipTransfer_DescriptionInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3297]!, self._r[3297]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3303]!, self._r[3303]!, [_1, _2]) } - public var Forward_ErrorPublicPollDisabledInChannels: String { return self._s[3298]! } + public var Forward_ErrorPublicPollDisabledInChannels: String { return self._s[3304]! } public func PUSH_CHAT_MESSAGE_GAME(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3299]!, self._r[3299]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3305]!, self._r[3305]!, [_1, _2, _3]) } - public var WallpaperPreview_PatternTitle: String { return self._s[3300]! } - public var GroupInfo_PublicLinkAdd: String { return self._s[3301]! } - public var Passport_PassportInformation: String { return self._s[3304]! } - public var Theme_Unsupported: String { return self._s[3305]! } - public var WatchRemote_AlertTitle: String { return self._s[3306]! } - public var Privacy_GroupsAndChannels_NeverAllow: String { return self._s[3307]! } - public var ConvertToSupergroup_HelpText: String { return self._s[3309]! } + public var WallpaperPreview_PatternTitle: String { return self._s[3306]! } + public var GroupInfo_PublicLinkAdd: String { return self._s[3307]! } + public var Passport_PassportInformation: String { return self._s[3310]! } + public var Theme_Unsupported: String { return self._s[3311]! } + public var WatchRemote_AlertTitle: String { return self._s[3312]! } + public var Privacy_GroupsAndChannels_NeverAllow: String { return self._s[3313]! } + public var ConvertToSupergroup_HelpText: String { return self._s[3315]! } public func Time_MonthOfYear_m7(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3310]!, self._r[3310]!, [_0]) + return formatWithArgumentRanges(self._s[3316]!, self._r[3316]!, [_0]) } public func PUSH_PHONE_CALL_REQUEST(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3311]!, self._r[3311]!, [_1]) + return formatWithArgumentRanges(self._s[3317]!, self._r[3317]!, [_1]) } - public var Privacy_GroupsAndChannels_CustomHelp: String { return self._s[3312]! } - public var Wallet_Navigation_Done: String { return self._s[3314]! } - public var TwoStepAuth_RecoveryCodeInvalid: String { return self._s[3315]! } - public var AccessDenied_CameraDisabled: String { return self._s[3316]! } + public var Privacy_GroupsAndChannels_CustomHelp: String { return self._s[3318]! } + public var Wallet_Navigation_Done: String { return self._s[3320]! } + public var TwoStepAuth_RecoveryCodeInvalid: String { return self._s[3321]! } + public var AccessDenied_CameraDisabled: String { return self._s[3322]! } public func Channel_Username_UsernameIsAvailable(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3317]!, self._r[3317]!, [_0]) + return formatWithArgumentRanges(self._s[3323]!, self._r[3323]!, [_0]) } - public var ClearCache_Forever: String { return self._s[3318]! } - public var AuthSessions_AddDeviceIntro_Title: String { return self._s[3319]! } - public var CreatePoll_Quiz: String { return self._s[3320]! } - public var PhotoEditor_ContrastTool: String { return self._s[3323]! } + public var ClearCache_Forever: String { return self._s[3324]! } + public var AuthSessions_AddDeviceIntro_Title: String { return self._s[3325]! } + public var CreatePoll_Quiz: String { return self._s[3326]! } + public var PhotoEditor_ContrastTool: String { return self._s[3329]! } public func PUSH_PINNED_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3324]!, self._r[3324]!, [_1]) + return formatWithArgumentRanges(self._s[3330]!, self._r[3330]!, [_1]) } - public var DialogList_Draft: String { return self._s[3325]! } - public var Wallet_Configuration_BlockchainIdInfo: String { return self._s[3326]! } + public var DialogList_Draft: String { return self._s[3331]! } + public var Wallet_Configuration_BlockchainIdInfo: String { return self._s[3332]! } public func PeopleNearby_VisibleUntil(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3327]!, self._r[3327]!, [_0]) + return formatWithArgumentRanges(self._s[3333]!, self._r[3333]!, [_0]) } - public var Privacy_TopPeersDelete: String { return self._s[3329]! } - public var LoginPassword_PasswordPlaceholder: String { return self._s[3330]! } - public var Passport_Identity_TypeIdentityCardUploadScan: String { return self._s[3331]! } - public var WebSearch_RecentSectionClear: String { return self._s[3332]! } - public var EditTheme_ErrorInvalidCharacters: String { return self._s[3333]! } - public var Watch_ChatList_NoConversationsTitle: String { return self._s[3335]! } - public var Common_Done: String { return self._s[3337]! } - public var Shortcut_SwitchAccount: String { return self._s[3338]! } - public var AuthSessions_EmptyText: String { return self._s[3339]! } - public var Wallet_Configuration_BlockchainNameChangedTitle: String { return self._s[3340]! } - public var Conversation_ShareBotContactConfirmation: String { return self._s[3341]! } - public var Tour_Title5: String { return self._s[3342]! } - public var Wallet_Settings_Title: String { return self._s[3343]! } + public var Privacy_TopPeersDelete: String { return self._s[3335]! } + public var LoginPassword_PasswordPlaceholder: String { return self._s[3336]! } + public var Passport_Identity_TypeIdentityCardUploadScan: String { return self._s[3337]! } + public var WebSearch_RecentSectionClear: String { return self._s[3338]! } + public var EditTheme_ErrorInvalidCharacters: String { return self._s[3339]! } + public var Watch_ChatList_NoConversationsTitle: String { return self._s[3341]! } + public var PeerInfo_ButtonMore: String { return self._s[3343]! } + public var Common_Done: String { return self._s[3344]! } + public var Shortcut_SwitchAccount: String { return self._s[3345]! } + public var AuthSessions_EmptyText: String { return self._s[3346]! } + public var Wallet_Configuration_BlockchainNameChangedTitle: String { return self._s[3347]! } + public var Conversation_ShareBotContactConfirmation: String { return self._s[3348]! } + public var Tour_Title5: String { return self._s[3349]! } + public var Wallet_Settings_Title: String { return self._s[3350]! } public func Map_DirectionsDriveEta(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3344]!, self._r[3344]!, [_0]) + return formatWithArgumentRanges(self._s[3351]!, self._r[3351]!, [_0]) } - public var ApplyLanguage_UnsufficientDataTitle: String { return self._s[3345]! } - public var Conversation_LinkDialogSave: String { return self._s[3346]! } - public var GroupInfo_ActionRestrict: String { return self._s[3347]! } - public var Checkout_Title: String { return self._s[3348]! } - public var Channel_DiscussionGroup_HeaderLabel: String { return self._s[3350]! } - public var Channel_AdminLog_CanChangeInfo: String { return self._s[3352]! } - public var Notification_RenamedGroup: String { return self._s[3353]! } - public var PeopleNearby_Groups: String { return self._s[3354]! } - public var Checkout_PayWithFaceId: String { return self._s[3355]! } - public var Channel_BanList_BlockedTitle: String { return self._s[3356]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsSound: String { return self._s[3358]! } - public var Checkout_WebConfirmation_Title: String { return self._s[3359]! } - public var Notifications_MessageNotificationsAlert: String { return self._s[3360]! } + public var ApplyLanguage_UnsufficientDataTitle: String { return self._s[3352]! } + public var Conversation_LinkDialogSave: String { return self._s[3353]! } + public var GroupInfo_ActionRestrict: String { return self._s[3354]! } + public var Checkout_Title: String { return self._s[3355]! } + public var Channel_DiscussionGroup_HeaderLabel: String { return self._s[3357]! } + public var Channel_AdminLog_CanChangeInfo: String { return self._s[3359]! } + public var Notification_RenamedGroup: String { return self._s[3360]! } + public var PeopleNearby_Groups: String { return self._s[3361]! } + public var Checkout_PayWithFaceId: String { return self._s[3362]! } + public var Channel_BanList_BlockedTitle: String { return self._s[3363]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsSound: String { return self._s[3365]! } + public var Checkout_WebConfirmation_Title: String { return self._s[3366]! } + public var Notifications_MessageNotificationsAlert: String { return self._s[3367]! } public func Activity_RemindAboutGroup(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3361]!, self._r[3361]!, [_0]) + return formatWithArgumentRanges(self._s[3368]!, self._r[3368]!, [_0]) } - public var Profile_AddToExisting: String { return self._s[3363]! } + public var Profile_AddToExisting: String { return self._s[3370]! } public func Profile_CreateEncryptedChatOutdatedError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3364]!, self._r[3364]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3371]!, self._r[3371]!, [_0, _1]) } - public var Cache_Files: String { return self._s[3366]! } - public var Permissions_PrivacyPolicy: String { return self._s[3367]! } - public var SocksProxySetup_ConnectAndSave: String { return self._s[3368]! } - public var UserInfo_NotificationsDefaultDisabled: String { return self._s[3369]! } - public var AutoDownloadSettings_TypeContacts: String { return self._s[3371]! } - public var Appearance_ThemePreview_ChatList_1_Text: String { return self._s[3373]! } - public var Calls_NoCallsPlaceholder: String { return self._s[3374]! } + public var Cache_Files: String { return self._s[3373]! } + public var Permissions_PrivacyPolicy: String { return self._s[3374]! } + public var SocksProxySetup_ConnectAndSave: String { return self._s[3375]! } + public var UserInfo_NotificationsDefaultDisabled: String { return self._s[3376]! } + public var AutoDownloadSettings_TypeContacts: String { return self._s[3378]! } + public var Appearance_ThemePreview_ChatList_1_Text: String { return self._s[3380]! } + public var Calls_NoCallsPlaceholder: String { return self._s[3381]! } public func Wallet_Receive_ShareInvoiceUrlInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3375]!, self._r[3375]!, [_0]) + return formatWithArgumentRanges(self._s[3382]!, self._r[3382]!, [_0]) } - public var Channel_Username_RevokeExistingUsernamesInfo: String { return self._s[3376]! } - public var VoiceOver_AttachMedia: String { return self._s[3379]! } - public var Notifications_ExceptionsGroupPlaceholder: String { return self._s[3380]! } + public var Channel_Username_RevokeExistingUsernamesInfo: String { return self._s[3383]! } + public var VoiceOver_AttachMedia: String { return self._s[3386]! } + public var Notifications_ExceptionsGroupPlaceholder: String { return self._s[3387]! } public func PUSH_CHAT_MESSAGE_INVOICE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3381]!, self._r[3381]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3388]!, self._r[3388]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsSound: String { return self._s[3382]! } - public var Conversation_SetReminder_Title: String { return self._s[3383]! } - public var Passport_FieldAddressHelp: String { return self._s[3384]! } - public var Privacy_GroupsAndChannels_InviteToChannelMultipleError: String { return self._s[3385]! } - public var PUSH_REMINDER_TITLE: String { return self._s[3386]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsSound: String { return self._s[3389]! } + public var Conversation_SetReminder_Title: String { return self._s[3390]! } + public var Passport_FieldAddressHelp: String { return self._s[3391]! } + public var Privacy_GroupsAndChannels_InviteToChannelMultipleError: String { return self._s[3392]! } + public var PUSH_REMINDER_TITLE: String { return self._s[3393]! } public func Login_TermsOfService_ProceedBot(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3387]!, self._r[3387]!, [_0]) + return formatWithArgumentRanges(self._s[3394]!, self._r[3394]!, [_0]) } - public var Channel_AdminLog_EmptyTitle: String { return self._s[3388]! } - public var Privacy_Calls_NeverAllow_Title: String { return self._s[3389]! } - public var Login_UnknownError: String { return self._s[3390]! } - public var Group_UpgradeNoticeText2: String { return self._s[3393]! } - public var Watch_Compose_AddContact: String { return self._s[3394]! } - public var ClearCache_StorageServiceFiles: String { return self._s[3395]! } - public var Web_Error: String { return self._s[3396]! } - public var Gif_Search: String { return self._s[3397]! } - public var Profile_MessageLifetime1h: String { return self._s[3398]! } - public var CheckoutInfo_ReceiverInfoEmailPlaceholder: String { return self._s[3399]! } - public var Channel_Username_CheckingUsername: String { return self._s[3400]! } - public var CallFeedback_ReasonSilentRemote: String { return self._s[3401]! } - public var AutoDownloadSettings_TypeChannels: String { return self._s[3402]! } - public var Channel_AboutItem: String { return self._s[3403]! } - public var Privacy_GroupsAndChannels_AlwaysAllow_Placeholder: String { return self._s[3405]! } - public var VoiceOver_Chat_VoiceMessage: String { return self._s[3406]! } - public var GroupInfo_SharedMedia: String { return self._s[3407]! } + public var Channel_AdminLog_EmptyTitle: String { return self._s[3395]! } + public var Privacy_Calls_NeverAllow_Title: String { return self._s[3396]! } + public var Login_UnknownError: String { return self._s[3397]! } + public var Group_UpgradeNoticeText2: String { return self._s[3400]! } + public var Watch_Compose_AddContact: String { return self._s[3401]! } + public var ClearCache_StorageServiceFiles: String { return self._s[3402]! } + public var Web_Error: String { return self._s[3403]! } + public var Gif_Search: String { return self._s[3404]! } + public var Profile_MessageLifetime1h: String { return self._s[3405]! } + public var CheckoutInfo_ReceiverInfoEmailPlaceholder: String { return self._s[3406]! } + public var Channel_Username_CheckingUsername: String { return self._s[3407]! } + public var CallFeedback_ReasonSilentRemote: String { return self._s[3408]! } + public var AutoDownloadSettings_TypeChannels: String { return self._s[3409]! } + public var Channel_AboutItem: String { return self._s[3410]! } + public var Privacy_GroupsAndChannels_AlwaysAllow_Placeholder: String { return self._s[3412]! } + public var VoiceOver_Chat_VoiceMessage: String { return self._s[3413]! } + public var GroupInfo_SharedMedia: String { return self._s[3414]! } public func Channel_AdminLog_MessagePromotedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3408]!, self._r[3408]!, [_1]) + return formatWithArgumentRanges(self._s[3415]!, self._r[3415]!, [_1]) } - public var Call_PhoneCallInProgressMessage: String { return self._s[3409]! } + public var Call_PhoneCallInProgressMessage: String { return self._s[3416]! } public func PUSH_CHANNEL_ALBUM(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3410]!, self._r[3410]!, [_1]) + return formatWithArgumentRanges(self._s[3417]!, self._r[3417]!, [_1]) } - public var ChatList_UndoArchiveRevealedText: String { return self._s[3411]! } - public var GroupInfo_InviteLink_RevokeAlert_Text: String { return self._s[3412]! } - public var Conversation_SearchByName_Placeholder: String { return self._s[3413]! } - public var CreatePoll_AddOption: String { return self._s[3414]! } - public var GroupInfo_Permissions_SearchPlaceholder: String { return self._s[3415]! } - public var Group_UpgradeNoticeHeader: String { return self._s[3416]! } - public var Channel_Management_AddModerator: String { return self._s[3417]! } - public var AutoDownloadSettings_MaxFileSize: String { return self._s[3418]! } - public var StickerPacksSettings_ShowStickersButton: String { return self._s[3419]! } - public var Wallet_Info_RefreshErrorNetworkText: String { return self._s[3420]! } - public var Theme_Colors_Background: String { return self._s[3421]! } - public var NotificationsSound_Hello: String { return self._s[3423]! } - public var SocksProxySetup_SavedProxies: String { return self._s[3424]! } - public var Channel_Stickers_Placeholder: String { return self._s[3426]! } + public var ChatList_UndoArchiveRevealedText: String { return self._s[3418]! } + public var GroupInfo_InviteLink_RevokeAlert_Text: String { return self._s[3419]! } + public var Conversation_SearchByName_Placeholder: String { return self._s[3420]! } + public var CreatePoll_AddOption: String { return self._s[3421]! } + public var GroupInfo_Permissions_SearchPlaceholder: String { return self._s[3422]! } + public var Group_UpgradeNoticeHeader: String { return self._s[3423]! } + public var Channel_Management_AddModerator: String { return self._s[3424]! } + public var AutoDownloadSettings_MaxFileSize: String { return self._s[3425]! } + public var StickerPacksSettings_ShowStickersButton: String { return self._s[3426]! } + public var Wallet_Info_RefreshErrorNetworkText: String { return self._s[3427]! } + public var Theme_Colors_Background: String { return self._s[3428]! } + public var NotificationsSound_Hello: String { return self._s[3430]! } + public var SocksProxySetup_SavedProxies: String { return self._s[3431]! } + public var Channel_Stickers_Placeholder: String { return self._s[3433]! } public func Login_EmailCodeBody(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3427]!, self._r[3427]!, [_0]) + return formatWithArgumentRanges(self._s[3434]!, self._r[3434]!, [_0]) } - public var PrivacyPolicy_DeclineDeclineAndDelete: String { return self._s[3428]! } - public var Channel_Management_AddModeratorHelp: String { return self._s[3429]! } - public var ContactInfo_BirthdayLabel: String { return self._s[3430]! } - public var ChangePhoneNumberCode_RequestingACall: String { return self._s[3431]! } - public var AutoDownloadSettings_Channels: String { return self._s[3432]! } - public var Passport_Language_mn: String { return self._s[3433]! } - public var Notifications_ResetAllNotificationsHelp: String { return self._s[3436]! } - public var GroupInfo_Permissions_SlowmodeValue_Off: String { return self._s[3437]! } - public var Passport_Language_ja: String { return self._s[3439]! } - public var Settings_About_Title: String { return self._s[3440]! } - public var Settings_NotificationsAndSounds: String { return self._s[3441]! } - public var ChannelInfo_DeleteGroup: String { return self._s[3442]! } - public var Settings_BlockedUsers: String { return self._s[3443]! } + public var PrivacyPolicy_DeclineDeclineAndDelete: String { return self._s[3435]! } + public var Channel_Management_AddModeratorHelp: String { return self._s[3436]! } + public var ContactInfo_BirthdayLabel: String { return self._s[3437]! } + public var ChangePhoneNumberCode_RequestingACall: String { return self._s[3438]! } + public var AutoDownloadSettings_Channels: String { return self._s[3439]! } + public var Passport_Language_mn: String { return self._s[3440]! } + public var Notifications_ResetAllNotificationsHelp: String { return self._s[3443]! } + public var GroupInfo_Permissions_SlowmodeValue_Off: String { return self._s[3444]! } + public var Passport_Language_ja: String { return self._s[3446]! } + public var Settings_About_Title: String { return self._s[3447]! } + public var Settings_NotificationsAndSounds: String { return self._s[3448]! } + public var ChannelInfo_DeleteGroup: String { return self._s[3449]! } + public var Settings_BlockedUsers: String { return self._s[3450]! } public func Time_MonthOfYear_m4(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3444]!, self._r[3444]!, [_0]) - } - public var EditTheme_Create_Preview_OutgoingText: String { return self._s[3445]! } - public var Wallet_Weekday_Today: String { return self._s[3446]! } - public var AutoDownloadSettings_PreloadVideo: String { return self._s[3447]! } - public var Widget_ApplicationLocked: String { return self._s[3448]! } - public var Passport_Address_AddResidentialAddress: String { return self._s[3449]! } - public var Channel_Username_Title: String { return self._s[3450]! } - public func Notification_RemovedGroupPhoto(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3451]!, self._r[3451]!, [_0]) } - public var AttachmentMenu_File: String { return self._s[3453]! } - public var AppleWatch_Title: String { return self._s[3454]! } - public var Activity_RecordingVideoMessage: String { return self._s[3455]! } - public func Channel_DiscussionGroup_PublicChannelLink(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3456]!, self._r[3456]!, [_1, _2]) + public var EditTheme_Create_Preview_OutgoingText: String { return self._s[3452]! } + public var Wallet_Weekday_Today: String { return self._s[3453]! } + public var AutoDownloadSettings_PreloadVideo: String { return self._s[3454]! } + public var Widget_ApplicationLocked: String { return self._s[3455]! } + public var Passport_Address_AddResidentialAddress: String { return self._s[3456]! } + public var Channel_Username_Title: String { return self._s[3457]! } + public func Notification_RemovedGroupPhoto(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3458]!, self._r[3458]!, [_0]) } - public var Theme_Colors_Messages: String { return self._s[3457]! } - public var Weekday_Saturday: String { return self._s[3458]! } - public var WallpaperPreview_SwipeColorsTopText: String { return self._s[3459]! } - public var Profile_CreateEncryptedChatError: String { return self._s[3460]! } - public var Common_Next: String { return self._s[3462]! } - public var Channel_Stickers_YourStickers: String { return self._s[3464]! } - public var Message_Theme: String { return self._s[3465]! } - public var Call_AudioRouteHeadphones: String { return self._s[3466]! } - public var TwoStepAuth_EnterPasswordForgot: String { return self._s[3468]! } - public var Watch_Contacts_NoResults: String { return self._s[3470]! } - public var PhotoEditor_TintTool: String { return self._s[3473]! } - public var LoginPassword_ResetAccount: String { return self._s[3475]! } - public var Settings_SavedMessages: String { return self._s[3476]! } - public var SettingsSearch_Synonyms_Appearance_Animations: String { return self._s[3477]! } - public var Bot_GenericSupportStatus: String { return self._s[3478]! } - public var StickerPack_Add: String { return self._s[3479]! } - public var Checkout_TotalAmount: String { return self._s[3480]! } - public var Your_cards_number_is_invalid: String { return self._s[3481]! } - public var SettingsSearch_Synonyms_Appearance_AutoNightTheme: String { return self._s[3482]! } - public var VoiceOver_Chat_VideoMessage: String { return self._s[3483]! } + public var AttachmentMenu_File: String { return self._s[3460]! } + public var AppleWatch_Title: String { return self._s[3461]! } + public var Activity_RecordingVideoMessage: String { return self._s[3462]! } + public func Channel_DiscussionGroup_PublicChannelLink(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3463]!, self._r[3463]!, [_1, _2]) + } + public var Theme_Colors_Messages: String { return self._s[3464]! } + public var Weekday_Saturday: String { return self._s[3465]! } + public var WallpaperPreview_SwipeColorsTopText: String { return self._s[3466]! } + public var Profile_CreateEncryptedChatError: String { return self._s[3467]! } + public var Common_Next: String { return self._s[3469]! } + public var Channel_Stickers_YourStickers: String { return self._s[3471]! } + public var Message_Theme: String { return self._s[3472]! } + public var Call_AudioRouteHeadphones: String { return self._s[3473]! } + public var TwoStepAuth_EnterPasswordForgot: String { return self._s[3475]! } + public var Watch_Contacts_NoResults: String { return self._s[3477]! } + public var PhotoEditor_TintTool: String { return self._s[3480]! } + public var LoginPassword_ResetAccount: String { return self._s[3482]! } + public var Settings_SavedMessages: String { return self._s[3483]! } + public var SettingsSearch_Synonyms_Appearance_Animations: String { return self._s[3484]! } + public var Bot_GenericSupportStatus: String { return self._s[3485]! } + public var StickerPack_Add: String { return self._s[3486]! } + public var Checkout_TotalAmount: String { return self._s[3487]! } + public var Your_cards_number_is_invalid: String { return self._s[3488]! } + public var SettingsSearch_Synonyms_Appearance_AutoNightTheme: String { return self._s[3489]! } + public var VoiceOver_Chat_VideoMessage: String { return self._s[3490]! } public func ChangePhoneNumberCode_CallTimer(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3484]!, self._r[3484]!, [_0]) + return formatWithArgumentRanges(self._s[3491]!, self._r[3491]!, [_0]) } public func GroupPermission_AddedInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3485]!, self._r[3485]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3492]!, self._r[3492]!, [_1, _2]) } - public var ChatSettings_ConnectionType_UseSocks5: String { return self._s[3486]! } + public var ChatSettings_ConnectionType_UseSocks5: String { return self._s[3493]! } public func PUSH_CHAT_PHOTO_EDITED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3488]!, self._r[3488]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3495]!, self._r[3495]!, [_1, _2]) } public func Conversation_RestrictedTextTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3489]!, self._r[3489]!, [_0]) + return formatWithArgumentRanges(self._s[3496]!, self._r[3496]!, [_0]) } - public var GroupInfo_InviteLink_ShareLink: String { return self._s[3490]! } - public var StickerPack_Share: String { return self._s[3491]! } - public var Passport_DeleteAddress: String { return self._s[3492]! } - public var Settings_Passport: String { return self._s[3493]! } - public var SharedMedia_EmptyFilesText: String { return self._s[3494]! } - public var Conversation_DeleteMessagesForMe: String { return self._s[3495]! } - public var PasscodeSettings_AutoLock_IfAwayFor_1hour: String { return self._s[3496]! } - public var Contacts_PermissionsText: String { return self._s[3497]! } - public var Group_Setup_HistoryVisible: String { return self._s[3498]! } - public var Wallet_Month_ShortDecember: String { return self._s[3500]! } - public var Channel_EditAdmin_PermissionEnabledByDefault: String { return self._s[3501]! } - public var Passport_Address_AddRentalAgreement: String { return self._s[3502]! } - public var SocksProxySetup_Title: String { return self._s[3503]! } - public var Notification_Mute1h: String { return self._s[3504]! } + public var GroupInfo_InviteLink_ShareLink: String { return self._s[3497]! } + public var StickerPack_Share: String { return self._s[3498]! } + public var Passport_DeleteAddress: String { return self._s[3499]! } + public var Settings_Passport: String { return self._s[3500]! } + public var SharedMedia_EmptyFilesText: String { return self._s[3501]! } + public var Conversation_DeleteMessagesForMe: String { return self._s[3502]! } + public var PasscodeSettings_AutoLock_IfAwayFor_1hour: String { return self._s[3503]! } + public var Contacts_PermissionsText: String { return self._s[3504]! } + public var Group_Setup_HistoryVisible: String { return self._s[3505]! } + public var Wallet_Month_ShortDecember: String { return self._s[3507]! } + public var Channel_EditAdmin_PermissionEnabledByDefault: String { return self._s[3508]! } + public var Passport_Address_AddRentalAgreement: String { return self._s[3509]! } + public var SocksProxySetup_Title: String { return self._s[3510]! } + public var Notification_Mute1h: String { return self._s[3511]! } public func Passport_Email_CodeHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3505]!, self._r[3505]!, [_0]) + return formatWithArgumentRanges(self._s[3512]!, self._r[3512]!, [_0]) } - public var NotificationSettings_ShowNotificationsAllAccountsInfoOff: String { return self._s[3506]! } + public var NotificationSettings_ShowNotificationsAllAccountsInfoOff: String { return self._s[3513]! } public func PUSH_PINNED_GEOLIVE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3507]!, self._r[3507]!, [_1]) + return formatWithArgumentRanges(self._s[3514]!, self._r[3514]!, [_1]) } - public var FastTwoStepSetup_PasswordSection: String { return self._s[3508]! } - public var NetworkUsageSettings_ResetStatsConfirmation: String { return self._s[3511]! } - public var InfoPlist_NSFaceIDUsageDescription: String { return self._s[3513]! } - public var DialogList_NoMessagesText: String { return self._s[3514]! } - public var Privacy_ContactsResetConfirmation: String { return self._s[3515]! } - public var Privacy_Calls_P2PHelp: String { return self._s[3516]! } - public var Channel_DiscussionGroup_SearchPlaceholder: String { return self._s[3518]! } - public var Your_cards_expiration_year_is_invalid: String { return self._s[3519]! } - public var Common_TakePhotoOrVideo: String { return self._s[3520]! } - public var Wallet_Words_Text: String { return self._s[3521]! } - public var Call_StatusBusy: String { return self._s[3522]! } - public var Conversation_PinnedMessage: String { return self._s[3523]! } - public var AutoDownloadSettings_VoiceMessagesTitle: String { return self._s[3524]! } - public var Wallet_Configuration_BlockchainNameChangedProceed: String { return self._s[3525]! } - public var TwoStepAuth_SetupPasswordConfirmFailed: String { return self._s[3526]! } - public var Undo_ChatCleared: String { return self._s[3527]! } - public var AppleWatch_ReplyPresets: String { return self._s[3528]! } - public var Passport_DiscardMessageDescription: String { return self._s[3530]! } - public var Login_NetworkError: String { return self._s[3531]! } + public var FastTwoStepSetup_PasswordSection: String { return self._s[3515]! } + public var NetworkUsageSettings_ResetStatsConfirmation: String { return self._s[3518]! } + public var InfoPlist_NSFaceIDUsageDescription: String { return self._s[3520]! } + public var DialogList_NoMessagesText: String { return self._s[3521]! } + public var Privacy_ContactsResetConfirmation: String { return self._s[3522]! } + public var Privacy_Calls_P2PHelp: String { return self._s[3523]! } + public var Channel_DiscussionGroup_SearchPlaceholder: String { return self._s[3525]! } + public var Your_cards_expiration_year_is_invalid: String { return self._s[3526]! } + public var Common_TakePhotoOrVideo: String { return self._s[3527]! } + public var Wallet_Words_Text: String { return self._s[3528]! } + public var Call_StatusBusy: String { return self._s[3529]! } + public var Conversation_PinnedMessage: String { return self._s[3530]! } + public var AutoDownloadSettings_VoiceMessagesTitle: String { return self._s[3531]! } + public var Wallet_Configuration_BlockchainNameChangedProceed: String { return self._s[3532]! } + public var TwoStepAuth_SetupPasswordConfirmFailed: String { return self._s[3533]! } + public var Undo_ChatCleared: String { return self._s[3534]! } + public var AppleWatch_ReplyPresets: String { return self._s[3535]! } + public var Passport_DiscardMessageDescription: String { return self._s[3537]! } + public var Login_NetworkError: String { return self._s[3538]! } public func Notification_PinnedRoundMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3532]!, self._r[3532]!, [_0]) - } - public func Channel_AdminLog_MessageRemovedChannelUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3533]!, self._r[3533]!, [_0]) - } - public var SocksProxySetup_PasswordPlaceholder: String { return self._s[3534]! } - public var Wallet_WordCheck_ViewWords: String { return self._s[3536]! } - public var Login_ResetAccountProtected_LimitExceeded: String { return self._s[3537]! } - public func Watch_LastSeen_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3539]!, self._r[3539]!, [_0]) } - public var Call_ConnectionErrorMessage: String { return self._s[3540]! } - public var VoiceOver_Chat_Music: String { return self._s[3541]! } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsSound: String { return self._s[3542]! } - public var Compose_GroupTokenListPlaceholder: String { return self._s[3544]! } - public var ConversationMedia_Title: String { return self._s[3545]! } - public var EncryptionKey_Title: String { return self._s[3547]! } - public var TwoStepAuth_EnterPasswordTitle: String { return self._s[3548]! } - public var Notification_Exceptions_AddException: String { return self._s[3549]! } - public var PrivacySettings_BlockedPeersEmpty: String { return self._s[3550]! } - public var Profile_MessageLifetime1m: String { return self._s[3551]! } + public func Channel_AdminLog_MessageRemovedChannelUsername(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3540]!, self._r[3540]!, [_0]) + } + public var SocksProxySetup_PasswordPlaceholder: String { return self._s[3541]! } + public var Wallet_WordCheck_ViewWords: String { return self._s[3543]! } + public var Login_ResetAccountProtected_LimitExceeded: String { return self._s[3544]! } + public func Watch_LastSeen_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3546]!, self._r[3546]!, [_0]) + } + public var Call_ConnectionErrorMessage: String { return self._s[3547]! } + public var VoiceOver_Chat_Music: String { return self._s[3548]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsSound: String { return self._s[3549]! } + public var Compose_GroupTokenListPlaceholder: String { return self._s[3551]! } + public var ConversationMedia_Title: String { return self._s[3552]! } + public var EncryptionKey_Title: String { return self._s[3554]! } + public var TwoStepAuth_EnterPasswordTitle: String { return self._s[3555]! } + public var Notification_Exceptions_AddException: String { return self._s[3556]! } + public var PrivacySettings_BlockedPeersEmpty: String { return self._s[3557]! } + public var Profile_MessageLifetime1m: String { return self._s[3558]! } public func Channel_AdminLog_MessageUnkickedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3552]!, self._r[3552]!, [_1]) + return formatWithArgumentRanges(self._s[3559]!, self._r[3559]!, [_1]) } - public var Month_GenMay: String { return self._s[3553]! } + public var Month_GenMay: String { return self._s[3560]! } public func LiveLocationUpdated_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3554]!, self._r[3554]!, [_0]) + return formatWithArgumentRanges(self._s[3561]!, self._r[3561]!, [_0]) } - public var PeopleNearby_Users: String { return self._s[3555]! } - public var Wallet_Send_AddressInfo: String { return self._s[3556]! } - public var ChannelMembers_WhoCanAddMembersAllHelp: String { return self._s[3557]! } - public var AutoDownloadSettings_ResetSettings: String { return self._s[3558]! } + public var PeopleNearby_Users: String { return self._s[3562]! } + public var Wallet_Send_AddressInfo: String { return self._s[3563]! } + public var ChannelMembers_WhoCanAddMembersAllHelp: String { return self._s[3564]! } + public var AutoDownloadSettings_ResetSettings: String { return self._s[3565]! } public func Wallet_Updated_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3560]!, self._r[3560]!, [_0]) + return formatWithArgumentRanges(self._s[3567]!, self._r[3567]!, [_0]) } - public var Conversation_EmptyPlaceholder: String { return self._s[3561]! } - public var Passport_Address_AddPassportRegistration: String { return self._s[3562]! } - public var Notifications_ChannelNotificationsAlert: String { return self._s[3563]! } - public var ChatSettings_AutoDownloadUsingCellular: String { return self._s[3564]! } - public var Camera_TapAndHoldForVideo: String { return self._s[3565]! } - public var Channel_JoinChannel: String { return self._s[3567]! } - public var Appearance_Animations: String { return self._s[3570]! } + public var Conversation_EmptyPlaceholder: String { return self._s[3568]! } + public var Passport_Address_AddPassportRegistration: String { return self._s[3569]! } + public var Notifications_ChannelNotificationsAlert: String { return self._s[3570]! } + public var ChatSettings_AutoDownloadUsingCellular: String { return self._s[3571]! } + public var Camera_TapAndHoldForVideo: String { return self._s[3572]! } + public var Channel_JoinChannel: String { return self._s[3574]! } + public var Appearance_Animations: String { return self._s[3577]! } public func Notification_MessageLifetimeChanged(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3571]!, self._r[3571]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3578]!, self._r[3578]!, [_1, _2]) } - public var Stickers_GroupStickers: String { return self._s[3573]! } - public var Appearance_ShareTheme: String { return self._s[3574]! } - public var TwoFactorSetup_Hint_Placeholder: String { return self._s[3575]! } - public var ConvertToSupergroup_HelpTitle: String { return self._s[3577]! } - public var StickerPackActionInfo_RemovedTitle: String { return self._s[3578]! } - public var Passport_Address_Street: String { return self._s[3579]! } - public var Conversation_AddContact: String { return self._s[3580]! } - public var Login_PhonePlaceholder: String { return self._s[3581]! } - public var Channel_Members_InviteLink: String { return self._s[3583]! } - public var Bot_Stop: String { return self._s[3584]! } - public var SettingsSearch_Synonyms_Proxy_UseForCalls: String { return self._s[3586]! } - public var Notification_PassportValueAddress: String { return self._s[3587]! } - public var Month_ShortJuly: String { return self._s[3588]! } - public var Passport_Address_TypeTemporaryRegistrationUploadScan: String { return self._s[3589]! } - public var Channel_AdminLog_BanSendMedia: String { return self._s[3590]! } - public var Passport_Identity_ReverseSide: String { return self._s[3591]! } - public var Watch_Stickers_Recents: String { return self._s[3594]! } - public var PrivacyLastSeenSettings_EmpryUsersPlaceholder: String { return self._s[3596]! } - public var Map_SendThisLocation: String { return self._s[3597]! } + public var Stickers_GroupStickers: String { return self._s[3580]! } + public var Appearance_ShareTheme: String { return self._s[3581]! } + public var TwoFactorSetup_Hint_Placeholder: String { return self._s[3582]! } + public var ConvertToSupergroup_HelpTitle: String { return self._s[3584]! } + public var StickerPackActionInfo_RemovedTitle: String { return self._s[3585]! } + public var Passport_Address_Street: String { return self._s[3586]! } + public var Conversation_AddContact: String { return self._s[3587]! } + public var Login_PhonePlaceholder: String { return self._s[3588]! } + public var Channel_Members_InviteLink: String { return self._s[3590]! } + public var Bot_Stop: String { return self._s[3591]! } + public var SettingsSearch_Synonyms_Proxy_UseForCalls: String { return self._s[3593]! } + public var Notification_PassportValueAddress: String { return self._s[3594]! } + public var Month_ShortJuly: String { return self._s[3595]! } + public var Passport_Address_TypeTemporaryRegistrationUploadScan: String { return self._s[3596]! } + public var Channel_AdminLog_BanSendMedia: String { return self._s[3597]! } + public var Passport_Identity_ReverseSide: String { return self._s[3598]! } + public var Watch_Stickers_Recents: String { return self._s[3601]! } + public var PrivacyLastSeenSettings_EmpryUsersPlaceholder: String { return self._s[3603]! } + public var Map_SendThisLocation: String { return self._s[3604]! } public func Time_MonthOfYear_m1(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3598]!, self._r[3598]!, [_0]) + return formatWithArgumentRanges(self._s[3605]!, self._r[3605]!, [_0]) } public func InviteText_SingleContact(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3599]!, self._r[3599]!, [_0]) + return formatWithArgumentRanges(self._s[3606]!, self._r[3606]!, [_0]) } - public var ConvertToSupergroup_Note: String { return self._s[3600]! } - public var Wallet_Intro_NotNow: String { return self._s[3601]! } + public var ConvertToSupergroup_Note: String { return self._s[3607]! } + public var Wallet_Intro_NotNow: String { return self._s[3608]! } public func FileSize_MB(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3602]!, self._r[3602]!, [_0]) + return formatWithArgumentRanges(self._s[3609]!, self._r[3609]!, [_0]) } - public var NetworkUsageSettings_GeneralDataSection: String { return self._s[3603]! } + public var NetworkUsageSettings_GeneralDataSection: String { return self._s[3610]! } public func Compatibility_SecretMediaVersionTooLow(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3604]!, self._r[3604]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3611]!, self._r[3611]!, [_0, _1]) } - public var Login_CallRequestState3: String { return self._s[3606]! } - public var Wallpaper_SearchShort: String { return self._s[3607]! } - public var SettingsSearch_Synonyms_Appearance_ColorTheme: String { return self._s[3609]! } - public var PasscodeSettings_UnlockWithFaceId: String { return self._s[3610]! } - public var Channel_BotDoesntSupportGroups: String { return self._s[3611]! } + public var Login_CallRequestState3: String { return self._s[3613]! } + public var Wallpaper_SearchShort: String { return self._s[3614]! } + public var SettingsSearch_Synonyms_Appearance_ColorTheme: String { return self._s[3616]! } + public var PasscodeSettings_UnlockWithFaceId: String { return self._s[3617]! } + public var Channel_BotDoesntSupportGroups: String { return self._s[3618]! } public func PUSH_CHAT_MESSAGE_GEOLIVE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3612]!, self._r[3612]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3619]!, self._r[3619]!, [_1, _2]) } - public var Channel_AdminLogFilter_Title: String { return self._s[3613]! } - public var Appearance_ThemePreview_Chat_4_Text: String { return self._s[3615]! } - public var Notifications_GroupNotificationsExceptions: String { return self._s[3618]! } + public var Channel_AdminLogFilter_Title: String { return self._s[3620]! } + public var Appearance_ThemePreview_Chat_4_Text: String { return self._s[3622]! } + public var Notifications_GroupNotificationsExceptions: String { return self._s[3625]! } public func FileSize_B(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3619]!, self._r[3619]!, [_0]) + return formatWithArgumentRanges(self._s[3626]!, self._r[3626]!, [_0]) } - public var Passport_CorrectErrors: String { return self._s[3620]! } - public var VoiceOver_Chat_YourAnonymousPoll: String { return self._s[3621]! } + public var Passport_CorrectErrors: String { return self._s[3627]! } + public var VoiceOver_Chat_YourAnonymousPoll: String { return self._s[3628]! } public func Channel_MessageTitleUpdated(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3622]!, self._r[3622]!, [_0]) + return formatWithArgumentRanges(self._s[3629]!, self._r[3629]!, [_0]) } - public var Map_SendMyCurrentLocation: String { return self._s[3623]! } - public var Channel_DiscussionGroup: String { return self._s[3624]! } - public var TwoFactorSetup_Email_SkipConfirmationSkip: String { return self._s[3625]! } + public var Map_SendMyCurrentLocation: String { return self._s[3630]! } + public var Channel_DiscussionGroup: String { return self._s[3631]! } + public var TwoFactorSetup_Email_SkipConfirmationSkip: String { return self._s[3632]! } public func PUSH_PINNED_CONTACT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3626]!, self._r[3626]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3633]!, self._r[3633]!, [_1, _2]) } - public var SharedMedia_SearchNoResults: String { return self._s[3627]! } - public var Permissions_NotificationsText_v0: String { return self._s[3628]! } - public var Channel_EditAdmin_PermissionDeleteMessagesOfOthers: String { return self._s[3629]! } - public var Appearance_AppIcon: String { return self._s[3630]! } - public var Appearance_ThemePreview_ChatList_3_AuthorName: String { return self._s[3631]! } - public var LoginPassword_FloodError: String { return self._s[3632]! } - public var Wallet_Send_OwnAddressAlertProceed: String { return self._s[3634]! } - public var Group_Setup_HistoryHiddenHelp: String { return self._s[3635]! } + public var SharedMedia_SearchNoResults: String { return self._s[3634]! } + public var Permissions_NotificationsText_v0: String { return self._s[3635]! } + public var Channel_EditAdmin_PermissionDeleteMessagesOfOthers: String { return self._s[3636]! } + public var Appearance_AppIcon: String { return self._s[3637]! } + public var Appearance_ThemePreview_ChatList_3_AuthorName: String { return self._s[3638]! } + public var LoginPassword_FloodError: String { return self._s[3639]! } + public var Wallet_Send_OwnAddressAlertProceed: String { return self._s[3641]! } + public var Group_Setup_HistoryHiddenHelp: String { return self._s[3642]! } public func TwoStepAuth_PendingEmailHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3636]!, self._r[3636]!, [_0]) + return formatWithArgumentRanges(self._s[3643]!, self._r[3643]!, [_0]) } - public var Passport_Language_bn: String { return self._s[3637]! } + public var Passport_Language_bn: String { return self._s[3644]! } public func DialogList_SingleUploadingPhotoSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3638]!, self._r[3638]!, [_0]) + return formatWithArgumentRanges(self._s[3645]!, self._r[3645]!, [_0]) } - public var ChatList_Context_Pin: String { return self._s[3639]! } + public var ChatList_Context_Pin: String { return self._s[3646]! } public func Notification_PinnedAudioMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3640]!, self._r[3640]!, [_0]) + return formatWithArgumentRanges(self._s[3647]!, self._r[3647]!, [_0]) } public func Channel_AdminLog_MessageChangedGroupStickerPack(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3641]!, self._r[3641]!, [_0]) + return formatWithArgumentRanges(self._s[3648]!, self._r[3648]!, [_0]) } - public var Wallet_Navigation_Close: String { return self._s[3642]! } - public var GroupInfo_InvitationLinkGroupFull: String { return self._s[3646]! } - public var Group_EditAdmin_PermissionChangeInfo: String { return self._s[3648]! } - public var Wallet_Month_GenDecember: String { return self._s[3649]! } - public var Contacts_PermissionsAllow: String { return self._s[3650]! } - public var ReportPeer_ReasonCopyright: String { return self._s[3651]! } - public var Channel_EditAdmin_PermissinAddAdminOn: String { return self._s[3652]! } - public var WallpaperPreview_Pattern: String { return self._s[3653]! } - public var Paint_Duplicate: String { return self._s[3654]! } - public var Passport_Address_Country: String { return self._s[3655]! } - public var Notification_RenamedChannel: String { return self._s[3657]! } - public var ChatList_Context_Unmute: String { return self._s[3658]! } - public var CheckoutInfo_ErrorPostcodeInvalid: String { return self._s[3659]! } - public var Group_MessagePhotoUpdated: String { return self._s[3660]! } - public var Channel_BanUser_PermissionSendMedia: String { return self._s[3661]! } - public var Conversation_ContextMenuBan: String { return self._s[3662]! } - public var TwoStepAuth_EmailSent: String { return self._s[3663]! } - public var MessagePoll_NoVotes: String { return self._s[3664]! } - public var Wallet_Send_ErrorNotEnoughFundsTitle: String { return self._s[3665]! } - public var Passport_Language_is: String { return self._s[3667]! } - public var PeopleNearby_UsersEmpty: String { return self._s[3669]! } - public var Tour_Text5: String { return self._s[3670]! } + public var Wallet_Navigation_Close: String { return self._s[3649]! } + public var GroupInfo_InvitationLinkGroupFull: String { return self._s[3653]! } + public var Group_EditAdmin_PermissionChangeInfo: String { return self._s[3655]! } + public var Wallet_Month_GenDecember: String { return self._s[3656]! } + public var Contacts_PermissionsAllow: String { return self._s[3657]! } + public var ReportPeer_ReasonCopyright: String { return self._s[3658]! } + public var Channel_EditAdmin_PermissinAddAdminOn: String { return self._s[3659]! } + public var WallpaperPreview_Pattern: String { return self._s[3660]! } + public var Paint_Duplicate: String { return self._s[3661]! } + public var Passport_Address_Country: String { return self._s[3662]! } + public var Notification_RenamedChannel: String { return self._s[3664]! } + public var ChatList_Context_Unmute: String { return self._s[3665]! } + public var CheckoutInfo_ErrorPostcodeInvalid: String { return self._s[3666]! } + public var Group_MessagePhotoUpdated: String { return self._s[3667]! } + public var Channel_BanUser_PermissionSendMedia: String { return self._s[3668]! } + public var Conversation_ContextMenuBan: String { return self._s[3669]! } + public var TwoStepAuth_EmailSent: String { return self._s[3670]! } + public var MessagePoll_NoVotes: String { return self._s[3671]! } + public var Wallet_Send_ErrorNotEnoughFundsTitle: String { return self._s[3672]! } + public var Passport_Language_is: String { return self._s[3674]! } + public var PeopleNearby_UsersEmpty: String { return self._s[3676]! } + public var Tour_Text5: String { return self._s[3677]! } public func Call_GroupFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3673]!, self._r[3673]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3680]!, self._r[3680]!, [_1, _2]) } - public var Undo_SecretChatDeleted: String { return self._s[3674]! } - public var SocksProxySetup_ShareQRCode: String { return self._s[3675]! } + public var Undo_SecretChatDeleted: String { return self._s[3681]! } + public var SocksProxySetup_ShareQRCode: String { return self._s[3682]! } public func VoiceOver_Chat_Size(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3676]!, self._r[3676]!, [_0]) + return formatWithArgumentRanges(self._s[3683]!, self._r[3683]!, [_0]) } - public var Forward_ErrorDisabledForChat: String { return self._s[3677]! } - public var LogoutOptions_ChangePhoneNumberText: String { return self._s[3678]! } - public var Paint_Edit: String { return self._s[3680]! } - public var ScheduledMessages_ReminderNotification: String { return self._s[3682]! } - public var Undo_DeletedGroup: String { return self._s[3684]! } - public var LoginPassword_ForgotPassword: String { return self._s[3685]! } - public var Wallet_WordImport_IncorrectTitle: String { return self._s[3686]! } - public var GroupInfo_GroupNamePlaceholder: String { return self._s[3687]! } + public var Forward_ErrorDisabledForChat: String { return self._s[3684]! } + public var LogoutOptions_ChangePhoneNumberText: String { return self._s[3685]! } + public var Paint_Edit: String { return self._s[3687]! } + public var ScheduledMessages_ReminderNotification: String { return self._s[3689]! } + public var Undo_DeletedGroup: String { return self._s[3691]! } + public var LoginPassword_ForgotPassword: String { return self._s[3692]! } + public var Wallet_WordImport_IncorrectTitle: String { return self._s[3693]! } + public var GroupInfo_GroupNamePlaceholder: String { return self._s[3694]! } public func Notification_Kicked(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3688]!, self._r[3688]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3695]!, self._r[3695]!, [_0, _1]) } - public var AppWallet_TransactionInfo_FeeInfoURL: String { return self._s[3689]! } - public var Conversation_InputTextCaptionPlaceholder: String { return self._s[3690]! } - public var AutoDownloadSettings_VideoMessagesTitle: String { return self._s[3691]! } - public var Passport_Language_uz: String { return self._s[3692]! } - public var Conversation_PinMessageAlertGroup: String { return self._s[3693]! } - public var SettingsSearch_Synonyms_Privacy_GroupsAndChannels: String { return self._s[3694]! } - public var Map_StopLiveLocation: String { return self._s[3696]! } - public var VoiceOver_MessageContextSend: String { return self._s[3698]! } - public var PasscodeSettings_Help: String { return self._s[3699]! } - public var NotificationsSound_Input: String { return self._s[3700]! } - public var Share_Title: String { return self._s[3703]! } - public var LogoutOptions_Title: String { return self._s[3704]! } - public var Wallet_Send_AddressText: String { return self._s[3705]! } - public var Login_TermsOfServiceAgree: String { return self._s[3706]! } - public var Compose_NewEncryptedChatTitle: String { return self._s[3707]! } - public var Channel_AdminLog_TitleSelectedEvents: String { return self._s[3708]! } - public var Channel_EditAdmin_PermissionEditMessages: String { return self._s[3709]! } - public var EnterPasscode_EnterTitle: String { return self._s[3710]! } + public var AppWallet_TransactionInfo_FeeInfoURL: String { return self._s[3696]! } + public var Conversation_InputTextCaptionPlaceholder: String { return self._s[3697]! } + public var AutoDownloadSettings_VideoMessagesTitle: String { return self._s[3698]! } + public var Passport_Language_uz: String { return self._s[3699]! } + public var Conversation_PinMessageAlertGroup: String { return self._s[3700]! } + public var SettingsSearch_Synonyms_Privacy_GroupsAndChannels: String { return self._s[3701]! } + public var Map_StopLiveLocation: String { return self._s[3703]! } + public var VoiceOver_MessageContextSend: String { return self._s[3705]! } + public var PasscodeSettings_Help: String { return self._s[3706]! } + public var NotificationsSound_Input: String { return self._s[3707]! } + public var Share_Title: String { return self._s[3710]! } + public var LogoutOptions_Title: String { return self._s[3711]! } + public var Wallet_Send_AddressText: String { return self._s[3712]! } + public var Login_TermsOfServiceAgree: String { return self._s[3713]! } + public var Compose_NewEncryptedChatTitle: String { return self._s[3714]! } + public var Channel_AdminLog_TitleSelectedEvents: String { return self._s[3715]! } + public var Channel_EditAdmin_PermissionEditMessages: String { return self._s[3716]! } + public var EnterPasscode_EnterTitle: String { return self._s[3717]! } public func Call_PrivacyErrorMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3711]!, self._r[3711]!, [_0]) + return formatWithArgumentRanges(self._s[3718]!, self._r[3718]!, [_0]) } - public var Settings_CopyPhoneNumber: String { return self._s[3712]! } - public var Conversation_AddToContacts: String { return self._s[3713]! } + public var Settings_CopyPhoneNumber: String { return self._s[3719]! } + public var Conversation_AddToContacts: String { return self._s[3720]! } public func VoiceOver_Chat_ReplyFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3714]!, self._r[3714]!, [_0]) + return formatWithArgumentRanges(self._s[3721]!, self._r[3721]!, [_0]) } - public var NotificationsSound_Keys: String { return self._s[3715]! } + public var NotificationsSound_Keys: String { return self._s[3722]! } public func Call_ParticipantVersionOutdatedError(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3716]!, self._r[3716]!, [_0]) + return formatWithArgumentRanges(self._s[3723]!, self._r[3723]!, [_0]) } - public var Notification_MessageLifetime1w: String { return self._s[3717]! } - public var Message_Video: String { return self._s[3718]! } - public var AutoDownloadSettings_CellularTitle: String { return self._s[3719]! } + public var Notification_MessageLifetime1w: String { return self._s[3724]! } + public var Message_Video: String { return self._s[3725]! } + public var AutoDownloadSettings_CellularTitle: String { return self._s[3726]! } public func PUSH_CHANNEL_MESSAGE_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3720]!, self._r[3720]!, [_1]) + return formatWithArgumentRanges(self._s[3727]!, self._r[3727]!, [_1]) } - public var Wallet_Receive_AmountInfo: String { return self._s[3723]! } + public var Wallet_Receive_AmountInfo: String { return self._s[3730]! } public func Notification_JoinedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3724]!, self._r[3724]!, [_0]) + return formatWithArgumentRanges(self._s[3731]!, self._r[3731]!, [_0]) } public func PrivacySettings_LastSeenContactsPlus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3725]!, self._r[3725]!, [_0]) + return formatWithArgumentRanges(self._s[3732]!, self._r[3732]!, [_0]) } - public var Passport_Language_mk: String { return self._s[3726]! } + public var Passport_Language_mk: String { return self._s[3733]! } public func Wallet_Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3727]!, self._r[3727]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3734]!, self._r[3734]!, [_1, _2, _3]) } - public var CreatePoll_CancelConfirmation: String { return self._s[3728]! } - public var MessagePoll_LabelAnonymousQuiz: String { return self._s[3729]! } - public var Conversation_SilentBroadcastTooltipOn: String { return self._s[3731]! } - public var PrivacyPolicy_Decline: String { return self._s[3732]! } - public var Passport_Identity_DoesNotExpire: String { return self._s[3733]! } - public var Channel_AdminLogFilter_EventsRestrictions: String { return self._s[3734]! } - public var AuthSessions_AddDeviceIntro_Action: String { return self._s[3735]! } - public var Permissions_SiriAllow_v0: String { return self._s[3737]! } - public var Wallet_Month_ShortAugust: String { return self._s[3738]! } - public var Appearance_ThemeCarouselNight: String { return self._s[3739]! } + public var CreatePoll_CancelConfirmation: String { return self._s[3735]! } + public var MessagePoll_LabelAnonymousQuiz: String { return self._s[3736]! } + public var Conversation_SilentBroadcastTooltipOn: String { return self._s[3738]! } + public var PrivacyPolicy_Decline: String { return self._s[3739]! } + public var Passport_Identity_DoesNotExpire: String { return self._s[3740]! } + public var Channel_AdminLogFilter_EventsRestrictions: String { return self._s[3741]! } + public var AuthSessions_AddDeviceIntro_Action: String { return self._s[3742]! } + public var Permissions_SiriAllow_v0: String { return self._s[3744]! } + public var Wallet_Month_ShortAugust: String { return self._s[3745]! } + public var Appearance_ThemeCarouselNight: String { return self._s[3746]! } public func LOCAL_CHAT_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3740]!, self._r[3740]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[3747]!, self._r[3747]!, [_1, "\(_2)"]) } public func Notification_RenamedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3741]!, self._r[3741]!, [_0]) + return formatWithArgumentRanges(self._s[3748]!, self._r[3748]!, [_0]) } - public var Paint_Regular: String { return self._s[3742]! } - public var ChatSettings_AutoDownloadReset: String { return self._s[3743]! } - public var SocksProxySetup_ShareLink: String { return self._s[3744]! } - public var Wallet_Qr_Title: String { return self._s[3745]! } - public var BlockedUsers_SelectUserTitle: String { return self._s[3746]! } - public var VoiceOver_Chat_RecordModeVoiceMessage: String { return self._s[3748]! } - public var Wallet_Settings_Configuration: String { return self._s[3749]! } - public var GroupInfo_InviteByLink: String { return self._s[3750]! } - public var MessageTimer_Custom: String { return self._s[3751]! } - public var UserInfo_NotificationsDefaultEnabled: String { return self._s[3752]! } - public var Conversation_StopQuizConfirmationTitle: String { return self._s[3753]! } - public var Passport_Address_TypeTemporaryRegistration: String { return self._s[3755]! } - public var Conversation_SendMessage_SetReminder: String { return self._s[3756]! } - public var VoiceOver_Chat_Selected: String { return self._s[3757]! } - public var ChatSettings_AutoDownloadUsingWiFi: String { return self._s[3758]! } - public var Channel_Username_InvalidTaken: String { return self._s[3759]! } - public var Conversation_ClousStorageInfo_Description3: String { return self._s[3760]! } - public var Wallet_WordCheck_TryAgain: String { return self._s[3761]! } - public var Wallet_Info_TransactionPendingHeader: String { return self._s[3762]! } - public var Settings_ChatBackground: String { return self._s[3763]! } - public var Channel_Subscribers_Title: String { return self._s[3764]! } - public var Wallet_Receive_InvoiceUrlHeader: String { return self._s[3765]! } - public var ApplyLanguage_ChangeLanguageTitle: String { return self._s[3766]! } - public var Watch_ConnectionDescription: String { return self._s[3767]! } - public var OldChannels_NoticeText: String { return self._s[3770]! } - public var Wallet_Configuration_ApplyErrorTitle: String { return self._s[3771]! } - public var IntentsSettings_SuggestBy: String { return self._s[3773]! } - public var Theme_ThemeChangedText: String { return self._s[3774]! } - public var ChatList_ArchivedChatsTitle: String { return self._s[3775]! } - public var Wallpaper_ResetWallpapers: String { return self._s[3776]! } - public var Wallet_Send_TransactionInProgress: String { return self._s[3777]! } - public var EditProfile_Title: String { return self._s[3778]! } - public var NotificationsSound_Bamboo: String { return self._s[3780]! } - public var Channel_AdminLog_MessagePreviousMessage: String { return self._s[3782]! } - public var Login_SmsRequestState2: String { return self._s[3783]! } - public var Passport_Language_ar: String { return self._s[3784]! } + public var Paint_Regular: String { return self._s[3749]! } + public var ChatSettings_AutoDownloadReset: String { return self._s[3750]! } + public var SocksProxySetup_ShareLink: String { return self._s[3751]! } + public var Wallet_Qr_Title: String { return self._s[3752]! } + public var BlockedUsers_SelectUserTitle: String { return self._s[3753]! } + public var VoiceOver_Chat_RecordModeVoiceMessage: String { return self._s[3755]! } + public var Wallet_Settings_Configuration: String { return self._s[3756]! } + public var GroupInfo_InviteByLink: String { return self._s[3757]! } + public var MessageTimer_Custom: String { return self._s[3758]! } + public var UserInfo_NotificationsDefaultEnabled: String { return self._s[3759]! } + public var Conversation_StopQuizConfirmationTitle: String { return self._s[3760]! } + public var Passport_Address_TypeTemporaryRegistration: String { return self._s[3762]! } + public var Conversation_SendMessage_SetReminder: String { return self._s[3763]! } + public var VoiceOver_Chat_Selected: String { return self._s[3764]! } + public var ChatSettings_AutoDownloadUsingWiFi: String { return self._s[3765]! } + public var Channel_Username_InvalidTaken: String { return self._s[3766]! } + public var Conversation_ClousStorageInfo_Description3: String { return self._s[3767]! } + public var Wallet_WordCheck_TryAgain: String { return self._s[3768]! } + public var Wallet_Info_TransactionPendingHeader: String { return self._s[3769]! } + public var Settings_ChatBackground: String { return self._s[3770]! } + public var Channel_Subscribers_Title: String { return self._s[3771]! } + public var Wallet_Receive_InvoiceUrlHeader: String { return self._s[3772]! } + public var ApplyLanguage_ChangeLanguageTitle: String { return self._s[3773]! } + public var Watch_ConnectionDescription: String { return self._s[3774]! } + public var OldChannels_NoticeText: String { return self._s[3777]! } + public var Wallet_Configuration_ApplyErrorTitle: String { return self._s[3778]! } + public var IntentsSettings_SuggestBy: String { return self._s[3780]! } + public var Theme_ThemeChangedText: String { return self._s[3781]! } + public var ChatList_ArchivedChatsTitle: String { return self._s[3782]! } + public var Wallpaper_ResetWallpapers: String { return self._s[3783]! } + public var Wallet_Send_TransactionInProgress: String { return self._s[3784]! } + public var EditProfile_Title: String { return self._s[3785]! } + public var NotificationsSound_Bamboo: String { return self._s[3787]! } + public var Channel_AdminLog_MessagePreviousMessage: String { return self._s[3789]! } + public var Login_SmsRequestState2: String { return self._s[3790]! } + public var Passport_Language_ar: String { return self._s[3791]! } public func Message_AuthorPinnedGame(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3785]!, self._r[3785]!, [_0]) + return formatWithArgumentRanges(self._s[3792]!, self._r[3792]!, [_0]) } - public var SettingsSearch_Synonyms_EditProfile_Title: String { return self._s[3786]! } - public var Wallet_Created_Text: String { return self._s[3787]! } - public var Conversation_MessageDialogEdit: String { return self._s[3789]! } - public var Wallet_Created_Proceed: String { return self._s[3790]! } - public var Wallet_Words_Done: String { return self._s[3791]! } - public var VoiceOver_Media_PlaybackPause: String { return self._s[3792]! } + public var SettingsSearch_Synonyms_EditProfile_Title: String { return self._s[3793]! } + public var Wallet_Created_Text: String { return self._s[3794]! } + public var Conversation_MessageDialogEdit: String { return self._s[3796]! } + public var Wallet_Created_Proceed: String { return self._s[3797]! } + public var Wallet_Words_Done: String { return self._s[3798]! } + public var VoiceOver_Media_PlaybackPause: String { return self._s[3799]! } public func PUSH_AUTH_UNKNOWN(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3793]!, self._r[3793]!, [_1]) + return formatWithArgumentRanges(self._s[3800]!, self._r[3800]!, [_1]) } - public var Common_Close: String { return self._s[3794]! } - public var GroupInfo_PublicLink: String { return self._s[3795]! } - public var Channel_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[3796]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsPreview: String { return self._s[3797]! } + public var Common_Close: String { return self._s[3801]! } + public var GroupInfo_PublicLink: String { return self._s[3802]! } + public var Channel_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[3803]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsPreview: String { return self._s[3804]! } public func Channel_AdminLog_MessageToggleInvitesOff(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3801]!, self._r[3801]!, [_0]) + return formatWithArgumentRanges(self._s[3808]!, self._r[3808]!, [_0]) } - public var UserInfo_About_Placeholder: String { return self._s[3802]! } + public var UserInfo_About_Placeholder: String { return self._s[3809]! } public func Conversation_FileHowToText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3803]!, self._r[3803]!, [_0]) + return formatWithArgumentRanges(self._s[3810]!, self._r[3810]!, [_0]) } - public var GroupInfo_Permissions_SectionTitle: String { return self._s[3804]! } - public var Channel_Info_Banned: String { return self._s[3806]! } + public var GroupInfo_Permissions_SectionTitle: String { return self._s[3811]! } + public var Channel_Info_Banned: String { return self._s[3813]! } public func Time_MonthOfYear_m11(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3807]!, self._r[3807]!, [_0]) + return formatWithArgumentRanges(self._s[3814]!, self._r[3814]!, [_0]) } - public var Appearance_Other: String { return self._s[3808]! } - public var Passport_Language_my: String { return self._s[3809]! } - public var Group_Setup_BasicHistoryHiddenHelp: String { return self._s[3810]! } + public var Appearance_Other: String { return self._s[3815]! } + public var Passport_Language_my: String { return self._s[3816]! } + public var Group_Setup_BasicHistoryHiddenHelp: String { return self._s[3817]! } public func Time_PreciseDate_m9(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3811]!, self._r[3811]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3818]!, self._r[3818]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Privacy_PasscodeAndFaceId: String { return self._s[3812]! } - public var IntentsSettings_SuggestedAndSpotlightChatsInfo: String { return self._s[3813]! } - public var Preview_CopyAddress: String { return self._s[3814]! } + public var SettingsSearch_Synonyms_Privacy_PasscodeAndFaceId: String { return self._s[3819]! } + public var IntentsSettings_SuggestedAndSpotlightChatsInfo: String { return self._s[3820]! } + public var Preview_CopyAddress: String { return self._s[3821]! } public func DialogList_SinglePlayingGameSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3815]!, self._r[3815]!, [_0]) + return formatWithArgumentRanges(self._s[3822]!, self._r[3822]!, [_0]) } - public var KeyCommand_JumpToPreviousChat: String { return self._s[3816]! } - public var UserInfo_BotSettings: String { return self._s[3817]! } - public var LiveLocation_MenuStopAll: String { return self._s[3819]! } - public var Passport_PasswordCreate: String { return self._s[3820]! } - public var StickerSettings_MaskContextInfo: String { return self._s[3821]! } - public var Message_PinnedLocationMessage: String { return self._s[3822]! } - public var Map_Satellite: String { return self._s[3823]! } - public var Watch_Message_Unsupported: String { return self._s[3824]! } - public var Username_TooManyPublicUsernamesError: String { return self._s[3825]! } - public var TwoStepAuth_EnterPasswordInvalid: String { return self._s[3826]! } + public var KeyCommand_JumpToPreviousChat: String { return self._s[3823]! } + public var UserInfo_BotSettings: String { return self._s[3824]! } + public var LiveLocation_MenuStopAll: String { return self._s[3826]! } + public var Passport_PasswordCreate: String { return self._s[3827]! } + public var StickerSettings_MaskContextInfo: String { return self._s[3828]! } + public var Message_PinnedLocationMessage: String { return self._s[3829]! } + public var Map_Satellite: String { return self._s[3830]! } + public var Watch_Message_Unsupported: String { return self._s[3831]! } + public var Username_TooManyPublicUsernamesError: String { return self._s[3832]! } + public var TwoStepAuth_EnterPasswordInvalid: String { return self._s[3833]! } public func Notification_PinnedTextMessage(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3827]!, self._r[3827]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3834]!, self._r[3834]!, [_0, _1]) } public func Conversation_OpenBotLinkText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3828]!, self._r[3828]!, [_0]) + return formatWithArgumentRanges(self._s[3835]!, self._r[3835]!, [_0]) } - public var Wallet_WordImport_Continue: String { return self._s[3829]! } + public var Wallet_WordImport_Continue: String { return self._s[3836]! } public func TwoFactorSetup_EmailVerification_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3830]!, self._r[3830]!, [_0]) + return formatWithArgumentRanges(self._s[3837]!, self._r[3837]!, [_0]) } - public var Notifications_ChannelNotificationsHelp: String { return self._s[3831]! } - public var Privacy_Calls_P2PContacts: String { return self._s[3832]! } - public var NotificationsSound_None: String { return self._s[3833]! } - public var Wallet_TransactionInfo_StorageFeeHeader: String { return self._s[3834]! } - public var Channel_DiscussionGroup_UnlinkGroup: String { return self._s[3836]! } - public var AccessDenied_VoiceMicrophone: String { return self._s[3837]! } + public var Notifications_ChannelNotificationsHelp: String { return self._s[3838]! } + public var Privacy_Calls_P2PContacts: String { return self._s[3839]! } + public var NotificationsSound_None: String { return self._s[3840]! } + public var Wallet_TransactionInfo_StorageFeeHeader: String { return self._s[3841]! } + public var Channel_DiscussionGroup_UnlinkGroup: String { return self._s[3843]! } + public var AccessDenied_VoiceMicrophone: String { return self._s[3844]! } public func ApplyLanguage_ChangeLanguageAlreadyActive(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3838]!, self._r[3838]!, [_1]) + return formatWithArgumentRanges(self._s[3845]!, self._r[3845]!, [_1]) } - public var Cache_Indexing: String { return self._s[3839]! } - public var DialogList_RecentTitlePeople: String { return self._s[3841]! } - public var DialogList_EncryptionRejected: String { return self._s[3842]! } - public var GroupInfo_Administrators: String { return self._s[3843]! } - public var Passport_ScanPassportHelp: String { return self._s[3844]! } - public var Application_Name: String { return self._s[3845]! } - public var Channel_AdminLogFilter_ChannelEventsInfo: String { return self._s[3846]! } - public var PeopleNearby_MakeVisible: String { return self._s[3848]! } - public var Appearance_ThemeCarouselDay: String { return self._s[3849]! } - public var Passport_Identity_TranslationHelp: String { return self._s[3850]! } + public var Cache_Indexing: String { return self._s[3846]! } + public var DialogList_RecentTitlePeople: String { return self._s[3848]! } + public var DialogList_EncryptionRejected: String { return self._s[3849]! } + public var GroupInfo_Administrators: String { return self._s[3850]! } + public var Passport_ScanPassportHelp: String { return self._s[3851]! } + public var Application_Name: String { return self._s[3852]! } + public var Channel_AdminLogFilter_ChannelEventsInfo: String { return self._s[3853]! } + public var PeopleNearby_MakeVisible: String { return self._s[3855]! } + public var Appearance_ThemeCarouselDay: String { return self._s[3856]! } + public var Passport_Identity_TranslationHelp: String { return self._s[3857]! } public func VoiceOver_Chat_VideoMessageFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3851]!, self._r[3851]!, [_0]) + return formatWithArgumentRanges(self._s[3858]!, self._r[3858]!, [_0]) } public func Notification_JoinedGroupByLink(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3852]!, self._r[3852]!, [_0]) + return formatWithArgumentRanges(self._s[3859]!, self._r[3859]!, [_0]) } public func DialogList_EncryptedChatStartedOutgoing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3853]!, self._r[3853]!, [_0]) + return formatWithArgumentRanges(self._s[3860]!, self._r[3860]!, [_0]) } - public var Channel_EditAdmin_PermissionDeleteMessages: String { return self._s[3854]! } - public var Privacy_ChatsTitle: String { return self._s[3855]! } - public var DialogList_ClearHistoryConfirmation: String { return self._s[3856]! } - public var SettingsSearch_Synonyms_Data_Storage_ClearCache: String { return self._s[3857]! } - public var Watch_Suggestion_HoldOn: String { return self._s[3858]! } - public var Group_EditAdmin_TransferOwnership: String { return self._s[3859]! } - public var WebBrowser_Title: String { return self._s[3860]! } - public var Group_LinkedChannel: String { return self._s[3861]! } - public var VoiceOver_Chat_SeenByRecipient: String { return self._s[3862]! } - public var SocksProxySetup_RequiredCredentials: String { return self._s[3863]! } - public var Passport_Address_TypeRentalAgreementUploadScan: String { return self._s[3864]! } - public var Appearance_TextSize_UseSystem: String { return self._s[3865]! } - public var TwoStepAuth_EmailSkipAlert: String { return self._s[3866]! } - public var ScheduledMessages_RemindersTitle: String { return self._s[3868]! } - public var Channel_Setup_TypePublic: String { return self._s[3870]! } + public var Channel_EditAdmin_PermissionDeleteMessages: String { return self._s[3861]! } + public var Privacy_ChatsTitle: String { return self._s[3862]! } + public var DialogList_ClearHistoryConfirmation: String { return self._s[3863]! } + public var SettingsSearch_Synonyms_Data_Storage_ClearCache: String { return self._s[3864]! } + public var Watch_Suggestion_HoldOn: String { return self._s[3865]! } + public var Group_EditAdmin_TransferOwnership: String { return self._s[3866]! } + public var WebBrowser_Title: String { return self._s[3867]! } + public var Group_LinkedChannel: String { return self._s[3868]! } + public var VoiceOver_Chat_SeenByRecipient: String { return self._s[3869]! } + public var SocksProxySetup_RequiredCredentials: String { return self._s[3870]! } + public var Passport_Address_TypeRentalAgreementUploadScan: String { return self._s[3871]! } + public var Appearance_TextSize_UseSystem: String { return self._s[3872]! } + public var TwoStepAuth_EmailSkipAlert: String { return self._s[3873]! } + public var ScheduledMessages_RemindersTitle: String { return self._s[3875]! } + public var Channel_Setup_TypePublic: String { return self._s[3877]! } public func Channel_AdminLog_MessageToggleInvitesOn(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3871]!, self._r[3871]!, [_0]) + return formatWithArgumentRanges(self._s[3878]!, self._r[3878]!, [_0]) } - public var Channel_TypeSetup_Title: String { return self._s[3873]! } - public var MessagePoll_ViewResults: String { return self._s[3874]! } - public var Map_OpenInMaps: String { return self._s[3876]! } + public var Channel_TypeSetup_Title: String { return self._s[3880]! } + public var MessagePoll_ViewResults: String { return self._s[3881]! } + public var Map_OpenInMaps: String { return self._s[3883]! } public func PUSH_PINNED_NOTEXT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3877]!, self._r[3877]!, [_1]) + return formatWithArgumentRanges(self._s[3884]!, self._r[3884]!, [_1]) } - public var NotificationsSound_Tremolo: String { return self._s[3879]! } + public var NotificationsSound_Tremolo: String { return self._s[3886]! } public func Date_ChatDateHeaderYear(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3880]!, self._r[3880]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3887]!, self._r[3887]!, [_1, _2, _3]) } - public var ConversationProfile_UnknownAddMemberError: String { return self._s[3881]! } - public var Channel_OwnershipTransfer_PasswordPlaceholder: String { return self._s[3882]! } - public var Passport_PasswordHelp: String { return self._s[3883]! } - public var Login_CodeExpiredError: String { return self._s[3884]! } - public var Channel_EditAdmin_PermissionChangeInfo: String { return self._s[3885]! } - public var Conversation_TitleUnmute: String { return self._s[3886]! } - public var Passport_Identity_ScansHelp: String { return self._s[3887]! } - public var Passport_Language_lo: String { return self._s[3888]! } - public var Camera_FlashAuto: String { return self._s[3889]! } - public var Conversation_OpenBotLinkOpen: String { return self._s[3890]! } - public var Common_Cancel: String { return self._s[3891]! } - public var DialogList_SavedMessagesTooltip: String { return self._s[3892]! } - public var TwoStepAuth_SetupPasswordTitle: String { return self._s[3893]! } - public var Appearance_TintAllColors: String { return self._s[3894]! } + public var ConversationProfile_UnknownAddMemberError: String { return self._s[3888]! } + public var Channel_OwnershipTransfer_PasswordPlaceholder: String { return self._s[3889]! } + public var Passport_PasswordHelp: String { return self._s[3890]! } + public var Login_CodeExpiredError: String { return self._s[3891]! } + public var Channel_EditAdmin_PermissionChangeInfo: String { return self._s[3892]! } + public var Conversation_TitleUnmute: String { return self._s[3893]! } + public var Passport_Identity_ScansHelp: String { return self._s[3894]! } + public var Passport_Language_lo: String { return self._s[3895]! } + public var Camera_FlashAuto: String { return self._s[3896]! } + public var Conversation_OpenBotLinkOpen: String { return self._s[3897]! } + public var Common_Cancel: String { return self._s[3898]! } + public var DialogList_SavedMessagesTooltip: String { return self._s[3899]! } + public var TwoStepAuth_SetupPasswordTitle: String { return self._s[3900]! } + public var Appearance_TintAllColors: String { return self._s[3901]! } public func PUSH_MESSAGE_FWD(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3895]!, self._r[3895]!, [_1]) + return formatWithArgumentRanges(self._s[3902]!, self._r[3902]!, [_1]) } - public var Conversation_ReportSpamConfirmation: String { return self._s[3896]! } - public var ChatSettings_Title: String { return self._s[3898]! } - public var Passport_PasswordReset: String { return self._s[3899]! } - public var SocksProxySetup_TypeNone: String { return self._s[3900]! } - public var EditTheme_Title: String { return self._s[3903]! } - public var PhoneNumberHelp_Help: String { return self._s[3904]! } - public var Checkout_EnterPassword: String { return self._s[3905]! } - public var Activity_UploadingDocument: String { return self._s[3907]! } - public var Share_AuthTitle: String { return self._s[3908]! } - public var State_Connecting: String { return self._s[3909]! } - public var Profile_MessageLifetime1w: String { return self._s[3910]! } - public var Conversation_ContextMenuReport: String { return self._s[3911]! } - public var CheckoutInfo_ReceiverInfoPhone: String { return self._s[3912]! } - public var AutoNightTheme_ScheduledTo: String { return self._s[3913]! } + public var Conversation_ReportSpamConfirmation: String { return self._s[3903]! } + public var ChatSettings_Title: String { return self._s[3905]! } + public var Passport_PasswordReset: String { return self._s[3906]! } + public var SocksProxySetup_TypeNone: String { return self._s[3907]! } + public var EditTheme_Title: String { return self._s[3910]! } + public var PhoneNumberHelp_Help: String { return self._s[3911]! } + public var Checkout_EnterPassword: String { return self._s[3912]! } + public var Activity_UploadingDocument: String { return self._s[3914]! } + public var Share_AuthTitle: String { return self._s[3915]! } + public var State_Connecting: String { return self._s[3916]! } + public var Profile_MessageLifetime1w: String { return self._s[3917]! } + public var Conversation_ContextMenuReport: String { return self._s[3918]! } + public var CheckoutInfo_ReceiverInfoPhone: String { return self._s[3919]! } + public var AutoNightTheme_ScheduledTo: String { return self._s[3920]! } public func VoiceOver_Chat_AnonymousPollFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3914]!, self._r[3914]!, [_0]) + return formatWithArgumentRanges(self._s[3921]!, self._r[3921]!, [_0]) } - public var AuthSessions_Terminate: String { return self._s[3915]! } - public var Wallet_WordImport_CanNotRemember: String { return self._s[3916]! } - public var Checkout_NewCard_CardholderNamePlaceholder: String { return self._s[3918]! } - public var KeyCommand_JumpToPreviousUnreadChat: String { return self._s[3919]! } - public var PhotoEditor_Set: String { return self._s[3920]! } - public var EmptyGroupInfo_Title: String { return self._s[3921]! } - public var Login_PadPhoneHelp: String { return self._s[3922]! } - public var AutoDownloadSettings_TypeGroupChats: String { return self._s[3924]! } - public var PrivacyPolicy_DeclineLastWarning: String { return self._s[3926]! } - public var NotificationsSound_Complete: String { return self._s[3927]! } - public var SettingsSearch_Synonyms_Privacy_Data_Title: String { return self._s[3928]! } - public var Group_Info_AdminLog: String { return self._s[3929]! } - public var GroupPermission_NotAvailableInPublicGroups: String { return self._s[3930]! } + public var AuthSessions_Terminate: String { return self._s[3922]! } + public var Wallet_WordImport_CanNotRemember: String { return self._s[3923]! } + public var Checkout_NewCard_CardholderNamePlaceholder: String { return self._s[3925]! } + public var KeyCommand_JumpToPreviousUnreadChat: String { return self._s[3926]! } + public var PhotoEditor_Set: String { return self._s[3927]! } + public var EmptyGroupInfo_Title: String { return self._s[3928]! } + public var Login_PadPhoneHelp: String { return self._s[3929]! } + public var AutoDownloadSettings_TypeGroupChats: String { return self._s[3931]! } + public var PrivacyPolicy_DeclineLastWarning: String { return self._s[3933]! } + public var NotificationsSound_Complete: String { return self._s[3934]! } + public var SettingsSearch_Synonyms_Privacy_Data_Title: String { return self._s[3935]! } + public var Group_Info_AdminLog: String { return self._s[3936]! } + public var GroupPermission_NotAvailableInPublicGroups: String { return self._s[3937]! } public func Wallet_Time_PreciseDate_m11(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3931]!, self._r[3931]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3938]!, self._r[3938]!, [_1, _2, _3]) } - public var Channel_AdminLog_InfoPanelAlertText: String { return self._s[3932]! } - public var Group_Location_CreateInThisPlace: String { return self._s[3934]! } - public var Conversation_Admin: String { return self._s[3935]! } - public var Conversation_GifTooltip: String { return self._s[3936]! } - public var Passport_NotLoggedInMessage: String { return self._s[3937]! } + public var Channel_AdminLog_InfoPanelAlertText: String { return self._s[3939]! } + public var Group_Location_CreateInThisPlace: String { return self._s[3941]! } + public var Conversation_Admin: String { return self._s[3942]! } + public var Conversation_GifTooltip: String { return self._s[3943]! } + public var Passport_NotLoggedInMessage: String { return self._s[3944]! } public func AutoDownloadSettings_OnFor(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3939]!, self._r[3939]!, [_0]) + return formatWithArgumentRanges(self._s[3946]!, self._r[3946]!, [_0]) } - public var Profile_MessageLifetimeForever: String { return self._s[3940]! } - public var SharedMedia_EmptyTitle: String { return self._s[3942]! } - public var Channel_Edit_PrivatePublicLinkAlert: String { return self._s[3944]! } - public var Username_Help: String { return self._s[3945]! } - public var DialogList_LanguageTooltip: String { return self._s[3947]! } - public var Map_LoadError: String { return self._s[3948]! } - public var Login_PhoneNumberAlreadyAuthorized: String { return self._s[3949]! } - public var Channel_AdminLog_AddMembers: String { return self._s[3950]! } - public var ArchivedChats_IntroTitle2: String { return self._s[3951]! } - public var Notification_Exceptions_NewException: String { return self._s[3952]! } - public var TwoStepAuth_EmailTitle: String { return self._s[3953]! } - public var WatchRemote_AlertText: String { return self._s[3954]! } + public var Profile_MessageLifetimeForever: String { return self._s[3947]! } + public var SharedMedia_EmptyTitle: String { return self._s[3949]! } + public var Channel_Edit_PrivatePublicLinkAlert: String { return self._s[3951]! } + public var Username_Help: String { return self._s[3952]! } + public var DialogList_LanguageTooltip: String { return self._s[3954]! } + public var Map_LoadError: String { return self._s[3955]! } + public var Login_PhoneNumberAlreadyAuthorized: String { return self._s[3956]! } + public var Channel_AdminLog_AddMembers: String { return self._s[3957]! } + public var ArchivedChats_IntroTitle2: String { return self._s[3958]! } + public var Notification_Exceptions_NewException: String { return self._s[3959]! } + public var TwoStepAuth_EmailTitle: String { return self._s[3960]! } + public var WatchRemote_AlertText: String { return self._s[3961]! } public func Wallet_Send_ConfirmationText(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3955]!, self._r[3955]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3962]!, self._r[3962]!, [_1, _2, _3]) } - public var ChatSettings_ConnectionType_Title: String { return self._s[3959]! } + public var ChatSettings_ConnectionType_Title: String { return self._s[3966]! } public func PUSH_PINNED_QUIZ(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3960]!, self._r[3960]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3967]!, self._r[3967]!, [_1, _2]) } public func Settings_CheckPhoneNumberTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3961]!, self._r[3961]!, [_0]) + return formatWithArgumentRanges(self._s[3968]!, self._r[3968]!, [_0]) } - public var SettingsSearch_Synonyms_Calls_CallTab: String { return self._s[3962]! } - public var WebBrowser_DefaultBrowser: String { return self._s[3963]! } - public var Passport_Address_CountryPlaceholder: String { return self._s[3964]! } + public var SettingsSearch_Synonyms_Calls_CallTab: String { return self._s[3969]! } + public var WebBrowser_DefaultBrowser: String { return self._s[3970]! } + public var Passport_Address_CountryPlaceholder: String { return self._s[3971]! } public func DialogList_AwaitingEncryption(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3965]!, self._r[3965]!, [_0]) + return formatWithArgumentRanges(self._s[3972]!, self._r[3972]!, [_0]) } public func Time_PreciseDate_m6(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3966]!, self._r[3966]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3973]!, self._r[3973]!, [_1, _2, _3]) } - public var Group_AdminLog_EmptyText: String { return self._s[3967]! } - public var SettingsSearch_Synonyms_Appearance_Title: String { return self._s[3968]! } - public var Conversation_PrivateChannelTooltip: String { return self._s[3970]! } - public var Wallet_Created_ExportErrorText: String { return self._s[3971]! } - public var ChatList_UndoArchiveText1: String { return self._s[3972]! } - public var AccessDenied_VideoMicrophone: String { return self._s[3973]! } - public var Conversation_ContextMenuStickerPackAdd: String { return self._s[3974]! } - public var Cache_ClearNone: String { return self._s[3975]! } - public var SocksProxySetup_FailedToConnect: String { return self._s[3976]! } - public var Permissions_NotificationsTitle_v0: String { return self._s[3977]! } + public var Group_AdminLog_EmptyText: String { return self._s[3974]! } + public var SettingsSearch_Synonyms_Appearance_Title: String { return self._s[3975]! } + public var Conversation_PrivateChannelTooltip: String { return self._s[3977]! } + public var Wallet_Created_ExportErrorText: String { return self._s[3978]! } + public var ChatList_UndoArchiveText1: String { return self._s[3979]! } + public var AccessDenied_VideoMicrophone: String { return self._s[3980]! } + public var Conversation_ContextMenuStickerPackAdd: String { return self._s[3981]! } + public var Cache_ClearNone: String { return self._s[3982]! } + public var SocksProxySetup_FailedToConnect: String { return self._s[3983]! } + public var Permissions_NotificationsTitle_v0: String { return self._s[3984]! } public func Channel_AdminLog_MessageEdited(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3978]!, self._r[3978]!, [_0]) + return formatWithArgumentRanges(self._s[3985]!, self._r[3985]!, [_0]) } - public var Passport_Identity_Country: String { return self._s[3979]! } + public var Passport_Identity_Country: String { return self._s[3986]! } public func ChatSettings_AutoDownloadSettings_TypeFile(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3980]!, self._r[3980]!, [_0]) + return formatWithArgumentRanges(self._s[3987]!, self._r[3987]!, [_0]) } public func Notification_CreatedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3981]!, self._r[3981]!, [_0]) + return formatWithArgumentRanges(self._s[3988]!, self._r[3988]!, [_0]) } - public var Exceptions_AddToExceptions: String { return self._s[3982]! } - public var AccessDenied_Settings: String { return self._s[3983]! } - public var Passport_Address_TypeUtilityBillUploadScan: String { return self._s[3984]! } - public var Month_ShortMay: String { return self._s[3985]! } - public var Compose_NewGroup: String { return self._s[3987]! } - public var Group_Setup_TypePrivate: String { return self._s[3989]! } - public var Login_PadPhoneHelpTitle: String { return self._s[3991]! } - public var Appearance_ThemeDayClassic: String { return self._s[3992]! } - public var Channel_AdminLog_MessagePreviousCaption: String { return self._s[3993]! } - public var AutoDownloadSettings_OffForAll: String { return self._s[3994]! } - public var Privacy_GroupsAndChannels_WhoCanAddMe: String { return self._s[3995]! } - public var Conversation_typing: String { return self._s[3997]! } - public var Undo_ScheduledMessagesCleared: String { return self._s[3998]! } - public var Paint_Masks: String { return self._s[3999]! } - public var Contacts_DeselectAll: String { return self._s[4000]! } + public var Exceptions_AddToExceptions: String { return self._s[3989]! } + public var AccessDenied_Settings: String { return self._s[3990]! } + public var Passport_Address_TypeUtilityBillUploadScan: String { return self._s[3991]! } + public var Month_ShortMay: String { return self._s[3992]! } + public var Compose_NewGroup: String { return self._s[3994]! } + public var Group_Setup_TypePrivate: String { return self._s[3996]! } + public var Login_PadPhoneHelpTitle: String { return self._s[3998]! } + public var Appearance_ThemeDayClassic: String { return self._s[3999]! } + public var Channel_AdminLog_MessagePreviousCaption: String { return self._s[4000]! } + public var AutoDownloadSettings_OffForAll: String { return self._s[4001]! } + public var Privacy_GroupsAndChannels_WhoCanAddMe: String { return self._s[4002]! } + public var Conversation_typing: String { return self._s[4004]! } + public var Undo_ScheduledMessagesCleared: String { return self._s[4005]! } + public var Paint_Masks: String { return self._s[4006]! } + public var Contacts_DeselectAll: String { return self._s[4007]! } public func Wallet_Updated_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4001]!, self._r[4001]!, [_0]) + return formatWithArgumentRanges(self._s[4008]!, self._r[4008]!, [_0]) } - public var CreatePoll_MultipleChoiceQuizAlert: String { return self._s[4002]! } - public var Username_InvalidTaken: String { return self._s[4003]! } - public var Call_StatusNoAnswer: String { return self._s[4004]! } - public var TwoStepAuth_EmailAddSuccess: String { return self._s[4005]! } - public var SettingsSearch_Synonyms_Privacy_BlockedUsers: String { return self._s[4006]! } - public var Passport_Identity_Selfie: String { return self._s[4007]! } - public var Login_InfoLastNamePlaceholder: String { return self._s[4008]! } - public var Privacy_SecretChatsLinkPreviewsHelp: String { return self._s[4009]! } - public var Conversation_ClearSecretHistory: String { return self._s[4010]! } - public var PeopleNearby_Description: String { return self._s[4012]! } - public var NetworkUsageSettings_Title: String { return self._s[4013]! } - public var Your_cards_security_code_is_invalid: String { return self._s[4015]! } + public var CreatePoll_MultipleChoiceQuizAlert: String { return self._s[4009]! } + public var Username_InvalidTaken: String { return self._s[4010]! } + public var Call_StatusNoAnswer: String { return self._s[4011]! } + public var TwoStepAuth_EmailAddSuccess: String { return self._s[4012]! } + public var SettingsSearch_Synonyms_Privacy_BlockedUsers: String { return self._s[4013]! } + public var Passport_Identity_Selfie: String { return self._s[4014]! } + public var Login_InfoLastNamePlaceholder: String { return self._s[4015]! } + public var Privacy_SecretChatsLinkPreviewsHelp: String { return self._s[4016]! } + public var Conversation_ClearSecretHistory: String { return self._s[4017]! } + public var PeopleNearby_Description: String { return self._s[4019]! } + public var NetworkUsageSettings_Title: String { return self._s[4020]! } + public var Your_cards_security_code_is_invalid: String { return self._s[4022]! } public func Notification_LeftChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4017]!, self._r[4017]!, [_0]) + return formatWithArgumentRanges(self._s[4024]!, self._r[4024]!, [_0]) } public func Call_CallInProgressMessage(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4018]!, self._r[4018]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4025]!, self._r[4025]!, [_1, _2]) } - public var SaveIncomingPhotosSettings_From: String { return self._s[4020]! } - public var VoiceOver_Navigation_Search: String { return self._s[4021]! } - public var Map_LiveLocationTitle: String { return self._s[4022]! } - public var Login_InfoAvatarAdd: String { return self._s[4023]! } - public var Passport_Identity_FilesView: String { return self._s[4024]! } - public var UserInfo_GenericPhoneLabel: String { return self._s[4025]! } - public var Privacy_Calls_NeverAllow: String { return self._s[4026]! } - public var VoiceOver_Chat_File: String { return self._s[4027]! } - public var Wallet_Settings_DeleteWalletInfo: String { return self._s[4028]! } + public var SaveIncomingPhotosSettings_From: String { return self._s[4027]! } + public var VoiceOver_Navigation_Search: String { return self._s[4028]! } + public var Map_LiveLocationTitle: String { return self._s[4029]! } + public var Login_InfoAvatarAdd: String { return self._s[4030]! } + public var Passport_Identity_FilesView: String { return self._s[4031]! } + public var UserInfo_GenericPhoneLabel: String { return self._s[4032]! } + public var Privacy_Calls_NeverAllow: String { return self._s[4033]! } + public var VoiceOver_Chat_File: String { return self._s[4034]! } + public var Wallet_Settings_DeleteWalletInfo: String { return self._s[4035]! } public func Contacts_AddPhoneNumber(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4029]!, self._r[4029]!, [_0]) + return formatWithArgumentRanges(self._s[4036]!, self._r[4036]!, [_0]) } - public var ContactInfo_PhoneNumberHidden: String { return self._s[4030]! } - public var TwoStepAuth_ConfirmationText: String { return self._s[4031]! } - public var ChatSettings_AutomaticVideoMessageDownload: String { return self._s[4032]! } + public var ContactInfo_PhoneNumberHidden: String { return self._s[4037]! } + public var TwoStepAuth_ConfirmationText: String { return self._s[4038]! } + public var ChatSettings_AutomaticVideoMessageDownload: String { return self._s[4039]! } public func PUSH_CHAT_MESSAGE_VIDEOS(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4033]!, self._r[4033]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4040]!, self._r[4040]!, [_1, _2, _3]) } - public var Channel_AdminLogFilter_AdminsAll: String { return self._s[4034]! } - public var Wallet_Intro_CreateErrorText: String { return self._s[4035]! } - public var Tour_Title2: String { return self._s[4036]! } - public var Wallet_Sent_ViewWallet: String { return self._s[4037]! } - public var Conversation_FileOpenIn: String { return self._s[4038]! } - public var Checkout_ErrorPrecheckoutFailed: String { return self._s[4039]! } - public var Wallet_Send_ErrorInvalidAddress: String { return self._s[4040]! } - public var Wallpaper_Set: String { return self._s[4041]! } - public var Passport_Identity_Translations: String { return self._s[4043]! } + public var Channel_AdminLogFilter_AdminsAll: String { return self._s[4041]! } + public var Wallet_Intro_CreateErrorText: String { return self._s[4042]! } + public var Tour_Title2: String { return self._s[4043]! } + public var Wallet_Sent_ViewWallet: String { return self._s[4044]! } + public var Conversation_FileOpenIn: String { return self._s[4045]! } + public var Checkout_ErrorPrecheckoutFailed: String { return self._s[4046]! } + public var Wallet_Send_ErrorInvalidAddress: String { return self._s[4047]! } + public var Wallpaper_Set: String { return self._s[4048]! } + public var Passport_Identity_Translations: String { return self._s[4050]! } public func Channel_AdminLog_MessageChangedChannelAbout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4044]!, self._r[4044]!, [_0]) + return formatWithArgumentRanges(self._s[4051]!, self._r[4051]!, [_0]) } - public var Channel_LeaveChannel: String { return self._s[4045]! } + public var Channel_LeaveChannel: String { return self._s[4052]! } public func PINNED_INVOICE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4046]!, self._r[4046]!, [_1]) + return formatWithArgumentRanges(self._s[4053]!, self._r[4053]!, [_1]) } - public var SettingsSearch_Synonyms_Proxy_AddProxy: String { return self._s[4048]! } - public var PhotoEditor_HighlightsTint: String { return self._s[4049]! } - public var MessagePoll_LabelPoll: String { return self._s[4050]! } - public var Passport_Email_Delete: String { return self._s[4051]! } - public var Conversation_Mute: String { return self._s[4053]! } - public var Channel_AddBotAsAdmin: String { return self._s[4054]! } - public var Channel_AdminLog_CanSendMessages: String { return self._s[4056]! } - public var Wallet_Configuration_BlockchainNameChangedText: String { return self._s[4057]! } - public var ChatSettings_IntentsSettings: String { return self._s[4059]! } - public var Channel_Management_LabelOwner: String { return self._s[4060]! } + public var SettingsSearch_Synonyms_Proxy_AddProxy: String { return self._s[4055]! } + public var PhotoEditor_HighlightsTint: String { return self._s[4056]! } + public var MessagePoll_LabelPoll: String { return self._s[4057]! } + public var Passport_Email_Delete: String { return self._s[4058]! } + public var Conversation_Mute: String { return self._s[4060]! } + public var Channel_AddBotAsAdmin: String { return self._s[4061]! } + public var Channel_AdminLog_CanSendMessages: String { return self._s[4063]! } + public var Wallet_Configuration_BlockchainNameChangedText: String { return self._s[4064]! } + public var ChatSettings_IntentsSettings: String { return self._s[4066]! } + public var Channel_Management_LabelOwner: String { return self._s[4067]! } public func Notification_PassportValuesSentMessage(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4061]!, self._r[4061]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4068]!, self._r[4068]!, [_1, _2]) } - public var Calls_CallTabDescription: String { return self._s[4062]! } - public var Passport_Identity_NativeNameHelp: String { return self._s[4063]! } - public var Common_No: String { return self._s[4064]! } - public var Weekday_Sunday: String { return self._s[4065]! } - public var Notification_Reply: String { return self._s[4066]! } - public var Conversation_ViewMessage: String { return self._s[4067]! } + public var Calls_CallTabDescription: String { return self._s[4069]! } + public var Passport_Identity_NativeNameHelp: String { return self._s[4070]! } + public var Common_No: String { return self._s[4071]! } + public var Weekday_Sunday: String { return self._s[4072]! } + public var Notification_Reply: String { return self._s[4073]! } + public var Conversation_ViewMessage: String { return self._s[4074]! } public func Checkout_SavePasswordTimeoutAndFaceId(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4068]!, self._r[4068]!, [_0]) + return formatWithArgumentRanges(self._s[4075]!, self._r[4075]!, [_0]) } public func Map_LiveLocationPrivateDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4069]!, self._r[4069]!, [_0]) + return formatWithArgumentRanges(self._s[4076]!, self._r[4076]!, [_0]) } public func Wallet_Time_PreciseDate_m7(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4070]!, self._r[4070]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4077]!, self._r[4077]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_EditProfile_AddAccount: String { return self._s[4071]! } - public var Wallet_Send_Title: String { return self._s[4072]! } - public var Message_PinnedDocumentMessage: String { return self._s[4073]! } - public var Wallet_Info_RefreshErrorText: String { return self._s[4074]! } - public var DialogList_TabTitle: String { return self._s[4076]! } - public var ChatSettings_AutoPlayTitle: String { return self._s[4077]! } - public var Passport_FieldEmail: String { return self._s[4078]! } - public var Conversation_UnpinMessageAlert: String { return self._s[4079]! } - public var Passport_Address_TypeBankStatement: String { return self._s[4080]! } - public var Wallet_SecureStorageReset_Title: String { return self._s[4081]! } - public var Passport_Identity_ExpiryDate: String { return self._s[4082]! } - public var Privacy_Calls_P2P: String { return self._s[4083]! } + public var SettingsSearch_Synonyms_EditProfile_AddAccount: String { return self._s[4078]! } + public var Wallet_Send_Title: String { return self._s[4079]! } + public var Message_PinnedDocumentMessage: String { return self._s[4080]! } + public var Wallet_Info_RefreshErrorText: String { return self._s[4081]! } + public var DialogList_TabTitle: String { return self._s[4083]! } + public var ChatSettings_AutoPlayTitle: String { return self._s[4084]! } + public var Passport_FieldEmail: String { return self._s[4085]! } + public var Conversation_UnpinMessageAlert: String { return self._s[4086]! } + public var Passport_Address_TypeBankStatement: String { return self._s[4087]! } + public var Wallet_SecureStorageReset_Title: String { return self._s[4088]! } + public var Passport_Identity_ExpiryDate: String { return self._s[4089]! } + public var Privacy_Calls_P2P: String { return self._s[4090]! } public func CancelResetAccount_Success(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4085]!, self._r[4085]!, [_0]) + return formatWithArgumentRanges(self._s[4092]!, self._r[4092]!, [_0]) } - public var SocksProxySetup_UseForCallsHelp: String { return self._s[4086]! } + public var SocksProxySetup_UseForCallsHelp: String { return self._s[4093]! } public func PUSH_CHAT_ALBUM(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4087]!, self._r[4087]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4094]!, self._r[4094]!, [_1, _2]) } - public var Stickers_ClearRecent: String { return self._s[4088]! } - public var EnterPasscode_ChangeTitle: String { return self._s[4089]! } - public var TwoFactorSetup_Email_Title: String { return self._s[4090]! } - public var Passport_InfoText: String { return self._s[4091]! } - public var Checkout_NewCard_SaveInfoEnableHelp: String { return self._s[4092]! } + public var Stickers_ClearRecent: String { return self._s[4095]! } + public var EnterPasscode_ChangeTitle: String { return self._s[4096]! } + public var TwoFactorSetup_Email_Title: String { return self._s[4097]! } + public var Passport_InfoText: String { return self._s[4098]! } + public var Checkout_NewCard_SaveInfoEnableHelp: String { return self._s[4099]! } public func Login_InvalidPhoneEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4093]!, self._r[4093]!, [_0]) + return formatWithArgumentRanges(self._s[4100]!, self._r[4100]!, [_0]) } public func Time_PreciseDate_m3(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4094]!, self._r[4094]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4101]!, self._r[4101]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChannels: String { return self._s[4095]! } - public var ScheduledMessages_PollUnavailable: String { return self._s[4096]! } - public var VoiceOver_Navigation_Compose: String { return self._s[4097]! } - public var Passport_Identity_EditDriversLicense: String { return self._s[4098]! } - public var Conversation_TapAndHoldToRecord: String { return self._s[4100]! } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChats: String { return self._s[4101]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChannels: String { return self._s[4102]! } + public var ScheduledMessages_PollUnavailable: String { return self._s[4103]! } + public var VoiceOver_Navigation_Compose: String { return self._s[4104]! } + public var Passport_Identity_EditDriversLicense: String { return self._s[4105]! } + public var Conversation_TapAndHoldToRecord: String { return self._s[4107]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChats: String { return self._s[4108]! } public func Notification_CallTimeFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4102]!, self._r[4102]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4109]!, self._r[4109]!, [_1, _2]) } - public var Channel_EditAdmin_PermissionInviteViaLink: String { return self._s[4105]! } - public var ChatSettings_OpenLinksIn: String { return self._s[4106]! } - public var Map_HomeAndWorkTitle: String { return self._s[4107]! } + public var Channel_EditAdmin_PermissionInviteViaLink: String { return self._s[4112]! } + public var ChatSettings_OpenLinksIn: String { return self._s[4113]! } + public var Map_HomeAndWorkTitle: String { return self._s[4114]! } public func Generic_OpenHiddenLinkAlert(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4109]!, self._r[4109]!, [_0]) + return formatWithArgumentRanges(self._s[4116]!, self._r[4116]!, [_0]) } - public var DialogList_Unread: String { return self._s[4110]! } + public var DialogList_Unread: String { return self._s[4117]! } public func PUSH_CHAT_MESSAGE_GIF(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4111]!, self._r[4111]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4118]!, self._r[4118]!, [_1, _2]) } - public var User_DeletedAccount: String { return self._s[4112]! } - public var OwnershipTransfer_SetupTwoStepAuth: String { return self._s[4113]! } + public var User_DeletedAccount: String { return self._s[4119]! } + public var OwnershipTransfer_SetupTwoStepAuth: String { return self._s[4120]! } public func Watch_Time_ShortYesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4114]!, self._r[4114]!, [_0]) + return formatWithArgumentRanges(self._s[4121]!, self._r[4121]!, [_0]) } - public var UserInfo_NotificationsDefault: String { return self._s[4115]! } - public var SharedMedia_CategoryMedia: String { return self._s[4116]! } - public var SocksProxySetup_ProxyStatusUnavailable: String { return self._s[4117]! } - public var Channel_AdminLog_MessageRestrictedForever: String { return self._s[4118]! } - public var Watch_ChatList_Compose: String { return self._s[4119]! } - public var Notifications_MessageNotificationsExceptionsHelp: String { return self._s[4120]! } - public var AutoDownloadSettings_Delimeter: String { return self._s[4121]! } - public var Watch_Microphone_Access: String { return self._s[4122]! } - public var Group_Setup_HistoryHeader: String { return self._s[4123]! } - public var Map_SetThisLocation: String { return self._s[4124]! } - public var Appearance_ThemePreview_Chat_2_ReplyName: String { return self._s[4125]! } - public var Activity_UploadingPhoto: String { return self._s[4126]! } - public var Conversation_Edit: String { return self._s[4128]! } - public var Group_ErrorSendRestrictedMedia: String { return self._s[4129]! } - public var Login_TermsOfServiceDecline: String { return self._s[4130]! } - public var Message_PinnedContactMessage: String { return self._s[4131]! } + public var UserInfo_NotificationsDefault: String { return self._s[4122]! } + public var SharedMedia_CategoryMedia: String { return self._s[4123]! } + public var SocksProxySetup_ProxyStatusUnavailable: String { return self._s[4124]! } + public var Channel_AdminLog_MessageRestrictedForever: String { return self._s[4125]! } + public var Watch_ChatList_Compose: String { return self._s[4126]! } + public var Notifications_MessageNotificationsExceptionsHelp: String { return self._s[4127]! } + public var AutoDownloadSettings_Delimeter: String { return self._s[4128]! } + public var Watch_Microphone_Access: String { return self._s[4129]! } + public var Group_Setup_HistoryHeader: String { return self._s[4130]! } + public var Map_SetThisLocation: String { return self._s[4131]! } + public var Appearance_ThemePreview_Chat_2_ReplyName: String { return self._s[4132]! } + public var Activity_UploadingPhoto: String { return self._s[4133]! } + public var Conversation_Edit: String { return self._s[4135]! } + public var Group_ErrorSendRestrictedMedia: String { return self._s[4136]! } + public var Login_TermsOfServiceDecline: String { return self._s[4137]! } + public var Message_PinnedContactMessage: String { return self._s[4138]! } public func Channel_AdminLog_MessageRestrictedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4132]!, self._r[4132]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4139]!, self._r[4139]!, [_1, _2]) } public func Login_PhoneBannedEmailBody(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4133]!, self._r[4133]!, [_1, _2, _3, _4, _5]) + return formatWithArgumentRanges(self._s[4140]!, self._r[4140]!, [_1, _2, _3, _4, _5]) } - public var Appearance_LargeEmoji: String { return self._s[4134]! } - public var TwoStepAuth_AdditionalPassword: String { return self._s[4136]! } - public var EditTheme_Edit_Preview_IncomingReplyText: String { return self._s[4137]! } + public var Appearance_LargeEmoji: String { return self._s[4141]! } + public var TwoStepAuth_AdditionalPassword: String { return self._s[4143]! } + public var EditTheme_Edit_Preview_IncomingReplyText: String { return self._s[4144]! } public func PUSH_CHAT_DELETE_YOU(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4138]!, self._r[4138]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4145]!, self._r[4145]!, [_1, _2]) } - public var Passport_Phone_EnterOtherNumber: String { return self._s[4139]! } - public var Message_PinnedPhotoMessage: String { return self._s[4140]! } - public var Passport_FieldPhone: String { return self._s[4141]! } - public var TwoStepAuth_RecoveryEmailAddDescription: String { return self._s[4142]! } - public var ChatSettings_AutoPlayGifs: String { return self._s[4143]! } - public var InfoPlist_NSCameraUsageDescription: String { return self._s[4145]! } - public var Conversation_Call: String { return self._s[4146]! } - public var Common_TakePhoto: String { return self._s[4148]! } - public var Group_EditAdmin_RankTitle: String { return self._s[4149]! } - public var Wallet_Receive_CommentHeader: String { return self._s[4150]! } - public var Channel_NotificationLoading: String { return self._s[4151]! } + public var Passport_Phone_EnterOtherNumber: String { return self._s[4146]! } + public var Message_PinnedPhotoMessage: String { return self._s[4147]! } + public var Passport_FieldPhone: String { return self._s[4148]! } + public var TwoStepAuth_RecoveryEmailAddDescription: String { return self._s[4149]! } + public var ChatSettings_AutoPlayGifs: String { return self._s[4150]! } + public var InfoPlist_NSCameraUsageDescription: String { return self._s[4152]! } + public var Conversation_Call: String { return self._s[4153]! } + public var Common_TakePhoto: String { return self._s[4155]! } + public var Group_EditAdmin_RankTitle: String { return self._s[4156]! } + public var Wallet_Receive_CommentHeader: String { return self._s[4157]! } + public var Channel_NotificationLoading: String { return self._s[4158]! } public func Notification_Exceptions_Sound(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4152]!, self._r[4152]!, [_0]) + return formatWithArgumentRanges(self._s[4159]!, self._r[4159]!, [_0]) } public func ScheduledMessages_ScheduledDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4153]!, self._r[4153]!, [_0]) + return formatWithArgumentRanges(self._s[4160]!, self._r[4160]!, [_0]) } public func PUSH_CHANNEL_MESSAGE_VIDEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4154]!, self._r[4154]!, [_1]) + return formatWithArgumentRanges(self._s[4161]!, self._r[4161]!, [_1]) } - public var Permissions_SiriTitle_v0: String { return self._s[4155]! } + public var Permissions_SiriTitle_v0: String { return self._s[4162]! } public func VoiceOver_Chat_VoiceMessageFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4156]!, self._r[4156]!, [_0]) + return formatWithArgumentRanges(self._s[4163]!, self._r[4163]!, [_0]) } public func Login_ResetAccountProtected_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4157]!, self._r[4157]!, [_0]) + return formatWithArgumentRanges(self._s[4164]!, self._r[4164]!, [_0]) } - public var Channel_MessagePhotoRemoved: String { return self._s[4158]! } - public var Wallet_Info_ReceiveGrams: String { return self._s[4159]! } - public var ClearCache_FreeSpace: String { return self._s[4160]! } - public var Appearance_BubbleCorners_Apply: String { return self._s[4161]! } - public var Common_edit: String { return self._s[4162]! } - public var PrivacySettings_AuthSessions: String { return self._s[4163]! } - public var Month_ShortJune: String { return self._s[4164]! } - public var PrivacyLastSeenSettings_AlwaysShareWith_Placeholder: String { return self._s[4165]! } - public var Call_ReportSend: String { return self._s[4166]! } - public var Watch_LastSeen_JustNow: String { return self._s[4167]! } - public var Notifications_MessageNotifications: String { return self._s[4168]! } - public var WallpaperSearch_ColorGreen: String { return self._s[4169]! } - public var BroadcastListInfo_AddRecipient: String { return self._s[4171]! } - public var Group_Status: String { return self._s[4172]! } + public var Channel_MessagePhotoRemoved: String { return self._s[4165]! } + public var Wallet_Info_ReceiveGrams: String { return self._s[4166]! } + public var ClearCache_FreeSpace: String { return self._s[4167]! } + public var Appearance_BubbleCorners_Apply: String { return self._s[4168]! } + public var Common_edit: String { return self._s[4169]! } + public var PrivacySettings_AuthSessions: String { return self._s[4170]! } + public var Month_ShortJune: String { return self._s[4171]! } + public var PrivacyLastSeenSettings_AlwaysShareWith_Placeholder: String { return self._s[4172]! } + public var Call_ReportSend: String { return self._s[4173]! } + public var Watch_LastSeen_JustNow: String { return self._s[4174]! } + public var Notifications_MessageNotifications: String { return self._s[4175]! } + public var WallpaperSearch_ColorGreen: String { return self._s[4176]! } + public var BroadcastListInfo_AddRecipient: String { return self._s[4178]! } + public var Group_Status: String { return self._s[4179]! } public func AutoNightTheme_LocationHelp(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4173]!, self._r[4173]!, [_0, _1]) + return formatWithArgumentRanges(self._s[4180]!, self._r[4180]!, [_0, _1]) } - public var TextFormat_AddLinkTitle: String { return self._s[4174]! } - public var ShareMenu_ShareTo: String { return self._s[4175]! } - public var Conversation_Moderate_Ban: String { return self._s[4176]! } + public var TextFormat_AddLinkTitle: String { return self._s[4181]! } + public var ShareMenu_ShareTo: String { return self._s[4182]! } + public var Conversation_Moderate_Ban: String { return self._s[4183]! } public func Conversation_DeleteMessagesFor(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4177]!, self._r[4177]!, [_0]) + return formatWithArgumentRanges(self._s[4184]!, self._r[4184]!, [_0]) } - public var SharedMedia_ViewInChat: String { return self._s[4178]! } - public var Map_LiveLocationFor8Hours: String { return self._s[4179]! } + public var SharedMedia_ViewInChat: String { return self._s[4185]! } + public var Map_LiveLocationFor8Hours: String { return self._s[4186]! } public func PUSH_PINNED_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4180]!, self._r[4180]!, [_1]) + return formatWithArgumentRanges(self._s[4187]!, self._r[4187]!, [_1]) } public func PUSH_PINNED_POLL(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4181]!, self._r[4181]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4188]!, self._r[4188]!, [_1, _2]) } public func Map_AccurateTo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4183]!, self._r[4183]!, [_0]) + return formatWithArgumentRanges(self._s[4190]!, self._r[4190]!, [_0]) } - public var Map_OpenInHereMaps: String { return self._s[4184]! } - public var Appearance_ReduceMotion: String { return self._s[4185]! } + public var Map_OpenInHereMaps: String { return self._s[4191]! } + public var Appearance_ReduceMotion: String { return self._s[4192]! } public func PUSH_MESSAGE_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4186]!, self._r[4186]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4193]!, self._r[4193]!, [_1, _2]) } - public var Channel_Setup_TypePublicHelp: String { return self._s[4187]! } - public var Passport_Identity_EditInternalPassport: String { return self._s[4188]! } - public var PhotoEditor_Skip: String { return self._s[4189]! } - public func PasscodeSettings_FailedAttempts(_ value: Int32) -> String { + public var Channel_Setup_TypePublicHelp: String { return self._s[4194]! } + public var Passport_Identity_EditInternalPassport: String { return self._s[4195]! } + public var PhotoEditor_Skip: String { return self._s[4196]! } + public func MessageTimer_Days(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue) } - public func Conversation_LiveLocationMembersCount(_ value: Int32) -> String { + public func Contacts_ImportersCount(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue) } - public func ServiceMessage_GameScoreSelfSimple(_ value: Int32) -> String { + public func Map_ETAMinutes(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[2 * 6 + Int(form.rawValue)]!, stringValue) } - public func StickerPack_AddMaskCount(_ value: Int32) -> String { + public func LastSeen_HoursAgo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[3 * 6 + Int(form.rawValue)]!, stringValue) } - public func PollResults_ShowMore(_ value: Int32) -> String { + public func DialogList_LiveLocationChatsCount(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[4 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[5 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func Media_ShareItem(_ value: Int32) -> String { + public func Conversation_SelectedMessages(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[6 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_File(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[7 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreExtended(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[8 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[9 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func MuteExpires_Minutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[10 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Watch_LastSeen_HoursAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[11 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortWeeks(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[12 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Media_SharePhoto(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[13 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_Link(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[14 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Wallet_Updated_HoursAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[15 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedContacts(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[16 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Chat_DeleteMessagesConfirmation(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[17 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_ShortSeconds(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[18 * 6 + Int(form.rawValue)]!, stringValue) - } - public func DialogList_LiveLocationChatsCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[19 * 6 + Int(form.rawValue)]!, stringValue) - } - public func GroupInfo_ParticipantCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[20 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Theme_UsersCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[21 * 6 + Int(form.rawValue)]!, stringValue) - } - public func InviteText_ContactsCountText(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[22 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Years(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[23 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGE_ROUNDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[24 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func Conversation_StatusOnline(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[25 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[26 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func AttachmentMenu_SendVideo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[27 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Contacts_ImportersCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[28 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Days(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[29 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_Generic(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[30 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGES(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[31 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func PUSH_CHANNEL_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[32 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func MessageTimer_Minutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[33 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_PollOptionCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[34 * 6 + Int(form.rawValue)]!, stringValue) - } - public func LiveLocationUpdated_MinutesAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[35 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortMinutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[36 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteExpires_Days(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[37 * 6 + Int(form.rawValue)]!, stringValue) - } - public func UserCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[38 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_ExceptionMuteExpires_Days(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[39 * 6 + Int(form.rawValue)]!, stringValue) - } - public func GroupInfo_ShowMoreMembers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[40 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PrivacyLastSeenSettings_AddUsers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[41 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[42 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func SharedMedia_DeleteItemsConfirmation(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[43 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[44 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func StickerPack_RemoveStickerCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[45 * 6 + Int(form.rawValue)]!, stringValue) - } - public func LastSeen_HoursAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[46 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[47 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func MessageTimer_Weeks(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[48 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_Video(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[49 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Wallpaper_DeleteConfirmation(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[50 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notification_GameScoreExtended(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[51 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortDays(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[52 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PeopleNearby_ShowMorePeople(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[53 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_ShortMinutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[54 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Watch_LastSeen_MinutesAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[55 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedGifs(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[56 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ChatList_DeletedChats(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[57 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Seconds(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[58 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Invitation_Members(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[59 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_PollVotes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[60 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedFiles(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[61 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedPolls(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[62 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[63 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func MessagePoll_VotedCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[64 * 6 + Int(form.rawValue)]!, stringValue) - } - public func CreatePoll_AddMoreOptions(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[65 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notification_GameScoreSelfSimple(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[66 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGE_VIDEOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[67 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func LiveLocation_MenuChatsCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[68 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ChatList_SelectedChats(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[69 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedPhotos(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[70 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedLocations(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[71 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGE_PHOTOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[72 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func OldChannels_Leave(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[73 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[74 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func Contacts_InviteContacts(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[75 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_ExceptionMuteExpires_Minutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[76 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[77 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func Media_ShareVideo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[78 * 6 + Int(form.rawValue)]!, stringValue) - } - public func OldChannels_InactiveYear(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[79 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedAuthorsOthers(_ selector: Int32, _ _0: String, _ _1: String) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[80 * 6 + Int(form.rawValue)]!, _0, _1) - } - public func AttachmentMenu_SendPhoto(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[81 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Conversation_StatusMembers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[82 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteFor_Days(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[83 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreSimple(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[84 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedAudios(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[85 * 6 + Int(form.rawValue)]!, stringValue) - } - public func OldChannels_InactiveWeek(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[86 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGE_FWDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[87 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func StickerPack_StickerCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[88 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_Seconds(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[89 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Map_ETAHours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[90 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[5 * 6 + Int(form.rawValue)]!, stringValue) } public func MessageTimer_Months(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[91 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[6 * 6 + Int(form.rawValue)]!, stringValue) } - public func Conversation_SelectedMessages(_ value: Int32) -> String { + public func PUSH_CHANNEL_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[7 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func SharedMedia_Video(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[92 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[8 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedContacts(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[9 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHAT_MESSAGE_ROUNDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[10 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func Map_ETAHours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[11 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Chat_DeleteMessagesConfirmation(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[12 * 6 + Int(form.rawValue)]!, stringValue) } public func Call_Minutes(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[93 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[13 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessagePoll_QuizCount(_ value: Int32) -> String { + public func ServiceMessage_GameScoreSelfSimple(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[94 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_ContactEmailCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[95 * 6 + Int(form.rawValue)]!, stringValue) - } - public func QuickSend_Photos(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[96 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_ContactPhoneNumberCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[97 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Conversation_StatusSubscribers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[98 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedMessages(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[99 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Passport_Scans(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[100 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Forward_ConfirmMultipleFiles(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[101 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedStickers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[102 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortSeconds(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[103 * 6 + Int(form.rawValue)]!, stringValue) - } - public func OldChannels_InactiveMonth(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[104 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Map_ETAMinutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[105 * 6 + Int(form.rawValue)]!, stringValue) - } - public func AttachmentMenu_SendItem(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[106 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedVideos(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[107 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ChatList_DeleteConfirmation(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[108 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Hours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[109 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_AddStickerCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[110 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedVideoMessages(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[111 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteExpires_Hours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[112 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notification_GameScoreSimple(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[113 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_RemoveMaskCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[114 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteFor_Hours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[115 * 6 + Int(form.rawValue)]!, stringValue) - } - public func AttachmentMenu_SendGif(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[116 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortHours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[117 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[118 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_ExceptionMuteExpires_Hours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[119 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_Photo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[120 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Watch_UserInfo_Mute(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[121 * 6 + Int(form.rawValue)]!, stringValue) - } - public func LastSeen_MinutesAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[122 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreSelfExtended(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[123 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[14 * 6 + Int(form.rawValue)]!, stringValue) } public func Notification_GameScoreSelfExtended(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[124 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[15 * 6 + Int(form.rawValue)]!, stringValue) + } + public func OldChannels_InactiveYear(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[16 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_PollVotes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[17 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_LiveLocationMembersCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[18 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreSimple(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[19 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_RemoveStickerCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[20 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteFor_Days(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[21 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHAT_MESSAGE_FWDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[22 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func PeopleNearby_ShowMorePeople(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[23 * 6 + Int(form.rawValue)]!, stringValue) + } + public func QuickSend_Photos(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[24 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[25 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func Watch_LastSeen_MinutesAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[26 * 6 + Int(form.rawValue)]!, stringValue) + } + public func UserCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[27 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessagePoll_VotedCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[28 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_StickerCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[29 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Weeks(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[30 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_StatusOnline(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[31 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreSelfSimple(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[32 * 6 + Int(form.rawValue)]!, stringValue) } public func Notifications_Exceptions(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[125 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[33 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessagePoll_QuizCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[34 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedAuthorsOthers(_ selector: Int32, _ _0: String, _ _1: String) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[35 * 6 + Int(form.rawValue)]!, _0, _1) + } + public func PUSH_CHANNEL_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[36 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func MessageTimer_Minutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[37 * 6 + Int(form.rawValue)]!, stringValue) + } + public func GroupInfo_ParticipantCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[38 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_DeleteItemsConfirmation(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[39 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[40 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func ServiceMessage_GameScoreSelfExtended(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[41 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedFiles(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[42 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_Seconds(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[43 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Wallpaper_DeleteConfirmation(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[44 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Invitation_Members(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[45 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_ContactPhoneNumberCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[46 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortWeeks(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[47 * 6 + Int(form.rawValue)]!, stringValue) + } + public func CreatePoll_AddMoreOptions(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[48 * 6 + Int(form.rawValue)]!, stringValue) + } + public func InviteText_ContactsCountText(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[49 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHAT_MESSAGE_PHOTOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[50 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func MessageTimer_ShortHours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[51 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_File(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[52 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_StatusMembers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[53 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Contacts_InviteContacts(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[54 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ChatList_DeletedChats(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[55 * 6 + Int(form.rawValue)]!, stringValue) + } + public func OldChannels_Leave(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[56 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[57 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func PasscodeSettings_FailedAttempts(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[58 * 6 + Int(form.rawValue)]!, stringValue) + } + public func LastSeen_MinutesAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[59 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedPolls(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[60 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Wallet_Updated_HoursAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[61 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_RemoveMaskCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[62 * 6 + Int(form.rawValue)]!, stringValue) + } + public func OldChannels_InactiveWeek(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[63 * 6 + Int(form.rawValue)]!, stringValue) + } + public func LiveLocationUpdated_MinutesAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[64 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortSeconds(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[65 * 6 + Int(form.rawValue)]!, stringValue) + } + public func AttachmentMenu_SendItem(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[66 * 6 + Int(form.rawValue)]!, stringValue) + } + public func LiveLocation_MenuChatsCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[67 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[68 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func SharedMedia_Link(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[69 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[70 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func MessageTimer_Seconds(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[71 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_ContactEmailCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[72 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[73 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func PollResults_ShowMore(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[74 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Years(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[75 * 6 + Int(form.rawValue)]!, stringValue) + } + public func AttachmentMenu_SendGif(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[76 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreExtended(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[77 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_ShortSeconds(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[78 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedStickers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[79 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_StatusSubscribers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[80 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Watch_LastSeen_HoursAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[81 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreSimple(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[82 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_PollOptionCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[83 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedAudios(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[84 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Passport_Scans(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[85 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteExpires_Days(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[86 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Media_ShareVideo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[87 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notifications_ExceptionMuteExpires_Hours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[88 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Media_SharePhoto(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[89 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ChatList_SelectedChats(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[90 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteFor_Hours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[91 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_AddMaskCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[92 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedPhotos(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[93 * 6 + Int(form.rawValue)]!, stringValue) + } + public func GroupInfo_ShowMoreMembers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[94 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_Photo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[95 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Hours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[96 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_AddStickerCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[97 * 6 + Int(form.rawValue)]!, stringValue) + } + public func OldChannels_InactiveMonth(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[98 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[99 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func AttachmentMenu_SendPhoto(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[100 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedMessages(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[101 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedGifs(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[102 * 6 + Int(form.rawValue)]!, stringValue) } public func OldChannels_GroupFormat(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[103 * 6 + Int(form.rawValue)]!, stringValue) + } + public func AttachmentMenu_SendVideo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[104 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedLocations(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[105 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteExpires_Minutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[106 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Forward_ConfirmMultipleFiles(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[107 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHAT_MESSAGE_VIDEOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[108 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func SharedMedia_Generic(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[109 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[110 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func PrivacyLastSeenSettings_AddUsers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[111 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedVideos(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[112 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notifications_ExceptionMuteExpires_Minutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[113 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortMinutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[114 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHAT_MESSAGES(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[115 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func MessageTimer_ShortDays(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[116 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreExtended(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[117 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Watch_UserInfo_Mute(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[118 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notifications_ExceptionMuteExpires_Days(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[119 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ChatList_DeleteConfirmation(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[120 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Media_ShareItem(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[121 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedVideoMessages(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[122 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteExpires_Hours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[123 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_ShortMinutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[124 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[125 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Theme_UsersCount(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[126 * 6 + Int(form.rawValue)]!, stringValue) diff --git a/submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIcon.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIcon.imageset/Contents.json new file mode 100644 index 0000000000..55305eb8ca --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIcon.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_verify_big.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIcon.imageset/ic_verify_big.pdf b/submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIcon.imageset/ic_verify_big.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e368606b86a193e74c1ccb6006f728abf68ab69f GIT binary patch literal 4624 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 Void + private let groupsInCommonContext: GroupsInCommonContext private let listNode: ListView - private var peers: [Peer] = [] + private var state: GroupsInCommonState? private var currentEntries: [GroupsInCommonListEntry] = [] private var enqueuedTransactions: [GroupsInCommonListTransaction] = [] @@ -76,11 +77,14 @@ final class PeerInfoGroupsInCommonPaneNode: ASDisplayNode, PeerInfoPaneNode { return self.ready.get() } - init(context: AccountContext, peerId: PeerId, chatControllerInteraction: ChatControllerInteraction, openPeerContextAction: @escaping (Peer, ASDisplayNode, ContextGesture?) -> Void, peers: [Peer]) { + private var disposable: Disposable? + + init(context: AccountContext, peerId: PeerId, chatControllerInteraction: ChatControllerInteraction, openPeerContextAction: @escaping (Peer, ASDisplayNode, ContextGesture?) -> Void, groupsInCommonContext: GroupsInCommonContext) { self.context = context self.peerId = peerId self.chatControllerInteraction = chatControllerInteraction self.openPeerContextAction = openPeerContextAction + self.groupsInCommonContext = groupsInCommonContext self.listNode = ListView() @@ -89,10 +93,29 @@ final class PeerInfoGroupsInCommonPaneNode: ASDisplayNode, PeerInfoPaneNode { self.listNode.preloadPages = true self.addSubnode(self.listNode) - self.peers = peers + self.disposable = (groupsInCommonContext.state + |> deliverOnMainQueue).start(next: { [weak self] state in + guard let strongSelf = self else { + return + } + strongSelf.state = state + if let (_, _, presentationData) = strongSelf.currentParams { + strongSelf.updatePeers(state: state, presentationData: presentationData) + } + }) + + self.listNode.visibleBottomContentOffsetChanged = { [weak self] offset in + guard let strongSelf = self, let state = strongSelf.state, case .ready(true) = state.dataState else { + return + } + if case let .known(value) = offset, value < 100.0, case .ready(true) = state.dataState { + strongSelf.groupsInCommonContext.loadMore() + } + } } deinit { + self.disposable?.dispose() } func scrollToTop() -> Bool { @@ -115,15 +138,17 @@ final class PeerInfoGroupsInCommonPaneNode: ASDisplayNode, PeerInfoPaneNode { self.listNode.scrollEnabled = !isScrollingLockedAtTop - if isFirstLayout { - self.updatePeers(peers: self.peers, presentationData: presentationData) + if isFirstLayout, let state = self.state { + self.updatePeers(state: state, presentationData: presentationData) } } - private func updatePeers(peers: [Peer], presentationData: PresentationData) { + private func updatePeers(state: GroupsInCommonState, presentationData: PresentationData) { var entries: [GroupsInCommonListEntry] = [] - for peer in peers { - entries.append(GroupsInCommonListEntry(index: entries.count, peer: peer)) + for peer in state.peers { + if let peer = peer.peer { + entries.append(GroupsInCommonListEntry(index: entries.count, peer: peer)) + } } let transaction = preparedTransition(from: self.currentEntries, to: entries, context: self.context, presentationData: presentationData, openPeer: { [weak self] peer in self?.chatControllerInteraction.openPeer(peer.id, .default, nil) diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoMembersPane.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoMembersPane.swift index d555c930a0..f22ca30ca6 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoMembersPane.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoMembersPane.swift @@ -17,6 +17,7 @@ private struct PeerMembersListTransaction { let deletions: [ListViewDeleteItem] let insertions: [ListViewInsertItem] let updates: [ListViewUpdateItem] + let animated: Bool } enum PeerMembersListAction { @@ -94,7 +95,7 @@ private func preparedTransition(from fromEntries: [PeerMembersListEntry], to toE let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enclosingPeer: enclosingPeer, action: action), directionHint: nil) } let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enclosingPeer: enclosingPeer, action: action), directionHint: nil) } - return PeerMembersListTransaction(deletions: deletions, insertions: insertions, updates: updates) + return PeerMembersListTransaction(deletions: deletions, insertions: insertions, updates: updates, animated: toEntries.count < fromEntries.count) } final class PeerInfoMembersPaneNode: ASDisplayNode, PeerInfoPaneNode { @@ -207,7 +208,11 @@ final class PeerInfoMembersPaneNode: ASDisplayNode, PeerInfoPaneNode { self.enqueuedTransactions.remove(at: 0) var options = ListViewDeleteAndInsertOptions() - options.insert(.Synchronous) + if transaction.animated { + options.insert(.AnimateInsertion) + } else { + options.insert(.Synchronous) + } self.listNode.transaction(deleteIndices: transaction.deletions, insertIndicesAndItems: transaction.insertions, updateIndicesAndItems: transaction.updates, options: options, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { [weak self] _ in guard let strongSelf = self else { diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift index 34e7e78ef9..a7733e39d9 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift @@ -237,6 +237,8 @@ private final class VisualMediaItemNode: ASDisplayNode { func updateSelectionState(animated: Bool) { if let (item, media, _, mediaDimensions) = self.item, let theme = self.theme { + self.containerNode.isGestureEnabled = self.interaction.selectedMessageIds == nil + if let selectedIds = self.interaction.selectedMessageIds { let selected = selectedIds.contains(item.message.id) diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift index a2a81d49fe..04bb02018e 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoData.swift @@ -63,7 +63,7 @@ final class PeerInfoScreenData { let globalNotificationSettings: GlobalNotificationSettings? let isContact: Bool let availablePanes: [PeerInfoPaneKey] - let groupsInCommon: [Peer]? + let groupsInCommon: GroupsInCommonContext? let linkedDiscussionPeer: Peer? let members: PeerInfoMembersData? @@ -75,7 +75,7 @@ final class PeerInfoScreenData { globalNotificationSettings: GlobalNotificationSettings?, isContact: Bool, availablePanes: [PeerInfoPaneKey], - groupsInCommon: [Peer]?, + groupsInCommon: GroupsInCommonContext?, linkedDiscussionPeer: Peer?, members: PeerInfoMembersData? ) { @@ -105,7 +105,7 @@ private enum PeerInfoScreenInputData: Equatable { case group(groupId: PeerId) } -func peerInfoAvailableMediaPanes(context: AccountContext, peerId: PeerId) -> Signal<[PeerInfoPaneKey], NoError> { +private func peerInfoAvailableMediaPanes(context: AccountContext, peerId: PeerId) -> Signal<[PeerInfoPaneKey]?, NoError> { let tags: [(MessageTags, PeerInfoPaneKey)] = [ (.photoOrVideo, .media), (.file, .files), @@ -113,34 +113,51 @@ func peerInfoAvailableMediaPanes(context: AccountContext, peerId: PeerId) -> Sig //(.voiceOrInstantVideo, .voice), (.webPage, .links) ] - return combineLatest(tags.map { tagAndKey -> Signal in + enum PaneState { + case loading + case empty + case present + } + let loadedOnce = Atomic(value: false) + return combineLatest(queue: .mainQueue(), tags.map { tagAndKey -> Signal<(PeerInfoPaneKey, PaneState), NoError> in let (tag, key) = tagAndKey return context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId), index: .upperBound, anchorIndex: .upperBound, count: 20, clipHoles: false, fixedCombinedReadStates: nil, tagMask: tag) - |> map { (view, _, _) -> PeerInfoPaneKey? in + |> map { (view, _, _) -> (PeerInfoPaneKey, PaneState) in if view.entries.isEmpty { - return nil + if view.isLoading { + return (key, .loading) + } else { + return (key, .empty) + } } else { - return key + return (key, .present) } } }) - |> map { keys -> [PeerInfoPaneKey] in - return keys.compactMap { $0 } + |> map { keysAndStates -> [PeerInfoPaneKey]? in + let loadedOnceValue = loadedOnce.with { $0 } + var result: [PeerInfoPaneKey] = [] + var hasNonLoaded = false + for (key, state) in keysAndStates { + switch state { + case .present: + result.append(key) + case .empty: + break + case .loading: + hasNonLoaded = true + } + } + if !hasNonLoaded || loadedOnceValue { + if !loadedOnceValue { + let _ = loadedOnce.swap(true) + } + return result + } else { + return nil + } } |> distinctUntilChanged - /*return context.account.postbox.combinedView(keys: tags.map { (tag, _) -> PostboxViewKey in - return .historyTagInfo(peerId: peerId, tag: tag) - }) - |> map { view -> [PeerInfoPaneKey] in - return tags.compactMap { (tag, key) -> PeerInfoPaneKey? in - if let info = view.views[.historyTagInfo(peerId: peerId, tag: tag)] as? HistoryTagInfoView, !info.isEmpty { - return key - } else { - return nil - } - } - } - |> distinctUntilChanged*/ } struct PeerInfoStatusData: Equatable { @@ -258,17 +275,13 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen members: nil )) case let .user(peerId, secretChatId, kind): - let groupsInCommonSignal: Signal<[Peer]?, NoError> - switch kind { - case .user: - groupsInCommonSignal = .single(nil) - |> then( - groupsInCommon(account: context.account, peerId: peerId) - |> map(Optional.init) - ) - default: - groupsInCommonSignal = .single([]) + let groupsInCommon: GroupsInCommonContext? + if case .user = kind { + groupsInCommon = GroupsInCommonContext(account: context.account, peerId: peerId) + } else { + groupsInCommon = nil } + enum StatusInputData: Equatable { case none case presence(TelegramUserPresence) @@ -359,10 +372,9 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen context.account.viewTracker.peerView(peerId, updateData: true), peerInfoAvailableMediaPanes(context: context, peerId: peerId), context.account.postbox.combinedView(keys: combinedKeys), - status, - groupsInCommonSignal + status ) - |> map { peerView, availablePanes, combinedView, status, groupsInCommon -> PeerInfoScreenData in + |> map { peerView, availablePanes, combinedView, status -> PeerInfoScreenData in var globalNotificationSettings: GlobalNotificationSettings = .defaultSettings if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView { if let settings = preferencesView.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings { @@ -371,13 +383,9 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen } var availablePanes = availablePanes - if let groupsInCommon = groupsInCommon { - if !groupsInCommon.isEmpty { - availablePanes.append(.groupsInCommon) - } - } else if let cachedData = peerView.cachedData as? CachedUserData { + if availablePanes != nil, groupsInCommon != nil, let cachedData = peerView.cachedData as? CachedUserData { if cachedData.commonGroupCount != 0 { - availablePanes.append(.groupsInCommon) + availablePanes?.append(.groupsInCommon) } } @@ -388,7 +396,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings, globalNotificationSettings: globalNotificationSettings, isContact: peerView.peerIsContact, - availablePanes: availablePanes, + availablePanes: availablePanes ?? [], groupsInCommon: groupsInCommon, linkedDiscussionPeer: nil, members: nil @@ -437,8 +445,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings, globalNotificationSettings: globalNotificationSettings, isContact: peerView.peerIsContact, - availablePanes: availablePanes, - groupsInCommon: [], + availablePanes: availablePanes ?? [], + groupsInCommon: nil, linkedDiscussionPeer: discussionPeer, members: nil ) @@ -447,7 +455,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen let status = context.account.viewTracker.peerView(groupId, updateData: false) |> map { peerView -> PeerInfoStatusData? in guard let channel = peerView.peers[groupId] as? TelegramChannel else { - return PeerInfoStatusData(text: strings.Channel_Status, isActivity: false) + return PeerInfoStatusData(text: strings.Group_Status, isActivity: false) } if let cachedChannelData = peerView.cachedData as? CachedChannelData, let memberCount = cachedChannelData.participantsSummary.memberCount, memberCount != 0 { return PeerInfoStatusData(text: strings.Conversation_StatusMembers(memberCount), isActivity: false) @@ -494,7 +502,11 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen var availablePanes = availablePanes if let membersData = membersData, case .longList = membersData { - availablePanes.insert(.members, at: 0) + if availablePanes != nil { + availablePanes?.insert(.members, at: 0) + } else { + availablePanes = [.members] + } } return PeerInfoScreenData( @@ -504,8 +516,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings, globalNotificationSettings: globalNotificationSettings, isContact: peerView.peerIsContact, - availablePanes: availablePanes, - groupsInCommon: [], + availablePanes: availablePanes ?? [], + groupsInCommon: nil, linkedDiscussionPeer: discussionPeer, members: membersData ) @@ -612,8 +624,11 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?) -> [PeerInf if let user = peer as? TelegramUser { result.append(.message) var callsAvailable = false - if !user.isDeleted, user.botInfo == nil, !user.flags.contains(.isSupport), let cachedUserData = cachedData as? CachedUserData { - callsAvailable = cachedUserData.callsAvailable + if !user.isDeleted, user.botInfo == nil, !user.flags.contains(.isSupport) { + if let cachedUserData = cachedData as? CachedUserData { + callsAvailable = cachedUserData.callsAvailable + } + callsAvailable = true } if callsAvailable { result.append(.call) diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift index ff3b630069..39d84c0a23 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift @@ -375,7 +375,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { if strongSelf.items.count > 1 { highlightedSide = false } - } else if point.x > size.width * 4.0 / 5.0 { + } else { if strongSelf.items.count > 1 { highlightedSide = true } @@ -423,7 +423,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { self.currentIndex = self.items.count - 1 self.updateItems(size: size, transition: .immediate, synchronous: true) } - } else if location.x > size.width * 4.0 / 5.0 { + } else { if self.currentIndex < self.items.count - 1 { self.currentIndex += 1 self.updateItems(size: size, transition: .immediate) @@ -986,13 +986,15 @@ final class PeerInfoHeaderNavigationButtonContainerNode: ASDisplayNode { } else { nextRegularButtonOrigin = nextButtonOrigin } + let alphaFactor: CGFloat = spec.isForExpandedView ? expandFraction : (1.0 - expandFraction) if wasAdded { buttonNode.frame = buttonFrame + buttonNode.alpha = 0.0 + transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor) } else { transition.updateFrameAdditiveToCenter(node: buttonNode, frame: buttonFrame) + transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor) } - let alphaFactor: CGFloat = spec.isForExpandedView ? expandFraction : (1.0 - expandFraction) - transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor) } var removeKeys: [PeerInfoHeaderNavigationButtonKey] = [] for (key, _) in self.buttonNodes { @@ -1189,16 +1191,20 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode { var isEnabled = true switch key { case .firstName: - placeholder = "First Name" + placeholder = presentationData.strings.UserInfo_FirstNamePlaceholder isEnabled = isContact case .lastName: - placeholder = "Last Name" + placeholder = presentationData.strings.UserInfo_LastNamePlaceholder isEnabled = isContact case .title: - placeholder = "Title" + if let channel = peer as? TelegramChannel, case .broadcast = channel.info { + placeholder = presentationData.strings.GroupInfo_ChannelListNamePlaceholder + } else { + placeholder = presentationData.strings.GroupInfo_GroupNamePlaceholder + } isEnabled = canEditPeerInfo(peer: peer) case .description: - placeholder = "Description" + placeholder = presentationData.strings.Channel_Edit_AboutItem isEnabled = canEditPeerInfo(peer: peer) } let itemHeight = itemNode.update(width: width, safeInset: safeInset, hasPrevious: hasPrevious, placeholder: placeholder, isEnabled: isEnabled, presentationData: presentationData, updateText: updateText) @@ -1330,7 +1336,17 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.presentationData = presentationData if themeUpdated { - self.titleCredibilityIconNode.image = PresentationResourcesItemList.verifiedPeerIcon(presentationData.theme) + if let sourceImage = UIImage(bundleImageName: "Peer Info/VerifiedIcon") { + self.titleCredibilityIconNode.image = generateImage(sourceImage.size, contextGenerator: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + context.setFillColor(presentationData.theme.list.itemCheckColors.foregroundColor.cgColor) + context.fillEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: 7.0, dy: 7.0)) + context.setFillColor(presentationData.theme.list.itemCheckColors.fillColor.cgColor) + context.clip(to: CGRect(origin: CGPoint(), size: size), mask: sourceImage.cgImage!) + context.fill(CGRect(origin: CGPoint(), size: size)) + }) + //self.titleCredibilityIconNode.image = PresentationResourcesItemList.verifiedPeerIcon(presentationData.theme) + } } self.regularContentNode.alpha = state.isEditing ? 0.0 : 1.0 @@ -1392,7 +1408,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.subtitleNode.attributedText = subtitleString } - let textSideInset: CGFloat = 16.0 + let textSideInset: CGFloat = 44.0 let expandedAvatarControlsHeight: CGFloat = 64.0 let expandedAvatarHeight: CGFloat = expandedAvatarListSize.height + expandedAvatarControlsHeight @@ -1691,46 +1707,49 @@ final class PeerInfoHeaderNode: ASDisplayNode { let buttonIcon: PeerInfoHeaderButtonIcon switch buttonKey { case .message: - buttonText = "Message" + buttonText = presentationData.strings.PeerInfo_ButtonMessage buttonIcon = .message case .discussion: - buttonText = "Discuss" + buttonText = presentationData.strings.PeerInfo_ButtonDiscuss buttonIcon = .message case .call: - buttonText = "Call" + buttonText = presentationData.strings.PeerInfo_ButtonCall buttonIcon = .call case .mute: if let notificationSettings = notificationSettings, case .muted = notificationSettings.muteState { - buttonText = "Unmute" + buttonText = presentationData.strings.PeerInfo_ButtonUnmute buttonIcon = .unmute } else { - buttonText = "Mute" + buttonText = presentationData.strings.PeerInfo_ButtonMute buttonIcon = .mute } case .more: - buttonText = "More" + buttonText = presentationData.strings.PeerInfo_ButtonMore buttonIcon = .more case .addMember: - buttonText = "Add Member" + buttonText = presentationData.strings.PeerInfo_ButtonAddMember buttonIcon = .addMember } buttonNode.update(size: buttonFrame.size, text: buttonText, icon: buttonIcon, isExpanded: self.isAvatarExpanded, presentationData: presentationData, transition: buttonTransition) transition.updateSublayerTransformScaleAdditive(node: buttonNode, scale: buttonsScale) + if wasAdded { + buttonNode.alpha = 0.0 + } transition.updateAlpha(node: buttonNode, alpha: buttonsAlpha) let hiddenWhileExpanded: Bool switch self.keepExpandedButtons { case .message: switch buttonKey { - case .mute, .addMember: + case .mute: hiddenWhileExpanded = true default: hiddenWhileExpanded = false } case .mute: switch buttonKey { - case .message, .addMember: + case .message: hiddenWhileExpanded = true default: hiddenWhileExpanded = false diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift index 97da970c3b..c13323bca0 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoPaneContainerNode.swift @@ -174,7 +174,6 @@ final class PeerInfoPaneTabsContainerNode: ASDisplayNode { self?.paneSelected(specifier.key) }) self.paneNodes[specifier.key] = paneNode - self.scrollNode.addSubnode(paneNode) } paneNode.updateText(specifier.title, isSelected: selectedPane == specifier.key, presentationData: presentationData) } @@ -191,7 +190,7 @@ final class PeerInfoPaneTabsContainerNode: ASDisplayNode { } } - var tabSizes: [(CGSize, PeerInfoPaneTabsContainerPaneNode)] = [] + var tabSizes: [(CGSize, PeerInfoPaneTabsContainerPaneNode, Bool)] = [] var totalRawTabSize: CGFloat = 0.0 var selectedFrame: CGRect? @@ -199,20 +198,30 @@ final class PeerInfoPaneTabsContainerNode: ASDisplayNode { guard let paneNode = self.paneNodes[specifier.key] else { continue } + let wasAdded = paneNode.supernode == nil + if wasAdded { + self.scrollNode.addSubnode(paneNode) + } let paneNodeWidth = paneNode.updateLayout(height: size.height) let paneNodeSize = CGSize(width: paneNodeWidth, height: size.height) - tabSizes.append((paneNodeSize, paneNode)) + tabSizes.append((paneNodeSize, paneNode, wasAdded)) totalRawTabSize += paneNodeSize.width } let spacing: CGFloat = 32.0 if tabSizes.count == 1 { for i in 0 ..< tabSizes.count { - let (paneNodeSize, paneNode) = tabSizes[i] + let (paneNodeSize, paneNode, wasAdded) = tabSizes[i] let leftOffset: CGFloat = 16.0 let paneFrame = CGRect(origin: CGPoint(x: leftOffset, y: floor((size.height - paneNodeSize.height) / 2.0)), size: paneNodeSize) - paneNode.frame = paneFrame + if wasAdded { + paneNode.frame = paneFrame + paneNode.alpha = 0.0 + transition.updateAlpha(node: paneNode, alpha: 1.0) + } else { + transition.updateFrameAdditiveToCenter(node: paneNode, frame: paneFrame) + } let areaSideInset: CGFloat = 16.0 paneNode.updateArea(size: paneFrame.size, sideInset: areaSideInset) paneNode.hitTestSlop = UIEdgeInsets(top: 0.0, left: -areaSideInset, bottom: 0.0, right: -areaSideInset) @@ -229,10 +238,16 @@ final class PeerInfoPaneTabsContainerNode: ASDisplayNode { var leftOffset = perTabSpacing for i in 0 ..< tabSizes.count { - let (paneNodeSize, paneNode) = tabSizes[i] + let (paneNodeSize, paneNode, wasAdded) = tabSizes[i] let paneFrame = CGRect(origin: CGPoint(x: leftOffset, y: floor((size.height - paneNodeSize.height) / 2.0)), size: paneNodeSize) - paneNode.frame = paneFrame + if wasAdded { + paneNode.frame = paneFrame + paneNode.alpha = 0.0 + transition.updateAlpha(node: paneNode, alpha: 1.0) + } else { + transition.updateFrameAdditiveToCenter(node: paneNode, frame: paneFrame) + } let areaSideInset = floor(perTabSpacing / 2.0) paneNode.updateArea(size: paneFrame.size, sideInset: areaSideInset) paneNode.hitTestSlop = UIEdgeInsets(top: 0.0, left: -areaSideInset, bottom: 0.0, right: -areaSideInset) @@ -248,9 +263,15 @@ final class PeerInfoPaneTabsContainerNode: ASDisplayNode { let sideInset: CGFloat = 16.0 var leftOffset: CGFloat = sideInset for i in 0 ..< tabSizes.count { - let (paneNodeSize, paneNode) = tabSizes[i] + let (paneNodeSize, paneNode, wasAdded) = tabSizes[i] let paneFrame = CGRect(origin: CGPoint(x: leftOffset, y: floor((size.height - paneNodeSize.height) / 2.0)), size: paneNodeSize) - paneNode.frame = paneFrame + if wasAdded { + paneNode.frame = paneFrame + paneNode.alpha = 0.0 + transition.updateAlpha(node: paneNode, alpha: 1.0) + } else { + transition.updateFrameAdditiveToCenter(node: paneNode, frame: paneFrame) + } paneNode.updateArea(size: paneFrame.size, sideInset: spacing) paneNode.hitTestSlop = UIEdgeInsets(top: 0.0, left: -spacing, bottom: 0.0, right: -spacing) if paneList[i].key == selectedPane { @@ -262,13 +283,21 @@ final class PeerInfoPaneTabsContainerNode: ASDisplayNode { } if let selectedFrame = selectedFrame { + let wasAdded = self.selectedLineNode.isHidden self.selectedLineNode.isHidden = false - transition.updateFrame(node: self.selectedLineNode, frame: CGRect(origin: CGPoint(x: selectedFrame.minX, y: size.height - 4.0), size: CGSize(width: selectedFrame.width, height: 4.0))) + let lineFrame = CGRect(origin: CGPoint(x: selectedFrame.minX, y: size.height - 4.0), size: CGSize(width: selectedFrame.width, height: 4.0)) + if wasAdded { + self.selectedLineNode.frame = lineFrame + self.selectedLineNode.alpha = 0.0 + transition.updateAlpha(node: self.selectedLineNode, alpha: 1.0) + } else { + transition.updateFrame(node: self.selectedLineNode, frame: lineFrame) + } if focusOnSelectedPane { if selectedPane == paneList.first?.key { transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(), size: self.scrollNode.bounds.size)) } else if selectedPane == paneList.last?.key { - transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: self.scrollNode.view.contentSize.width - self.scrollNode.bounds.width, y: 0.0), size: self.scrollNode.bounds.size)) + transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: max(0.0, self.scrollNode.view.contentSize.width - self.scrollNode.bounds.width), y: 0.0), size: self.scrollNode.bounds.size)) } else { let contentOffsetX = max(0.0, min(self.scrollNode.view.contentSize.width - self.scrollNode.bounds.width, floor(selectedFrame.midX - self.scrollNode.bounds.width / 2.0))) transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: contentOffsetX, y: 0.0), size: self.scrollNode.bounds.size)) @@ -457,7 +486,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode { case .music: paneNode = PeerInfoListPaneNode(context: self.context, chatControllerInteraction: self.chatControllerInteraction!, peerId: self.peerId, tagMask: .music) case .groupsInCommon: - paneNode = PeerInfoGroupsInCommonPaneNode(context: self.context, peerId: self.peerId, chatControllerInteraction: self.chatControllerInteraction!, openPeerContextAction: self.openPeerContextAction!, peers: data?.groupsInCommon ?? []) + paneNode = PeerInfoGroupsInCommonPaneNode(context: self.context, peerId: self.peerId, chatControllerInteraction: self.chatControllerInteraction!, openPeerContextAction: self.openPeerContextAction!, groupsInCommonContext: data!.groupsInCommon!) case .members: if case let .longList(membersContext) = data?.members { paneNode = PeerInfoMembersPaneNode(context: self.context, peerId: self.peerId, membersContext: membersContext, action: { [weak self] member, action in diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift index e849ff7995..7dcead0b6c 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift @@ -575,14 +575,14 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese if let user = data.peer as? TelegramUser { if let phone = user.phone { let formattedPhone = formatPhoneNumber(phone) - items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 2, label: "mobile", text: formattedPhone, textColor: .accent, action: { + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 2, label: presentationData.strings.ContactInfo_PhoneLabelMobile, text: formattedPhone, textColor: .accent, action: { interaction.openPhone(phone) }, longTapAction: { sourceNode in interaction.openPeerInfoContextMenu(.phone(formattedPhone), sourceNode) })) } if let username = user.username { - items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 1, label: "username", text: "@\(username)", textColor: .accent, action: { + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 1, label: presentationData.strings.Profile_Username, text: "@\(username)", textColor: .accent, action: { interaction.openUsername(username) }, longTapAction: { sourceNode in interaction.openPeerInfoContextMenu(.link, sourceNode) @@ -590,26 +590,26 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese } if let cachedData = data.cachedData as? CachedUserData { if user.isScam { - items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: user.botInfo != nil ? presentationData.strings.UserInfo_ScamBotWarning : presentationData.strings.UserInfo_ScamUserWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: user.botInfo != nil ? enabledBioEntities : []), action: nil)) + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: user.botInfo == nil ? presentationData.strings.Profile_About : presentationData.strings.Channel_AboutItem, text: user.botInfo != nil ? presentationData.strings.UserInfo_ScamBotWarning : presentationData.strings.UserInfo_ScamUserWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: user.botInfo != nil ? enabledBioEntities : []), action: nil)) } else if let about = cachedData.about, !about.isEmpty { - items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction)) + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: user.botInfo == nil ? presentationData.strings.Profile_About : presentationData.strings.Channel_AboutItem, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction)) } } if !data.isContact { if user.botInfo == nil { - items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 3, text: "Add Contact", action: { + items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 3, text: presentationData.strings.UserInfo_AddContact, action: { interaction.openAddContact() })) } if let cachedData = data.cachedData as? CachedUserData { if cachedData.isBlocked { - items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 4, text: user.botInfo != nil ? "Restart Bot" : "Unblock", action: { + items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 4, text: user.botInfo != nil ? presentationData.strings.Bot_Unblock : presentationData.strings.Conversation_Unblock, action: { interaction.updateBlocked(false) })) } else { if user.flags.contains(.isSupport) { } else { - items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 4, text: user.botInfo != nil ? "Stop Bot" : "Block User", color: .destructive, action: { + items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 4, text: user.botInfo != nil ? presentationData.strings.Bot_Stop : presentationData.strings.Conversation_BlockUser, color: .destructive, action: { interaction.updateBlocked(true) })) } @@ -655,9 +655,9 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese } if let cachedData = data.cachedData as? CachedChannelData { if channel.isScam { - items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Profile_About, text: presentationData.strings.GroupInfo_ScamGroupWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil)) + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Channel_AboutItem, text: presentationData.strings.GroupInfo_ScamGroupWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil)) } else if let about = cachedData.about, !about.isEmpty { - items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Profile_About, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction)) + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Channel_AboutItem, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction)) } if case .broadcast = channel.info { @@ -687,9 +687,9 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese } else if let group = data.peer as? TelegramGroup { if let cachedData = data.cachedData as? CachedGroupData { if group.isScam { - items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: presentationData.strings.GroupInfo_ScamGroupWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil)) + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Channel_AboutItem, text: presentationData.strings.GroupInfo_ScamGroupWarning, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil)) } else if let about = cachedData.about, !about.isEmpty { - items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Profile_About, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction)) + items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Channel_AboutItem, text: about, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction)) } } } @@ -755,13 +755,13 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr let globalNotificationSettings: GlobalNotificationSettings = data.globalNotificationSettings ?? GlobalNotificationSettings.defaultSettings soundLabel = localizedPeerNotificationSoundString(strings: presentationData.strings, sound: notificationSettings.messageSound, default: globalNotificationSettings.effective.privateChats.sound) - items[.notifications]!.append(PeerInfoScreenDisclosureItem(id: 0, label: notificationsLabel, text: "Notifications", action: { + items[.notifications]!.append(PeerInfoScreenDisclosureItem(id: 0, label: notificationsLabel, text: presentationData.strings.GroupInfo_Notifications, action: { interaction.editingOpenNotificationSettings() })) - items[.notifications]!.append(PeerInfoScreenDisclosureItem(id: 1, label: soundLabel, text: "Sound", action: { + items[.notifications]!.append(PeerInfoScreenDisclosureItem(id: 1, label: soundLabel, text: presentationData.strings.GroupInfo_Sound, action: { interaction.editingOpenSoundSettings() })) - items[.notifications]!.append(PeerInfoScreenSwitchItem(id: 2, text: "Show Message Text", value: notificationSettings.displayPreviews != .hide, toggled: { value in + items[.notifications]!.append(PeerInfoScreenSwitchItem(id: 2, text: presentationData.strings.Notification_Exceptions_PreviewAlwaysOn, value: notificationSettings.displayPreviews != .hide, toggled: { value in interaction.editingToggleShowMessageText(value) })) } @@ -1170,6 +1170,14 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } })) } + + items.append( ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_ContextMenuMore, color: .accent, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + if let strongSelf = self { + strongSelf.chatInterfaceInteraction.toggleMessagesSelection([message.id], true) + strongSelf.expandTabs() + } + })) actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [ ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in actionSheet?.dismissAnimated() @@ -1274,6 +1282,18 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }))) } + items.append(.separator) + items.append(.action(ContextMenuActionItem(text: strings.Conversation_ContextMenuMore, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/More"), color: theme.actionSheet.primaryTextColor) + }, action: { _, f in + guard let strongSelf = self else { + return + } + strongSelf.chatInterfaceInteraction.toggleMessagesSelection([message.id], true) + strongSelf.expandTabs() + f(.default) + }))) + return items } @@ -1717,9 +1737,27 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } private func updateData(_ data: PeerInfoScreenData) { + var previousMemberCount: Int? + if let data = self.data { + if let members = data.members, case let .shortList(_, memberList) = members { + previousMemberCount = memberList.count + } + } self.data = data if let (layout, navigationHeight) = self.validLayout { - self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: self.didSetReady ? .animated(duration: 0.3, curve: .spring) : .immediate) + var updatedMemberCount: Int? + if let data = self.data { + if let members = data.members, case let .shortList(_, memberList) = members { + updatedMemberCount = memberList.count + } + } + + var membersUpdated = false + if let previousMemberCount = previousMemberCount, let updatedMemberCount = updatedMemberCount, previousMemberCount > updatedMemberCount { + membersUpdated = true + } + + self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: self.didSetReady && membersUpdated ? .animated(duration: 0.3, curve: .spring) : .immediate) } } @@ -1729,6 +1767,16 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } } + private func expandTabs() { + if let (layout, navigationHeight) = self.validLayout { + let contentOffset = self.scrollNode.view.contentOffset + let paneAreaExpansionFinalPoint: CGFloat = self.paneContainerNode.frame.minY - navigationHeight + if contentOffset.y < paneAreaExpansionFinalPoint - CGFloat.ulpOfOne { + self.scrollNode.view.setContentOffset(CGPoint(x: 0.0, y: paneAreaExpansionFinalPoint), animated: true) + } + } + } + @objc private func editingCancelPressed() { self.headerNode.navigationButtonContainer.performAction?(.cancel) } @@ -1855,41 +1903,13 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD case .call: self.requestCall() case .mute: - let peerId = self.peerId - let _ = (self.context.account.postbox.transaction { transaction -> (TelegramPeerNotificationSettings, GlobalNotificationSettings) in - let peerSettings: TelegramPeerNotificationSettings = (transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings) ?? TelegramPeerNotificationSettings.defaultSettings - let globalSettings: GlobalNotificationSettings = (transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications) as? GlobalNotificationSettings) ?? GlobalNotificationSettings.defaultSettings - return (peerSettings, globalSettings) + let muteInterval: Int32? + if let notificationSettings = self.data?.notificationSettings, case .muted = notificationSettings.muteState { + muteInterval = nil + } else { + muteInterval = Int32.max } - |> deliverOnMainQueue).start(next: { [weak self] peerSettings, globalSettings in - guard let strongSelf = self else { - return - } - let soundSettings: NotificationSoundSettings? - if case .default = peerSettings.messageSound { - soundSettings = NotificationSoundSettings(value: nil) - } else { - soundSettings = NotificationSoundSettings(value: peerSettings.messageSound) - } - let muteSettingsController = notificationMuteSettingsController(presentationData: strongSelf.presentationData, notificationSettings: globalSettings.effective.groupChats, soundSettings: soundSettings, openSoundSettings: { - guard let strongSelf = self else { - return - } - let soundController = notificationSoundSelectionController(context: strongSelf.context, isModal: true, currentSound: peerSettings.messageSound, defaultSound: globalSettings.effective.groupChats.sound, completion: { sound in - guard let strongSelf = self else { - return - } - let _ = updatePeerNotificationSoundInteractive(account: strongSelf.context.account, peerId: strongSelf.peerId, sound: sound).start() - }) - strongSelf.controller?.present(soundController, in: .window(.root)) - }, updateSettings: { value in - guard let strongSelf = self else { - return - } - let _ = updatePeerMuteSetting(account: strongSelf.context.account, peerId: strongSelf.peerId, muteInterval: value).start() - }) - strongSelf.controller?.present(muteSettingsController, in: .window(.root)) - }) + let _ = updatePeerMuteSetting(account: self.context.account, peerId: self.peerId, muteInterval: muteInterval).start() case .more: guard let data = self.data, let peer = data.peer else { return @@ -2212,6 +2232,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } let _ = updatePeerNotificationSoundInteractive(account: strongSelf.context.account, peerId: strongSelf.peerId, sound: sound).start() }) + soundController.navigationPresentation = .modal strongSelf.controller?.push(soundController) }, updateSettings: { value in guard let strongSelf = self else { @@ -3419,10 +3440,12 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD for (sectionId, sectionItems) in editingItems(data: self.data, context: self.context, presentationData: self.presentationData, interaction: self.interaction) { validEditingSections.append(sectionId) + var wasAdded = false let sectionNode: PeerInfoScreenItemSectionContainerNode if let current = self.editingSections[sectionId] { sectionNode = current } else { + wasAdded = true sectionNode = PeerInfoScreenItemSectionContainerNode() self.editingSections[sectionId] = sectionNode self.scrollNode.addSubnode(sectionNode) @@ -3430,13 +3453,18 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD let sectionHeight = sectionNode.update(width: layout.size.width, presentationData: self.presentationData, items: sectionItems, transition: transition) let sectionFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: sectionHeight)) - if additive { - transition.updateFrameAdditive(node: sectionNode, frame: sectionFrame) - } else { - transition.updateFrame(node: sectionNode, frame: sectionFrame) - } - transition.updateAlpha(node: sectionNode, alpha: self.state.isEditing ? 1.0 : 0.0) + if wasAdded { + sectionNode.frame = sectionFrame + sectionNode.alpha = self.state.isEditing ? 1.0 : 0.0 + } else { + if additive { + transition.updateFrameAdditive(node: sectionNode, frame: sectionFrame) + } else { + transition.updateFrame(node: sectionNode, frame: sectionFrame) + } + transition.updateAlpha(node: sectionNode, alpha: self.state.isEditing ? 1.0 : 0.0) + } if !sectionHeight.isZero && self.state.isEditing { contentHeight += sectionHeight contentHeight += sectionSpacing @@ -3632,7 +3660,8 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } switch currentPaneKey { case .media, .files, .music, .links, .voice: - navigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .select, isForExpandedView: true)) + //navigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .select, isForExpandedView: true)) + break default: break } diff --git a/submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping b/submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping index 65d4ae5d0d7a18e76c92b167eb914ff65ba39eb4..16074d02e91a61d6e8233a6501ed646ec90a2714 100644 GIT binary patch delta 36485 zcmZsE2Y6J)_cn9MO|sck(sr{wn_e~vRXQPbNr8X}NLk22B1txtUR9b>0wWxXG^I%m zqDXHdHmZsZX;u^wus7g)XEufZ@A;lblg!MSxpU{9@}4tihF^a2{p@F7_Qf9d&uDu@ zlO|2_T&{}VrDNQVuGLjl?$T^mWu}miiW4LLZ zflnw1Rsx&yJr{L86>dQv#J3jMSuj6S5W_!dR`SFOtK$gT~3scR>7$O)0W|oz?oE6T}(Jse;qN-xK8mUbw<22Lx zG-n`iH0AyFhVrBP19@$subPH_$-I2Nj;wF7W}05E;xaL>bbhxmo@H=dQ4(v;vx*W} z3tn7gR$4YC$0(-r?@?4->?(LtkhbErMe$1Oru@W~Q2tXfnTL?O3JIfq>-J_jVMWtiAS5&ww#7G@@m!}iejv$Gpdke6B^Pdi3o%rgf zn=750(v4VV@qSFaLKptq)3ItM=q&uiM>@K5f_d`}<9yYwsEQUZ!>`Q@ke{p@uN;@c zy7Tqp9IOXFKhB``1dWYvs1D~|#i431lytP`B#ZECSgt;N&2&A#n(NJn7HieVK@r98 z+zjV4i~U(&zOXorW%DD&CMBmSxnE=P+E$JnXNg?sTpn0rQ1j5k$ZHN7QhHRlOT>%y zLyctELU)zBdqGi^yTUQZSy56|IKb^L78Ly@H#V!1>yQufNL1zx%39W>Nk{mCjN4+G3cI zywsh*oSfWNHj3v|MDTNNe|5AR{KS_L{C9VVQsCjRbMN~E7r9Hb1TWV0cJbzA@oWqq zQf5%cqK`?gJg+GWWQBZPnNBT2r9sZ}0_vXT*UFNWaZTw?0gL92azCZGDZg<-$NQIu zvl3odo}!kbLlm#M7|CnP{leWS`CyiUyYRo5a9LA25y3)vnU6nR@6NpaQes^AaG z6P3!Qv?o#trI{Jb*Kc5HQB|erRfSiJX4SmBB21aslxDdw!m5f;Hkt3Lh-XvyClxWu zRQbuYg_A^wX?SuR9XBble)S?Wy(zaXH1L_{RBu5sqbXn0&Xk^6P*4FqmE|rg@~r4g z^b}tq&skJj<;W_A^k%tB#}rja&Y8teR2r0LJTKvq`O>|<;MEdWfq02$c|cV?Y!&yL zkf^Q(RixnZ2%a;+*RTe~KoB;tW?qGRqFn5?ynKR%t>a53v{u)HDxBY5q?6*lL9*n- z3I6KKs5g-_okh^`5Jlz56E*5a)Y-?)pu~Bb;AV56HT~gvMb##NERLRwOliMcS z)%|ET^I07X+Qyax+&wvt9pcL;Thzm7H}K46;r#sM0Ct35nViawa_y9OcAU4E5~H3( zdm>%*#>Xw2Vq|aeg;O3=-j;mJuTAk*PB-O8elchUxSUc6y~DLrP3pVol+1608uT;7sN|ka3#W=Dxg;qK~Ri~V7%4Y?J^4n8`*g1ZGYK(dw z?J>N|0aGZLKHF6?%2gqS>w@gJI+Z2LZ+4MCH!X&J$X}h7%0A+sPD@}PFP$E*UXs0M z>^1P7(}UGdP}1`yU3Hqg+`fIqls@Itrd!zO(A7!m7idkBQ(kQLr_$UJ$5 zpZX=5lX-foi4U3)&aUv18FA`W)J4GLhVtz*{FG~+H90@So891_%&@Cpp*fLrE8q$0 zntYGO_&UoJ!EW+DW?C&j)OUdOsBk*+%d4FguIxI2`mrg`cqNqb%9t1LJIkQn0EW}x{O&9hyT=2cNoKzQaX_~|6Uu(&W1dN3zwsr{IN0y}_%ku;9~i|%AHuxEXgznjv?RuGTcm$ZELv!Uw0qA$NVM3;)C%zyy1H9Yg=@5!nVj(hw8Zj^a6SL~*--Y72Rvt1n|KM<+t7+dN}f@8 z-{)+sDKC94PVw^M=Uh>|_Bmfw1(iwI_CDaaJZEKP8RQ(#XyT0qVSokXDDGL|t}d&? zj15NL2Nd-H&G875^yS9cb|}*>vtyZ-kC~mI1bESj%lPh_X9Glf2?&rFP!9ltFiJDp z-IImOX$EuOIW{H4OCqjLb0U;xUNlPuYAl%(1dB3lP8uY0Cw@lqD{~SRofl8P8pe%t zL!hx8bL~o$7nNVb-^Fu-frh5djZutvpdJjke{K*n@ptFinVJ7IH;P%f&%8ut%(tjXXon1s!|+4qH)F}X zWPYrgf=Vm(6YzG|{9xwb$L8D3X{eOQ&4aRmUy6&%oMj%ckiPW!XiEkt1gFXMmAD+L zy8-z%=b6t(0YyIbyp6Tw)1QxvZdEs;z{Cy@!}f3%)j@^Uat^hBiluozn6=?QKcB`P z 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�x#`FEQ4{mm#dhwD@Io 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 String { + public func Wallet_Updated_HoursAgo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue) } - public func Wallet_Updated_HoursAgo(_ value: Int32) -> String { + public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue) From 3cc7be592c6aeb491c38f0f5646c91306407b17f Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 11 Feb 2020 23:10:17 +0100 Subject: [PATCH 26/30] Peer Info screen fixes --- .../ChannelMembersSearchContainerNode.swift | 18 +-- .../ChannelMembersSearchController.swift | 2 +- .../Sources/ChannelVisibilityController.swift | 21 ++- .../Panes/PeerInfoVisualMediaPaneNode.swift | 7 +- .../PeerInfo/PeerInfoHeaderNode.swift | 150 ++++++++++++++++-- .../TelegramUI/PeerInfo/PeerInfoScreen.swift | 136 +++++++++++----- 6 files changed, 267 insertions(+), 67 deletions(-) diff --git a/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift b/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift index 16aa80cbfb..e6ba424e59 100644 --- a/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift +++ b/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift @@ -17,7 +17,7 @@ import ContactsPeerItem import ChatListSearchItemHeader import ItemListUI -enum ChannelMembersSearchMode { +public enum ChannelMembersSearchMode { case searchMembers case searchAdmins case searchBanned @@ -239,10 +239,10 @@ private struct GroupMembersSearchContextState { var members: [RenderedChannelParticipant] = [] } -final class GroupMembersSearchContext { +public final class GroupMembersSearchContext { fileprivate let state = Promise() - init(context: AccountContext, peerId: PeerId) { + public init(context: AccountContext, peerId: PeerId) { assert(Queue.mainQueue().isCurrent()) let combinedSignal = combineLatest(queue: .mainQueue(), categorySignal(context: context, peerId: peerId, category: .contacts), categorySignal(context: context, peerId: peerId, category: .bots), categorySignal(context: context, peerId: peerId, category: .admins), categorySignal(context: context, peerId: peerId, category: .members)) @@ -275,7 +275,7 @@ private struct ChannelMembersSearchContainerState: Equatable { var removingParticipantIds = Set() } -final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNode { +public final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNode { private let context: AccountContext private let openPeer: (Peer, RenderedChannelParticipant?) -> Void private let mode: ChannelMembersSearchMode @@ -298,7 +298,7 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod private let presentationDataPromise: Promise - init(context: AccountContext, peerId: PeerId, mode: ChannelMembersSearchMode, filters: [ChannelMembersSearchFilter], searchContext: GroupMembersSearchContext?, openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void, updateActivity: @escaping (Bool) -> Void, pushController: @escaping (ViewController) -> Void) { + public init(context: AccountContext, peerId: PeerId, mode: ChannelMembersSearchMode, filters: [ChannelMembersSearchFilter], searchContext: GroupMembersSearchContext?, openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void, updateActivity: @escaping (Bool) -> Void, pushController: @escaping (ViewController) -> Void) { self.context = context self.openPeer = openPeer self.mode = mode @@ -1170,7 +1170,7 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod self.removeMemberDisposable.dispose() } - override func didLoad() { + override public func didLoad() { super.didLoad() } @@ -1179,7 +1179,7 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod self.listNode.backgroundColor = theme.chatList.backgroundColor } - override func searchTextUpdated(text: String) { + override public func searchTextUpdated(text: String) { if text.isEmpty { self.searchQuery.set(.single(nil)) } else { @@ -1244,7 +1244,7 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod } } - override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { + override public func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { super.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition) let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition) @@ -1268,7 +1268,7 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod } } - override func scrollToTop() { + override public func scrollToTop() { if self.listNode.isHidden { self.emptyQueryListNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) } else { diff --git a/submodules/PeerInfoUI/Sources/ChannelMembersSearchController.swift b/submodules/PeerInfoUI/Sources/ChannelMembersSearchController.swift index a9350d7aba..4125fbe79c 100644 --- a/submodules/PeerInfoUI/Sources/ChannelMembersSearchController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelMembersSearchController.swift @@ -14,7 +14,7 @@ enum ChannelMembersSearchControllerMode { case ban } -enum ChannelMembersSearchFilter { +public enum ChannelMembersSearchFilter { case exclude([PeerId]) case disable([PeerId]) } diff --git a/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift b/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift index 478b46d720..018c87d2d6 100644 --- a/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift @@ -813,7 +813,7 @@ public enum ChannelVisibilityControllerMode { case privateLink } -public func channelVisibilityController(context: AccountContext, peerId: PeerId, mode: ChannelVisibilityControllerMode, upgradedToSupergroup: @escaping (PeerId, @escaping () -> Void) -> Void) -> ViewController { +public func channelVisibilityController(context: AccountContext, peerId: PeerId, mode: ChannelVisibilityControllerMode, upgradedToSupergroup: @escaping (PeerId, @escaping () -> Void) -> Void, onDismissRemoveController: ViewController? = nil) -> ViewController { let statePromise = ValuePromise(ChannelVisibilityControllerState(), ignoreRepeated: true) let stateValue = Atomic(value: ChannelVisibilityControllerState()) let updateState: ((ChannelVisibilityControllerState) -> ChannelVisibilityControllerState) -> Void = { f in @@ -1231,9 +1231,22 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId, } let controller = ItemListController(context: context, state: signal) - dismissImpl = { [weak controller] in - controller?.view.endEditing(true) - controller?.dismiss() + dismissImpl = { [weak controller, weak onDismissRemoveController] in + guard let controller = controller else { + return + } + controller.view.endEditing(true) + if let onDismissRemoveController = onDismissRemoveController, let navigationController = controller.navigationController { + navigationController.setViewControllers(navigationController.viewControllers.filter { c in + if c === controller || c === onDismissRemoveController { + return false + } else { + return true + } + }, animated: true) + } else { + controller.dismiss() + } } dismissInputImpl = { [weak controller] in controller?.view.endEditing(true) diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift index a7733e39d9..8f901e2cd8 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/Panes/PeerInfoVisualMediaPaneNode.swift @@ -87,7 +87,11 @@ private final class VisualMediaItemNode: ASDisplayNode { override func didLoad() { super.didLoad() - self.view.addGestureRecognizer(TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))) + let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))) + recognizer.tapActionAtPoint = { _ in + return .waitForSingleTap + } + self.imageNode.view.addGestureRecognizer(recognizer) } @objc func tapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { @@ -375,6 +379,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro self.itemInteraction.selectedMessageIds = chatControllerInteraction.selectionState.flatMap { $0.selectedIds } self.scrollNode.view.delaysContentTouches = false + self.scrollNode.view.canCancelContentTouches = true self.scrollNode.view.showsVerticalScrollIndicator = false if #available(iOS 11.0, *) { self.scrollNode.view.contentInsetAdjustmentBehavior = .never diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift index 39d84c0a23..f7c9aadc5d 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift @@ -1099,30 +1099,135 @@ final class PeerInfoHeaderSingleLineTextFieldNode: ASDisplayNode, PeerInfoHeader } } -/*final class PeerInfoHeaderMultiLineTextFieldNode: ASDisplayNode, PeerInfoHeaderTextFieldNode { - private let textNode: TextFieldNode +final class PeerInfoHeaderMultiLineTextFieldNode: ASDisplayNode, PeerInfoHeaderTextFieldNode, ASEditableTextNodeDelegate { + private let textNode: EditableTextNode + private let textNodeContainer: ASDisplayNode + private let measureTextNode: ImmediateTextNode private let topSeparator: ASDisplayNode - override init() { - self.textNode = TextFieldNode() + private let requestUpdateHeight: () -> Void + + private var theme: PresentationTheme? + private var currentParams: (width: CGFloat, safeInset: CGFloat)? + private var currentMeasuredHeight: CGFloat? + + var text: String { + return self.textNode.attributedText?.string ?? "" + } + + init(requestUpdateHeight: @escaping () -> Void) { + self.requestUpdateHeight = requestUpdateHeight + + self.textNode = EditableTextNode() + self.textNodeContainer = ASDisplayNode() + self.measureTextNode = ImmediateTextNode() + self.measureTextNode.maximumNumberOfLines = 0 self.topSeparator = ASDisplayNode() super.init() + + self.textNodeContainer.addSubnode(self.textNode) + self.addSubnode(self.textNodeContainer) + self.addSubnode(self.topSeparator) } - func update(width: CGFloat, safeInset: CGFloat) -> CGFloat { - return 44.0 + func update(width: CGFloat, safeInset: CGFloat, hasPrevious: Bool, placeholder: String, isEnabled: Bool, presentationData: PresentationData, updateText: String?) -> CGFloat { + self.currentParams = (width, safeInset) + + if self.theme !== presentationData.theme { + self.theme = presentationData.theme + let textColor = presentationData.theme.list.itemPrimaryTextColor + self.textNode.typingAttributes = [NSAttributedString.Key.font.rawValue: Font.regular(17.0), NSAttributedString.Key.foregroundColor.rawValue: textColor] + + self.textNode.clipsToBounds = true + self.textNode.delegate = self + self.textNode.hitTestSlop = UIEdgeInsets(top: -5.0, left: -5.0, bottom: -5.0, right: -5.0) + } + + self.topSeparator.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + self.topSeparator.frame = CGRect(origin: CGPoint(x: safeInset + (hasPrevious ? 16.0 : 0.0), y: 0.0), size: CGSize(width: width, height: UIScreenPixel)) + + let attributedPlaceholderText = NSAttributedString(string: placeholder, font: Font.regular(17.0), textColor: presentationData.theme.list.itemPlaceholderTextColor) + if self.textNode.attributedPlaceholderText == nil || !self.textNode.attributedPlaceholderText!.isEqual(to: attributedPlaceholderText) { + self.textNode.attributedPlaceholderText = attributedPlaceholderText + } + + if let updateText = updateText { + let attributedText = NSAttributedString(string: updateText, font: Font.regular(17.0), textColor: presentationData.theme.list.itemPrimaryTextColor) + self.textNode.attributedText = attributedText + } + + var measureText = self.textNode.attributedText?.string ?? "" + if measureText.hasSuffix("\n") || measureText.isEmpty { + measureText += "|" + } + let attributedMeasureText = NSAttributedString(string: measureText, font: Font.regular(17.0), textColor: .black) + self.measureTextNode.attributedText = attributedMeasureText + let measureTextSize = self.measureTextNode.updateLayout(CGSize(width: width - safeInset * 2.0 - 16 * 2.0, height: .greatestFiniteMagnitude)) + self.currentMeasuredHeight = measureTextSize.height + + let height = measureTextSize.height + 22.0 + + let textNodeFrame = CGRect(origin: CGPoint(x: safeInset + 16.0, y: 10.0), size: CGSize(width: width - safeInset * 2.0 - 16.0 * 2.0, height: max(height, 1000.0))) + self.textNodeContainer.frame = textNodeFrame + self.textNode.frame = CGRect(origin: CGPoint(), size: textNodeFrame.size) + + return height } -}*/ + + func editableTextNode(_ editableTextNode: ASEditableTextNode, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { + guard let theme = self.theme else { + return true + } + let updatedText = (editableTextNode.textView.text as NSString).replacingCharacters(in: range, with: text) + if updatedText.count > 255 { + let attributedText = NSAttributedString(string: String(updatedText[updatedText.startIndex.. 0.1 { + self.requestUpdateHeight() + } + } + } + + func editableTextNodeShouldPaste(_ editableTextNode: ASEditableTextNode) -> Bool { + let text: String? = UIPasteboard.general.string + if let _ = text { + return true + } else { + return false + } + } +} final class PeerInfoHeaderEditingContentNode: ASDisplayNode { private let context: AccountContext + private let requestUpdateLayout: () -> Void + let avatarNode: PeerInfoEditingAvatarNode var itemNodes: [PeerInfoHeaderTextFieldNodeKey: PeerInfoHeaderTextFieldNode] = [:] - init(context: AccountContext) { + init(context: AccountContext, requestUpdateLayout: @escaping () -> Void) { self.context = context + self.requestUpdateLayout = requestUpdateLayout + self.avatarNode = PeerInfoEditingAvatarNode(context: context) super.init() @@ -1167,6 +1272,7 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode { if let current = self.itemNodes[key] { itemNode = current } else { + var isMultiline = false switch key { case .firstName: updateText = (peer as? TelegramUser)?.firstName ?? "" @@ -1175,6 +1281,7 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode { case .title: updateText = peer?.debugDisplayTitle ?? "" case .description: + isMultiline = true if let cachedData = cachedData as? CachedChannelData { updateText = cachedData.about ?? "" } else if let cachedData = cachedData as? CachedGroupData { @@ -1183,7 +1290,13 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode { updateText = "" } } - itemNode = PeerInfoHeaderSingleLineTextFieldNode() + if isMultiline { + itemNode = PeerInfoHeaderMultiLineTextFieldNode(requestUpdateHeight: { [weak self] in + self?.requestUpdateLayout() + }) + } else { + itemNode = PeerInfoHeaderSingleLineTextFieldNode() + } self.itemNodes[key] = itemNode self.addSubnode(itemNode) } @@ -1256,6 +1369,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { var performButtonAction: ((PeerInfoHeaderButtonKey) -> Void)? var requestAvatarExpansion: (([AvatarGalleryEntry], (ASDisplayNode, CGRect, () -> (UIView?, UIView?))) -> Void)? var requestOpenAvatarForEditing: (() -> Void)? + var requestUpdateLayout: (() -> Void)? var navigationTransition: PeerInfoHeaderNavigationTransition? @@ -1282,7 +1396,10 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.subtitleNode.displaysAsynchronously = false self.regularContentNode = PeerInfoHeaderRegularContentNode() - self.editingContentNode = PeerInfoHeaderEditingContentNode(context: context) + var requestUpdateLayoutImpl: (() -> Void)? + self.editingContentNode = PeerInfoHeaderEditingContentNode(context: context, requestUpdateLayout: { + requestUpdateLayoutImpl?() + }) self.editingContentNode.alpha = 0.0 self.navigationButtonContainer = PeerInfoHeaderNavigationButtonContainerNode() @@ -1297,6 +1414,10 @@ final class PeerInfoHeaderNode: ASDisplayNode { super.init() + requestUpdateLayoutImpl = { [weak self] in + self?.requestUpdateLayout?() + } + self.addSubnode(self.backgroundNode) self.addSubnode(self.expandedBackgroundNode) self.addSubnode(self.separatorNode) @@ -1650,7 +1771,14 @@ final class PeerInfoHeaderNode: ASDisplayNode { let buttonsAlpha: CGFloat let apparentButtonSize: CGFloat let buttonsVerticalOffset: CGFloat + + var buttonsAlphaTransition = transition + if self.navigationTransition != nil { + if case let .animated(duration, curve) = transition, transitionFraction >= 1.0 - CGFloat.ulpOfOne { + buttonsAlphaTransition = .animated(duration: duration * 0.6, curve: curve) + } + if self.isAvatarExpanded { apparentButtonSize = expandedButtonSize } else { @@ -1736,7 +1864,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { if wasAdded { buttonNode.alpha = 0.0 } - transition.updateAlpha(node: buttonNode, alpha: buttonsAlpha) + buttonsAlphaTransition.updateAlpha(node: buttonNode, alpha: buttonsAlpha) let hiddenWhileExpanded: Bool switch self.keepExpandedButtons { diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift index 7dcead0b6c..b0e57aa3b3 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift @@ -601,25 +601,26 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese interaction.openAddContact() })) } - if let cachedData = data.cachedData as? CachedUserData { - if cachedData.isBlocked { - items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 4, text: user.botInfo != nil ? presentationData.strings.Bot_Unblock : presentationData.strings.Conversation_Unblock, action: { - interaction.updateBlocked(false) - })) + } + if let cachedData = data.cachedData as? CachedUserData { + if cachedData.isBlocked { + items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 4, text: user.botInfo != nil ? presentationData.strings.Bot_Unblock : presentationData.strings.Conversation_Unblock, action: { + interaction.updateBlocked(false) + })) + } else { + if user.flags.contains(.isSupport) { } else { - if user.flags.contains(.isSupport) { - } else { - items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 4, text: user.botInfo != nil ? presentationData.strings.Bot_Stop : presentationData.strings.Conversation_BlockUser, color: .destructive, action: { - interaction.updateBlocked(true) - })) - } + items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 4, text: user.botInfo != nil ? presentationData.strings.Bot_Stop : presentationData.strings.Conversation_BlockUser, color: .destructive, action: { + interaction.updateBlocked(true) + })) } } - if user.botInfo != nil, !user.isVerified { - items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 5, text: presentationData.strings.ReportPeer_Report, action: { - interaction.openReport() - })) - } + } + + if user.botInfo != nil, !user.isVerified { + items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 5, text: presentationData.strings.ReportPeer_Report, action: { + interaction.openReport() + })) } } else if let channel = data.peer as? TelegramChannel { let ItemUsername = 1 @@ -1170,14 +1171,15 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } })) } - - items.append( ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_ContextMenuMore, color: .accent, action: { [weak actionSheet] in - actionSheet?.dismissAnimated() - if let strongSelf = self { - strongSelf.chatInterfaceInteraction.toggleMessagesSelection([message.id], true) - strongSelf.expandTabs() - } - })) + if strongSelf.searchDisplayController == nil { + items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_ContextMenuMore, color: .accent, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + if let strongSelf = self { + strongSelf.chatInterfaceInteraction.toggleMessagesSelection([message.id], true) + strongSelf.expandTabs() + } + })) + } actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [ ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in actionSheet?.dismissAnimated() @@ -1575,6 +1577,15 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD self?.openAvatarForEditing() } + self.headerNode.requestUpdateLayout = { [weak self] in + guard let strongSelf = self else { + return + } + if let (layout, navigationHeight) = strongSelf.validLayout { + strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false) + } + } + self.headerNode.navigationButtonContainer.performAction = { [weak self] key in guard let strongSelf = self else { return @@ -1646,7 +1657,36 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } } else if let group = data.peer as? TelegramGroup, canEditPeerInfo(peer: group) { let title = strongSelf.headerNode.editingContentNode.editingTextForKey(.title) ?? "" + let description = strongSelf.headerNode.editingContentNode.editingTextForKey(.description) ?? "" + var updateDataSignals: [Signal] = [] + + if title != group.title { + updateDataSignals.append( + updatePeerTitle(account: strongSelf.context.account, peerId: group.id, title: title) + |> ignoreValues + |> mapError { _ in return Void() } + ) + } + if description != (data.cachedData as? CachedGroupData)?.about { + updateDataSignals.append( + updatePeerDescription(account: strongSelf.context.account, peerId: group.id, description: description.isEmpty ? nil : description) + |> ignoreValues + |> mapError { _ in return Void() } + ) + } + strongSelf.activeActionDisposable.set((combineLatest(updateDataSignals) + |> deliverOnMainQueue).start(error: { _ in + guard let strongSelf = self else { + return + } + strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel) + }, completed: { + guard let strongSelf = self else { + return + } + strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel) + })) } else if let channel = data.peer as? TelegramChannel, canEditPeerInfo(peer: channel) { let title = strongSelf.headerNode.editingContentNode.editingTextForKey(.title) ?? "" let description = strongSelf.headerNode.editingContentNode.editingTextForKey(.description) ?? "" @@ -3106,17 +3146,19 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } else { mode = .privateLink } - let visibilityController = channelVisibilityController(context: strongSelf.context, peerId: groupPeer.id, mode: mode, upgradedToSupergroup: { _, f in f() }) - visibilityController.navigationPresentation = .modal + let visibilityController = channelVisibilityController(context: strongSelf.context, peerId: groupPeer.id, mode: mode, upgradedToSupergroup: { _, f in f() }, onDismissRemoveController: contactsController) + //visibilityController.navigationPresentation = .modal - if let navigationController = strongSelf.controller?.navigationController as? NavigationController { + contactsController?.push(visibilityController) + + /*if let navigationController = strongSelf.controller?.navigationController as? NavigationController { var controllers = navigationController.viewControllers if let contactsController = contactsController { controllers.removeAll(where: { $0 === contactsController }) } controllers.append(visibilityController) navigationController.setViewControllers(controllers, animated: true) - } + }*/ } strongSelf.controller?.push(contactsController) @@ -3312,21 +3354,33 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD return } - var tagMask: MessageTags = .file - if let currentPaneKey = self.paneContainerNode.currentPaneKey { - switch currentPaneKey { - case .links: - tagMask = .webPage - case .music: - tagMask = .music - default: - break + if let currentPaneKey = self.paneContainerNode.currentPaneKey, case .members = currentPaneKey { + self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, placeholder: self.presentationData.strings.Common_Search, contentNode: ChannelMembersSearchContainerNode(context: self.context, peerId: self.peerId, mode: .searchMembers, filters: [], searchContext: nil, openPeer: { [weak self] peer, participant in + self?.openPeer(peerId: peer.id, navigation: .info) + }, updateActivity: { _ in + }, pushController: { [weak self] c in + self?.controller?.push(c) + }), cancel: { [weak self] in + self?.deactivateSearch() + }) + } else { + var tagMask: MessageTags = .file + if let currentPaneKey = self.paneContainerNode.currentPaneKey { + switch currentPaneKey { + case .links: + tagMask = .webPage + case .music: + tagMask = .music + default: + break + } } + + self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, placeholder: self.presentationData.strings.Common_Search, contentNode: ChatHistorySearchContainerNode(context: self.context, peerId: self.peerId, tagMask: tagMask, interfaceInteraction: self.chatInterfaceInteraction), cancel: { [weak self] in + self?.deactivateSearch() + }) } - self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, placeholder: self.presentationData.strings.Common_Search, contentNode: ChatHistorySearchContainerNode(context: self.context, peerId: self.peerId, tagMask: tagMask, interfaceInteraction: self.chatInterfaceInteraction), cancel: { [weak self] in - self?.deactivateSearch() - }) let transition: ContainedViewLayoutTransition = .animated(duration: 0.2, curve: .easeInOut) if let navigationBar = self.controller?.navigationBar { transition.updateAlpha(node: navigationBar, alpha: 0.0) @@ -3653,7 +3707,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD if self.state.selectedMessageIds == nil { if let currentPaneKey = self.paneContainerNode.currentPaneKey { switch currentPaneKey { - case .files, .music, .links: + case .files, .music, .links, .members: navigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .search, isForExpandedView: true)) default: break From 8c209b78bdf46e55c14080a5bd3d51497eb0bb46 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 12 Feb 2020 02:47:38 +0400 Subject: [PATCH 27/30] Various fixes --- Telegram-iOS/en.lproj/Localizable.strings | 2 +- .../ChatItemGalleryFooterContentNode.swift | 7 +++++- .../GalleryUI/Sources/GalleryItemNode.swift | 2 ++ .../GalleryUI/Sources/GalleryPagerNode.swift | 12 ++++++++++ .../Items/UniversalVideoGalleryItem.swift | 20 ++++++++++++---- .../ZoomableContentGalleryItemNode.swift | 4 ++-- .../Sources/PeerReportController.swift | 24 +++++++------------ 7 files changed, 47 insertions(+), 24 deletions(-) diff --git a/Telegram-iOS/en.lproj/Localizable.strings b/Telegram-iOS/en.lproj/Localizable.strings index 363e615909..5cfd6af771 100644 --- a/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram-iOS/en.lproj/Localizable.strings @@ -5317,7 +5317,7 @@ Any member of this group will be able to see messages in the channel."; "PeopleNearby.VisibleUntil" = "visible until %@"; "PeopleNearby.MakeVisibleTitle" = "Make Myself Visible"; -"PeopleNearby.MakeVisibleDescription" = "Users nearby will be able to view your profile and send you messages. This may help you find new friends, but could also attract excessive attention. You can stop sharing your profile and location at any time.\n\nYour phone number will remain hidden."; +"PeopleNearby.MakeVisibleDescription" = "Users nearby will be able to view your profile and send you messages. This may help you find new friends, but could also attract excessive attention. You can stop sharing your profile at any time.\n\nYour phone number will remain hidden."; "PeopleNearby.DiscoverDescription" = "Exchange contact info with people nearby\nand find new friends."; diff --git a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift index df429f52d5..2a31c310a1 100644 --- a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift +++ b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift @@ -168,7 +168,12 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll self.dateNode.isHidden = true self.backwardButton.isHidden = true self.forwardButton.isHidden = true - self.playbackControlButton.isHidden = true + if status == .Local { + self.playbackControlButton.isHidden = false + self.playbackControlButton.setImage(playImage, for: []) + } else { + self.playbackControlButton.isHidden = true + } self.statusButtonNode.isHidden = false self.statusNode.isHidden = false diff --git a/submodules/GalleryUI/Sources/GalleryItemNode.swift b/submodules/GalleryUI/Sources/GalleryItemNode.swift index 615bdde364..b2c513654f 100644 --- a/submodules/GalleryUI/Sources/GalleryItemNode.swift +++ b/submodules/GalleryUI/Sources/GalleryItemNode.swift @@ -23,6 +23,8 @@ open class GalleryItemNode: ASDisplayNode { public var toggleControlsVisibility: () -> Void = { } public var goToPreviousItem: () -> Void = { } public var goToNextItem: () -> Void = { } + public var canGoToPreviousItem: () -> Bool = { return false } + public var canGoToNextItem: () -> Bool = { return false } public var dismiss: () -> Void = { } public var beginCustomDismiss: () -> Void = { } public var completeCustomDismiss: () -> Void = { } diff --git a/submodules/GalleryUI/Sources/GalleryPagerNode.swift b/submodules/GalleryUI/Sources/GalleryPagerNode.swift index 125b432cdc..1b2f7e5649 100644 --- a/submodules/GalleryUI/Sources/GalleryPagerNode.swift +++ b/submodules/GalleryUI/Sources/GalleryPagerNode.swift @@ -255,6 +255,18 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate { } } } + node.canGoToPreviousItem = { [weak self] in + if let strongSelf = self, let index = strongSelf.centralItemIndex, index > 0 { + return true + } + return false + } + node.canGoToNextItem = { [weak self] in + if let strongSelf = self, let index = strongSelf.centralItemIndex, index < strongSelf.items.count - 1 { + return true + } + return false + } node.dismiss = self.dismiss node.beginCustomDismiss = self.beginCustomDismiss node.completeCustomDismiss = self.completeCustomDismiss diff --git a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift index dc01efd988..48431dbfea 100644 --- a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift @@ -255,6 +255,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { private var _isVisible: Bool? private var initiallyActivated = false private var hideStatusNodeUntilCentrality = false + private var playOnContentOwnership = false private var validLayout: (ContainerViewLayout, CGFloat)? private var didPause = false private var isPaused = true @@ -475,6 +476,12 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { videoNode.ownsContentNodeUpdated = { [weak self] value in if let strongSelf = self { strongSelf.updateDisplayPlaceholder(!value) + + if strongSelf.playOnContentOwnership { + strongSelf.playOnContentOwnership = false + strongSelf.initiallyActivated = true + strongSelf.videoNode?.playOnceWithSound(playAndRecord: false, actionAtEnd: .stop) + } } } self.videoNode = videoNode @@ -710,7 +717,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { } private func shouldAutoplayOnCentrality() -> Bool { - if let item = self.item, let content = item.content as? NativeVideoContent, !self.initiallyActivated { +// !self.initiallyActivated + if let item = self.item, let content = item.content as? NativeVideoContent { var isLocal = false if let fetchStatus = self.fetchStatus, case .Local = fetchStatus { isLocal = true @@ -743,15 +751,19 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { self.hideStatusNodeUntilCentrality = false self.statusButtonNode.isHidden = self.hideStatusNodeUntilCentrality || self.statusNodeShouldBeHidden + if videoNode.ownsContentNode { if isAnimated { videoNode.seek(0.0) videoNode.play() - } - else if self.shouldAutoplayOnCentrality() { + } else if self.shouldAutoplayOnCentrality() { self.initiallyActivated = true videoNode.playOnceWithSound(playAndRecord: false, actionAtEnd: .stop) } + } else { + if self.shouldAutoplayOnCentrality() { + self.playOnContentOwnership = true + } } } else { self.dismissOnOrientationChange = false @@ -1283,6 +1295,6 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { } override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { - return .single((self.footerContentNode, self.overlayContentNode)) + return .single((self.footerContentNode, nil)) } } diff --git a/submodules/GalleryUI/Sources/ZoomableContentGalleryItemNode.swift b/submodules/GalleryUI/Sources/ZoomableContentGalleryItemNode.swift index a420bcbf20..58550dd126 100644 --- a/submodules/GalleryUI/Sources/ZoomableContentGalleryItemNode.swift +++ b/submodules/GalleryUI/Sources/ZoomableContentGalleryItemNode.swift @@ -91,12 +91,12 @@ open class ZoomableContentGalleryItemNode: GalleryItemNode, UIScrollViewDelegate tapRecognizer.highlight = { [weak self] location in if let strongSelf = self { let transition: ContainedViewLayoutTransition = .animated(duration: 0.07, curve: .easeInOut) - if let location = location, location.x < 44.0 { + if let location = location, location.x < 44.0 && strongSelf.canGoToPreviousItem() { transition.updateAlpha(node: strongSelf.leftFadeNode, alpha: 1.0) } else { transition.updateAlpha(node: strongSelf.leftFadeNode, alpha: 0.0) } - if let location = location, location.x > strongSelf.frame.width - 44.0 { + if let location = location, location.x > strongSelf.frame.width - 44.0 && strongSelf.canGoToNextItem() { transition.updateAlpha(node: strongSelf.rightFadeNode, alpha: 1.0) } else { transition.updateAlpha(node: strongSelf.rightFadeNode, alpha: 0.0) diff --git a/submodules/PeerInfoUI/Sources/PeerReportController.swift b/submodules/PeerInfoUI/Sources/PeerReportController.swift index 5e057cf581..21fb66aeb3 100644 --- a/submodules/PeerInfoUI/Sources/PeerReportController.swift +++ b/submodules/PeerInfoUI/Sources/PeerReportController.swift @@ -18,26 +18,18 @@ public enum PeerReportSubject { case messages([MessageId]) } -private enum PeerReportOption { +public enum PeerReportOption { case spam case violence case copyright - case pornoghraphy + case pornography case childAbuse case other } -public func presentPeerReportOptions(context: AccountContext, parent: ViewController, contextController: ContextController?, subject: PeerReportSubject, completion: @escaping (Bool) -> Void) { +public func presentPeerReportOptions(context: AccountContext, parent: ViewController, contextController: ContextController?, subject: PeerReportSubject, options: [PeerReportOption] = [.spam, .violence, .pornography, .childAbuse, .copyright, .other], completion: @escaping (Bool) -> Void) { if let contextController = contextController { let presentationData = context.sharedContext.currentPresentationData.with { $0 } - let options: [PeerReportOption] = [ - .spam, - .violence, - .pornoghraphy, - .childAbuse, - .copyright, - .other - ] var items: [ContextMenuItem] = [] for option in options { let title: String @@ -47,7 +39,7 @@ public func presentPeerReportOptions(context: AccountContext, parent: ViewContro title = presentationData.strings.ReportPeer_ReasonSpam case .violence: title = presentationData.strings.ReportPeer_ReasonViolence - case .pornoghraphy: + case .pornography: title = presentationData.strings.ReportPeer_ReasonPornography case .childAbuse: title = presentationData.strings.ReportPeer_ReasonChildAbuse @@ -67,7 +59,7 @@ public func presentPeerReportOptions(context: AccountContext, parent: ViewContro reportReason = .spam case .violence: reportReason = .violence - case .pornoghraphy: + case .pornography: reportReason = .porno case .childAbuse: reportReason = .childAbuse @@ -116,7 +108,7 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe let options: [PeerReportOption] = [ .spam, .violence, - .pornoghraphy, + .pornography, .childAbuse, .copyright, .other @@ -131,7 +123,7 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe title = presentationData.strings.ReportPeer_ReasonSpam case .violence: title = presentationData.strings.ReportPeer_ReasonViolence - case .pornoghraphy: + case .pornography: title = presentationData.strings.ReportPeer_ReasonPornography case .childAbuse: title = presentationData.strings.ReportPeer_ReasonChildAbuse @@ -147,7 +139,7 @@ public func peerReportOptionsController(context: AccountContext, subject: PeerRe reportReason = .spam case .violence: reportReason = .violence - case .pornoghraphy: + case .pornography: reportReason = .porno case .childAbuse: reportReason = .childAbuse From c896a5886c2e35d4d35e88ab2a786551fe43abbe Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 12 Feb 2020 03:06:42 +0400 Subject: [PATCH 28/30] Fixes --- .../Sources/Items/UniversalVideoGalleryItem.swift | 10 ++++++++-- submodules/MediaPlayer/Sources/MediaPlayer.swift | 3 +-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift index 48431dbfea..f0b6c51d16 100644 --- a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift @@ -256,6 +256,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { private var initiallyActivated = false private var hideStatusNodeUntilCentrality = false private var playOnContentOwnership = false + private var skipInitialPause = false private var validLayout: (ContainerViewLayout, CGFloat)? private var didPause = false private var isPaused = true @@ -480,6 +481,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { if strongSelf.playOnContentOwnership { strongSelf.playOnContentOwnership = false strongSelf.initiallyActivated = true + strongSelf.skipInitialPause = true strongSelf.videoNode?.playOnceWithSound(playAndRecord: false, actionAtEnd: .stop) } } @@ -786,8 +788,12 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { if hadPreviousValue { videoNode.canAttachContent = isVisible if isVisible { - videoNode.pause() - videoNode.seek(0.0) + if self.skipInitialPause { + self.skipInitialPause = false + } else { + videoNode.pause() + videoNode.seek(0.0) + } } else { videoNode.continuePlayingWithoutSound() } diff --git a/submodules/MediaPlayer/Sources/MediaPlayer.swift b/submodules/MediaPlayer/Sources/MediaPlayer.swift index d57c7d5366..9f3ab99e65 100644 --- a/submodules/MediaPlayer/Sources/MediaPlayer.swift +++ b/submodules/MediaPlayer/Sources/MediaPlayer.swift @@ -530,8 +530,7 @@ private final class MediaPlayerContext { } else { if case let .timecode(time) = seek { self.seek(timestamp: Double(time), action: .play) - } - else if case .playing = self.state { + } else if case .playing = self.state { } else { self.play() } From a1f45bc7e8af73f47570051677dcccc798695656 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 12 Feb 2020 03:15:13 +0400 Subject: [PATCH 29/30] Fix gallery footer hit test --- submodules/GalleryUI/Sources/GalleryFooterNode.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/GalleryUI/Sources/GalleryFooterNode.swift b/submodules/GalleryUI/Sources/GalleryFooterNode.swift index 155f2cc358..027ea8a682 100644 --- a/submodules/GalleryUI/Sources/GalleryFooterNode.swift +++ b/submodules/GalleryUI/Sources/GalleryFooterNode.swift @@ -118,7 +118,7 @@ public final class GalleryFooterNode: ASDisplayNode { if let overlayResult = self.currentOverlayContentNode?.hitTest(point, with: event) { return overlayResult } - if !self.backgroundNode.frame.contains(point) { + if !self.backgroundNode.frame.contains(point) || self.visibilityAlpha < 1.0 { return nil } let result = super.hitTest(point, with: event) From 220373339ac4b778d28ddb2a8f9a66d2d5bda42d Mon Sep 17 00:00:00 2001 From: Ali <> Date: Wed, 12 Feb 2020 00:47:00 +0100 Subject: [PATCH 30/30] Fix layout --- .../TelegramUI/MultiScaleTextNode.swift | 17 +++- .../PeerInfo/PeerInfoHeaderNode.swift | 92 ++++++++++++------- .../TelegramUI/PeerInfo/PeerInfoScreen.swift | 6 +- 3 files changed, 79 insertions(+), 36 deletions(-) diff --git a/submodules/TelegramUI/TelegramUI/MultiScaleTextNode.swift b/submodules/TelegramUI/TelegramUI/MultiScaleTextNode.swift index 9eec9f4aa9..8a82226ae8 100644 --- a/submodules/TelegramUI/TelegramUI/MultiScaleTextNode.swift +++ b/submodules/TelegramUI/TelegramUI/MultiScaleTextNode.swift @@ -10,6 +10,7 @@ private final class MultiScaleTextStateNode: ASDisplayNode { override init() { self.textNode = ImmediateTextNode() + self.textNode.displaysAsynchronously = false super.init() @@ -44,20 +45,32 @@ final class MultiScaleTextNode: ASDisplayNode { } } - func updateLayout(states: [AnyHashable: MultiScaleTextState]) -> [AnyHashable: MultiScaleTextLayout] { + func updateLayout(states: [AnyHashable: MultiScaleTextState], mainState: AnyHashable) -> [AnyHashable: MultiScaleTextLayout] { assert(Set(states.keys) == Set(self.stateNodes.keys)) + assert(states[mainState] != nil) var result: [AnyHashable: MultiScaleTextLayout] = [:] + var mainLayout: MultiScaleTextLayout? for (key, state) in states { if let node = self.stateNodes[key] { node.textNode.attributedText = state.attributedText let nodeSize = node.textNode.updateLayout(state.constrainedSize) let nodeLayout = MultiScaleTextLayout(size: nodeSize) + if key == mainState { + mainLayout = nodeLayout + } node.currentLayout = nodeLayout - node.textNode.frame = CGRect(origin: CGPoint(x: -nodeSize.width / 2.0, y: -nodeSize.height / 2.0), size: nodeSize) result[key] = nodeLayout } } + if let mainLayout = mainLayout { + let mainBounds = CGRect(origin: CGPoint(x: -mainLayout.size.width / 2.0, y: -mainLayout.size.height / 2.0), size: mainLayout.size) + for (key, _) in states { + if let node = self.stateNodes[key], let nodeLayout = result[key] { + node.textNode.frame = CGRect(origin: CGPoint(x: mainBounds.minX, y: mainBounds.minY + floor((mainBounds.height - nodeLayout.size.height) / 2.0)), size: nodeLayout.size) + } + } + } return result } diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift index f7c9aadc5d..16620fe3b8 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoHeaderNode.swift @@ -600,7 +600,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { if hadOneStripNode && self.stripNodes.count > 1 { self.stripContainerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) } - let stripInset: CGFloat = 5.0 + let stripInset: CGFloat = 8.0 let stripSpacing: CGFloat = 4.0 let stripWidth: CGFloat = max(5.0, floor((size.width - stripInset * 2.0 - stripSpacing * CGFloat(self.stripNodes.count - 1)) / CGFloat(self.stripNodes.count))) var stripX: CGFloat = stripInset @@ -610,7 +610,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode { } else { self.stripNodes[i].isHidden = false } - self.stripNodes[i].frame = CGRect(origin: CGPoint(x: stripX, y: 0.0), size: CGSize(width: stripWidth, height: 2.0)) + self.stripNodes[i].frame = CGRect(origin: CGPoint(x: stripX, y: 0.0), size: CGSize(width: stripWidth + 1.0, height: 2.0)) stripX += stripWidth + stripSpacing } @@ -1341,6 +1341,9 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode { } } +private let TitleNodeStateRegular = 0 +private let TitleNodeStateExpanded = 1 + final class PeerInfoHeaderNode: ASDisplayNode { private var context: AccountContext private var presentationData: PresentationData? @@ -1355,11 +1358,11 @@ final class PeerInfoHeaderNode: ASDisplayNode { let editingContentNode: PeerInfoHeaderEditingContentNode let titleNodeContainer: ASDisplayNode let titleNodeRawContainer: ASDisplayNode - let titleNode: ImmediateTextNode + let titleNode: MultiScaleTextNode let titleCredibilityIconNode: ASImageNode let subtitleNodeContainer: ASDisplayNode let subtitleNodeRawContainer: ASDisplayNode - let subtitleNode: ImmediateTextNode + let subtitleNode: MultiScaleTextNode private var buttonNodes: [PeerInfoHeaderButtonKey: PeerInfoHeaderButtonNode] = [:] private let backgroundNode: ASDisplayNode private let expandedBackgroundNode: ASDisplayNode @@ -1382,7 +1385,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.titleNodeContainer = ASDisplayNode() self.titleNodeRawContainer = ASDisplayNode() - self.titleNode = ImmediateTextNode() + self.titleNode = MultiScaleTextNode(stateKeys: [TitleNodeStateRegular, TitleNodeStateExpanded]) self.titleNode.displaysAsynchronously = false self.titleCredibilityIconNode = ASImageNode() @@ -1392,7 +1395,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.subtitleNodeContainer = ASDisplayNode() self.subtitleNodeRawContainer = ASDisplayNode() - self.subtitleNode = ImmediateTextNode() + self.subtitleNode = MultiScaleTextNode(stateKeys: [TitleNodeStateRegular, TitleNodeStateExpanded]) self.subtitleNode.displaysAsynchronously = false self.regularContentNode = PeerInfoHeaderRegularContentNode() @@ -1506,15 +1509,22 @@ final class PeerInfoHeaderNode: ASDisplayNode { let defaultButtonSize: CGFloat = 40.0 let defaultMaxButtonSpacing: CGFloat = 40.0 - let expandedAvatarListHeight = min(width, containerHeight - 64.0) + let expandedAvatarControlsHeight: CGFloat = 61.0 + let expandedAvatarListHeight = min(width, containerHeight - expandedAvatarControlsHeight) let expandedAvatarListSize = CGSize(width: width, height: expandedAvatarListHeight) let buttonKeys: [PeerInfoHeaderButtonKey] = peerInfoHeaderButtons(peer: peer, cachedData: cachedData) + var isVerified = false + let titleString: NSAttributedString + let subtitleString: NSAttributedString + if let peer = peer, peer.isVerified { + isVerified = true + } + if let peer = peer { - self.titleNode.attributedText = NSAttributedString(string: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.medium(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor) + titleString = NSAttributedString(string: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.medium(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor) - let subtitleString: NSAttributedString? if let statusData = statusData { let subtitleColor: UIColor if statusData.isActivity { @@ -1524,26 +1534,44 @@ final class PeerInfoHeaderNode: ASDisplayNode { } subtitleString = NSAttributedString(string: statusData.text, font: Font.regular(15.0), textColor: subtitleColor) } else { - subtitleString = nil + subtitleString = NSAttributedString(string: " ", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor) } - self.subtitleNode.attributedText = subtitleString + } else { + titleString = NSAttributedString(string: " ", font: Font.medium(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor) + subtitleString = NSAttributedString(string: " ", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor) } let textSideInset: CGFloat = 44.0 - let expandedAvatarControlsHeight: CGFloat = 64.0 let expandedAvatarHeight: CGFloat = expandedAvatarListSize.height + expandedAvatarControlsHeight + let titleConstrainedSize = CGSize(width: width - textSideInset * 2.0 - (isVerified ? 16.0 : 0.0), height: .greatestFiniteMagnitude) + + let titleNodeLayout = self.titleNode.updateLayout(states: [ + TitleNodeStateRegular: MultiScaleTextState(attributedText: titleString, constrainedSize: titleConstrainedSize), + TitleNodeStateExpanded: MultiScaleTextState(attributedText: titleString, constrainedSize: CGSize(width: titleConstrainedSize.width, height: titleConstrainedSize.height)) + ], mainState: TitleNodeStateRegular) + + let subtitleNodeLayout = self.subtitleNode.updateLayout(states: [ + TitleNodeStateRegular: MultiScaleTextState(attributedText: subtitleString, constrainedSize: titleConstrainedSize), + TitleNodeStateExpanded: MultiScaleTextState(attributedText: subtitleString, constrainedSize: CGSize(width: titleConstrainedSize.width - 82.0, height: titleConstrainedSize.height)) + ], mainState: TitleNodeStateRegular) + + self.titleNode.update(stateFractions: [ + TitleNodeStateRegular: self.isAvatarExpanded ? 0.0 : 1.0, + TitleNodeStateExpanded: self.isAvatarExpanded ? 1.0 : 0.0 + ], transition: transition) + + self.subtitleNode.update(stateFractions: [ + TitleNodeStateRegular: self.isAvatarExpanded ? 0.0 : 1.0, + TitleNodeStateExpanded: self.isAvatarExpanded ? 1.0 : 0.0 + ], transition: transition) + let avatarSize: CGFloat = 100.0 let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 10.0), size: CGSize(width: avatarSize, height: avatarSize)) let avatarCenter = CGPoint(x: (1.0 - transitionFraction) * avatarFrame.midX + transitionFraction * transitionSourceAvatarFrame.midX, y: (1.0 - transitionFraction) * avatarFrame.midY + transitionFraction * transitionSourceAvatarFrame.midY) - var isVerified = false - if let peer = peer, peer.isVerified { - isVerified = true - } - - let titleSize = self.titleNode.updateLayout(CGSize(width: width - textSideInset * 2.0 - (isVerified ? 16.0 : 0.0), height: .greatestFiniteMagnitude)) - let subtitleSize = self.subtitleNode.updateLayout(CGSize(width: width - textSideInset * 2.0, height: .greatestFiniteMagnitude)) + let titleSize = titleNodeLayout[TitleNodeStateRegular]!.size + let subtitleSize = subtitleNodeLayout[TitleNodeStateRegular]!.size if let image = self.titleCredibilityIconNode.image { transition.updateFrame(node: self.titleCredibilityIconNode, frame: CGRect(origin: CGPoint(x: titleSize.width + 4.0, y: floor((titleSize.height - image.size.height) / 2.0) + 1.0), size: image.size)) @@ -1553,8 +1581,10 @@ final class PeerInfoHeaderNode: ASDisplayNode { let titleFrame: CGRect let subtitleFrame: CGRect if self.isAvatarExpanded { - titleFrame = CGRect(origin: CGPoint(x: 16.0, y: expandedAvatarHeight - expandedAvatarControlsHeight + 12.0 + (subtitleSize.height.isZero ? 10.0 : 0.0)), size: titleSize) - subtitleFrame = CGRect(origin: CGPoint(x: 16.0, y: titleFrame.maxY - 5.0), size: subtitleSize) + let minTitleSize = CGSize(width: titleSize.width * 0.7, height: titleSize.height * 0.7) + let minTitleFrame = CGRect(origin: CGPoint(x: 16.0, y: expandedAvatarHeight - expandedAvatarControlsHeight + 9.0 + (subtitleSize.height.isZero ? 10.0 : 0.0)), size: minTitleSize) + titleFrame = CGRect(origin: CGPoint(x: minTitleFrame.midX - titleSize.width / 2.0, y: minTitleFrame.midY - titleSize.height / 2.0), size: titleSize) + subtitleFrame = CGRect(origin: CGPoint(x: 16.0, y: minTitleFrame.maxY + 4.0), size: subtitleSize) } else { titleFrame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: avatarFrame.maxY + 10.0 + (subtitleSize.height.isZero ? 11.0 : 0.0)), size: titleSize) subtitleFrame = CGRect(origin: CGPoint(x: floor((width - subtitleSize.width) / 2.0), y: titleFrame.maxY + 1.0), size: subtitleSize) @@ -1713,14 +1743,14 @@ final class PeerInfoHeaderNode: ASDisplayNode { let titleCenter = CGPoint(x: transitionFraction * transitionSourceTitleFrame.midX + (1.0 - transitionFraction) * titleFrame.midX, y: transitionFraction * transitionSourceTitleFrame.midY + (1.0 - transitionFraction) * titleFrame.midY) let subtitleCenter = CGPoint(x: transitionFraction * transitionSourceSubtitleFrame.midX + (1.0 - transitionFraction) * subtitleFrame.midX, y: transitionFraction * transitionSourceSubtitleFrame.midY + (1.0 - transitionFraction) * subtitleFrame.midY) - let rawTitleFrame = CGRect(origin: CGPoint(x: titleCenter.x - titleFrame.size.width * titleScale / 2.0, y: titleCenter.y - titleFrame.size.height * titleScale / 2.0), size: CGSize(width: titleFrame.size.width * titleScale, height: titleFrame.size.height * titleScale)) + let rawTitleFrame = CGRect(origin: CGPoint(x: titleCenter.x - titleFrame.size.width * neutralTitleScale / 2.0, y: titleCenter.y - titleFrame.size.height * neutralTitleScale / 2.0), size: CGSize(width: titleFrame.size.width * neutralTitleScale, height: titleFrame.size.height * neutralTitleScale)) self.titleNodeRawContainer.frame = rawTitleFrame transition.updateFrameAdditiveToCenter(node: self.titleNodeContainer, frame: CGRect(origin: rawTitleFrame.center, size: CGSize())) - transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: -titleFrame.size.width * 1.0 / titleScale / 2.0, y: -titleFrame.size.height * 1.0 / titleScale / 2.0), size: titleFrame.size)) + transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(), size: CGSize())) let rawSubtitleFrame = CGRect(origin: CGPoint(x: subtitleCenter.x - subtitleFrame.size.width / 2.0, y: subtitleCenter.y - subtitleFrame.size.height / 2.0), size: subtitleFrame.size) self.subtitleNodeRawContainer.frame = rawSubtitleFrame - transition.updateFrameAdditiveToCenter(node: self.subtitleNodeContainer, frame: rawSubtitleFrame) - transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(), size: subtitleFrame.size)) + transition.updateFrameAdditiveToCenter(node: self.subtitleNodeContainer, frame: CGRect(origin: rawSubtitleFrame.center, size: CGSize())) + transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(), size: CGSize())) transition.updateSublayerTransformScale(node: self.titleNodeContainer, scale: titleScale) transition.updateSublayerTransformScale(node: self.subtitleNodeContainer, scale: subtitleScale) } else { @@ -1736,17 +1766,17 @@ final class PeerInfoHeaderNode: ASDisplayNode { let rawTitleFrame = titleFrame self.titleNodeRawContainer.frame = rawTitleFrame - transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(), size: titleFrame.size)) + transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(), size: CGSize())) let rawSubtitleFrame = subtitleFrame self.subtitleNodeRawContainer.frame = rawSubtitleFrame if self.isAvatarExpanded { - transition.updateFrameAdditive(node: self.titleNodeContainer, frame: rawTitleFrame.offsetBy(dx: 0.0, dy: titleOffset + apparentTitleLockOffset).offsetBy(dx: rawTitleFrame.width * 0.5 * (titleScale - 1.0), dy: rawTitleFrame.height * 0.5 * (titleScale - 1.0))) - transition.updateFrameAdditive(node: self.subtitleNodeContainer, frame: rawSubtitleFrame.offsetBy(dx: 0.0, dy: titleOffset).offsetBy(dx: rawSubtitleFrame.width * 0.5 * (subtitleScale - 1.0), dy: rawSubtitleFrame.height * 0.5 * (subtitleScale - 1.0))) + transition.updateFrameAdditive(node: self.titleNodeContainer, frame: CGRect(origin: rawTitleFrame.center, size: CGSize()).offsetBy(dx: 0.0, dy: titleOffset + apparentTitleLockOffset)) + transition.updateFrameAdditive(node: self.subtitleNodeContainer, frame: CGRect(origin: rawSubtitleFrame.center, size: CGSize()).offsetBy(dx: 0.0, dy: titleOffset)) } else { - transition.updateFrameAdditiveToCenter(node: self.titleNodeContainer, frame: rawTitleFrame.offsetBy(dx: 0.0, dy: titleOffset + apparentTitleLockOffset)) - transition.updateFrameAdditiveToCenter(node: self.subtitleNodeContainer, frame: rawSubtitleFrame.offsetBy(dx: 0.0, dy: titleOffset)) + transition.updateFrameAdditiveToCenter(node: self.titleNodeContainer, frame: CGRect(origin: rawTitleFrame.center, size: CGSize()).offsetBy(dx: 0.0, dy: titleOffset + apparentTitleLockOffset)) + transition.updateFrameAdditiveToCenter(node: self.subtitleNodeContainer, frame: CGRect(origin: rawSubtitleFrame.center, size: CGSize()).offsetBy(dx: 0.0, dy: titleOffset)) } - transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(), size: subtitleFrame.size)) + transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(), size: CGSize())) transition.updateSublayerTransformScaleAdditive(node: self.titleNodeContainer, scale: titleScale) transition.updateSublayerTransformScaleAdditive(node: self.subtitleNodeContainer, scale: subtitleScale) } diff --git a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift index b0e57aa3b3..e4af5f64a2 100644 --- a/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/TelegramUI/PeerInfo/PeerInfoScreen.swift @@ -608,7 +608,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese interaction.updateBlocked(false) })) } else { - if user.flags.contains(.isSupport) { + if user.flags.contains(.isSupport) || data.isContact { } else { items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 4, text: user.botInfo != nil ? presentationData.strings.Bot_Stop : presentationData.strings.Conversation_BlockUser, color: .destructive, action: { interaction.updateBlocked(true) @@ -4152,8 +4152,8 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: layout.safeInsets.left, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, contentOffset: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, notificationSettings: self.screenNode.data?.notificationSettings, statusData: self.screenNode.data?.status, isContact: self.screenNode.data?.isContact ?? false, state: self.screenNode.state, transition: transition, additive: false) } - let titleScale = (fraction * previousTitleNode.bounds.height + (1.0 - fraction) * self.headerNode.titleNode.bounds.height) / previousTitleNode.bounds.height - let subtitleScale = max(0.01, min(10.0, (fraction * previousStatusNode.bounds.height + (1.0 - fraction) * self.headerNode.subtitleNode.bounds.height) / previousStatusNode.bounds.height)) + let titleScale = (fraction * previousTitleNode.bounds.height + (1.0 - fraction) * self.headerNode.titleNodeRawContainer.bounds.height) / previousTitleNode.bounds.height + let subtitleScale = max(0.01, min(10.0, (fraction * previousStatusNode.bounds.height + (1.0 - fraction) * self.headerNode.subtitleNodeRawContainer.bounds.height) / previousStatusNode.bounds.height)) transition.updateFrame(node: previousTitleContainerNode, frame: CGRect(origin: self.headerNode.titleNodeRawContainer.frame.center, size: CGSize())) transition.updateFrame(node: previousTitleNode, frame: CGRect(origin: CGPoint(x: -previousTitleFrame.width / 2.0, y: -previousTitleFrame.height / 2.0), size: previousTitleFrame.size))