From 02e1612e7a31195ed52c6ee7644126e30b5a2367 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Mon, 16 Nov 2020 15:40:06 +0400 Subject: [PATCH] Cherry-pick various fixes --- .../Telegram-iOS/en.lproj/Localizable.strings | 3 + .../Sources/GalleryController.swift | 4 +- .../Sources/ChatListControllerNode.swift | 12 +- .../Sources/ChatListSearchContainerNode.swift | 68 +- .../Sources/Node/ChatListNode.swift | 17 +- submodules/GZip/Sources/GZip.m | 2 +- .../ChatItemGalleryFooterContentNode.swift | 63 +- .../GalleryUI/Sources/GalleryController.swift | 11 +- .../Sources/GalleryFooterContentNode.swift | 5 +- .../GalleryUI/Sources/GalleryPagerNode.swift | 2 +- .../GalleryThumbnailContainerNode.swift | 8 +- .../Items/UniversalVideoGalleryItem.swift | 34 +- .../SecretMediaPreviewController.swift | 1 + .../Sources/InstantPageControllerNode.swift | 10 +- .../InstantPageGalleryController.swift | 13 +- .../Sources/InstantPageTextItem.swift | 4 +- .../Sources/ItemListStickerPackItem.swift | 4 +- .../LegacyComponents/LegacyComponents.h | 11 - .../LegacyComponentsGlobals.h | 9 - .../TGLocationLiveElapsedView.h | 8 - .../TGLocationLiveSessionItemView.h | 12 - .../TGLocationMapViewController.h | 84 - .../TGLocationPickerController.h | 29 - .../LegacyComponents/TGLocationPulseView.h | 8 - .../LegacyComponents/TGLocationVenue.h | 34 - .../TGLocationViewController.h | 59 - .../LegacyComponents/TGLocationWavesView.h | 11 - .../TGMediaPickerGalleryModel.h | 2 + .../LegacyComponents/TGPhotoVideoEditor.h | 2 +- .../LegacyComponents/TGSearchBar.h | 94 - .../LegacyComponents/TGSearchDisplayMixin.h | 46 - .../AttachmentMenuInteractiveCameraIcon.png | Bin 328 -> 0 bytes ...AttachmentMenuInteractiveCameraIcon@2x.png | Bin 640 -> 0 bytes ...AttachmentMenuInteractiveCameraIcon@3x.png | Bin 911 -> 0 bytes .../AttachmentTipIcons@2x.png | Bin 20164 -> 0 bytes .../CalloutAccessory@2x.png | Bin 153 -> 0 bytes .../CalloutArrow@2x.png | Bin 424 -> 0 bytes .../CalloutArrow_Highlighted@2x.png | Bin 422 -> 0 bytes .../CalloutBackground@2x.png | Bin 534 -> 0 bytes .../CalloutBackground_Highlighted@2x.png | Bin 554 -> 0 bytes .../CalloutDrivingBackground@2x.png | Bin 262 -> 0 bytes ...alloutDrivingBackground_Highlighted@2x.png | Bin 262 -> 0 bytes .../CalloutDrivingIcon@2x.png | Bin 623 -> 0 bytes .../CoubWatermark@2x.png | Bin 2065 -> 0 bytes .../EmbedVideoFullScreenIcon@2x.png | Bin 155 -> 0 bytes .../EmbedVideoPIPIcon@2x.png | Bin 1198 -> 0 bytes .../EmbedVideoPauseIcon@2x.png | Bin 139 -> 0 bytes .../EmbedVideoPlayIcon@2x.png | Bin 479 -> 0 bytes .../EmbedVideoTrackHollow@2x.png | Bin 979 -> 0 bytes .../FoursquareAttribution@2x.png | Bin 4953 -> 0 bytes .../LocationInfo.png | Bin 442 -> 0 bytes .../LocationInfo@2x.png | Bin 1112 -> 0 bytes .../LocationInfo@3x.png | Bin 908 -> 0 bytes .../LocationInfo_Active.png | Bin 384 -> 0 bytes .../LocationInfo_Active@2x.png | Bin 740 -> 0 bytes .../LocationInfo_Active@3x.png | Bin 619 -> 0 bytes .../LocationMessageLiveIcon@2x.png | Bin 2078 -> 0 bytes .../LocationMessageLiveIcon@3x.png | Bin 2587 -> 0 bytes .../LocationMessagePinBackground@2x.png | Bin 2524 -> 0 bytes .../LocationMessagePinBackground@3x.png | Bin 3981 -> 0 bytes .../LocationMessagePinIcon@2x.png | Bin 1372 -> 0 bytes .../LocationMessagePinIcon@3x.png | Bin 1485 -> 0 bytes .../LocationMessagePinShadow@2x.png | Bin 5505 -> 0 bytes .../LocationMessagePinShadow@3x.png | Bin 9741 -> 0 bytes .../LocationPanelEdge@2x.png | Bin 716 -> 0 bytes .../LocationPanelEdge@3x.png | Bin 1932 -> 0 bytes .../LocationPanelEdge_Highlighted@2x.png | Bin 1262 -> 0 bytes .../LocationPanelEdge_Highlighted@3x.png | Bin 1401 -> 0 bytes .../LocationPin@2x.png | Bin 851 -> 0 bytes .../LocationPinBackground@2x.png | Bin 3383 -> 0 bytes .../LocationPinBackground@3x.png | Bin 4687 -> 0 bytes .../LocationPinIcon@2x.png | Bin 1170 -> 0 bytes .../LocationPinIcon@3x.png | Bin 1731 -> 0 bytes .../LocationPinPoint@2x.png | Bin 107 -> 0 bytes .../LocationPinShadow@2x.png | Bin 7424 -> 0 bytes .../LocationPinShadow@3x.png | Bin 13092 -> 0 bytes .../LocationSmallCircle@2x.png | Bin 4660 -> 0 bytes .../LocationSmallCircle@3x.png | Bin 6410 -> 0 bytes .../LocationTopPanel@2x.png | Bin 1928 -> 0 bytes .../LocationTopPanel@3x.png | Bin 1872 -> 0 bytes .../LocationWave@3x.png | Bin 1252 -> 0 bytes ...odernConversationAudioSlideToCancel@2x.png | Bin 496 -> 0 bytes ...odernConversationAudioSlideToCancel@3x.png | Bin 645 -> 0 bytes .../ModernSegmentedControlBackground@2x.png | Bin 294 -> 0 bytes .../ModernSegmentedControlBackground@3x.png | Bin 916 -> 0 bytes .../ModernSegmentedControlDivider@2x.png | Bin 74 -> 0 bytes .../ModernSegmentedControlDivider@3x.png | Bin 105 -> 0 bytes .../ModernSegmentedControlHighlighted@2x.png | Bin 294 -> 0 bytes .../ModernSegmentedControlHighlighted@3x.png | Bin 902 -> 0 bytes .../ModernSegmentedControlSelected@2x.png | Bin 235 -> 0 bytes .../ModernSegmentedControlSelected@3x.png | Bin 664 -> 0 bytes .../PaintBrushIcon@2x.png | Bin 1178 -> 0 bytes .../PaintBrushIcon@3x.png | Bin 1804 -> 0 bytes .../PaintCheck@2x.png | Bin 1420 -> 0 bytes .../PaintEraserIcon@2x.png | Bin 749 -> 0 bytes .../PaintEraserIcon@3x.png | Bin 1036 -> 0 bytes .../PaintMirrorIcon@2x.png | Bin 914 -> 0 bytes .../PaintMirrorIcon@3x.png | Bin 1460 -> 0 bytes .../PaintPopupCenterBackground@2x.png | Bin 1218 -> 0 bytes .../PaintPopupLandscapeLeftBackground@2x.png | Bin 1083 -> 0 bytes .../PaintPopupLandscapeRightBackground@2x.png | Bin 949 -> 0 bytes .../PaintPopupPortraitBackground@2x.png | Bin 936 -> 0 bytes .../PaintRedoIcon@2x.png | Bin 720 -> 0 bytes .../PaintSegmentedControlHighlighted@2x.png | Bin 305 -> 0 bytes .../PaintStickersIcon@2x.png | Bin 1050 -> 0 bytes .../PaintStickersIcon@3x.png | Bin 1522 -> 0 bytes .../PaintTextIcon@2x.png | Bin 263 -> 0 bytes .../PaintTextIcon@3x.png | Bin 353 -> 0 bytes .../PaintTextSettingsIcon@2x.png | Bin 1314 -> 0 bytes .../PaintTextSettingsIcon@3x.png | Bin 2001 -> 0 bytes .../PaintUndoIcon@2x.png | Bin 400 -> 0 bytes .../PaintUndoIcon@3x.png | Bin 539 -> 0 bytes .../PhotoEditorAspectRatioIcon@2x.png | Bin 178 -> 0 bytes .../PhotoEditorAspectRatioIcon@3x.png | Bin 248 -> 0 bytes .../PhotoEditorBlurIcon@2x.png | Bin 660 -> 0 bytes .../PhotoEditorBlurIcon@3x.png | Bin 1027 -> 0 bytes .../PhotoEditorBlurLinear.png | Bin 165 -> 0 bytes .../PhotoEditorBlurLinear@2x.png | Bin 276 -> 0 bytes .../PhotoEditorBlurLinear@3x.png | Bin 402 -> 0 bytes .../PhotoEditorBlurOff.png | Bin 146 -> 0 bytes .../PhotoEditorBlurOff@2x.png | Bin 263 -> 0 bytes .../PhotoEditorBlurOff@3x.png | Bin 388 -> 0 bytes .../PhotoEditorBlurRadial.png | Bin 371 -> 0 bytes .../PhotoEditorBlurRadial@2x.png | Bin 875 -> 0 bytes .../PhotoEditorBlurRadial@3x.png | Bin 1299 -> 0 bytes .../PhotoEditorCaption.png | Bin 87 -> 0 bytes .../PhotoEditorCaption@2x.png | Bin 111 -> 0 bytes .../PhotoEditorCaption@3x.png | Bin 122 -> 0 bytes .../PhotoEditorCrop@2x.png | Bin 194 -> 0 bytes .../PhotoEditorCrop@3x.png | Bin 274 -> 0 bytes .../PhotoEditorCurvesIcon@2x.png | Bin 589 -> 0 bytes .../PhotoEditorCurvesIcon@3x.png | Bin 862 -> 0 bytes .../PhotoEditorGif@2x.png | Bin 1296 -> 0 bytes .../PhotoEditorGif@3x.png | Bin 1943 -> 0 bytes .../PhotoEditorGifShadow@2x.png | Bin 5268 -> 0 bytes .../PhotoEditorGifShadow@3x.png | Bin 4610 -> 0 bytes .../PhotoEditorPaint@2x.png | Bin 509 -> 0 bytes .../PhotoEditorPaint@3x.png | Bin 674 -> 0 bytes .../PhotoEditorQuality@2x.png | Bin 144 -> 0 bytes .../PhotoEditorQuality@3x.png | Bin 207 -> 0 bytes .../PhotoEditorTintIcon@2x.png | Bin 712 -> 0 bytes .../PhotoEditorTintIcon@3x.png | Bin 977 -> 0 bytes .../PhotoEditorTintTool@2x.png | Bin 418 -> 0 bytes .../PhotoEditorTools@2x.png | Bin 175 -> 0 bytes .../PhotoEditorTools@3x.png | Bin 257 -> 0 bytes .../RecordVideoIconOverlay@3x.png | Bin 2553 -> 0 bytes .../StickerKeyboardFavoriteTab@2x.png | Bin 2181 -> 0 bytes .../StickerKeyboardFavoriteTab@3x.png | Bin 3482 -> 0 bytes .../StickerKeyboardGifIcon@2x.png | Bin 1264 -> 0 bytes .../StickerKeyboardGifIcon@3x.png | Bin 1798 -> 0 bytes .../StickerKeyboardRecentTab@1x.png | Bin 383 -> 0 bytes .../StickerKeyboardRecentTab@2x.png | Bin 698 -> 0 bytes .../StickerKeyboardRecentTab@3x.png | Bin 1082 -> 0 bytes .../StickerKeyboardSettingsIcon@2x.png | Bin 1152 -> 0 bytes .../StickerKeyboardSettingsIcon@3x.png | Bin 1807 -> 0 bytes .../StickerKeyboardTrendingIcon@2x.png | Bin 933 -> 0 bytes .../StickerKeyboardTrendingIcon@3x.png | Bin 1291 -> 0 bytes .../TrackingHeading@2x.png | Bin 598 -> 0 bytes .../TrackingHeading@3x.png | Bin 840 -> 0 bytes .../TrackingLocation@2x.png | Bin 499 -> 0 bytes .../TrackingLocation@3x.png | Bin 605 -> 0 bytes .../TrackingLocationOff@2x.png | Bin 649 -> 0 bytes .../TrackingLocationOff@3x.png | Bin 796 -> 0 bytes .../VineWatermark@2x.png | Bin 1238 -> 0 bytes .../YoutubeWatermark@2x.png | Bin 2781 -> 0 bytes .../Sources/AVAsset+CBExtension.h | 16 - .../Sources/AVAsset+CBExtension.m | 25 - .../Sources/CBAssetDownloadManager.h | 66 - .../Sources/CBAssetDownloadManager.m | 290 - .../Sources/CBChunkDownloadOperation.h | 14 - .../Sources/CBChunkDownloadOperation.m | 65 - .../LegacyComponents/Sources/CBConstance.h | 33 - .../LegacyComponents/Sources/CBConstance.m | 21 - .../LegacyComponents/Sources/CBCoubAsset.h | 25 - .../Sources/CBCoubAudioSource.h | 21 - .../Sources/CBCoubAudioSource.m | 32 - .../LegacyComponents/Sources/CBCoubAuthorVO.h | 23 - .../LegacyComponents/Sources/CBCoubAuthorVO.m | 42 - .../Sources/CBCoubDownloadOperation.h | 12 - .../Sources/CBCoubDownloadOperation.m | 190 - .../Sources/CBCoubLoopCompositionMaker.h | 41 - .../Sources/CBCoubLoopCompositionMaker.m | 322 - .../LegacyComponents/Sources/CBCoubNew.h | 70 - .../LegacyComponents/Sources/CBCoubNew.m | 199 - .../LegacyComponents/Sources/CBCoubPlayer.h | 96 - .../LegacyComponents/Sources/CBCoubPlayer.m | 585 -- .../Sources/CBCoubPlayerContance.h | 20 - .../Sources/CBCoubPlayerContance.m | 13 - .../Sources/CBCoubVideoSource.h | 20 - .../Sources/CBCoubVideoSource.m | 33 - .../Sources/CBDownloadOperation.h | 37 - .../Sources/CBDownloadOperationDelegate.h | 17 - .../Sources/CBGenericDownloadOperation.h | 28 - .../Sources/CBGenericDownloadOperation.m | 89 - .../Sources/CBJSONCoubMapper.h | 18 - .../Sources/CBJSONCoubMapper.m | 254 - .../LegacyComponents/Sources/CBLibrary.h | 36 - .../LegacyComponents/Sources/CBLibrary.m | 236 - .../Sources/CBPlayerLayerView.h | 13 - .../Sources/CBPlayerLayerView.m | 20 - .../LegacyComponents/Sources/CBPlayerView.h | 27 - .../LegacyComponents/Sources/CBPlayerView.m | 101 - .../LegacyComponents/Sources/CBTagNew.h | 18 - .../LegacyComponents/Sources/CBTagNew.m | 29 - .../LegacyComponents/Sources/CBVideoPlayer.h | 36 - .../LegacyComponents/Sources/CBVideoPlayer.m | 193 - .../Sources/NSDictionary+CBExtensions.h | 16 - .../Sources/NSDictionary+CBExtensions.m | 38 - .../Sources/NSMutableArray+STKAudioPlayer.h | 17 - .../Sources/NSMutableArray+STKAudioPlayer.m | 50 - .../LegacyComponents/Sources/PGPhotoFilter.h | 19 - .../LegacyComponents/Sources/PGPhotoFilter.m | 242 - .../Sources/PGPhotoFilterDefinition.h | 21 - .../Sources/PGPhotoFilterDefinition.m | 35 - .../Sources/PGPhotoFilterThumbnailManager.h | 20 - .../Sources/PGPhotoFilterThumbnailManager.m | 277 - .../LegacyComponents/Sources/STKAudioPlayer.h | 266 - .../LegacyComponents/Sources/STKAudioPlayer.m | 3157 ------ .../Sources/STKAutoRecoveringHTTPDataSource.h | 52 - .../Sources/STKAutoRecoveringHTTPDataSource.m | 391 - .../Sources/STKCoreFoundationDataSource.h | 63 - .../Sources/STKCoreFoundationDataSource.m | 201 - .../LegacyComponents/Sources/STKDataSource.h | 61 - .../LegacyComponents/Sources/STKDataSource.m | 82 - .../Sources/STKDataSourceWrapper.h | 43 - .../Sources/STKDataSourceWrapper.m | 120 - .../Sources/STKHTTPDataSource.h | 55 - .../Sources/STKHTTPDataSource.m | 383 - .../Sources/STKLocalFileDataSource.h | 43 - .../Sources/STKLocalFileDataSource.m | 243 - .../LegacyComponents/Sources/STKQueueEntry.h | 45 - .../LegacyComponents/Sources/STKQueueEntry.m | 121 - .../Sources/TGCameraController.m | 4 +- .../Sources/TGListsTableView.m | 8 - .../Sources/TGLocationAnnotation.h | 33 - .../Sources/TGLocationAnnotation.m | 164 - .../Sources/TGLocationCurrentLocationCell.h | 22 - .../Sources/TGLocationCurrentLocationCell.m | 409 - .../Sources/TGLocationInfoCell.h | 23 - .../Sources/TGLocationInfoCell.m | 357 - .../Sources/TGLocationLiveCell.h | 24 - .../Sources/TGLocationLiveCell.m | 361 - .../Sources/TGLocationLiveElapsedView.m | 101 - .../Sources/TGLocationLiveSessionItemView.m | 127 - .../Sources/TGLocationMapModeControl.h | 5 - .../Sources/TGLocationMapModeControl.m | 27 - .../Sources/TGLocationMapView.h | 17 - .../Sources/TGLocationMapView.m | 114 - .../Sources/TGLocationMapViewController.m | 642 -- .../Sources/TGLocationOptionsView.h | 15 - .../Sources/TGLocationOptionsView.m | 213 - .../Sources/TGLocationPickerController.m | 1324 --- .../Sources/TGLocationPinAnnotationView.h | 23 - .../Sources/TGLocationPinAnnotationView.m | 679 -- .../Sources/TGLocationPinView.h | 11 - .../Sources/TGLocationPinView.m | 125 - .../Sources/TGLocationPulseView.m | 59 - .../Sources/TGLocationReverseGeocodeResult.h | 23 - .../Sources/TGLocationReverseGeocodeResult.m | 85 - .../Sources/TGLocationSectionHeaderCell.h | 14 - .../Sources/TGLocationSectionHeaderCell.m | 73 - .../Sources/TGLocationSignals.h | 18 - .../Sources/TGLocationSignals.m | 257 - .../Sources/TGLocationTitleView.h | 12 - .../Sources/TGLocationTitleView.m | 135 - .../Sources/TGLocationTrackingButton.h | 23 - .../Sources/TGLocationTrackingButton.m | 151 - .../Sources/TGLocationUtils.h | 50 - .../Sources/TGLocationUtils.m | 381 - .../Sources/TGLocationVenue.m | 118 - .../Sources/TGLocationVenueCell.h | 17 - .../Sources/TGLocationVenueCell.m | 140 - .../Sources/TGLocationViewController.m | 1410 --- .../Sources/TGLocationWavesView.m | 126 - .../Sources/TGMediaAssetsController.m | 18 - .../Sources/TGMediaAssetsGifCell.m | 6 +- .../Sources/TGMediaAssetsTipView.h | 5 - .../Sources/TGMediaAssetsTipView.m | 97 - .../Sources/TGMediaAssetsVideoCell.m | 8 +- .../Sources/TGMediaPickerLayoutMetrics.m | 33 +- .../Sources/TGMentionPanelCell.m | 2 +- .../Sources/TGNavigationBar.m | 30 +- .../Sources/TGPhotoBrushSettingsView.m | 4 - .../Sources/TGPhotoEditorBlurToolView.m | 9 +- .../Sources/TGPhotoEditorBlurTypeButton.m | 2 +- .../Sources/TGPhotoEditorCollectionView.h | 13 - .../Sources/TGPhotoEditorCollectionView.m | 127 +- .../Sources/TGPhotoEditorInterfaceAssets.m | 2 +- .../Sources/TGPhotoEditorUtils.m | 16 +- .../Sources/TGPhotoFilterCell.h | 19 - .../Sources/TGPhotoFilterCell.m | 126 - .../Sources/TGPhotoPaintController.m | 2 +- .../Sources/TGPhotoPaintSettingsView.h | 4 - .../Sources/TGPhotoPaintSettingsView.m | 33 - .../Sources/TGPhotoVideoEditor.m | 16 +- .../LegacyComponents/Sources/TGSearchBar.m | 1197 --- .../Sources/TGSearchDisplayMixin.m | 457 - .../Sources/TGViewController.mm | 12 +- .../Sources/UIDevice+PlatformInfo.m | 216 - .../Sources/LegacyAttachmentMenu.swift | 87 +- .../Sources/LegacyAvatarPicker.swift | 26 - .../Sources/LegacySuggestionContext.swift | 2 +- .../Sources/LegacyComponentsStickers.swift | 221 - .../Sources/LegacyHTTPOperationImpl.swift | 7 - .../LegacyLocationVenueIconDataSource.swift | 193 - .../TelegramInitializeLegacyComponents.swift | 64 - .../Sources/LegacyLocationController.swift | 288 - .../Sources/LegacyLocationPicker.swift | 113 - .../LocationUI/Sources/LocationUtils.swift | 2 +- .../MediaPlayer/Sources/MediaPlayer.swift | 17 +- .../MtProtoKit/Sources/MTApiEnvironment.m | 18 +- .../SecureIdDocumentGalleryController.swift | 13 +- .../Sources/AvatarGalleryController.swift | 1 + .../ChannelMembersSearchContainerNode.swift | 12 + .../Sources/GroupInfoController.swift | 2555 ----- .../PrivacyAndSecurityController.swift | 8 +- .../Themes/WallpaperGalleryController.swift | 1 + .../Sources/SolidRoundedButtonNode.swift | 2 +- submodules/TelegramApi/Sources/Api0.swift | 1 + submodules/TelegramApi/Sources/Api1.swift | 24 + .../TelegramCore/Sources/EnqueueMessage.swift | 29 +- .../TelegramCore/Sources/StickerPack.swift | 6 +- .../Sources/TelegramMediaFile.swift | 2 + .../Sources/TelegramMediaImage.swift | 2 + .../Sources/PresentationStrings.swift | 8502 +++++++++-------- .../Caption.imageset/Contents.json | 12 + .../Caption.imageset/ic_menu_font1.pdf | Bin 0 -> 4027 bytes .../Context Menu/Draw.imageset/Contents.json | 12 + .../Draw.imageset/ic_menu_brush1.pdf | Bin 0 -> 4162 bytes .../Replace.imageset/Contents.json | 12 + .../Replace.imageset/ic_menu_replace.pdf | Bin 0 -> 4883 bytes .../Media Gallery/Contents.json | 6 +- .../Media Gallery/Draw.imageset/Contents.json | 12 + .../Draw.imageset/ic_editor_brush1.pdf | Bin 0 -> 4155 bytes .../Settings/Permissions/Contents.json | 6 +- .../Permissions/Siri.imageset/Contents.json | 22 - .../Permissions/Siri.imageset/Siri@2x.png | Bin 66768 -> 0 bytes .../Permissions/Siri.imageset/Siri@3x.png | Bin 136003 -> 0 bytes .../Resources/PresentationStrings.mapping | Bin 159214 -> 159277 bytes .../TelegramUI/Sources/ChatBotInfoItem.swift | 2 +- .../TelegramUI/Sources/ChatController.swift | 104 +- .../Sources/ChatControllerInteraction.swift | 8 + .../Sources/ChatControllerNode.swift | 4 +- .../ChatHistoryNavigationButtons.swift | 13 +- .../ChatInterfaceStateContextMenus.swift | 15 +- .../Sources/ChatMediaInputNode.swift | 14 +- .../ChatMessageAnimatedStickerItemNode.swift | 123 +- .../ChatMessageBubbleContentNode.swift | 1 + .../Sources/ChatMessageBubbleItemNode.swift | 10 +- .../ChatMessageInteractiveFileNode.swift | 2 + .../TelegramUI/Sources/ChatMessageItem.swift | 2 +- .../Sources/ChatMessageNotificationItem.swift | 54 + .../ChatMessageTextBubbleContentNode.swift | 2 + .../ChatRecentActionsControllerNode.swift | 2 + .../ChatTextInputActionButtonsNode.swift | 2 - .../Sources/DrawingStickersScreen.swift | 2 + .../TelegramUI/Sources/OpenChatMessage.swift | 14 +- .../OverlayAudioPlayerControllerNode.swift | 2 + .../Sources/PeerInfo/PeerInfoScreen.swift | 31 +- .../Sources/SharedAccountContext.swift | 2 + .../Sources/StickerShimmerEffectNode.swift | 605 ++ .../Sources/StringWithAppliedEntities.swift | 20 +- .../Sources/TelegramAttributes.swift | 1 + .../Sources/UndoOverlayControllerNode.swift | 2 +- .../Sources/WebSearchGalleryController.swift | 13 +- submodules/rlottie/BUILD | 1 + 366 files changed, 5680 insertions(+), 28180 deletions(-) delete mode 100644 submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationLiveElapsedView.h delete mode 100644 submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationLiveSessionItemView.h delete mode 100644 submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationMapViewController.h delete mode 100644 submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationPickerController.h delete mode 100644 submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationPulseView.h delete mode 100644 submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationVenue.h delete mode 100644 submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationViewController.h delete mode 100644 submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationWavesView.h delete mode 100644 submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGSearchBar.h delete mode 100644 submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGSearchDisplayMixin.h delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/AttachmentMenuInteractiveCameraIcon.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/AttachmentMenuInteractiveCameraIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/AttachmentMenuInteractiveCameraIcon@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/AttachmentTipIcons@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CalloutAccessory@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CalloutArrow@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CalloutArrow_Highlighted@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CalloutBackground@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CalloutBackground_Highlighted@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CalloutDrivingBackground@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CalloutDrivingBackground_Highlighted@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CalloutDrivingIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CoubWatermark@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/EmbedVideoFullScreenIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/EmbedVideoPIPIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/EmbedVideoPauseIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/EmbedVideoPlayIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/EmbedVideoTrackHollow@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/FoursquareAttribution@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationInfo.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationInfo@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationInfo@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationInfo_Active.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationInfo_Active@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationInfo_Active@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationMessageLiveIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationMessageLiveIcon@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationMessagePinBackground@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationMessagePinBackground@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationMessagePinIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationMessagePinIcon@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationMessagePinShadow@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationMessagePinShadow@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPanelEdge@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPanelEdge@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPanelEdge_Highlighted@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPanelEdge_Highlighted@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPin@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPinBackground@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPinBackground@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPinIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPinIcon@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPinPoint@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPinShadow@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPinShadow@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationSmallCircle@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationSmallCircle@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationTopPanel@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationTopPanel@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationWave@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernConversationAudioSlideToCancel@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernConversationAudioSlideToCancel@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernSegmentedControlBackground@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernSegmentedControlBackground@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernSegmentedControlDivider@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernSegmentedControlDivider@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernSegmentedControlHighlighted@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernSegmentedControlHighlighted@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernSegmentedControlSelected@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernSegmentedControlSelected@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintBrushIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintBrushIcon@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintCheck@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintEraserIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintEraserIcon@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintMirrorIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintMirrorIcon@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintPopupCenterBackground@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintPopupLandscapeLeftBackground@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintPopupLandscapeRightBackground@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintPopupPortraitBackground@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintRedoIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintSegmentedControlHighlighted@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintStickersIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintStickersIcon@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintTextIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintTextIcon@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintTextSettingsIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintTextSettingsIcon@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintUndoIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintUndoIcon@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorAspectRatioIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorAspectRatioIcon@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurIcon@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurLinear.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurLinear@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurLinear@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurOff.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurOff@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurOff@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurRadial.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurRadial@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurRadial@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorCaption.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorCaption@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorCaption@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorCrop@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorCrop@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorCurvesIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorCurvesIcon@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorGif@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorGif@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorGifShadow@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorGifShadow@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorPaint@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorPaint@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorQuality@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorQuality@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorTintIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorTintIcon@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorTintTool@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorTools@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorTools@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/RecordVideoIconOverlay@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardFavoriteTab@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardFavoriteTab@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardGifIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardGifIcon@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardRecentTab@1x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardRecentTab@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardRecentTab@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardSettingsIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardSettingsIcon@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardTrendingIcon@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardTrendingIcon@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/TrackingHeading@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/TrackingHeading@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/TrackingLocation@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/TrackingLocation@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/TrackingLocationOff@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/TrackingLocationOff@3x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/VineWatermark@2x.png delete mode 100644 submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/YoutubeWatermark@2x.png delete mode 100755 submodules/LegacyComponents/Sources/AVAsset+CBExtension.h delete mode 100755 submodules/LegacyComponents/Sources/AVAsset+CBExtension.m delete mode 100755 submodules/LegacyComponents/Sources/CBAssetDownloadManager.h delete mode 100755 submodules/LegacyComponents/Sources/CBAssetDownloadManager.m delete mode 100755 submodules/LegacyComponents/Sources/CBChunkDownloadOperation.h delete mode 100755 submodules/LegacyComponents/Sources/CBChunkDownloadOperation.m delete mode 100755 submodules/LegacyComponents/Sources/CBConstance.h delete mode 100755 submodules/LegacyComponents/Sources/CBConstance.m delete mode 100755 submodules/LegacyComponents/Sources/CBCoubAsset.h delete mode 100755 submodules/LegacyComponents/Sources/CBCoubAudioSource.h delete mode 100755 submodules/LegacyComponents/Sources/CBCoubAudioSource.m delete mode 100755 submodules/LegacyComponents/Sources/CBCoubAuthorVO.h delete mode 100755 submodules/LegacyComponents/Sources/CBCoubAuthorVO.m delete mode 100755 submodules/LegacyComponents/Sources/CBCoubDownloadOperation.h delete mode 100755 submodules/LegacyComponents/Sources/CBCoubDownloadOperation.m delete mode 100755 submodules/LegacyComponents/Sources/CBCoubLoopCompositionMaker.h delete mode 100755 submodules/LegacyComponents/Sources/CBCoubLoopCompositionMaker.m delete mode 100755 submodules/LegacyComponents/Sources/CBCoubNew.h delete mode 100755 submodules/LegacyComponents/Sources/CBCoubNew.m delete mode 100755 submodules/LegacyComponents/Sources/CBCoubPlayer.h delete mode 100755 submodules/LegacyComponents/Sources/CBCoubPlayer.m delete mode 100755 submodules/LegacyComponents/Sources/CBCoubPlayerContance.h delete mode 100755 submodules/LegacyComponents/Sources/CBCoubPlayerContance.m delete mode 100755 submodules/LegacyComponents/Sources/CBCoubVideoSource.h delete mode 100755 submodules/LegacyComponents/Sources/CBCoubVideoSource.m delete mode 100755 submodules/LegacyComponents/Sources/CBDownloadOperation.h delete mode 100755 submodules/LegacyComponents/Sources/CBDownloadOperationDelegate.h delete mode 100755 submodules/LegacyComponents/Sources/CBGenericDownloadOperation.h delete mode 100755 submodules/LegacyComponents/Sources/CBGenericDownloadOperation.m delete mode 100755 submodules/LegacyComponents/Sources/CBJSONCoubMapper.h delete mode 100755 submodules/LegacyComponents/Sources/CBJSONCoubMapper.m delete mode 100755 submodules/LegacyComponents/Sources/CBLibrary.h delete mode 100755 submodules/LegacyComponents/Sources/CBLibrary.m delete mode 100755 submodules/LegacyComponents/Sources/CBPlayerLayerView.h delete mode 100755 submodules/LegacyComponents/Sources/CBPlayerLayerView.m delete mode 100755 submodules/LegacyComponents/Sources/CBPlayerView.h delete mode 100755 submodules/LegacyComponents/Sources/CBPlayerView.m delete mode 100755 submodules/LegacyComponents/Sources/CBTagNew.h delete mode 100755 submodules/LegacyComponents/Sources/CBTagNew.m delete mode 100755 submodules/LegacyComponents/Sources/CBVideoPlayer.h delete mode 100755 submodules/LegacyComponents/Sources/CBVideoPlayer.m delete mode 100755 submodules/LegacyComponents/Sources/NSDictionary+CBExtensions.h delete mode 100755 submodules/LegacyComponents/Sources/NSDictionary+CBExtensions.m delete mode 100755 submodules/LegacyComponents/Sources/NSMutableArray+STKAudioPlayer.h delete mode 100755 submodules/LegacyComponents/Sources/NSMutableArray+STKAudioPlayer.m delete mode 100644 submodules/LegacyComponents/Sources/PGPhotoFilter.h delete mode 100644 submodules/LegacyComponents/Sources/PGPhotoFilter.m delete mode 100644 submodules/LegacyComponents/Sources/PGPhotoFilterDefinition.h delete mode 100644 submodules/LegacyComponents/Sources/PGPhotoFilterDefinition.m delete mode 100644 submodules/LegacyComponents/Sources/PGPhotoFilterThumbnailManager.h delete mode 100644 submodules/LegacyComponents/Sources/PGPhotoFilterThumbnailManager.m delete mode 100755 submodules/LegacyComponents/Sources/STKAudioPlayer.h delete mode 100755 submodules/LegacyComponents/Sources/STKAudioPlayer.m delete mode 100755 submodules/LegacyComponents/Sources/STKAutoRecoveringHTTPDataSource.h delete mode 100755 submodules/LegacyComponents/Sources/STKAutoRecoveringHTTPDataSource.m delete mode 100755 submodules/LegacyComponents/Sources/STKCoreFoundationDataSource.h delete mode 100755 submodules/LegacyComponents/Sources/STKCoreFoundationDataSource.m delete mode 100755 submodules/LegacyComponents/Sources/STKDataSource.h delete mode 100755 submodules/LegacyComponents/Sources/STKDataSource.m delete mode 100755 submodules/LegacyComponents/Sources/STKDataSourceWrapper.h delete mode 100755 submodules/LegacyComponents/Sources/STKDataSourceWrapper.m delete mode 100755 submodules/LegacyComponents/Sources/STKHTTPDataSource.h delete mode 100755 submodules/LegacyComponents/Sources/STKHTTPDataSource.m delete mode 100755 submodules/LegacyComponents/Sources/STKLocalFileDataSource.h delete mode 100755 submodules/LegacyComponents/Sources/STKLocalFileDataSource.m delete mode 100755 submodules/LegacyComponents/Sources/STKQueueEntry.h delete mode 100755 submodules/LegacyComponents/Sources/STKQueueEntry.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationAnnotation.h delete mode 100644 submodules/LegacyComponents/Sources/TGLocationAnnotation.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationCurrentLocationCell.h delete mode 100644 submodules/LegacyComponents/Sources/TGLocationCurrentLocationCell.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationInfoCell.h delete mode 100644 submodules/LegacyComponents/Sources/TGLocationInfoCell.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationLiveCell.h delete mode 100644 submodules/LegacyComponents/Sources/TGLocationLiveCell.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationLiveElapsedView.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationLiveSessionItemView.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationMapModeControl.h delete mode 100644 submodules/LegacyComponents/Sources/TGLocationMapModeControl.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationMapView.h delete mode 100644 submodules/LegacyComponents/Sources/TGLocationMapView.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationMapViewController.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationOptionsView.h delete mode 100644 submodules/LegacyComponents/Sources/TGLocationOptionsView.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationPickerController.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationPinAnnotationView.h delete mode 100644 submodules/LegacyComponents/Sources/TGLocationPinAnnotationView.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationPinView.h delete mode 100644 submodules/LegacyComponents/Sources/TGLocationPinView.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationPulseView.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationReverseGeocodeResult.h delete mode 100644 submodules/LegacyComponents/Sources/TGLocationReverseGeocodeResult.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationSectionHeaderCell.h delete mode 100644 submodules/LegacyComponents/Sources/TGLocationSectionHeaderCell.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationSignals.h delete mode 100644 submodules/LegacyComponents/Sources/TGLocationSignals.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationTitleView.h delete mode 100644 submodules/LegacyComponents/Sources/TGLocationTitleView.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationTrackingButton.h delete mode 100644 submodules/LegacyComponents/Sources/TGLocationTrackingButton.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationUtils.h delete mode 100644 submodules/LegacyComponents/Sources/TGLocationUtils.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationVenue.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationVenueCell.h delete mode 100644 submodules/LegacyComponents/Sources/TGLocationVenueCell.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationViewController.m delete mode 100644 submodules/LegacyComponents/Sources/TGLocationWavesView.m delete mode 100644 submodules/LegacyComponents/Sources/TGMediaAssetsTipView.h delete mode 100644 submodules/LegacyComponents/Sources/TGMediaAssetsTipView.m delete mode 100644 submodules/LegacyComponents/Sources/TGPhotoFilterCell.h delete mode 100644 submodules/LegacyComponents/Sources/TGPhotoFilterCell.m delete mode 100644 submodules/LegacyComponents/Sources/TGSearchBar.m delete mode 100644 submodules/LegacyComponents/Sources/TGSearchDisplayMixin.m delete mode 100644 submodules/LegacyComponents/Sources/UIDevice+PlatformInfo.m delete mode 100644 submodules/LegacyUI/Sources/LegacyComponentsStickers.swift delete mode 100644 submodules/LegacyUI/Sources/LegacyHTTPOperationImpl.swift delete mode 100644 submodules/LegacyUI/Sources/LegacyLocationVenueIconDataSource.swift delete mode 100644 submodules/LocationUI/Sources/LegacyLocationController.swift delete mode 100644 submodules/LocationUI/Sources/LegacyLocationPicker.swift delete mode 100644 submodules/PeerInfoUI/Sources/GroupInfoController.swift create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Caption.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Caption.imageset/ic_menu_font1.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Draw.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Draw.imageset/ic_menu_brush1.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Replace.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Replace.imageset/ic_menu_replace.pdf create mode 100644 submodules/TelegramUI/Images.xcassets/Media Gallery/Draw.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Media Gallery/Draw.imageset/ic_editor_brush1.pdf delete mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Permissions/Siri.imageset/Contents.json delete mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Permissions/Siri.imageset/Siri@2x.png delete mode 100644 submodules/TelegramUI/Images.xcassets/Settings/Permissions/Siri.imageset/Siri@3x.png create mode 100644 submodules/TelegramUI/Sources/StickerShimmerEffectNode.swift diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 467f1f58b0..7406d8cc76 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -5867,6 +5867,7 @@ Sorry for the inconvenience."; "Chat.PinnedMessagesHiddenText" = "You will see the bar with pinned messages only if a new message is pinned."; "OpenFile.PotentiallyDangerousContentAlert" = "Previewing this file can potentially expose your IP address to its sender. Continue?"; +"OpenFile.Proceed" = "Proceed"; "Chat.PinnedListPreview.ShowAllMessages" = "Show All Messages"; "Chat.PinnedListPreview.UnpinAllMessages" = "Unpin All Messages"; @@ -5887,3 +5888,5 @@ Sorry for the inconvenience."; "Stats.Message.Views" = "Views"; "Stats.Message.PublicShares" = "Public Shares"; "Stats.Message.PrivateShares" = "Private Shares"; + +"Conversation.TextCopied" = "Text copied to clipboard"; diff --git a/submodules/AccountContext/Sources/GalleryController.swift b/submodules/AccountContext/Sources/GalleryController.swift index 24d7acda1f..5ac13919b4 100644 --- a/submodules/AccountContext/Sources/GalleryController.swift +++ b/submodules/AccountContext/Sources/GalleryController.swift @@ -18,8 +18,9 @@ public final class GalleryControllerActionInteraction { public let openBotCommand: (String) -> Void public let addContact: (String) -> Void public let storeMediaPlaybackState: (MessageId, Double?) -> Void + public let editMedia: (MessageId) -> Void - public init(openUrl: @escaping (String, Bool) -> Void, openUrlIn: @escaping (String) -> Void, openPeerMention: @escaping (String) -> Void, openPeer: @escaping (PeerId) -> Void, openHashtag: @escaping (String?, String) -> Void, openBotCommand: @escaping (String) -> Void, addContact: @escaping (String) -> Void, storeMediaPlaybackState: @escaping (MessageId, Double?) -> Void) { + public init(openUrl: @escaping (String, Bool) -> Void, openUrlIn: @escaping (String) -> Void, openPeerMention: @escaping (String) -> Void, openPeer: @escaping (PeerId) -> Void, openHashtag: @escaping (String?, String) -> Void, openBotCommand: @escaping (String) -> Void, addContact: @escaping (String) -> Void, storeMediaPlaybackState: @escaping (MessageId, Double?) -> Void, editMedia: @escaping (MessageId) -> Void) { self.openUrl = openUrl self.openUrlIn = openUrlIn self.openPeerMention = openPeerMention @@ -28,5 +29,6 @@ public final class GalleryControllerActionInteraction { self.openBotCommand = openBotCommand self.addContact = addContact self.storeMediaPlaybackState = storeMediaPlaybackState + self.editMedia = editMedia } } diff --git a/submodules/ChatListUI/Sources/ChatListControllerNode.swift b/submodules/ChatListUI/Sources/ChatListControllerNode.swift index 1a35682cd4..e3d192d648 100644 --- a/submodules/ChatListUI/Sources/ChatListControllerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListControllerNode.swift @@ -264,6 +264,7 @@ private final class ChatListContainerItemNode: ASDisplayNode { private(set) var emptyNode: ChatListEmptyNode? var emptyShimmerEffectNode: ChatListShimmerNode? + private var shimmerNodeOffset: CGFloat = 0.0 let listNode: ChatListNode private var validLayout: (CGSize, UIEdgeInsets, CGFloat)? @@ -285,8 +286,12 @@ private final class ChatListContainerItemNode: ASDisplayNode { return } var needsShimmerNode = false + var shimmerNodeOffset: CGFloat = 0.0 switch isEmptyState { - case let .empty(isLoading): + case let .empty(isLoading, hasArchiveInfo): + if hasArchiveInfo { + shimmerNodeOffset = 253.0 + } if isLoading { needsShimmerNode = true @@ -326,12 +331,13 @@ private final class ChatListContainerItemNode: ASDisplayNode { } } if needsShimmerNode { + strongSelf.shimmerNodeOffset = shimmerNodeOffset if strongSelf.emptyShimmerEffectNode == nil { let emptyShimmerEffectNode = ChatListShimmerNode() strongSelf.emptyShimmerEffectNode = emptyShimmerEffectNode strongSelf.insertSubnode(emptyShimmerEffectNode, belowSubnode: strongSelf.listNode) if let (size, insets, _) = strongSelf.validLayout, let offset = strongSelf.floatingHeaderOffset { - strongSelf.layoutEmptyShimmerEffectNode(node: emptyShimmerEffectNode, size: size, insets: insets, verticalOffset: offset, transition: .immediate) + strongSelf.layoutEmptyShimmerEffectNode(node: emptyShimmerEffectNode, size: size, insets: insets, verticalOffset: offset + strongSelf.shimmerNodeOffset, transition: .immediate) } } } else if let emptyShimmerEffectNode = strongSelf.emptyShimmerEffectNode { @@ -349,7 +355,7 @@ private final class ChatListContainerItemNode: ASDisplayNode { } strongSelf.floatingHeaderOffset = offset if let (size, insets, _) = strongSelf.validLayout, let emptyShimmerEffectNode = strongSelf.emptyShimmerEffectNode { - strongSelf.layoutEmptyShimmerEffectNode(node: emptyShimmerEffectNode, size: size, insets: insets, verticalOffset: offset, transition: transition) + strongSelf.layoutEmptyShimmerEffectNode(node: emptyShimmerEffectNode, size: size, insets: insets, verticalOffset: offset + strongSelf.shimmerNodeOffset, transition: transition) } } } diff --git a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift index ecfc3045ed..01ed04e0c2 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift @@ -226,25 +226,23 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo self.paneContainerNode.interaction = interaction self.paneContainerNode.currentPaneUpdated = { [weak self] key, transitionFraction, transition in - if let strongSelf = self { - var filterKey: ChatListSearchFilter? - if let key = key { - switch key { - case .chats: - filterKey = .chats - case .media: - filterKey = .media - case .links: - filterKey = .links - case .files: - filterKey = .files - case .music: - filterKey = .music - case .voice: - filterKey = .voice - } + if let strongSelf = self, let key = key { + var filterKey: ChatListSearchFilter + switch key { + case .chats: + filterKey = .chats + case .media: + filterKey = .media + case .links: + filterKey = .links + case .files: + filterKey = .files + case .music: + filterKey = .music + case .voice: + filterKey = .voice } - strongSelf.selectedFilterKey = filterKey.flatMap { .filter($0.id) } + strongSelf.selectedFilterKey = .filter(filterKey.id) strongSelf.selectedFilterKeyPromise.set(.single(strongSelf.selectedFilterKey)) strongSelf.transitionFraction = transitionFraction @@ -306,16 +304,19 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo return .single([]) } } + + let accountPeer = self.context.account.postbox.loadedPeerWithId(self.context.account.peerId) + |> take(1) - self.suggestedFiltersDisposable.set((combineLatest(suggestedPeers, self.suggestedDates.get(), self.selectedFilterKeyPromise.get(), self.searchQuery.get()) - |> mapToSignal { peers, dates, selectedFilter, searchQuery -> Signal<([Peer], [(Date?, Date, String?)], ChatListSearchFilterEntryId?), NoError> in + self.suggestedFiltersDisposable.set((combineLatest(suggestedPeers, self.suggestedDates.get(), self.selectedFilterKeyPromise.get(), self.searchQuery.get(), accountPeer) + |> mapToSignal { peers, dates, selectedFilter, searchQuery, accountPeer -> Signal<([Peer], [(Date?, Date, String?)], ChatListSearchFilterEntryId?, String?, Peer?), NoError> in if searchQuery?.isEmpty ?? true { - return .single((peers, dates, selectedFilter)) + return .single((peers, dates, selectedFilter, searchQuery, accountPeer)) } else { return (.complete() |> delay(0.25, queue: Queue.mainQueue())) - |> then(.single((peers, dates, selectedFilter))) + |> then(.single((peers, dates, selectedFilter, searchQuery, accountPeer))) } - } |> map { peers, dates, selectedFilter -> [ChatListSearchFilter] in + } |> map { peers, dates, selectedFilter, searchQuery, accountPeer -> [ChatListSearchFilter] in var suggestedFilters: [ChatListSearchFilter] = [] if !dates.isEmpty { let formatter = DateFormatter() @@ -327,8 +328,18 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo suggestedFilters.append(.date(minDate.flatMap { Int32($0.timeIntervalSince1970) }, Int32(maxDate.timeIntervalSince1970), title)) } } + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + var existingPeerIds = Set() + var peers = peers + if let accountPeer = accountPeer, let lowercasedQuery = searchQuery?.lowercased(), lowercasedQuery.count > 1 && (presentationData.strings.DialogList_SavedMessages.lowercased().hasPrefix(lowercasedQuery) || "saved messages".hasPrefix(lowercasedQuery)) { + peers.insert(accountPeer, at: 0) + } + if !peers.isEmpty && selectedFilter != .filter(ChatListSearchFilter.chats.id) { for peer in peers { + if existingPeerIds.contains(peer.id) { + continue + } let isGroup: Bool if peer.id.namespace == Namespaces.Peer.SecretChat { continue @@ -339,8 +350,15 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo } else { isGroup = false } - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - suggestedFilters.append(.peer(peer.id, isGroup, peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), peer.compactDisplayTitle)) + + var title: String = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + var compactDisplayTitle = peer.compactDisplayTitle + if peer.id == accountPeer?.id { + title = presentationData.strings.DialogList_SavedMessages + compactDisplayTitle = title + } + suggestedFilters.append(.peer(peer.id, isGroup, title, compactDisplayTitle)) + existingPeerIds.insert(peer.id) } } return suggestedFilters diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index e329990c03..69d4afd6c6 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -403,7 +403,7 @@ public enum ChatListNodeScrollPosition { public enum ChatListNodeEmptyState: Equatable { case notEmpty(containsChats: Bool) - case empty(isLoading: Bool) + case empty(isLoading: Bool, hasArchiveInfo: Bool) } public final class ChatListNode: ListView { @@ -1411,6 +1411,7 @@ public final class ChatListNode: ListView { var isEmpty = false var isLoading = false + var hasArchiveInfo = false if transition.chatListView.filteredEntries.isEmpty { isEmpty = true } else { @@ -1421,6 +1422,9 @@ public final class ChatListNode: ListView { case .GroupReferenceEntry, .HeaderEntry, .HoleEntry: break default: + if case .ArchiveIntro = entry { + hasArchiveInfo = true + } isEmpty = false break loop1 } @@ -1441,14 +1445,21 @@ public final class ChatListNode: ListView { if !hasHoles { isLoading = false } + } else { + for entry in transition.chatListView.filteredEntries.reversed().prefix(2) { + if case .ArchiveIntro = entry { + hasArchiveInfo = true + break + } + } } } let isEmptyState: ChatListNodeEmptyState if transition.chatListView.isLoading { - isEmptyState = .empty(isLoading: true) + isEmptyState = .empty(isLoading: true, hasArchiveInfo: hasArchiveInfo) } else if isEmpty { - isEmptyState = .empty(isLoading: isLoading) + isEmptyState = .empty(isLoading: isLoading, hasArchiveInfo: false) } else { var containsChats = false loop: for entry in transition.chatListView.filteredEntries { diff --git a/submodules/GZip/Sources/GZip.m b/submodules/GZip/Sources/GZip.m index 1c1df4a450..ee2da568dd 100644 --- a/submodules/GZip/Sources/GZip.m +++ b/submodules/GZip/Sources/GZip.m @@ -4,7 +4,7 @@ bool TGIsGzippedData(NSData *data) { const UInt8 *bytes = (const UInt8 *)data.bytes; - return (data.length >= 2 && bytes[0] == 0x1f && bytes[1] == 0x8b); + return data.length >= 2 && ((bytes[0] == 0x1f && bytes[1] == 0x8b) || (bytes[0] == 0x78 && bytes[1] == 0x9c)); } NSData *TGGZipData(NSData *data, float level) { diff --git a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift index 164ffa37cf..3c643d9b7d 100644 --- a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift +++ b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift @@ -21,6 +21,7 @@ import TextSelectionNode private let deleteImage = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: .white) private let actionImage = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: .white) +private let editImage = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/Draw"), color: .white) private let backwardImage = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/BackwardButton"), color: .white) private let forwardImage = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/ForwardButton"), color: .white) @@ -47,7 +48,7 @@ private let dateFont = Font.regular(14.0) enum ChatItemGalleryFooterContent: Equatable { case info - case fetch(status: MediaResourceStatus) + case fetch(status: MediaResourceStatus, seekable: Bool) case playback(paused: Bool, seekable: Bool) static func ==(lhs: ChatItemGalleryFooterContent, rhs: ChatItemGalleryFooterContent) -> Bool { @@ -58,8 +59,8 @@ enum ChatItemGalleryFooterContent: Equatable { } else { return false } - case let .fetch(lhsStatus): - if case let .fetch(rhsStatus) = rhs, lhsStatus == rhsStatus { + case let .fetch(lhsStatus, lhsSeekable): + if case let .fetch(rhsStatus, rhsSeekable) = rhs, lhsStatus == rhsStatus, lhsSeekable == rhsSeekable { return true } else { return false @@ -116,6 +117,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll private let contentNode: ASDisplayNode private let deleteButton: UIButton private let actionButton: UIButton + private let editButton: UIButton private let maskNode: ASDisplayNode private let scrollWrapperNode: CaptionScrollWrapperNode private let scrollNode: ASScrollNode @@ -165,11 +167,11 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll self.playbackControlButton.isHidden = true self.statusButtonNode.isHidden = true self.statusNode.isHidden = true - case let .fetch(status): + case let .fetch(status, seekable): self.authorNameNode.isHidden = true self.dateNode.isHidden = true - self.backwardButton.isHidden = true - self.forwardButton.isHidden = true + self.backwardButton.isHidden = !seekable + self.forwardButton.isHidden = !seekable if status == .Local { self.playbackControlButton.isHidden = false self.playbackControlButton.setImage(playImage, for: []) @@ -217,8 +219,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll } } didSet { - if let scrubberView = self.scrubberView { - scrubberView.setCollapsed(self.visibilityAlpha < 1.0 ? true : false, animated: false) + if let scrubberView = self.scrubberView { + scrubberView.setCollapsed(self.visibilityAlpha < 1.0, animated: false) self.view.addSubview(scrubberView) scrubberView.updateScrubbingVisual = { [weak self] value in guard let strongSelf = self else { @@ -253,7 +255,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll override func setVisibilityAlpha(_ alpha: CGFloat, animated: Bool) { self.visibilityAlpha = alpha self.contentNode.alpha = alpha - self.scrubberView?.setCollapsed(alpha < 1.0 ? true : false, animated: animated) + self.scrubberView?.setCollapsed(alpha < 1.0, animated: animated) } init(context: AccountContext, presentationData: PresentationData, present: @escaping (ViewController, Any?) -> Void = { _, _ in }) { @@ -268,9 +270,11 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll self.deleteButton = UIButton() self.actionButton = UIButton() + self.editButton = UIButton() self.deleteButton.setImage(deleteImage, for: [.normal]) self.actionButton.setImage(actionImage, for: [.normal]) + self.editButton.setImage(editImage, for: [.normal]) self.scrollWrapperNode = CaptionScrollWrapperNode() self.scrollWrapperNode.clipsToBounds = true @@ -340,6 +344,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll self.contentNode.view.addSubview(self.deleteButton) self.contentNode.view.addSubview(self.actionButton) +// self.contentNode.view.addSubview(self.editButton) self.contentNode.addSubnode(self.scrollWrapperNode) self.scrollWrapperNode.addSubnode(self.scrollNode) self.scrollNode.addSubnode(self.textNode) @@ -356,6 +361,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll self.deleteButton.addTarget(self, action: #selector(self.deleteButtonPressed), for: [.touchUpInside]) self.actionButton.addTarget(self, action: #selector(self.actionButtonPressed), for: [.touchUpInside]) + self.editButton.addTarget(self, action: #selector(self.editButtonPressed), for: [.touchUpInside]) self.backwardButton.addTarget(self, action: #selector(self.backwardButtonPressed), forControlEvents: .touchUpInside) self.forwardButton.addTarget(self, action: #selector(self.forwardButtonPressed), forControlEvents: .touchUpInside) @@ -436,6 +442,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll if origin == nil { self.deleteButton.isHidden = true + self.editButton.isHidden = true } } @@ -444,6 +451,16 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll let canDelete: Bool var canShare = !message.containsSecretMedia && !Namespaces.Message.allScheduled.contains(message.id.namespace) + + var canEdit = false + for media in message.media { + if media is TelegramMediaImage { + canEdit = true + break + } + } + + canEdit = canEdit && !message.containsSecretMedia if let peer = message.peers[message.id.peerId] { if peer is TelegramUser || peer is TelegramSecretChat { canDelete = true @@ -452,17 +469,21 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll } else if let channel = peer as? TelegramChannel { if message.flags.contains(.Incoming) { canDelete = channel.hasPermission(.deleteAllMessages) + canEdit = canEdit && channel.hasPermission(.editAllMessages) } else { canDelete = true } } else { canDelete = false + canEdit = false } } else { canDelete = false canShare = false + canEdit = false } + var authorNameText: String? if let author = message.effectiveAuthor { authorNameText = author.displayTitle(strings: self.strings, displayOrder: self.nameOrder) @@ -496,10 +517,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll } messageText = galleryCaptionStringWithAppliedEntities(message.text, entities: entities) } + + self.editButton.isHidden = message.containsSecretMedia - self.actionButton.isHidden = message.containsSecretMedia || Namespaces.Message.allScheduled.contains(message.id.namespace) - - if self.currentMessageText != messageText || canDelete != !self.deleteButton.isHidden || canShare != !self.actionButton.isHidden || self.currentAuthorNameText != authorNameText || self.currentDateText != dateText { + if self.currentMessageText != messageText || canDelete != !self.deleteButton.isHidden || canShare != !self.actionButton.isHidden || canEdit != !self.editButton.isHidden || self.currentAuthorNameText != authorNameText || self.currentDateText != dateText { self.currentMessageText = messageText if messageText.length == 0 { @@ -519,6 +540,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll self.deleteButton.isHidden = !canDelete self.actionButton.isHidden = !canShare + self.editButton.isHidden = !canEdit self.requestLayout?(.immediate) } @@ -620,20 +642,22 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll if self.textNode.isHidden || !displayCaption { panelHeight += 8.0 } else { - scrubberY = panelHeight - bottomInset - 44.0 - 41.0 + scrubberY = panelHeight - bottomInset - 44.0 - 44.0 if contentInset > 0.0 { - scrubberY -= contentInset + 3.0 + scrubberY -= contentInset } } let scrubberFrame = CGRect(origin: CGPoint(x: leftInset, y: scrubberY), size: CGSize(width: width - leftInset - rightInset, height: 34.0)) scrubberView.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset, transition: .immediate) - transition.updateFrame(layer: scrubberView.layer, frame: scrubberFrame) + transition.updateBounds(layer: scrubberView.layer, bounds: CGRect(origin: CGPoint(), size: scrubberFrame.size)) + transition.updatePosition(layer: scrubberView.layer, position: CGPoint(x: scrubberFrame.midX, y: scrubberFrame.midY)) } transition.updateAlpha(node: self.textNode, alpha: displayCaption ? 1.0 : 0.0) self.actionButton.frame = CGRect(origin: CGPoint(x: leftInset, y: panelHeight - bottomInset - 44.0), size: CGSize(width: 44.0, height: 44.0)) self.deleteButton.frame = CGRect(origin: CGPoint(x: width - 44.0 - rightInset, y: panelHeight - bottomInset - 44.0), size: CGSize(width: 44.0, height: 44.0)) + self.editButton.frame = CGRect(origin: CGPoint(x: width - 44.0 - 50.0 - rightInset, y: panelHeight - bottomInset - 44.0), size: CGSize(width: 44.0, height: 44.0)) if let image = self.backwardButton.image(for: .normal) { self.backwardButton.frame = CGRect(origin: CGPoint(x: floor((width - image.size.width) / 2.0) - 66.0, y: panelHeight - bottomInset - 44.0 + 7.0), size: image.size) @@ -708,6 +732,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll self.authorNameNode.alpha = 1.0 self.deleteButton.alpha = 1.0 self.actionButton.alpha = 1.0 + self.editButton.alpha = 1.0 self.backwardButton.alpha = 1.0 self.forwardButton.alpha = 1.0 self.statusNode.alpha = 1.0 @@ -730,6 +755,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll self.authorNameNode.alpha = 0.0 self.deleteButton.alpha = 0.0 self.actionButton.alpha = 0.0 + self.editButton.alpha = 0.0 self.backwardButton.alpha = 0.0 self.forwardButton.alpha = 0.0 self.statusNode.alpha = 0.0 @@ -1049,6 +1075,13 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll } } + @objc func editButtonPressed() { + guard let message = self.currentMessage else { + return + } + self.controllerInteraction?.editMedia(message.id) + } + @objc func playbackControlPressed() { self.playbackControl?() } diff --git a/submodules/GalleryUI/Sources/GalleryController.swift b/submodules/GalleryUI/Sources/GalleryController.swift index 6bf56b2bc1..045a6b6373 100644 --- a/submodules/GalleryUI/Sources/GalleryController.swift +++ b/submodules/GalleryUI/Sources/GalleryController.swift @@ -441,9 +441,9 @@ public class GalleryController: ViewController, StandalonePresentableController namespaces = .not(Namespaces.Message.allScheduled) } return context.account.postbox.aroundMessageHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), anchor: .index(message!.index), count: 50, clipHoles: false, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: tags, namespaces: namespaces, orderStatistics: [.combinedLocation]) - |> mapToSignal { (view, _, _) -> Signal in - let mapped = GalleryMessageHistoryView.view(view) - return .single(mapped) + |> mapToSignal { (view, _, _) -> Signal in + let mapped = GalleryMessageHistoryView.view(view) + return .single(mapped) } } else { return .single(GalleryMessageHistoryView.entries([MessageHistoryEntry(message: message!, isRead: false, location: nil, monthLocation: nil, attributes: MutableMessageHistoryEntryAttributes(authorIsContact: false))], false, false)) @@ -911,6 +911,11 @@ public class GalleryController: ViewController, StandalonePresentableController if let strongSelf = self { strongSelf.replaceRootController(controller, ready) } + }, editMedia: { [weak self] messageId in + if let strongSelf = self { + strongSelf.dismiss(forceAway: true) + strongSelf.actionInteraction?.editMedia(messageId) + } }) self.displayNode = GalleryControllerNode(controllerInteraction: controllerInteraction) self.displayNodeDidLoad() diff --git a/submodules/GalleryUI/Sources/GalleryFooterContentNode.swift b/submodules/GalleryUI/Sources/GalleryFooterContentNode.swift index d1c25e9205..679c685ada 100644 --- a/submodules/GalleryUI/Sources/GalleryFooterContentNode.swift +++ b/submodules/GalleryUI/Sources/GalleryFooterContentNode.swift @@ -3,16 +3,19 @@ import UIKit import AsyncDisplayKit import Display import SwiftSignalKit +import Postbox public final class GalleryControllerInteraction { public let presentController: (ViewController, ViewControllerPresentationArguments?) -> Void public let dismissController: () -> Void public let replaceRootController: (ViewController, Promise?) -> Void + public let editMedia: (MessageId) -> Void - public init(presentController: @escaping (ViewController, ViewControllerPresentationArguments?) -> Void, dismissController: @escaping () -> Void, replaceRootController: @escaping (ViewController, Promise?) -> Void) { + public init(presentController: @escaping (ViewController, ViewControllerPresentationArguments?) -> Void, dismissController: @escaping () -> Void, replaceRootController: @escaping (ViewController, Promise?) -> Void, editMedia: @escaping (MessageId) -> Void) { self.presentController = presentController self.dismissController = dismissController self.replaceRootController = replaceRootController + self.editMedia = editMedia } } diff --git a/submodules/GalleryUI/Sources/GalleryPagerNode.swift b/submodules/GalleryUI/Sources/GalleryPagerNode.swift index f6ee2f8308..199d822c0b 100644 --- a/submodules/GalleryUI/Sources/GalleryPagerNode.swift +++ b/submodules/GalleryUI/Sources/GalleryPagerNode.swift @@ -517,7 +517,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest } if self.itemNodes.isEmpty { let node = self.makeNodeForItem(at: self.centralItemIndex ?? 0, synchronous: synchronous) - node.frame = CGRect(origin: CGPoint(), size: scrollView.bounds.size) + node.frame = CGRect(origin: CGPoint(), size: self.scrollView.bounds.size) if let containerLayout = self.containerLayout { node.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate) } diff --git a/submodules/GalleryUI/Sources/GalleryThumbnailContainerNode.swift b/submodules/GalleryUI/Sources/GalleryThumbnailContainerNode.swift index 2c6202d330..0af6fc4002 100644 --- a/submodules/GalleryUI/Sources/GalleryThumbnailContainerNode.swift +++ b/submodules/GalleryUI/Sources/GalleryThumbnailContainerNode.swift @@ -125,9 +125,15 @@ public final class GalleryThumbnailContainerNode: ASDisplayNode, UIScrollViewDel self.items = items self.itemNodes = itemNodes } + + var updatedIndexOnly = false + if let centralIndexAndProgress = self.centralIndexAndProgress, centralIndexAndProgress.0 != centralIndex, centralIndexAndProgress.1 == progress { + updatedIndexOnly = true + } + self.centralIndexAndProgress = (centralIndex, progress) if let size = self.currentLayout { - self.updateLayout(size: size, transition: .immediate) + self.updateLayout(size: size, transition: updatedIndexOnly ? .animated(duration: 0.2, curve: .spring) : .immediate) } } diff --git a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift index 8591cd76b1..414d9441b5 100644 --- a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift @@ -449,8 +449,13 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { if let (previousLayout, _) = self.validLayout, self.dismissOnOrientationChange, previousLayout.size.width > previousLayout.size.height && previousLayout.size.height == layout.size.width { dismiss = true } + let hadLayout = self.validLayout != nil self.validLayout = (layout, navigationBarHeight) + if !hadLayout { + self.zoomableContent = zoomableContent + } + let statusDiameter: CGFloat = 50.0 let statusFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - statusDiameter) / 2.0), y: floor((layout.size.height - statusDiameter) / 2.0)), size: CGSize(width: statusDiameter, height: statusDiameter)) transition.updateFrame(node: self.statusButtonNode, frame: statusFrame) @@ -530,7 +535,6 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { let mediaManager = item.context.sharedContext.mediaManager let videoNode = UniversalVideoNode(postbox: item.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: item.content, priority: .gallery) - let videoScale: CGFloat if item.content is WebEmbedVideoContent { videoScale = 1.0 @@ -578,6 +582,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { self.requiresDownload = true var mediaFileStatus: Signal = .single(nil) + + var hintSeekable = false if let contentInfo = item.contentInfo, case let .message(message) = contentInfo { if Namespaces.Message.allScheduled.contains(message.id.namespace) { disablePictureInPicture = true @@ -611,6 +617,12 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { } } if let file = file { + for attribute in file.attributes { + if case let .Video(duration, _, _) = attribute, duration >= 30 { + hintSeekable = true + break + } + } let status = messageMediaFileStatus(context: item.context, messageId: message.id, file: file) if !isWebpage { self.scrubberView.setFetchStatusSignal(status, strings: self.presentationData.strings, decimalSeparator: self.presentationData.dateTimeFormat.decimalSeparator, fileSize: file.size) @@ -634,7 +646,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { var initialBuffering = false var playing = false var isPaused = true - var seekable = false + var seekable = hintSeekable var hasStarted = false var displayProgress = true if let value = value { @@ -682,13 +694,15 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { if !content.enableSound { isPaused = false } - } else { + } else if strongSelf.actionAtEnd == .stop { strongSelf.updateControlsVisibility(true) strongSelf.controlsTimer?.invalidate() strongSelf.controlsTimer = nil } } - seekable = value.duration >= 30.0 + if !value.duration.isZero { + seekable = value.duration >= 30.0 + } } if strongSelf.isCentral && playing && strongSelf.previousPlaying != true && !disablePlayerControls { @@ -749,7 +763,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { if hasStarted || strongSelf.didPause { strongSelf.footerContentNode.content = .playback(paused: true, seekable: seekable) } else if let fetchStatus = fetchStatus, !strongSelf.requiresDownload { - strongSelf.footerContentNode.content = .fetch(status: fetchStatus) + strongSelf.footerContentNode.content = .fetch(status: fetchStatus, seekable: seekable) } } else { strongSelf.footerContentNode.content = .playback(paused: false, seekable: seekable) @@ -773,11 +787,17 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { } self._rightBarButtonItems.set(.single(barButtonItems)) - videoNode.playbackCompleted = { [weak videoNode] in + videoNode.playbackCompleted = { [weak self, weak videoNode] in Queue.mainQueue().async { item.playbackCompleted() - if !isAnimated { + if let strongSelf = self, !isAnimated { videoNode?.seek(0.0) + + if strongSelf.actionAtEnd == .stop { + strongSelf.updateControlsVisibility(true) + strongSelf.controlsTimer?.invalidate() + strongSelf.controlsTimer = nil + } } } } diff --git a/submodules/GalleryUI/Sources/SecretMediaPreviewController.swift b/submodules/GalleryUI/Sources/SecretMediaPreviewController.swift index 91f58c4643..34fc1e1adf 100644 --- a/submodules/GalleryUI/Sources/SecretMediaPreviewController.swift +++ b/submodules/GalleryUI/Sources/SecretMediaPreviewController.swift @@ -208,6 +208,7 @@ public final class SecretMediaPreviewController: ViewController { }, dismissController: { [weak self] in self?.dismiss(forceAway: true) }, replaceRootController: { _, _ in + }, editMedia: { _ in }) self.displayNode = SecretMediaPreviewControllerNode(controllerInteraction: controllerInteraction) self.displayNodeDidLoad() diff --git a/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift b/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift index 26019a1434..161e3e103c 100644 --- a/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift @@ -1228,7 +1228,15 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate { } if let map = media.media as? TelegramMediaMap { - let controller = legacyLocationController(message: nil, mapMedia: map, context: self.context, openPeer: { _ in }, sendLiveLocation: { _, _ in }, stopLiveLocation: { }, openUrl: { _ in }) + let controllerParams = LocationViewParams(sendLiveLocation: { _ in + }, stopLiveLocation: { _ in + }, openUrl: { _ in }, openPeer: { _ in + }, showAll: false) + + let peer = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 1), accessHash: nil, firstName: "", lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) + let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer, text: "", attributes: [], media: [map], peers: SimpleDictionary(), associatedMessages: SimpleDictionary(), associatedMessageIds: []) + + let controller = LocationViewController(context: self.context, subject: message, params: controllerParams) self.pushController(controller) return } diff --git a/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift b/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift index 91b2d00545..9d661bcd87 100644 --- a/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift +++ b/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift @@ -358,12 +358,13 @@ public class InstantPageGalleryController: ViewController, StandalonePresentable if let strongSelf = self { strongSelf.present(controller, in: .window(.root), with: arguments, blockInteraction: true) } - }, dismissController: { [weak self] in - self?.dismiss(forceAway: true) - }, replaceRootController: { [weak self] controller, ready in - if let strongSelf = self { - strongSelf.replaceRootController(controller, ready) - } + }, dismissController: { [weak self] in + self?.dismiss(forceAway: true) + }, replaceRootController: { [weak self] controller, ready in + if let strongSelf = self { + strongSelf.replaceRootController(controller, ready) + } + }, editMedia: { _ in }) self.displayNode = GalleryControllerNode(controllerInteraction: controllerInteraction) self.displayNodeDidLoad() diff --git a/submodules/InstantPageUI/Sources/InstantPageTextItem.swift b/submodules/InstantPageUI/Sources/InstantPageTextItem.swift index 56b8f119d3..c9483f1fba 100644 --- a/submodules/InstantPageUI/Sources/InstantPageTextItem.swift +++ b/submodules/InstantPageUI/Sources/InstantPageTextItem.swift @@ -753,8 +753,8 @@ func layoutTextItemWithString(_ string: NSAttributedString, boundingWidth: CGFlo let cfRunRange = CTRunGetStringRange(run) let runRange = NSMakeRange(cfRunRange.location == kCFNotFound ? NSNotFound : cfRunRange.location, cfRunRange.length) string.enumerateAttributes(in: runRange, options: []) { attributes, range, _ in - if let id = attributes[NSAttributedString.Key.init(rawValue: InstantPageMediaIdAttribute)] as? Int64, let dimensions = attributes[NSAttributedString.Key.init(rawValue: InstantPageMediaDimensionsAttribute)] as? CGSize { - var imageFrame = CGRect(origin: CGPoint(), size: dimensions) + if let id = attributes[NSAttributedString.Key.init(rawValue: InstantPageMediaIdAttribute)] as? Int64, let dimensions = attributes[NSAttributedString.Key.init(rawValue: InstantPageMediaDimensionsAttribute)] as? PixelDimensions { + var imageFrame = CGRect(origin: CGPoint(), size: dimensions.cgSize) let xOffset = CTLineGetOffsetForStringIndex(line, CTRunGetStringRange(run).location, nil) let yOffset = fontLineHeight.isZero ? 0.0 : floorToScreenPixels((fontLineHeight - imageFrame.size.height) / 2.0) diff --git a/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift b/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift index 52baa70a90..6a691bd2bb 100644 --- a/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift +++ b/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift @@ -457,9 +457,9 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode { } if let editableControlSizeAndApply = editableControlSizeAndApply { - let editableControlFrame = CGRect(origin: CGPoint(x: params.leftInset + revealOffset, y: 0.0), size: CGSize(width: editableControlSizeAndApply.0, height: layout.size.height)) + let editableControlFrame = CGRect(origin: CGPoint(x: params.leftInset + revealOffset, y: 0.0), size: CGSize(width: editableControlSizeAndApply.0, height: layout.contentSize.height)) if strongSelf.editableControlNode == nil { - let editableControlNode = editableControlSizeAndApply.1(layout.size.height) + let editableControlNode = editableControlSizeAndApply.1(layout.contentSize.height) editableControlNode.tapped = { if let strongSelf = self { strongSelf.setRevealOptionsOpened(true, animated: true) diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/LegacyComponents.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/LegacyComponents.h index 18f24fd501..92120ba582 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/LegacyComponents.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/LegacyComponents.h @@ -136,15 +136,7 @@ #import #import #import -#import -#import -#import #import -#import -#import -#import -#import -#import #import #import #import @@ -267,8 +259,6 @@ #import #import #import -#import -#import #import #import #import @@ -294,7 +284,6 @@ #import #import #import -#import #import #import #import diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/LegacyComponentsGlobals.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/LegacyComponentsGlobals.h index 304fe2cd9f..ee8dcc1e23 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/LegacyComponentsGlobals.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/LegacyComponentsGlobals.h @@ -58,10 +58,6 @@ typedef enum { - (id)accessChecker; -- (SSignal *)stickerPacksSignal; -- (SSignal *)maskStickerPacksSignal; -- (SSignal *)recentStickerMasksSignal; - - (id)requestAudioSession:(TGAudioSessionType)type interrupted:(void (^)())interrupted; - (SThreadPool *)sharedMediaImageProcessingThreadPool; @@ -71,11 +67,6 @@ typedef enum { - (NSString *)localDocumentDirectoryForLocalDocumentId:(int64_t)localDocumentId version:(int32_t)version; - (NSString *)localDocumentDirectoryForDocumentId:(int64_t)documentId version:(int32_t)version; -- (SSignal *)jsonForHttpLocation:(NSString *)httpLocation; -- (SSignal *)dataForHttpLocation:(NSString *)httpLocation; - -- (NSOperation *)makeHTTPRequestOperationWithRequest:(NSURLRequest *)request; - - (void)pausePictureInPicturePlayback; - (void)resumePictureInPicturePlayback; - (void)maybeReleaseVolumeOverlay; diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationLiveElapsedView.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationLiveElapsedView.h deleted file mode 100644 index 50f45e0d20..0000000000 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationLiveElapsedView.h +++ /dev/null @@ -1,8 +0,0 @@ -#import - -@interface TGLocationLiveElapsedView : UIView - -- (void)setColor:(UIColor *)color; -- (void)setRemaining:(int32_t)remaining period:(int32_t)period; - -@end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationLiveSessionItemView.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationLiveSessionItemView.h deleted file mode 100644 index eda2a3ab76..0000000000 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationLiveSessionItemView.h +++ /dev/null @@ -1,12 +0,0 @@ -#import -#import -#import - -@class TGUser; -@class TGMessage; - -@interface TGLocationLiveSessionItemView : TGMenuSheetButtonItemView - -- (instancetype)initWithMessage:(TGMessage *)message peer:(id)peer remaining:(SSignal *)remaining action:(void (^)(void))action; - -@end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationMapViewController.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationMapViewController.h deleted file mode 100644 index 3a7484e750..0000000000 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationMapViewController.h +++ /dev/null @@ -1,84 +0,0 @@ -#import -#import - -#import - -#import - -@class TGLocationMapView; -@class TGLocationOptionsView; - -@class TGSearchBarPallete; - -@interface TGLocationPallete : NSObject - -@property (nonatomic, readonly) UIColor *backgroundColor; -@property (nonatomic, readonly) UIColor *selectionColor; -@property (nonatomic, readonly) UIColor *separatorColor; -@property (nonatomic, readonly) UIColor *textColor; -@property (nonatomic, readonly) UIColor *secondaryTextColor; -@property (nonatomic, readonly) UIColor *accentColor; -@property (nonatomic, readonly) UIColor *destructiveColor; -@property (nonatomic, readonly) UIColor *locationColor; -@property (nonatomic, readonly) UIColor *liveLocationColor; -@property (nonatomic, readonly) UIColor *iconColor; -@property (nonatomic, readonly) UIColor *sectionHeaderBackgroundColor; -@property (nonatomic, readonly) UIColor *sectionHeaderTextColor; -@property (nonatomic, readonly) TGSearchBarPallete *searchBarPallete; -@property (nonatomic, readonly) UIImage *avatarPlaceholder; - -+ (instancetype)palleteWithBackgroundColor:(UIColor *)backgroundColor selectionColor:(UIColor *)selectionColor separatorColor:(UIColor *)separatorColor textColor:(UIColor *)textColor secondaryTextColor:(UIColor *)secondaryTextColor accentColor:(UIColor *)accentColor destructiveColor:(UIColor *)destructiveColor locationColor:(UIColor *)locationColor liveLocationColor:(UIColor *)liveLocationColor iconColor:(UIColor *)iconColor sectionHeaderBackgroundColor:(UIColor *)sectionHeaderBackgroundColor sectionHeaderTextColor:(UIColor *)sectionHeaderTextColor searchBarPallete:(TGSearchBarPallete *)searchBarPallete avatarPlaceholder:(UIImage *)avatarPlaceholder; - -@end - -@interface TGLocationMapViewController : TGViewController -{ - CLLocationManager *_locationManager; - bool _locationServicesDisabled; - - CGFloat _tableViewTopInset; - CGFloat _tableViewBottomInset; - UITableView *_tableView; - UIActivityIndicatorView *_activityIndicator; - UILabel *_messageLabel; - - UIView *_mapViewWrapper; - TGLocationMapView *_mapView; - TGLocationOptionsView *_optionsView; - UIImageView *_edgeView; - UIImageView *_edgeHighlightView; -} - -@property (nonatomic, copy) void (^liveLocationStarted)(CLLocationCoordinate2D coordinate, int32_t period); -@property (nonatomic, copy) void (^liveLocationStopped)(void); - -@property (nonatomic, strong) TGLocationPallete *pallete; -@property (nonatomic, readonly, strong) UIView *locationMapView; - -- (void)userLocationButtonPressed; - -- (void)setMapCenterCoordinate:(CLLocationCoordinate2D)coordinate offset:(CGPoint)offset animated:(bool)animated; -- (void)setMapCenterCoordinate:(CLLocationCoordinate2D)coordinate span:(MKCoordinateSpan)span offset:(CGPoint)offset animated:(bool)animated; - -- (void)updateInsets; -- (void)updateMapHeightAnimated:(bool)animated; - -- (CGFloat)visibleContentHeight; -- (CGFloat)mapHeight; -- (CGFloat)safeAreaInsetBottom; - -- (bool)hasUserLocation; -- (SSignal *)userLocationSignal; -- (bool)locationServicesDisabled; -- (void)updateLocationAvailability; - -@property (nonatomic, strong) id receivingPeer; -- (void)_presentLiveLocationMenu:(CLLocationCoordinate2D)coordinate dismissOnCompletion:(bool)dismissOnCompletion; -- (CGRect)_liveLocationMenuSourceRect; -- (void)_willStartOwnLiveLocation; - -@end - -extern const CGFloat TGLocationMapInset; -extern const CGFloat TGLocationMapClipHeight; -extern const MKCoordinateSpan TGLocationDefaultSpan; diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationPickerController.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationPickerController.h deleted file mode 100644 index 6f76489ad3..0000000000 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationPickerController.h +++ /dev/null @@ -1,29 +0,0 @@ -#import -#import - -#import - -@class TGVenueAttachment; -@class TGUser; -@class TGMessage; - -typedef enum { - TGLocationPickerControllerDefaultIntent, - TGLocationPickerControllerCustomLocationIntent -} TGLocationPickerControllerIntent; - -@interface TGLocationPickerController : TGLocationMapViewController - -@property (nonatomic, copy) void (^locationPicked)(CLLocationCoordinate2D coordinate, TGVenueAttachment *venue, NSString *address); - -@property (nonatomic, copy) SSignal *(^nearbyPlacesSignal)(NSString *query, CLLocation *coordinate); - -- (instancetype)initWithContext:(id)context intent:(TGLocationPickerControllerIntent)intent; - -- (void)setLiveLocationsSignal:(SSignal *)signal; -@property (nonatomic, copy) SSignal *(^remainingTimeForMessage)(TGMessage *message); - -@property (nonatomic, strong) id peer; -@property (nonatomic, assign) bool allowLiveLocationSharing; - -@end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationPulseView.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationPulseView.h deleted file mode 100644 index 9df57ec177..0000000000 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationPulseView.h +++ /dev/null @@ -1,8 +0,0 @@ -#import - -@interface TGLocationPulseView : UIView - -- (void)start; -- (void)stop; - -@end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationVenue.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationVenue.h deleted file mode 100644 index f93d5bece2..0000000000 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationVenue.h +++ /dev/null @@ -1,34 +0,0 @@ -#import - -@class TGVenueAttachment; -@class TGLocationMediaAttachment; - -@interface TGLocationVenue : NSObject - -@property (nonatomic, readonly) NSString *identifier; -@property (nonatomic, readonly) NSString *name; -@property (nonatomic, readonly) NSString *displayAddress; -@property (nonatomic, readonly) CLLocationCoordinate2D coordinate; -@property (nonatomic, readonly) NSString *categoryName; -@property (nonatomic, readonly) NSURL *categoryIconUrl; - -@property (nonatomic, readonly) NSString *provider; - -@property (readonly, nonatomic) NSString *country; -@property (readonly, nonatomic) NSString *state; -@property (readonly, nonatomic) NSString *city; -@property (readonly, nonatomic) NSString *address; -@property (readonly, nonatomic) NSString *crossStreet; -@property (readonly, nonatomic) NSString *street; - -- (TGVenueAttachment *)venueAttachment; - -+ (TGLocationVenue *)venueWithFoursquareDictionary:(NSDictionary *)dictionary; -+ (TGLocationVenue *)venueWithGooglePlacesDictionary:(NSDictionary *)dictionary; - -+ (TGLocationVenue *)venueWithLocationAttachment:(TGLocationMediaAttachment *)attachment; - -@end - -extern NSString *const TGLocationGooglePlacesVenueProvider; -extern NSString *const TGLocationFoursquareVenueProvider; diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationViewController.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationViewController.h deleted file mode 100644 index a14cf034c4..0000000000 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationViewController.h +++ /dev/null @@ -1,59 +0,0 @@ -#import -#import - -#import - -@class TGLocationMediaAttachment; -@class TGVenueAttachment; -@class TGMenuSheetController; -@class TGMessage; -@class TGUser; - -@interface TGLiveLocation : NSObject - -@property (nonatomic, strong, readonly) TGMessage *message; -@property (nonatomic, strong, readonly) id peer; -@property (nonatomic, readonly) bool hasOwnSession; -@property (nonatomic, readonly) bool isOwnLocation; -@property (nonatomic, readonly) bool isExpired; - -- (instancetype)initWithMessage:(TGMessage *)message peer:(id)peer hasOwnSession:(bool)hasOwnSession isOwnLocation:(bool)isOwnLocation isExpired:(bool)isExpired; -- (instancetype)initWithMessage:(TGMessage *)message peer:(id)peer; - -- (int64_t)peerId; - -@end - -@interface TGLocationViewController : TGLocationMapViewController; - -@property (nonatomic, assign) bool modalMode; -@property (nonatomic, assign) bool previewMode; - -@property (nonatomic, assign) bool allowLiveLocationSharing; -@property (nonatomic, assign) bool zoomToFitAllLocationsOnScreen; - - -@property (nonatomic, copy) void (^presentActionsMenu)(TGLocationMediaAttachment *, bool); -@property (nonatomic, copy) bool (^presentShareMenu)(TGMenuSheetController *, CLLocationCoordinate2D); -@property (nonatomic, copy) bool (^presentOpenInMenu)(TGLocationViewController *, TGLocationMediaAttachment *, bool, void (^)(TGMenuSheetController *)); -@property (nonatomic, copy) void (^shareAction)(NSArray *peerIds, NSString *caption); - -@property (nonatomic, copy) void (^openLocation)(TGMessage *message); -@property (nonatomic, copy) void (^onViewDidAppear)(void); - -@property (nonatomic, copy) void (^updateRightBarItem)(UIBarButtonItem *, bool, bool); - -@property (nonatomic, readonly) UIButton *directionsButton; - -@property (nonatomic, copy) SSignal *(^remainingTimeForMessage)(TGMessage *message); - -- (instancetype)initWithContext:(id)context liveLocation:(TGLiveLocation *)liveLocation; -- (instancetype)initWithContext:(id)context locationAttachment:(TGLocationMediaAttachment *)locationAttachment peer:(id)peer color:(UIColor *)color; -- (instancetype)initWithContext:(id)context message:(TGMessage *)message peer:(id)peer color:(UIColor *)color; - -- (void)actionsButtonPressed; - -- (void)setLiveLocationsSignal:(SSignal *)signal; -- (void)setFrequentUpdatesHandle:(id)disposable; - -@end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationWavesView.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationWavesView.h deleted file mode 100644 index 584ccc0a16..0000000000 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGLocationWavesView.h +++ /dev/null @@ -1,11 +0,0 @@ -#import - -@interface TGLocationWavesView : UIView - -@property (nonatomic, strong) UIColor *color; - -- (void)invalidate; -- (void)start; -- (void)stop; - -@end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerGalleryModel.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerGalleryModel.h index b65cc68ae5..af5300772c 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerGalleryModel.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaPickerGalleryModel.h @@ -50,4 +50,6 @@ - (instancetype)initWithContext:(id)context items:(NSArray *)items focusItem:(id)focusItem selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext hasCaptions:(bool)hasCaptions allowCaptionEntities:(bool)allowCaptionEntities hasTimer:(bool)hasTimer onlyCrop:(bool)onlyCrop inhibitDocumentCaptions:(bool)inhibitDocumentCaptions hasSelectionPanel:(bool)hasSelectionPanel hasCamera:(bool)hasCamera recipientName:(NSString *)recipientName; +- (void)presentPhotoEditorForItem:(id)item tab:(TGPhotoEditorTab)tab; + @end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h index cff37cb96a..7667dcf382 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoVideoEditor.h @@ -4,6 +4,6 @@ + (void)presentWithContext:(id)context parentController:(TGViewController *)parentController image:(UIImage *)image video:(NSURL *)video didFinishWithImage:(void (^)(UIImage *image))didFinishWithImage didFinishWithVideo:(void (^)(UIImage *image, NSURL *url, TGVideoEditAdjustments *adjustments))didFinishWithVideo dismissed:(void (^)(void))dismissed; -+ (void)presentWithContext:(id)context controller:(TGViewController *)controller caption:(NSString *)caption entities:(NSArray *)entities withItem:(id)item recipientName:(NSString *)recipientName stickersContext:(id)stickersContext completion:(void (^)(id, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed; ++ (void)presentWithContext:(id)context controller:(TGViewController *)controller caption:(NSString *)caption entities:(NSArray *)entities withItem:(id)item paint:(bool)paint recipientName:(NSString *)recipientName stickersContext:(id)stickersContext completion:(void (^)(id, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed; @end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGSearchBar.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGSearchBar.h deleted file mode 100644 index feab180b95..0000000000 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGSearchBar.h +++ /dev/null @@ -1,94 +0,0 @@ -#import - -@class TGSearchBar; - -typedef enum { - TGSearchBarStyleDefault = 0, - TGSearchBarStyleDark = 1, - TGSearchBarStyleLight = 2, - TGSearchBarStyleLightPlain = 3, - TGSearchBarStyleLightAlwaysPlain = 4, - TGSearchBarStyleHeader = 5, - TGSearchBarStyleKeyboard = 6 -} TGSearchBarStyle; - -@protocol TGSearchBarDelegate - -- (void)searchBar:(TGSearchBar *)searchBar willChangeHeight:(CGFloat)newHeight; - -@end - -@interface TGSearchBarPallete : NSObject - -@property (nonatomic, readonly) bool isDark; -@property (nonatomic, readonly) UIColor *backgroundColor; -@property (nonatomic, readonly) UIColor *highContrastBackgroundColor; -@property (nonatomic, readonly) UIColor *textColor; -@property (nonatomic, readonly) UIColor *placeholderColor; -@property (nonatomic, readonly) UIImage *clearIcon; -@property (nonatomic, readonly) UIColor *barBackgroundColor; -@property (nonatomic, readonly) UIColor *barSeparatorColor; -@property (nonatomic, readonly) UIColor *plainBackgroundColor; -@property (nonatomic, readonly) UIColor *accentColor; -@property (nonatomic, readonly) UIColor *accentContrastColor; -@property (nonatomic, readonly) UIColor *menuBackgroundColor; -@property (nonatomic, readonly) UIImage *segmentedControlBackgroundImage; -@property (nonatomic, readonly) UIImage *segmentedControlSelectedImage; -@property (nonatomic, readonly) UIImage *segmentedControlHighlightedImage; -@property (nonatomic, readonly) UIImage *segmentedControlDividerImage; - -+ (instancetype)palleteWithDark:(bool)dark backgroundColor:(UIColor *)backgroundColor highContrastBackgroundColor:(UIColor *)highContrastBackgroundColor textColor:(UIColor *)textColor placeholderColor:(UIColor *)placeholderColor clearIcon:(UIImage *)clearIcon barBackgroundColor:(UIColor *)barBackgroundColor barSeparatorColor:(UIColor *)barSeparatorColor plainBackgroundColor:(UIColor *)plainBackgroundColor accentColor:(UIColor *)accentColor accentContrastColor:(UIColor *)accentContrastColor menuBackgroundColor:(UIColor *)menuBackgroundColor segmentedControlBackgroundImage:(UIImage *)segmentedControlBackgroundImage segmentedControlSelectedImage:(UIImage *)segmentedControlSelectedImage segmentedControlHighlightedImage:(UIImage *)segmentedControlHighlightedImage segmentedControlDividerImage:(UIImage *)segmentedControlDividerImage; - -@end - -@interface TGSearchBar : UIView - -+ (CGFloat)searchBarBaseHeight; -+ (CGFloat)searchBarScopeHeight; -- (CGFloat)baseHeight; - -@property (nonatomic, copy) void (^clearPrefix)(bool); - -@property (nonatomic, assign) UIEdgeInsets safeAreaInset; - -@property (nonatomic, weak) id delegate; -@property (nonatomic) bool highContrast; - -@property (nonatomic, strong) UITextField *customTextField; -@property (nonatomic, readonly) UITextField *maybeCustomTextField; - -@property (nonatomic, strong) UIImageView *customBackgroundView; -@property (nonatomic, strong) UIImageView *customActiveBackgroundView; - -@property (nonatomic, strong) NSArray *customScopeButtonTitles; -@property (nonatomic) NSInteger selectedScopeButtonIndex; -@property (nonatomic) bool showsScopeBar; -@property (nonatomic) bool scopeBarCollapsed; - -@property (nonatomic) bool searchBarShouldShowScopeControl; -@property (nonatomic) bool alwaysExtended; -@property (nonatomic) bool hidesCancelButton; - -@property (nonatomic, strong) UIButton *customCancelButton; - -@property (nonatomic) TGSearchBarStyle style; -@property (nonatomic, strong) NSString *text; -@property (nonatomic, strong) NSString *placeholder; -@property (nonatomic, strong) NSAttributedString *prefixText; - -@property (nonatomic) bool showActivity; -@property (nonatomic) bool delayActivity; - -- (instancetype)initWithFrame:(CGRect)frame style:(TGSearchBarStyle)style; - -- (void)setShowsCancelButton:(bool)showsCancelButton animated:(bool)animated; - -- (void)setCustomScopeBarHidden:(bool)hidden; - -- (void)updateClipping:(CGFloat)clippedHeight; - -- (void)localizationUpdated; - -- (void)setPallete:(TGSearchBarPallete *)pallete; - -@end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGSearchDisplayMixin.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGSearchDisplayMixin.h deleted file mode 100644 index 18f042edf5..0000000000 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGSearchDisplayMixin.h +++ /dev/null @@ -1,46 +0,0 @@ -#import - -@class TGSearchDisplayMixin; -@class TGSearchBar; - -@protocol TGSearchDisplayMixinDelegate - -@required - -- (UITableView *)createTableViewForSearchMixin:(TGSearchDisplayMixin *)searchMixin; -- (UIView *)referenceViewForSearchResults; -- (void)searchMixin:(TGSearchDisplayMixin *)searchMixin hasChangedSearchQuery:(NSString *)searchQuery withScope:(int)scope; - -@optional - -- (void)searchMixinWillActivate:(bool)animated; -- (void)searchMixinWillDeactivate:(bool)animated; - -@end - -@interface TGSearchDisplayMixin : NSObject - -@property (nonatomic, weak) id delegate; - -@property (nonatomic, strong) TGSearchBar *searchBar; -@property (nonatomic) bool isActive; -@property (nonatomic, strong) UITableView *searchResultsTableView; -@property (nonatomic) bool alwaysShowsCancelButton; - -@property (nonatomic) bool searchResultsTableViewHidden; - -@property (nonatomic) bool simpleLayout; - -- (void)setSearchResultsTableViewHidden:(bool)searchResultsTableViewHidden animated:(bool)animated; - -- (void)setIsActive:(bool)isActive animated:(bool)animated; - -- (void)controllerInsetUpdated:(UIEdgeInsets)controllerInset; -- (void)controllerLayoutUpdated:(CGSize)layoutSize; - -- (void)reloadSearchResults; -- (void)resignResponderIfAny; - -- (void)unload; - -@end diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/AttachmentMenuInteractiveCameraIcon.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/AttachmentMenuInteractiveCameraIcon.png deleted file mode 100644 index 4edffbcd9eb615bd720dba6489719b43702a8222..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 328 zcmV-O0k{5%P)V0AkSy0`dvULKcM8S`#Pab3&7;2GbNXm4E06yS$EFM%++##u70>gZ4LQ z8DY7@2sh=1vRI+l#GqF$9ilk2LZf^avutpwX_hW+H_E3d3R(JOhdJVzBZlSrurCRP za@`yf=ZJ3k@Fk&Pxp~se$`8LJR4=zlnhp7u7liKIC220@z0bd*f@d@@Km78yc9i|r zzT`WC<%chOj!iB#%{_eC%kZ+0Qt5w9ju(cUzrPia7A-?8l!bPAJ$r6wls#U@HlyaB aA4&~Iw|12)I(~cr0000_0N@@=zR4q_UIMq za6u3RK@hNq&qVQ=Jz|do#Boq;v49%lsAZX0;tFwH5j$)riS3dOyC_9b%1%-A;xydC27!tIP~EWNj;*Ev^DmT#y)9V4B#zkyk&sI$2^WwN_#5hDD%XR z1^l5S{9%FkaFmX6RD38Ut|o4h#|9?QpZ-i>1G(I!iT|Br5|cQGU%B`YPa`GF6%Xc8 zLL*8|l4eZ8kMxCJvq~~x6|X&oCR!D`&RB66#bHkKj#|oj!f6gON*u;=69t@QB2zeP zQ|Kc7U49^i{Gp{k6fsDe(Vq*nU{UBP!(4hM5AcHr%ygNdJhd*=z$%xW$_Fy}z*OB! z4Yq|!bg}Nzn!CDi#g>JdnCp@SL{X@hK$Bge8!k7RzeMqu(Jp_(u27!K9U-bCE}v&t zXrs%WBC69azsau91ebeHRPSAWf>|NG5NnC5Rxe27LS?pv;xE}V`z7nLn>x26j=jOf zX#eOajP>Yfv?~O~E;)$%wB~{F!&Nn~Qpf#?Og`#duCRXnfF}%f=~@0f)h_QPtS__2Val+m8bILZPEf*=Tj az|KE04;wjS%0YGj0000Duyse0LS!D)^7wD!ivBKF#fld~^6Tfx~zbhZ&M#?g2hXFR7$rFKx;s7k** zd4I9^n&N=6tbI!SB%;jkYsLdcxGfx(=f&uC?zzSKze0r&0KMQ3Er|~iA z_>|LS2YX1*K3PEv1Egn=vt_wWruMnhR4XpV+{@CBK{;Be{zu;hu6r?t7;V1k*&3A3_c=T zA1Pe~9Og4h*jM5+4il&n%;Y`)9`dOqHCUbyejO{oFnXDKtrJuMDSW3VWK7huC{me?mu#rxZb+Sn@ ztmG#WG%9SbBIJ0G$~;I;5w_b4dqENMyi4WYC9eq2+X^dizCr}NLv`LEP>6FWSPHvb z5gw#^4=TdtcEW~eQHV{{W>akZI%Fm6*4P8SliGALSs`w>61GSo4p6&;3bDvWSeqgo zqjtv>q18gz!?71^eO4;O!xqAJD8yCN=PHHRVIgdtLcB?R-cpFQ7Q$vJL>u*KQ;3-s z!tx4Hpgu)~m~J3U5$dLhpRp#p$7WavTbsdCapgpPk8QOOc7Fz69`{=aJD$O};xYfa z_x~~fgC2M0@etK}$mYxg3Y@DD0UuJGkI2QQRKu3S;Q5s1iqF}b1n-%clVJFXm5O0g z1+)9j%`m%%J}y-ZlR3l*#&&{3qgGq`z-AZ>vToew$_mAAN#Rh*WvK4vfser9VO zE1EXLBF}SyD#isoPsDZ@6sy=ZPz3v7af95(r5YEPM*BRPDJ;^;!|Y%!GssKinZa7N z^Drlf7zi`S!+xbXm6VLnXilFg8HZ_3hn0*R-_v}4AU6@W&VJ8KRf2#cd_@`i%6!EU l0y*cLbIv*EoO8~_{SEAL=Dh-d|Nj60002ovPDHLkV1n)ssyP4v diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/AttachmentTipIcons@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/AttachmentTipIcons@2x.png deleted file mode 100644 index eb05b2f187adc2c49b431e9b81297755bd3a0920..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20164 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 D@JQQm diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CalloutAccessory@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CalloutAccessory@2x.png deleted file mode 100644 index 636dbe11001d7217c10a132b16eae16571a29c5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9T!2%?YomF20q!K(`978G?-<~_l*z6$SaIrIF zBFoz5S2thlGv=~ve^7R}zE1hl5q{@wht<>$-c+`MdT6Houk{NcNi)=v#0Ey#h;{{ITYFxR_4t}zW+XHD%_xYY+~`TL5-fhfQ4HCFGFfOgSN4W87`7XAsn<-d-kVDZVBEo? z=f-pG;ao??q?4sD4UTjMx7mbg0vBrB^ylVVP}zYc5?5OS_2oV-&_iPU{ceI@|r` z{T`z&~6;Sy*r~*POx|1pea|nseW5ZxNn|=y+Tg>r8IE1AoqAz?G;U+qdHhD2>;&s#d5kHSQ0Aws<{A@ug=sfYSNE*sI&<+rz=Hd= zG3ImqmG~lK(es8llOsJyAQ!Mq;9XmW@!awbD%Y?@!n?QFSZ@1MbtHGO?K}bF9R_Fm zDUP^;@?l9Y*OJB?1RQc(Z_;~<@J7Tw{YlrEX&YYuYtrYZP`HBQMBe}H7nz?$ zc-IiOdGK>?xDJJzxJKX+N?YcKrJb+q2jlI@;dpQfm&rWD0~J4BavjsY1LZXp#TIn} Q$N&HU07*qoM6N<$g3a*ARR910 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CalloutBackground@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CalloutBackground@2x.png deleted file mode 100644 index d30a7daf77f627d108fbaad6d5e298b896c3c7c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 534 zcmV+x0_pvUP)h=qtxEl_9G;lTASLoZ7a5ux%Yo+U(S5%#^|mo@ZzT^M`~>tDXIR-ge;9Y7+QI z`jvHRP<*BaudE{-7cwrd?R_CW>3w;5Eg86xfc9p$c=cvC8VPt1Lebv&%@;(8YpVIe z-uV;}f>%)#VqD+Ybh_`IGJj;7eear1U*Cj5AyN1&h(z)zLr)twX+qjKbjrvhksw_9 Y3`a=zT`1%wC;$Ke07*qoM6N<$g3fgM=>Px# diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CalloutBackground_Highlighted@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CalloutBackground_Highlighted@2x.png deleted file mode 100644 index 72ed8be57dd5880cd2a0a7b7e226e5d1dfb9f7bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 554 zcmV+_0@eMAP))vFF6pd zKYmqu$)B~HD+i3xr+^%Y)K3AFshe#x-Pq8ZZJW3!p3QO~T0NV` z?~(1*)95p=o?-)7gerQY&xl@B7D48%qjJECw~mqtrH%KkWg72O3QKguT1Gcm0xsj9 zwT$r(7pS7!T1IrEf+h#7iUz9au@(_MsNgdGTil!fxL}DcEuNHQ36#BhXf5;VA!U$x z$89Zh$4w?ILX&+KGJR+)00iGP=miN*qiOixP<9 z*aH%USf-Fw>2B$WEYi|Z=_ZRA6ju2}SNIXpRpq0QIVh_123o^hPHUx?B236asjUtj zsjWsK3v-CWd1>#vCfRS2=zrIAX)jLV2uTVKw3^dzYn$6d&-iE1-1fG%<}?}(QV5$E svZ-JhYRHq)$07*qoM6N<$g8EqeegFUf diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CalloutDrivingBackground@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CalloutDrivingBackground@2x.png deleted file mode 100644 index 1812b32a092fbf15bf362c2a184c7c1ee509916d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 262 zcmV+h0r~!kP))fh1~nXau#8Ft7}gxJBFSfHbHd z2@AVnVm}lNuW2MK?39V+nb<88`(k3k#J-u>9TO`tu?r?PkA(Sc{xLCyi4D*&72Ky` zDp+P>3+Ro4so*mDq+lwzgsK$GgdWi_6&yq<^dAiihS!mTYHq)-E|PLsE)BYoJpcdz M07*qoM6N<$f|ey{ZU6uP diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CalloutDrivingBackground_Highlighted@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/CalloutDrivingBackground_Highlighted@2x.png deleted file mode 100644 index 2697187254841eaf059a79414eb18922059daa07..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 262 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 vmP((YlryvUODajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_cg49qH-ArU1JzCKpT`MG+DAT@dwxdlMo3=B5*6$OdO*{LN8 zNvY|XdA3ULckfqH$V{%1*XSQL?vFu&J;D8jzb> zlBiITo0C^;Rbi_HHrEQs1_|pcDS(xfWZNo192Makpx~Tel&WB=XRMoSU}&gdW~OIo zVrph)sH0$HU}&Uo07PcGh9*{~W>!Y#3Q(W~w5=#5%__*n4QdyVXRDM^Qc_^0uU}qX zu2*iXmtT~wZ)j<02{OaTNEfI=x41H|B(Xv_uUHvof=g;~a#3bMNoIbY0?5R~r2Ntn zTP2`NAzsKWfE$}v3=Jk=fazBx7U&!58GyV5Q|Rl9UukYGTy=3tP%6T`SPd=?sVqp< z4@xc0FD*(2MqHXQ$f^P>=c3falKi5O{QMkPC z!8&|>tvvIJOA_;vQ$1a5m4IgGWoD*WSy~#HIJvkP8JHQE7#g~oS(sT^SeQGy7`VE* z8C#e*!t}c2Czs}?=9R$orXchhmw7Fj-? z%(;paLoUeNWnIG6SYk6Fu5HR3HY3T0IccGp!Y_V=DTKB?`O)d& znNg7Dr*eV!$o|G1{I7oKC7rr;FsRs%;ZcqXyD{G@0r@q&8y;Q`JIHkJv4Hr3(4vD^ zg$2OPr3X9n1)lEd8VJLp*qs zuUxx#izP^rbl(DIaZ U*E3Gz2%v!sp00i_>zopr0Qp%bQUCw| diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/EmbedVideoPlayIcon@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/EmbedVideoPlayIcon@2x.png deleted file mode 100644 index f2a2e4422ec85ff5e1ab3779de3632176a5b49d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 479 zcmV<50U-W~P)Px$nMp)JR5%f>l|N6yKp2O6{SzT1PHwI)n$T)U&uJny~jRdXnPqLglHYq)gAScPcX ztK&GQjYdOH!z9$UnFMH?mR0qAKa^riPva(~@o3~bwtZDDmorOK{uahz8p^hydhsfFZhCP zi^bw5k1Oq&1e%%>LOwJ?>S@fTfGD4&g+=J_-9{#}*X?$j<`iD-CNxa5+Ua!KB5f73 zAEN7*I1oG;#DS`2&#pBexF002ovPDHLkV1nq)(oz5b diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/EmbedVideoTrackHollow@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/EmbedVideoTrackHollow@2x.png deleted file mode 100644 index 7b0f4e5a009cc9041927f410fd18bb167bd181f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 979 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 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationInfo.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationInfo.png deleted file mode 100644 index 5b1496cd6be3eb2b9f47bd3b467989d1bed4ad50..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 442 zcmV;r0Y(0aP)P000>X1^@s6#OZ}&0004jNkl>T5|v1`QHaAUi68?mSVB(KT&-kv7;mhbIo zB@&ggrSB3jz=BKo0ZD7MZ_)V@;j|#B5Pa|e+Yp2f(CNHR`$0PY3`0=Nt)QM-xeCq9 zoMu?1yoO}Kz0@kdNTH}ac!B^_7_qA`^1q|eJTx;BkEoI(Mr;#ZS5rG~*k+D*E6k}iGkzOPwP8b0WTDV= zWDA<04o1QN9Dsx=W+fePE$9`YGm|D9R^oymp^^kjHY%YUsTRLk?#Zv(xPgu=Rnh^s zjJu0b3FGcEVLMBeY=Oyt;vH5(Py7pLq3^C0#&a?q!blRo0;93s!rlx$>E4jHaPGb* zp#eQ`pU#(&@_Um7*1##OIQYglQT!RyI{91ihy1MspdDNxPjWjQ-=;V}6sFRB4cuVU kME-(=U)s0nyq4%Xe{f=*CSmz+BLDyZ07*qoM6N<$f+`xx!2kdN diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationInfo@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationInfo@2x.png deleted file mode 100644 index 51f15f8690c17035cad2b47fd4f3ba98791076f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1112 zcmV-e1gHCnP) z1CS+26wI@2+qP}nwry3_*|u%l44!SHUVWX-zRlhjwdmcQY5X6Z5i|4oI^%UdR1Qkx zgw{eZ;W#+C0meTCBk#e;53uqptp6BBUV!tr!G_b}8Y{ykqoU_H!7l?BE`XIUVSJMF z=Q~)r5y#6$aLLH%DqM4ZSb1~^0@iz2xfCYs04J-%HRgr;abmdExNz;+;lhe=vNfEX z0xRzh`CWM%$A@*gK(swItXvN(|E3q>EqCFx0Y8f)Nk&2*oYvnF@qcJ0o`MTAqH3J>-2|}y z;+SnGXBE@7^DYLl;li$0x079Ay22 z8Z2b%e;;`Luy>!`AQl*9Pz28J3nTBq%IC0hHqJ@LLS7izCf?x_!U`BJ*t)d93Tf8J z9+^R5{j~)%eVVqs_i#rt%J7E5zicmsyMd9HGK5)3E*TSfad|QtjC`Uoc0&d_!O}ik z6vn@iAn)XCUG?gl!+N(}`gM`bhYA3#xXipIMZ4nYJL8NNu}lmT^b z{h6@xV=65pcfrY|CHwP+n#`9Fp<7qlQc6QJLk(5|b{Vd!M*hP|ooRHRRh{rcb%c?7 zR2F-I%eNNCr6_}Rb(B`-$9+3(dBR}_<@hkTOe^~xPzI-j$#8OWia2=m2TrC(S)ACO zLsjrGI3&_1$NSYPx_weP;nUmWY2p0>P7*%hNujQURdPS4@z{I$fXA9z6E^;%G#*<9 zAMgxTZ^H79W?1Jn4~+HB@OMzcFX+%%v95%)?2vPgd3^@79*E^;c`Gqtgv53YsQI-3ar@&k@g9Cxm%G#PLi=rgns7S=H|+ zgTJ`3zW5m(nOYIHa`(VE{){2gPGe3laA0i+yT+1QU%%qy_EZ=gbP@F;9ok2AARK3e zl@o{ef#mH*((+^g^(^w}Fn575F`C(O4nHl=So!h^?W2n90PVBdx>U23B!!k| zJo~8&Lq{gR$)`h#<5nkFY+dXIm4dpai>Nw_6DTz~!VYX}+AlN9H}_eth}^oAT>L(V zf_|?{po>Ujj#;LClyxhAhV>un8SJ~v`%zl{3>~+<1E&}5BRVqrZ`xmmCa0$07wPhC eFap diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationInfo@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationInfo@3x.png deleted file mode 100644 index 16cdbcec813a2c430ca30173ce81efdfc943c762..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 908 zcmeAS@N?(olHy`uVBq!ia0vp^P9V&|3?#2~eYgdrb_Mu^xB_X0`lk#H{~21|GSoi< zG3uT(GyoYu!KVz3FF>*&aUgoZ(D0U_;T1@v?ion14yfiiSUXVaIYZkgkVw-@kYbQ5 zm}~;;1&RZ?AQS#GO!^Np8Db_#9BfF#ONNejU|WF7fL4I@Ld*f04AT1+W+~X@x~Gm0 zyC(u2Z(9=N7tHXON%kyTd{4s)=f?XpB4kwF{`&f+-`o0a1D-tdVPT)L z-{wc8mL7lF5}ua_=j=3l#dl!#t`}c#zwl;YU~=(vaSW-5TRVfjNZOFcb>pRJE52ua z6%xJus>u7^-}O^dj>+}Nt_#2O(E5OU6GI2Tm(J88#pmL)-IiI=i%vQUK0~zX^ zZ`>NbE3nPWawu_rWh@v_Z8T>g+wFinr8`b<_ZO$wR_vQBy|bE4|F^2RT~4TCWHR@^ z=X=&LB#ZR_{=3*vEJ3x)r}2cshav`xJrX8L39Gn{OZNEev|u=JaLRPSGkvQ#KF`(U zx@UNF)9l6S>-i2wOs>9nQ~I??n|y6`aU30`?3h$N8pZdl2bWN(5 zdrC6u)ASy8?m(f*t8@;W?(mSS(|7gM(M_#v+S4&5K}S>4+0*5h!Ne&(3-p5;-4xvF zY7`1tcvpBxu1jj;SD6+cFpY^vWtvJSqlgN7VpXR=(IaQ|y)NuEnoj0>UBtUCwZv6* z%9$+Xb*$=SxW%U;!}92Xm8{BD$4pC&f?Q+e?OSG=?Oxhqw%g9KOz78>7l+gJ7xKr; z`FUq^*4CAB-0*%OFhOiiu4;+MONTAfE;O!4z8ROqo6lC9pt$gvgKk%1A45Z*&}P?8 zb1w}Q3DvFHVk=_34SKsynpkaE_l~EeO8R}>%nk9Gb9BSrUAK-kiWi>dbA0u>zlZ*Y jm2UdB`+rTr2i8yQn{sy7Jv5BH3(8iWu6{1-oD!M<*oukz diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationInfo_Active.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationInfo_Active.png deleted file mode 100644 index d8470628c4d54f1d70bbbbf985ec0936d8e9a52d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 384 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 AiU0rr diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationMessageLiveIcon@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationMessageLiveIcon@3x.png deleted file mode 100644 index 40f071a3b0f1aa3e00030e94e8fe820c6d4db328..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2587 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 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationMessagePinIcon@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationMessagePinIcon@2x.png deleted file mode 100644 index cff797ee18eea19b66bc9ec55338cb6b897070b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1372 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 X2L@0h%Qya1H=RA>>0EUB+JpZEh2!5v diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationMessagePinShadow@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationMessagePinShadow@3x.png deleted file mode 100644 index 38bf099fe4fd9d3a7a729914be9f1435bc706218..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9741 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%0AmqkD0+u z4_I2e$?bn$I^4H1txtB%N3syQtnQ7|jZdb^DgiyRRBVmJwQKz+Kc@1!i`Zst5y-eY zfFF72R?%Op1-It8c;oC`1h8|Ah<Rj3s3$ zH7vb%Z+9Wts@B{a7c*1>w{fDnk)wv;!%5FNI_2+FjNUAYoMR!%=Dz_ZIj4jC(3FzR zx$@yDbaU|yyhD(~LNXeG;)FBJQmsJgWP8awde5g>5Y}3hHWY&(AfwXUhSRhOdx}W) z`|MeQDbx#`BV=Ts1Uh`bs%T+?cB|>A$;+It-9b021J(a?xCI$}lLEJ4Ymf^fxXoB^ z78Fay4e<{ygH4tXYBZzMEG2n?1dHZMxo^`;gJ0}?YNMiF%98@8*3%+a2(E zs`J`$vLqiu2pwAjC3TEj$g}(E`NPP4RPi@?Qmoiv>+^LU{+0SQj0_ZiUL^c z6aNm8|IN8CyoHUQUO`5R(2E~D@5+36=I38S*ROqh=3>x$mTG4Z=j4LhB}>Ylz@8Z| zoa>u!px(JGn^`TGf)5pJ$5yz8IP_Q6I|NC-Zrh%;AODkpA+CP|^g>30nqTBJURhM$ z(IBfdi=4UVTq`@PAwvY(&(3qXicxN@WlHR9|D6?0hpo(Xk}D&!k(3|_t=(cDXsX+) zORTe&RIeXs{&~xW1Ct1i7TVpg!^iB8ne1u{c_^ zStWK95e|bz5N64iR*}MGI$nhjC~$~kzyJRjESz;%*f!5Z{2KN99W~|st{rDid7Y%3 Ixc1lo0&U^RKL7v# diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPanelEdge@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPanelEdge@2x.png deleted file mode 100644 index d1dc083322f841f5126a4e6c1b58b923fa6e8886..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 716 zcmV;-0yF)IP)2kt|@t)#te?p^7A~ zM;CN8;!LlL5O2Z-?YXK#i6m~wjcAf?(!?+~ATD9SE3}Q3ixNttz~Q(vlgc3>If}ZGQ#F>Q)5MRQ1?RB(`?eU|rgubgO0|+LfFpfVkW!v3u!GbIV z0szCH0t0}68Db1I7|IYZp{NK15IGY8LQpP&p;>I??wGYr?Y3>ZciZi~uQz@4yjn=L zyC3_E$NBsFeP6j;zAzXJDzn+_@n*9zDWz}1FzhqN#`15!-+$U}x7KR4dNH5RpE!Qc zw{5$EYGBLXQ>O}rLY6Vshls&B_gbx1{zuE$?sPi61rbH;)Fa7dl58{@InMcKh%U6< zZePZuK$1f4+Yn*!)ICKlNGc4&_Yh&w<*{KHIx$W2A^3WNu^TtARffyg<6$XyRl&V!_%GFeZTLW=Xt;9 zy?nFl^@(%XlR_o|0Kkr)izd-lMZdF|zVx>xGT1c3w9L#|ON)wTRgYi~u zIi7@LrrcHM@!0_2J>8OQpbWZsh>@`JF%O3CwAyJl9W2gi$BbDx1!myOEjBs#e<#1; zf)p)fiGO0m~32~WrR)Kxc9)>PJ|9%#VHJQT36ag#3|>#h>Or` zk6XY6UqGlVIrk4y2Av*M6Am1VNK@lXB2q0J>6!Rb<0>KC* z1jimOeVW5$Mv_qN*je;W&dsDKJ0cL|$+>o1kc5*&w!=vG!yG}#iMdA?ctj&CL{)y zN+6k5qY=TdP^girG;pj;s#FSNQJGXCR*iGxZ6t-+jQBX$@+TMlTP~t@;21?Xk_lqv zc=z;~1VxaUgdJ3?J>8Om({-59V)Hm>cnUnG7k5}b#7$ZUVFh1Q2(i3E1uWL8wJI$N zL+Drr8dw`Egw+tFR>g><+%c}{71@t*HUF0@pv4G0?fpx;$6fRcd6qASm)^V_f80jT zyn`O@Ee!|e(|6`+JgQ7~y6;)4NCv=wlyGrlw{P^MLsSPLFFSMU2vgUm7 zp!3sD+DG%Bt|iPTU7UAt}onH^0 zPGh3LeN4?w@j1&122Nyf64LJ=#lQkbNdU0@acfc7<{q?*H&amsG5|%?uA7nM!OE>1bcEDd4?lm>Gc^Pv*}E10vd zpUHK$jV`?zrK(`X{?$k5ToeQEq^v)Q~mXv5jE1Ia5cH`FcoUR-wjMC#n9 zq3;8Gl|u(ryLatc6teN##QMcQz%tom`K(!^WNvQbzzyFY_b1glKT>_WZRz#8{)o1q zHkOXFs(1is+adNB`&lNpwYBwKyLN5evO_)V^kLak@-P2%7-Jj!yG>bB4Lt97rz2atb|Izh_HEFg2X#~od91sw9>FAQG(fvM06VfBL zEv|kyjd%JZ{miYll-jO~Rp%HhO5N{3J9!W0zkh|?>y72-KjZhcuGlp5*8~>@`etHFYuC2hk1{h*D9U(w$=fm8FYL&F+_?Mh^kogbcY@Zs zGolhxGENIaQf6*FkY5OREm3UgPwwq~ugP2VO;gi9?r!P}yJus#4I7+()oT=dKL5v| z0a7*X7VFaBTRUB^!F&9pqN4T;c3p4H|5wwTLkkvn-X2+c>r`|5yO-+g>%Yn`1H3|% zwZ9BX%i}hl(OokiZZxNMlLM~qCnHt29)4A$C;;j!d%Mf8G&fgQS1$`( zkDhnwFSY*CWfDF4Z=N=q$73&KUi_!aC)0QM(a_b7j*eMVI)LHk${VgUz7#{nD~AV0 zMku$q?c4$%FL$AryRUE8o58_P%&6?qqema~tM=ae&gBHW=LNi;vu`qETDm)Ylb;vM z9{tA2*Rwgzz~P|>HFGB4ozTO+&+e^3ZyW-=fym>V^^jr+_WU2?HHqk#s`R4Y0lLlW AkpKVy diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPanelEdge_Highlighted@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPanelEdge_Highlighted@2x.png deleted file mode 100644 index d85ebddd5882ae759cdaa0a0e9b5a5ed91de0e7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1262 zcmeAS@N?(olHy`uVBq!ia0vp^IzX(!!3HE-MJ2?6lw^r(L`iUdT1k0gQ7VIDN`6wR zf@f}GdTLN=VoGJ<$y6H#24;=Skcg59UmvUF{9L_6kQ%*;+ybC(1_m4Zih{)C?9>v4 zq}24xJX@vryZ0+8WTx0Eg`4^s_!c;)W@LI)6{QAO`Gq7`WhYyvDB0U7*i={n4aiL` zNmQuF&B-gas<2f8n`;GRgM{^!6u?SKvTcwn`Gt*5rG`3JMx70H< zwX`rY(NQomFf`LQu+%p+(KRr%GO)BVFjRm7C7^9ZDQQ+gE^bh}fIM5JjFOT9D}DX) z@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7^KE~&-IMVSR9nfZANAQKal z@=Hr>m4GgVcpk{1iHq`B|o_|H#M)s)5TT^D595=nPO$)Wb9_(W?<@S zWNB$==xXldYH4a=?&xS}>SAGTX5s|X>zP+vl9-pA3e%g3&})KMua$FAYGO%#QAmD% z4lMQpGV)9Ei!<^I6r7zwv1P8H;hUJ8nFkWo1O+hEy{Sc+WvMA{Mftf3;1IIP#NrA| z6E|l!CpQ;M0~e?dTrJ&94K1Aw44j>ejm(vxdQ-6Y9;(+Br(S)aWAs7Mixk~3Az&H; zG2w|9$bl#S)I4CCF9Ig+lm0ht85kI2JY5_^DsH`*ZtH!-LBK)3d{O!GjD-p5a}OQ! zXSwL+^5(4wH@E8*w=d=ytEX~=O*3msSls&dZ_|WxYV{6Roctb1OB_5jS>?{$-3H9- zIdmSrO({rVWRTH`;}zoN0YqHX(~ zLxCbsBjejcZ?syz(4Vn_zoI>RM|1m`LxnQwk?J>ZxA}_Zmfty~X>v=^hELq!{=>&N zTeK~jt}mMIry{>wLHi=J^{ls5aS!coT-t1U>#5TQ7Jq};?iI22{%_~6y3TXwaD-Um z&6_isRm&q*pSTczD0tUqM)zMwl=8 z3t7ecQu_WOZi9zE?i6b*Zs7QSsFA&S)|4B6H<@)_nEcX6hx lJ=G67s(k;zZk~Eh1BRb7OmDjz{uct3K%TCCF6*2UngCWq!=eBH diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPanelEdge_Highlighted@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPanelEdge_Highlighted@3x.png deleted file mode 100644 index 7b6345b8ad8ac68b373b168134b7c5ae90407821..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1401 zcmeAS@N?(olHy`uVBq!ia0vp^PC#tK!3HER)#OA1DajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_cg49pstArU1JzCKpT`MG+DAT@dwxdlMoK*Q`S3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxOgGuk*h0bFQqR!T z(!$6@N5ROz&`jUJQs2--*TB%qz|zXVPyq^*fVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD#PU%0_}#n6BP2AO_EVu8M)o`HUDF34YC)x{-2sR(CaRb3oXS&*t9 zlvvtGSb_rKyFvqobjzi-ozFi4#n(XI^nhVqS78Om8MauK`}YR?bDKi6!|(A^G_^ zu-FU8$S=t+&d4uNaCQd8mbrq4Z(?$09!O9V6u?mTrWR$ErKY$Q<>xAZL&z!^MGl-2$;B+oeS4zU|@Xi>EaktaqG?O(_V)iMB37mwut7$a$IX_QYzKv z*w?^)wAZd#VG+NwUdc-R2TuiGxfLk>V9<^2U|iVIwQi00EBhiX$2}^!x9 zdGdPo$unDCrEOj*u~bKE0Y?{+$iweV*4A5VH;NyylVD_iw%bAef?Qwj-bMB7`43p{ zG?o@fwfEg%<9{GJ<)Fxk<~1D`j`&`f4z5lhG!+O zPE%)ISH+Z0?Nb*&InRu0Z{BB;w)E{Hy@RsBuZ?GLdmWM6F=bnKw9x~mH)UFfZrqvD z8W5A5b)V_;+zyNWoh;jXHkY~DcxJ1rN?NMNE9E)pHCC^lGiSECV0(hjL22LOyyI~$ zYurjUiafDOerhl1=aWDA?VG?k`&~prtAhUcwoIN7y>x!`s?U={=k9`)jxYHc*%-c?*?X^fEhG&p3_V@_T-G@yGywqV`Sf=H diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPin@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPin@2x.png deleted file mode 100644 index 709d3b08f9381c32d6e72da72c9c506159857e3a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 851 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 EU)?Fai2wiq diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPinBackground@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPinBackground@3x.png deleted file mode 100644 index c99da533a09a2ce00f35f139132038d780aa13c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4687 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 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPinIcon@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPinIcon@3x.png deleted file mode 100644 index a57e0d4252abf1eacf730e9885c4177d5ae27c32..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1731 zcmd^A|3A|S9G+#8E=^3g;(RWRPSSO~=nF};OS`n;MA7i-T#adyF>B0-@}*3jN-7I| zaatz%ve__kO-x&I4zsn3e2aZ3ZPLfqxgYLt=!g5^c|Xq&@7MGG>3Kgn{&?RN7HceE zFxU#*0c_wR3;u<<+2Zu4C~hy32`$ifFN`m@n}EU0SUBvSAcl!nUCmJi*_i$9ibLOh z;SZz-K3Q_tG1tbzh4k{ph!yEfR>EZliUfOdAb?@|7IOgTo`GT4$n#FD&$7>-mVcaj z2c}%(ORK9CO~%o}U(cL$5>SqsBLSZ@m!#c}H+RejS>Wvjcr^YsC> zD?K)aQw$B!RYSUVlIC`CvBA2^7A`|&`|r-t(`wmwbZ(VY&(V%}MOPO-7&trsy;4SM zcdL}P6`V^Ll38T~uQ>XJe(d!2=HAApTU*@=3RY#$s4wW-IFa(Yir(g=z~Axp;U(wX zlvLV12BFyFd|IDmqzSc%tOq?` z4PRjNO)2%HcGHDdf*X+g!!oBpWCgW zWIEw_X}J{l!3vZMcJLo)Yu4pEiP(v6j5%$Zsnpt{gMwRxd9!*pnyFbbto`ar|$HMH=4H%I(IK@?;LOEPE zxF%nk4A)#0f3}ak-5%cg_-=#i(>JYNnGn2V{5%E`gQKAlyjS0<4AU(l37M(DJjWQK zR@(arp%LTT=^L+TI2vyEz`mtOFttJ7)PB$P;0;-zpIg^H;pR&hDGYbf*xMx6Xtxly zzSz+s$vG&2tf(k_Tubc=b29ZB--=67eC7V zv}AB2BVyQ?JhqxS?0u76CRvHc47m_D0;)RWeu51W#2&jxMr4Zr(v0W8TZ^-K36*Ja zeV^9u3h)tHpT5dRA;D1g9cK&kq;>q4b?{c=B=rN<rCW7aO3 zg{r9LdT0Th*YVBHE+;@$6F^6WChA^B+b&w1s}?_dATH;8(Z?)67?-sCNlA?KycWLL PN-*4ycr1T! diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPinPoint@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPinPoint@2x.png deleted file mode 100644 index 7584de8b0f2d75a8d3c7be782c2ed29424fe6e53..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 107 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 a2cxD3_#-!;NLreQuGu(R*Z<-7*Z%@j-_V=@ diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPinShadow@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationPinShadow@3x.png deleted file mode 100644 index caffa8f166fc198d703995c86cf3877ec01b2806..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13092 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 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationSmallCircle@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationSmallCircle@2x.png deleted file mode 100644 index ae2064ea7ca7659e9c40b251adec9dc954a30588..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4660 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 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationSmallCircle@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationSmallCircle@3x.png deleted file mode 100644 index 5baaa60ba985134d53a5c44ba1d1af2f5b68b2c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6410 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 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationTopPanel@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationTopPanel@3x.png deleted file mode 100644 index 6b3d6b02527542e2e040f9ab75e014ebfecca18b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1872 zcmbtUc~sL^7ES;~6N2m!ESn@j3L+Fn>EMDi2_%FRk)<&$UMt@Q_W82m}I$dJ%juK=}Uvg+kG2G$xbDX0y3mF6T2QKEu}5 zwymvgY-|iTo1UH)2n0f*P$H46udi=yZEbIF%jI$+k;r1P0Q%hAoJb_v+}!Nz>jU@; z3kz#&Ypt!Vf2CwHnWm=Z(9qD-)Rb5(_Vx7zWOH+Kfh>>513aJ%gTb1cn-K^^PfrgH zhXY!&v9SRZ0OsiEsD*{ag9i^PD=Pv0Cr_RLR{&E3g@4UXrBcnz%m7+TON*tYWq*G^ z8jbGm?yj$|9~>Oi(9i%wvMiz9{NV(Gx3H( zX%N`IwYIJN3?tIUno=1r*;M*1ZYXt%Hc7hKwg|5GT!WU%t1t!w~i%D;q)890J zWB0RyjIvD<1MV3Nn!k30pEFD{%{dS{|eii`;m}f;qIaRSv%ujxZv9)&y$YUWVayNL?j-tpK7in5R_VbFP*3g-} z8Xt!vvt{-Uh6T|-=yI0$`-h$G+D;@oqNdMAj1^>vUx6?CxWU=0>lIlygH>9}p2cAx zwYT(rwJ;js?{+{t?JMddL7=@ZP_x6ex2rmzkVN>HSL{40J*h02nar41DWh6VoU#do z4CY78x9m-rcIgl~#az2Fht z(JHo>3!;cqZKDh)tCyVt>%R6cN$DnAy1x^yVJ2A46kWMa8oc_Mtnm6;vSpcUg;-03A zmWm`_QxqIpWVCQL9Dk@L3xo)3u-NGc&Yr;-Bd2Jk1*+7#cc$bm$QemF_6vF_W+R2J z^_Ke*SBi3`bkyqVB8R>8s?d|j*n;+?ZyRjjRtr0ivC%|&tzZ#pubYp0U;3DU`SP~^ zJ>P);#pI@bei6R^W!K{@|51Nvz6fKUW|BAAS=nASi$>*(g+{Ns%j9y=VYD zoojQI*_-M;{FHo*=>Fr_y-zV4yD^8zFwWxd^)+F)4iqt92g_$lSk+f=+%IzGpR9|p z^*>kmHJDt~ZEkPx5$|!WtmAx1|LXIJ!noOO0yfe?Sho~YyiStjc zx=z*G%7HWJu-8kX-%>|k$Q#{sNg~GppT1d0OhPiE*NBIH>@w~%3j1nMdLl=0CHDPF zVfeclefgIg#DneCdQN__QTE2GGX{w6pp$#KdbWK+gSG;C^*DUF)uEr~|8rfjOZ%jl z$G)>fuT};-9Vaz)+9_Ovh(ip52>Vldl$U7?CnIo^!*2W+y!erfYewvyf0)uEU%4a= z=9f#p%K8+Ivt?$~e@uX;H8PNW95@3@C>+Y@Mdqqs*XCT3wBJqDLLJ{J6%{d>rrPdi zwoZOzuTYlKFRD=Z5f_pc4N^kLajW6+QPRiO-KMb_Sm$_WbBdtn!nGqWjT&7}p1A+- z@qs-^M+8Lx4Wh(l?Sp}`x}d*o=ZMJuy9-G}aiOixU-;{A)sXD1;YG>3pv~Z?^rs)C zze!v^f5;=sE=>zHRLbi{b-x|)Crk3s+8MoWH(8CEkRbb@2KScX!NhN99oohNgMSv_ MFhq2VYsjrX04(g2f&c&j diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationWave@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/LocationWave@3x.png deleted file mode 100644 index 4819b3c862f19f36fffec9161526ce5b0e5c91c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1252 zcmeAS@N?(olHy`uVBq!ia0vp^d_b(n!3HEHo@hJ=Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS=07??FOLn2Bde0{8v^K*7iAWdWaj57fJ{tG z$}cUkRRX#c;)UD-xUqS~&|m@vn0`fKfxe-h0mw@*g}%P{mFDKcRTq~8r6Sym)!^cg z%7Rq=pw#00(xPNw#HA^NtSYc_E=o--$uA1Y&(DE{Vn9ZINq%ugeu09sGbq%|6*PPk zlQZ)`f|_7mzP?tTdBr7(dC94sF1AWQbM!JZQ>={4%uU_gTrDk)OkE8PUCk{_Eu7p; zEX>S}4UCOkjE!M>UGkGlb5rw5V0u#!dL41<1to~w0-((6`UmdCEizNFNUgT=Ozl9@nPLJzlJ)Oq(g&!rwdN)>>GD+TwFsWrvvWts5)LI=u^UQl{MkNPqE~)HN4MZ&psj_P zNkSHpo_&8@{PMOn9eu2-laBmN(nC(30;#C z{?wzloqdNCzlEt#*188*Ij-&zie~PV=#7}2V$j?3#EglNiHBk5(Uoo1>qA$8${kNv KKbLh*2~7YkwW|aG diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernConversationAudioSlideToCancel@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernConversationAudioSlideToCancel@2x.png deleted file mode 100644 index 4eaca6a59020e74d3fbbbf6c27dae5b76f643373..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 496 zcmVk00001b5ch_0Itp) z=>Px$s!2paR7ee-mO)O!Kp2HPe}Tval(i@D3?#19#FdL`NQh~aLx@4|04Tefa0wF5 zV4{bBD*%~sUg2-1(oSdEgmk9q`{um|e?kz{xW*q}SNK3GeD&jLGE_>AQZa?sRX$Q94CZNzk zRc;e-)PYNG6OeOolsgDk%|wN9F+hI(_5-fcW-t1OUXRk6Z^3 z^X1w{p#wl%`zQqf;?jo|07z9Ir5!-bm#vRV2Y}f6aB{#-@Y9w%xzPLcU<$>JlLH2z m4P001@!1^@s6G7~a@00001b5ch_0Itp) z=>Px%KS@MER9FeMm`_RrF%*ZBRG}7KxUpU9!V`Fb-a!S0LKjl?4pnIHP=ziE!U*cp zrQphIbZ?h}I7)5C{6okwyjQHwB(I$Hz?{g^RUm8AXaD&OPMlCA`MjvPr1oF4vvK?HItygM#I&1a|E^}F}HYd)ar zHRM)sH>1z0DKikc5^^SUByuafLuR{eJp);mp9};uTZW$;1R!cZGa&#``YD7^`YD89 zHB^4)LI9%hvk(GMs2?jxs2?i`RukgK8Um27A14SvK7O1bK7O1bSdFV6F9<*`e!L+7 z+4>2B*!m&KMv!bQ^#jgaKPs1-u#dx_?E*kwMSjpv2GM?0In?0vetq?U#EA}yQh(^g feTh}>@V)B?eXN*y$P!Y>00000NkvXXu0mjfaG4a+ diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernSegmentedControlBackground@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernSegmentedControlBackground@2x.png deleted file mode 100644 index 159b99f7c7b01b694ede5080b4fd908c0d0de05f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 294 zcmV+>0oneEP)l@d78cHBif* zadvPs1wCjT*)P(Tj&$0nc*0ff4fN7cO^b$$B0yNs(WuqM>Hwi$KIrlbga$n#6rl)3 zC_)j6P=q2Bp$J9z_reHIvj~sJiVG7UH0$SW26|vYzC)G+OGg%AMBpD{)Zh#b9?5~Z s+8ts<8?(6Ll&3#I=aF>G)pM;AACc_sSMU1)M*si-07*qoM6N<$f+5v*$^ZZW diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernSegmentedControlBackground@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernSegmentedControlBackground@3x.png deleted file mode 100644 index 90b1d048b206454b8984e2c18f52a0afd5e63279..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 916 zcmeAS@N?(olHy`uVBq!ia0vp^azGr;!3HFS)4zf!#^NA%Cx&(BWL`2bF#CDBIEG}f zzKz=GClV;KH{Z?S=G;Rz!0Ls&LJ1H9K}A!{H#mfW3o4MovJ^mIchcWo}C^ z>l+9Pai@BBv!}SGA1l89X3xyKsZZZlb)MbLdFJl!@^dq*pY6T=Ch*Jlh#QuEg*I-P zR$iKOU0w_PTg10L<4X3DjJZ>)oHKVgU2eW_{bf<^`idR4KD$rW)>QK@c^Ier``VPQ zi<@0)5Ayhim_`4--T8dGe&VU;8E;G?wU5=!H(mLG%Qrl3s`Ttm`4^r(mi?OErC+CM z#4g)V-@B;Mch|azOW!JHxouh8e^GC)YS8q;^R0_KRS)d-y?k-;o-lzAOFTCvd5YFD z9^f^pKQVjvu5&L16Lgbu=bU<%{3*d^zKyckdy{`XZEbt9diz3-zg+g~qG)9H=f__( zu5J(e$PjR_W!b+EJo`T%sCm*lW%8#bLQ8ng@Yn6IVw-uLm%sRrSDHomk?3dTe?_h1eg3dODSL^mI z-Ik*_*F@eXaNFD^o-!Y7Ha2@0>BePA%E|`pxx%M(a!bX^)RGd1k3rTQDwiKEop$je z<5BOo3X^=gr$@QDvy13&rILo9>x0Di@qH_j2{B2|p0^`y=a=)3+;gHuyk>38{?q-l zt+lWG{LL6E&E#g`Bd*78#Gs}v;RB!jZS`Sy-5U{$c@AbQ}d~!+qC`_`S}Mh*^4h-+Psw8UOZoNbJh0` z#e%*U?`9mdVg6?-TwGfATWRS>?v$YRPP57PR_;mpVdFK~)GMbj`TW$N?xR`fZ|~kQ zYwn_X5^KbQ+%o6y=(#)FyYTQF-aWpXWrN+e{FHZ)V_fj^oWxdOHe>K~^>bP0l+XkK DzGkDn diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernSegmentedControlDivider@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernSegmentedControlDivider@2x.png deleted file mode 100644 index fedfad1d89dea00611dc5df62c87bf48d846e9ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74 zcmeAS@N?(olHy`uVBq!ia0vp^Oh9bK0U|~J%5Mfzf}SppArj%q2`~P#I4!=Cu!zC( W=i1)DeD;e#Nd`|>KbLh*2~7YuEfWU- diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernSegmentedControlDivider@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernSegmentedControlDivider@3x.png deleted file mode 100644 index c165592d51dc22f7e6af82247bcec86ecd60a2fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 105 zcmeAS@N?(olHy`uVBq!ia0vp^%s?E@!3HD`n*WajQjEnx?oJHr&dIz4a+Ez?978Mw zlT%*&{W71CYeoW(fbA(s-sX!X3?~H_S2l80GBPw+G3&7QxV!@@XYh3Ob6Mw<&;$Sm Cj~nFx diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernSegmentedControlHighlighted@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/ModernSegmentedControlHighlighted@2x.png deleted file mode 100644 index 84fc7c3f7c19daca623eb17e99a9ea927b15e905..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 294 zcmV+>0oneEP)nM5uyMUeu3>81bgL}p8$My#EJ(80gb^ON%*+$kYJT$Z zTpt;z!3YdkJq&C0tCvqmbOIf)u3!htnUgO|!HrEb(4Yb(P#z^~n!PJ$Q&-rrFo81% zcVX|u+0MN)3uagLrF5nv+k_3jFaY%<10BsK9C@fBgcTiQ;#_PVAPx&KuJVFRA>e5TDxx4Koq?*11YjBB`6URk!a|76np{^kDfG?ASJ-kA`v87APPtn zpin?6C;}+?1Pa0jP!K6dzzRyNO#!iobH_Wj_rH{qNL6o+t1Z8b%q;?OJ)h94_mdKtduc-{Y*Qil{x;hgT-d$S^dkV?-c8tZm2CQRII%9YG6&(%V=T;*?JEgQnB)A; zwVU9D8KtVdi9Umx8vuvlR#fy#)Pd(pG;v!+fC>-`k2obFoGBQjPtqyx6 zgosuP85yRDR);+jLPV>Dj11F6tHT}%A)?hnMuusk)nSi>5YcKOBf~V&>aa&bh-kHt zkztx>b=V^zM6_DS$S_T`I_!}UB3dnEWSAye9rj2F5v>+7GE5V#4tpeoh*k?38K(KK zR&!LQJ&@%X+vwm>yn#x_cB zXlgR%HN-iIgu(e7&TI$|t54s*+FUYxl??8N~%6lBv^d$Qfxo4zaqM&LGP z&WFm%SQRTiNaiU+o(rKY_Wqt0%fK4z*Vuo^)B{TCQ2DvxOe;G0A{4eNqjN2S@i1E}ywpaHZ ie(l~Y!=*QWJ!4w+Px%Qb|NXRA>e5nmbOzKoEv!cY%VC0}xRl(Qp^UqlbnbBH#kR0YC^!5H!#SP&f+( zNEAE{V1)v(mzgytCdnjHGB(Yu6vdvM{J-b(?lu_%{l@Y848-v=c)tK1<}h^{KUL-@ z5ys!Zzyla_2i`ScXYz%~#k5}Iq*a5DWFKeO(bV-y85lDr#+-8)w|lTzdF{;aHa==C zVU?Gd$W_*X0N2j7gc2d=)%u9!48^uXe>$DVciTj^#5) zzBUOMyOLF&nuK>6--o9g*`TjL1QTwa-g%0e7LqJp&brS$cV=kwK!5vP*HPa#N&!u94RNLs5vs?aYZeTloM3c92xPr zq83NW2`XxijCfp8izDR(6*WgjJg%t4k#d5Hnj<3~SJdK2IYC9ukr9t8YH_5TprYo; zh{qMRI8shfQFCO(1&0n`ZgOrfI>sYc!`$q;dv% zp{IrVeV1yIK7#$F%0OGT!})aXS$SAZQzg$>kpZY^snYabxg z=w)H681qojHf&XHvbwr^w+>s2;NvSykZLB2LZvxVGH+L$JqlG$Jy*t@jPx(R7pfZRA>e5nMr6BK@f%$#oa^$F2RMk;f5IS5DyxZpa(@z1igp|;*y9GH$)L! z4hkLwkK#$a2rjtcC9Y`HAS!A^Pl`qpLl8xY3vr2G$uty6&wDfTW?r7s1wUO~-BtZp zy`H7#<>fhX6>t@B6>t@B6>t@B6>t@B6>t^!rz_Cj-d+tpfJ~*002e{OoGl3C_GX%; z#eb76;chl#Hf<1H&3e1Cxn`HHMZ%5h*SUn=D=Z;=R)OCt&O`Lv+tQHg4t^-2vm+$C z7Jr@W1Nuc_<790<u&+SMS+h#RK)LKx` zah_j4-)|tQoy8?)87KwAfNZlC&Xg6>kXn90u9fL|Xi}+yv-m!sCjR{L-E7$f?%P>KNoE10iW-UswV-_5?a}YE;U4$5NBhz>9F`33p zcHQb4Sp8+Cr;xY0bC6)8ufl43;c6}nE`}c!cEMFRkRRZ+EVP}$g`NoFCN??=27-Knr6Q>_|tQL8L z9!nv86H7I~;(HVsQ9pu(seFQt5oaj41B}RLo3fz(iOqw=7GREnhTKUMdHIMW_{yi6 z1{2I{mqiMegcF1o0R3@XILcok$3O)Lbns{1Bya|3k!NpJ61-EzOiLJ2@)yPduoiTj z-+=85xDTF#51W(H6<|7$L`DI5-IPaHGmt~TYfvNbzHFd6 saTRbCa20SBa20SBa20SB_&+P~2O}>c7`?bB_5c6?07*qoM6N<$g1cG@00000 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintBrushIcon@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintBrushIcon@3x.png deleted file mode 100644 index 50e06961857ecda50477139401d4b0f00f78c322..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1804 zcmajg`9Bkk0|)R8vzcQRmdx$JsFZ8Ocv!Bn5PHp(d+z1tam6fiC3kL9c~BlljICy} zh{S^;b5)2)jp89`^7Q-z-|r8f&-?ZI`~#nC2RkcKs5BG+0El9(%^iQ~_Fo`^zuKV5 zjPDn~Xh$mypmj{ zSL8+=xQLzwRTS5xWJ_SAu=JuFB+r3bg8claV1`9`-6=~qhv0JQA~#Ay0_$*ksk)!$ zsuLYBR(nBbtre6S7{Fz5=8leJ_dd^d=92|0D)<`G)V-nQ{~r-=(7}%%YNT;?a6#jt zMF-*Xt9WzC+xJE87Ju9d^tKWHVSMl2JwN*G)bm!~xbA1kD@*YK_ z*}E;l!xMW1HP0{Gk7$v$^J05}q&BjKz}V4Ja@>iisV%@|*o-80x$DZ+8y^LHe5v)H z$1EXE_U6|`Z_IY)4FrEOMC!nkCGSqC^P=ww)Ona+SFUF<%B;HN9SB)kg2{>xkbCEP z6Dk$;_% za>&X-a)i|9HViy?dMA;Y>37j`q4PdNZlPXxyUjuuBToQ93P>?HnHEob`XD?~IRT2#9D{-K0SU&}25(I;z&Ep$ z)nogH6z&@zKglduZLb#VwSR$X_}NzCg|I3&>}P|u9;QDNe(wwKkP)Ple<$P6wIjmV znSD17*|5JaNh^UMmGsx!CY)Lf&qv|CPYJOx;sOKV0d7bS?YrtNRPZQr!A0)-DXgwC zrN@l&x28XFg{>XzzI9sm3Ft-&Q~Ya244!2+AhfHR=BaQ_&Ig_pXbY7d2U63>i&hGq z`S*{1%yl;(Y6K<(1$T=#;?_9Yrv^q8*D+G-$FhkXe`OswNg#Bh1 zQL0d}`A(TM^>A1ZF2E!ORNSojtw_r~$#ifG6D2tquWg-L-_$b}U+azD9u6Dml4Tnb zW5p(4n%44KuhytsE*hS)uL|@kBD}4C$TF_BKJ#vkVkA2=vcZWPTH7t!2SXSZLK@BK z8Cq0~J>F&5ks#Nw`n9{Q9}J{oMiM(hnI2Y_95*@FdCi-Iv$QjB*L>XMxG<`f*OUxb ziI!X#$whNsz6hmayy}m=+|>QkZBp|)Z*@-SzwsPKhb0Zo7M4{CWSFe)cRZe=Wc#_Q z*ot#;G{km1nW&vU-q9KkW?eyJxY1nCOCT=<&qOura`>!kh~hJ z6(#~qB8Bek_*yJe7gju)s|ed0#oy4!5*-!QndwokX3FCPo9nJY(rYzg&3u>u=)Sw+ z!8OkmrEiWZN0grJz*=zBd-k=A`h`oA+FJmj=i=Qz4};{s>x={0!;40Bvkyj%94?tg z5od}@(L_5cp3Yk#4X_rG6S!WDHEmQ;qd4zQjBks4!`UppQx&eGAa_Y$J&vMX)Q>Rx zR!(R(zf}Sx)QJUen)bFaM8nXa>Gbv%eu*nMRNZLE`IyPq&sCE4b=}{@eCgru!=Nhv z2@aEaH}2t8fj@d4t6X5j>GCreTzd^`OIY8>l;uUUDn3Q`sOCW|TM>Oejj*nf&8&uJ z=hC0$NQ*b(Kf6f9ww#gX6WLv47)4oHx^X-54FDk23=7mXYOa@m;o{O19O%quV{?WP019$=xMnE`|HwD1RjU_5YwIc6bLVP3=Ik=OHPwg{Y?%< ztb1Okp>#;2aWq+b#wXR(sfAh?@RVbXYVVGMehyAsRWs=P`|zoGsK3*QT?9l1IK&2- z!nq)AFxAO8DvMTzygHCb=Y45piLwJpO(&&tSXF1dOOxUXKXj+jcyrEi`I~&Mm7^$6 z&}y|><8gc_8KAUJG~Ih^@wXk)F6>iK;Ydi`U`xA+c?HCO?DX$OlY7fcw`fi!*ZA_u z*bJ4*cE4VR-S jr#^}E|AQcT&`*Ahe4^N^*ZgmO-5UUFVQ1co@lO92Ovy_s diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintCheck@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintCheck@2x.png deleted file mode 100644 index 69d47f8abf8887a26357ba517437e0823252d3db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1420 zcmeAS@N?(olHy`uVBq!ia0vp^3P3Eu!3HE}2mdz#Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS=07?@QuLn2Bde0{8v^Kf6`()~Xj@TAnpKdC8`Lf!&sHg;q@=(~U%$M( zT(8_%FTW^V-_X+15@d#vkuFe$ZgFK^Nn(X=Ua>OF1ees}+T7#d8#0MoBXEYLU9GXQxBrqI_HztY@Xxa#7Ppj3o=u^L<)Qdy9y zACy|0Us{w5jJPyqkW~d%&PAz-CHX}m`T04pPz=b(FUc>?$S+WE4mMNJ@J&q4%mWE% zf_3=%T6yLbmn7yTr+T{BDgn*V%gju%a&)zDGqZFxGch+YGcT7;+1MHoK%2WtOF;xE1B+Du6w0m5JLeCOFN5 z>P^Az7E_#h^?{Dj2SqJXRKtXT=?BDwCtM&0p7c}mfa$#mn6NiALrL#cu8BH1 zx>H(PTYEPt^tXJpF7@lZZCjppX0GMe*LN)M+dlt4zxw>oeXlv$n%iPO``Alt-15L@ zUg=)5U5qc(zb!lFtIWvzF>V+0iw5PobhR@KNy#PB6O`ItJ#6`SXNR;y%CtPsm?)>v z0yi6LOTSy5I{TdL9~GPzs(z>`$F}Fw#B%F9mz#eq+fi`aVb-0Tv%3y6=61-hVl?MX zX^z<8Cj7sV?TEfJ`(2|6{EQk`kL*9t{$s1@gSN&b&A0`f^$wDc%F7%t7v<~;?E3xS zj^iK6u98RfJPL7+<=*!t7FGz)aayPLkE6B2`dLZ;3f7=M5=9S0qaGYejI+*hUZqyY z|FmO&%Wv^zt}(Kz8)s*m7PBSZcl^WVr6d@>KEc8zW^2jWiL)9^C%!a!9qXvN$9-34 z3uB;;S#FZ#q9VtwXP$oEkTCgrsIdP=KD)&?kE->*ioTL@ssCB z`}3oM&zF(g{63v{ g>GS?u>lv6CF3s;ac3{`uc2N1~>FVdQ&MBb@014d-Q2+n{ diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintEraserIcon@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintEraserIcon@2x.png deleted file mode 100644 index 20d8c4f293c9d894d377876e42bae582126cee9b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 749 zcmVPx%r%6OXRA>e5n!kz^K@f*;RSfPlF)Tys4QR5(Q(zmh8`oB7i-TYb~Lbit4AneM5ouV#0;XW5O7YPABj0;wv{G|kym zzO(WR=uLEpexr}*aaIX>CIj4U^c98n%rj0Fz98&^RrvLRZh`&8x%+4zSt}nJn()pF z>@E4&(QcxBWUX9iC^}*Fd&ZpgfR2G(8|X2x#Y0blEf#te*y5l)V2gqFgv}m01#Gs^ zz}`W2Z!9ka4>Vzq7JqH)^b-%?qkOc${^6Y15?vkTY+y3}Lg-`8T^YE{ZlfC^M06f>AF-`-by}5nNREs?T&Xu ze9E1EcM?Mzw>vv3U!rd#`!REe#{WFu*{({Ygw76Di;x03Ti6uP*~5B57X#}7Jtyo! z0j9JhzRh*7k*=G^^be4%tzCARfxBk#bk|uEcv4rOkzKMljJA2!*-514BJi%GH_@0) zBR}81K%2(RsdQKRNQW5$aE)^}P~YE=WQ+Kgt>RI5eLb!fs1>LcaH#+fqdoK!^W?uc6kmS9h_UBP>f1fV_((ZNa+4gZ)e6)K)C$xJ)C$xJ f)C$xJ%vOQFqYSu00000NkvXXu0mjfy0u*= diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintEraserIcon@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintEraserIcon@3x.png deleted file mode 100644 index 5b7b7e5bdad6dcfaf1266d261f305155c0d212b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1036 zcmV+n1oQieP)Px&#z{m$RCodH-M?Yi=+*+fHpuEt>=0;AWMU71`~|9;h_9+^WNz7Q(1GUKT?q1qtOxlH zg4k_P&1Kpm>+6WE5+2zXSyxSLm1vPek#*I?RtZP$ima<9wn|uXU&y*@Vyi?Y_l>Np zCbmi-4~48<5IX`gu_GcEjXm`4LUGMp)NUjdvZ5D(of^3a>|Bs1jopC!OMaadAZC_+ z5p`$%jxcXL*I7}l>r^LZpSOMdybu#v`$E4i>@8g`>x@CPK|Ytpj~uagvj&#p8j$~~ zu8~t>%at0l9cK-VYF%5hTp4+W_-l@8`8+x{`rSZCU1rPl}EHUC45ij@%KISMx>I>QiAiAkSqyT4Odj6j=ul8@ov4*w{rQ z$HFGEN+S=o8zFK9Ss(U|O=Oj|20w`i7ZGc{3*iLq9N;>g(8~HjmSxS+gUiNKhHm_D}&pUDvcH$xl)e{ zTP};)THeSqI8=RXseDrho+6_j7q(e${>V${U9)mLmkXM=Qy^=f=)Vp2IFOgnTNY@U zB-lx=URSW?N=@BmvGE`;p=TJ(5yIAzVWSw=N&9gjSGJsW4D8e z!7c(hHFizX7|#@`4?Z`Z$BtqyOFNaM6SMJOY9F_RgKr5 z;CX)c!c_;J;xSOx5YG{R5M7$w*1Lnam|`5EeGc|vSXU5$mJvr&Ko6rcbFC_n)UP#~2+&~Y@5g|DID7l^xvwN%AN?pKcE-ypVe9RJC;?@;L1 z=;*$0XA@ce0MHM7#}W!Hr#a=cWr^)4pfCFlJoHj%% zj8(=gV`rlP1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CXBX9<)9^(i}cu_k50000Px&Oi4sRRA>e5Si4dcK@bJ12#AOzgOnI^%=rMw2ndWUsx&b11N;DD3lbyA#he^s zQp_|lGO)_Jp5Ahn*|TT&?(Ch}ht5<@?ev+R?$h1(?xWY%^2iy;8ORy|Gqlg=h zVf*`Pe>NBbxWX)kBJK8Yy;A$Lz(9Tv^Op-ok#>83_4brbENml|Az|k&uuXw0$n;Eq zUIP`{!Tjk}tnEMQ)J%UTRivpZ`UZrz0!f>`otwu%RkksIxH7q`V(<36tDW0cx~pO- zD*6hf`jWMCc7ECe)!4%P=2fU%D(2;8bz$d2fA-3J1&dwLm$3e<;vrnH^JZt716A0> ze5@AdNm8tzc55rM)AiA$OxLiO6+MOZ-I|AffY~v7(;CSB2IfPpE*_v5d)sPh_F@)7 zQ3%68=!BS-uYL|!7TsRU^+cT;4Fl0TB6~@4mp3CmV)ET+L9t_yIU8 z>~j#{F|{%{ndep*u6m6~u0c+-FCG@Kq{m zrf!_w!LM*$G`%RGGV_G58mO5Yr-=r~Mbpa*sPbR(@M5Vd!8%Li;hSh6R5rala+SNI zhZoBTfezn919N^()}D6>0yUGDDq%@5INQbKH=kp6W~}_d`zHJQ9oOd9-ha_!Yb3;jBH4Z{A{|5wN#RS*d=^KU%T z3}jg~z0RAwaaEKa>jcQbO|+1Ta?|TO$bV1)41lF+q9N0&>GiHHAg+$mWt~7deiID@ z&WXg*pAPBAyzBa=8~-{gv8@=as;1Zb)?BJEidpz@i>b{hkQV(W8~4NX9v8{Y|}EK|rC o$Qj5P$Qj5P$Qj5P_@^`Q2X43U_V<7{`~Uy|07*qoM6N<$f`$0Fpa1{> diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintMirrorIcon@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintMirrorIcon@3x.png deleted file mode 100644 index 2c13f50e3509764816ead4521f388d594b096f4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1460 zcmV;l1xxygP)Px)Zb?KzRCodHoI8w_MHI(bA2Apcj0O`-FmVegq>x4%F%e8qqYx1kgav%?kcYDJ z*2IJc3<(t4Km{c=))HE%wZ+6j5(_FD3$p%>3CX>8zjMENoO#@vndA%m&73)N&Tr0s z``!7oyJSggjX)#N2s8qXKqJryGy;vlFoA`Ig=dF*hVS~uhpo%pJyvE}r&SO4Sj_?W znI4;>!&Sls+S5?^riaY)jDOW*Q*^jWxDeULwcLTsJR9+pgIy7m>fi$FNk|-bq_G0K z&mC>En^gxF0=v0ZdXPBDhCJ?JpUt!?xImJ4PI+ekGWMT(&dFk46)2TE=kIxAa^CnV51Yd!*m1(+RjO7V z3$?VQLZ&%fsA+CS;nzCEsIQ zqBe{+`LJ+tw6mi70~Ch2kZA^&;6xWYqyW1?)yl`+TAOHWUt0%f2A9C(Hy*o$M>&}J z(K_%1{*F>0rb4C(T!NBEfjknr+D)qVx2}Q8`sA^2&@v_yxCAs#c)Va4aAIHIQYi8R z&ZI@dC75x-<1MN-myBZpL|)0vgv@BT1T)9AQpqf*grkJu-EH<8nNe`5TA8m2k9Vos zU%gW+KVg;-wp)Y|1(yIm;;KP-v|usl<1B>}Eo8>R)lQW}c)U3n?Sy?TLguE}n1kW6 zv+uHaO~PX=i_!VodGx5AdLIlIkJ{pYFjhi%RFe!G5Fv9z;N1VG1;J&}bR(A(;F^TJ5G4K%sa4p8KocIjY^SkrF9jy2 zX3ov2a&fvGk6$`_olZkJ=RNL|niE_c&U1AMk3MTngRPg4>G}ihZ^)dhjLz*s@yLIA zk=M@F8i7Wj5oiP&fkvPaXapL8MxYUB1R8-xpb=;U8i7Wj5oiRagus8q4(5~tL diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintPopupCenterBackground@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintPopupCenterBackground@2x.png deleted file mode 100644 index 54f036c022c9fa461932a3f1ecbfd0accaf665ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1218 zcmeAS@N?(olHy`uVBq!ia0y~yV0s5+&*ESPk_X@0vN13)@&)*Wxc(mnNFne}Gdc_y zKv5+@e!&cCsZ)2~`}AM8?;)etQRCwr{eM-@TfX)DYOeBz{oKSqC%up8bwANbpLy_p z#?v1Cci$Z+oJgCt=gu#2tGvxW1WP$WWASzJE8pEkUlc{7XW%sHRujK!a? zD$JOF+LpWfs!Bx63Hxc&RtIj_GiCo8lRdK2!aucN-I^t_X6>`-UwgBpa@IUwel|-c z=UMy7FjKy5YCqF<#GY+_o4D_m=8FS<`)=vJIFPsRhW3j?ag+Ww>Ag|6)Oc~ou_)p~ z=V2Mql1CcHS?5}u^K?}AD~h_%d6|dH%Fx5nJZORS3%*^=?~tj*XhJs1tY|7g>ZvJ| z5^$l@(U04zaMt7|zd28KED%0!sr}+eBp*;{#vJjIhc+i&9mVw~#fX(WG>Y%xwlX*u zZp|ut<7D{Zw^?#I{GZRJtd?Srp8RJ+WN-7?KPGzveVcn<{xK>KeCBs*@0MPx{mjo&UOwYlsLWT5<;%l)8LFyfD%;|% zcUS*@&CXSE>EN$__uie;KbZdUC-cDx`@A$HKKwos-B6I?8lR&oB&N@_XycB39yVg4 z>zRa{e=#|8GTP|Oyp-;(%KBm3Pv+Wb&6SKc>+2uS%;q;xuwCXa<;|Voq_*1sL>h~M zlKJZXS!X#D+~VY?iXWI@|Et5EDdLgX7f04`hTtyMT8EVy4Tk4t+{->Acwo+^d#iOC z97XrKyE1g&S#>Y4l+|G6w)NZJTxT&jwemG@sXN1Fsm)bqbDS9t&#LkbX1MJ3$ B)7k(4 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintPopupLandscapeLeftBackground@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintPopupLandscapeLeftBackground@2x.png deleted file mode 100644 index 1efe4aaf28148a8b38818bafb2ee43c1080cbf0c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1083 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8I4M=vMPuFE&U}5rfaSW+oe0#(A%hPfZ*N^!* z(pOh>=H6bp$f!(ob9e3*NBP^^a%VsOnSDR$&CKuj{wCI6yH#7fDwvI(ef6DFTa;zJ z#V^nOVzAfs{)O{j_`e1|e`)`#OK$n>mljg4OM^o*b5>tsEYY;}u@5kP8NI8`Y}IFm z>C2s8hW%>zwX*Ju(p&%TD~S!SFTMPt(W`EH{PY%AQT821vd;cN_A7V(dKne9i;MYA z>2>b+w;ta#P~g`q|7ejd~00JvKk)*#7bh zgZN_Mm*SJ2J>!?UxRUXmL;hqF`+JL)ilsGZUy?O(xYV?x&XIkGcCGWJLoXKVK1*-t zzI618dyx7bukJIa8NwI+_I$O4`I*@P(-)$Xc0FvhMa z6gGHY5LWqmh~Jp+gVm&}%)=)i-@e&w+2}XJ=79N%>q~AY*X#~vdwEmhf$S8=Ush~C zI8!J5>t^g*EE2S^Ub9!`!QLrud<87Ni$sbVF0KT!4R+1Dbb?XO>3R^C<$;rPoolB! z@fldn__q+G!0ij`(h1Bx*A^_-Y?VpaA`$DW`Gi5e+@cpMYYCDKTjUOrz3T&(75W+o zH0p)MEC(QWv27*~NYS@Ng&>1(%~u22^Mb`onO)+pN9Gd-@#WJ&x=rRB14}RgC3f)q z^#Ex#2Dw+uWM0q-Mz`<5QkDlUg9N^TJfI6wrm}P*v&u=vQ;c4G0ek^P4Mh!S)!8-J zH7p%09bm#6em-G%%AkrYY&KtJfy@GA;RDYmGf!cjf-HQa24vnOWZ~KVFl%7K37=us zfNci}=hz|Jj>Ay_x(|Sk@>j@=QvX)eAU(-sEpM{K-Z$)%4)upr*&fjLDu=(%i}(xk}d z^~mX#(^0988?GYSOFT=D9d~U>ndDjY-m?5w+Plv+E%ImfKA-n_9;ae(iQxf_@EvEB z&HO{e|cmQ9`YQ0RWZ!?S6Zw_ZFiu{OGQ_MFGgad~|4 z`j4k9X4Na666^YCtFcdSQRriKJIyDYp6bC9`_b&Kbp1}d{!kYG(hZ){| z41IT$&w>hSuTkR>8T~UTTV0l>SXE4qeK- z>+rv=_P5l&oZMnrI7hdaLHkz9JEiq&+4d~+?pwEc@x1))YL>rSw@+i97obwU|I;y{ z2R(9vu}_b>?#t6vvfj&KvBKrcqpEn0#?M|Z--|gK=a+cAaCpEkDzr<$?5gGa|LgBJ zv3Z{5o^dUnY1!Ak4VtzKoexae$KiP3hntxFQ=N5*w^(}Cp1STmJ966g_L>bf)>l83 zcF+68TYLI)zxFw2mNQpZvN_AGO3CT#my%xer|Ld^gTr*_t}}Jd<0A;j^|4x}_lp zw%ijnSUZ<#*;d~JOCJ48JH#Rq;K1nXz{m=s$t1wqFMv%V)&y=A8>Ks+*&Z|Oo?0DO z-qF4L7NfDEncph*IUVdZ?zRc#9sL_GeU9bU4AituQ03jw+ZpuP_k!4^Mbon~f3Et{ z_C-Qd_ko9o(yf^~s`piHI~!g+*?j5a*-L_5-FDBsj+(p2Ync6-sV{i{VL;8E_(}4g zYQMESb5Rf0J#X%so)NdDcvjTuM^`15*_v2a?YuXs=5edeY~#8Ip;0-r6MOzW>ECvz z$Ck%%@5`6VBp0dwDZh9$ea=&@?G*+xE+%?g>ly`_0K$WCKSZ^2Z_}Hvm=A2 LtDnm{r-UW|uN$OB diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintPopupPortraitBackground@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintPopupPortraitBackground@2x.png deleted file mode 100644 index 41cca8ef2f5e8df63723a5bcd6ddbb8360d43543..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 936 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8I1xP9$TfdBffjQsP#WAGf*4w*#vqRHm4t%`7 zcAMLVtzs?$=Dy2TIkzQ5cXjbqIo@FjmyUP1qa(|5obOhKM&`MS% z2wUOetZTL6hf~(Adp}BdWC#_qK{wuzz z#V}XM?AWB%hUQ&MG727U+PTQ9OY8HrYg2Zt^n7*q&Z2=b7Tdl~2!jD0`nx z*J#^Dt_r8lp1Et7>_U{1>s?vmUrks%??D5X5&Z(pb>IG^+tbbCSyB$^dIu1DZfIGohPd?-VWd2epDlAs>_W)!2T|I#FZG z#kXq0V)nTH+3PoUJjj4`fZU+KP9_DXrPTPq>5v!^zgRi`kx z+ox9U>Wig|++N8Y%i(!7F;nof+=gyL*Pw67XL|GIWlmaEbf({KS%~Kyp74H-#=Ru-+k=)|K+h)NnFh#t$mL;#AoDLKiK!;NyNd6+va`o*)N}5 zYVati@1y^0hV!n5NxF-38UI*y33dP6`Lt&H;)ucpM_;%7(}>cYYiOI4DWbn^d(New zwIasbKIU`(m}erXSYq<7Lq?{+a+aJtdw-pv|4Pyfv9 zeDB-%P2N|1PUJL`^eMAd?@XTco^k$5v*{m}ht!CgWq*5k`bieofyZ6CDlsSbw$zCK z@K}FKfAVwAA9)*MR#&y`o|X5mE`6zAFGqdGiSO*$CRuJ3tMu+0Xn)D%i&*uu@Uyhv z=Z#jLg8ZNV+w6<3S?y(YsC3SA*7ZA2OKw~C^J#RNeBLJgvy~#i9LV75>gTe~DWM4f Dr9Pwk diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintRedoIcon@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintRedoIcon@2x.png deleted file mode 100644 index 10be9f4ea8acda07ded39b5c773bd82d42a24e92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 720 zcmV;>0x$iEP)Px%ib+I4RA>e5nXyk5K@i3{3QS1UP+0(lg`u=CF`?m=Lg0U}&|Ye-rLd-=r^P?Q zLK7`)3D8kMfff`-iFy1+cg=9`F5cbSz1t z6|f3e1#+sucs$+%cXHy~i7O(deF96J0_1YjADMsuoYReR;oX|25-R2uc-1;c4mXs9 z`r$std=C5@bM(q8`mgvNHV%~fg%tv|>l=e-scUG&Pphi2f8&1*ibes|MXhg8_x>|o z;x!zbU==(93t$e!XzvO7yeNvx7{MoEB5)SG07szjb}&IGh67bA;B(*VT)qSPyD@a# zh)I%laOslzP8N$@umzSu>&KRR{@3I?`UV8~%H0rE9*{&t{sO-Jz}Nxz%h$FY`+zll zf2%G8icI~%j9(2q*dy0UMV$wD+zi_ryklnuk+RYRC;0gsi~C|kh6g$e;g zM&Hz@B2-?}zNlFZ{+gDAP&cblU%ZnM>cnm^tL3AVxA^WQMKlB%M2T2^q{474tMOEa zVKEi1R6U2~H+1NX*fxI%N&auEgo( zUlLtsw9MJYRspMkRlq7>6|f3e1*`&A0joe}6}SfJ#01uFF^FOS0000Of|i+$nuhhWoBLW+@B}dr0Z@h z=2GFNuIHGQK3yVv%HsW< z_6pC>Tv2uVkuA1cA~d7>9RCF6R~D0ZJkLM%zjxg?UeBk%FktX>^>bP0l+XkKbx(R^ diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintStickersIcon@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintStickersIcon@2x.png deleted file mode 100644 index d06e5f6b3cc8bcf74a5e702c53897154fa0ee6c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1050 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 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintTextIcon@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PaintTextIcon@2x.png deleted file mode 100644 index 839068d0dc4bde0b7c9bcc2de88e5f90830e034b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 263 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 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorAspectRatioIcon@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorAspectRatioIcon@2x.png deleted file mode 100644 index c1944b5f66a5c576323c9feb85efd41009f407e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw0wgDV75oXLDm`5sLn02pyVrWV)3Is{E+mF3@;a#E7MYigJ)a!U6bC-?;ZX{>SLlT(`)hm z@(TyPC+l11M}BAIJK&qo$pZ&};&<@;JoH1pIJ)gXW9X5PmzPBQbmKcZUhL%ksIp7( U&m(b8pd%POUHx3vIVCg!0IS?VBLDyZ diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorAspectRatioIcon@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorAspectRatioIcon@3x.png deleted file mode 100644 index e4c5bd9b29043a3f90da9b13447a363b75c701d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 248 zcmeAS@N?(olHy`uVBq!ia0vp^Q6S900wgCb?Cb~9)sZKywc&?6R Z%+ouxZc>rfCZJasJYD@<);T3K0RUZ~WDfuU diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurIcon@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurIcon@2x.png deleted file mode 100644 index 17b1e58928cd6f47232e05bb963f8580de83b7dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 660 zcmV;F0&D$=P)7o!KE`c~XIQXmfnuMC#T!J8Kaf{|${0oB6p+OCE z@&`eRC^%@4B%x1(hnqs>eb3SBazEp}?}z7o?|aUdbF-|HN-8PFu;Hs=j~tbqHsS~z z8Mz9!ytL84F8W+X`V`x!(PE%S%gAO~mX(P%R%CA#Kf6_=$I8f-fi@o4g|lp+7Xm$A zM)nfv^VmzGJq+ypzu7>~2m0YfKJC1l=U#iWNT)uvUcX9Z&(Od0rm$^x^RQ>=UAJS| zI$yvyO}TnazJVomaqx3+;BM|_rvvajhHbPD9!1^sBd~um(eqVbgrBQA3a+*UUgRxa z_XG4tFU)@M!}XZja?(~@j<|JGU@{4w1XKA+8{l3Nd=G5osnmz}Q_P2dZit# zW{I&1+Dk9o2OpE+kKlgkg#j>=49|dp(hFT+E*YK!U8NV=z}IB>D`?9zx8SFmB(}y+ z$ThpddhAJpdm{FRSKwt5{1Uv%SLy?6@gqc)HPDx@R%;IoMZ-g2Pi@}f$@ya?Zh@(> z5_tyE5Dt1zqTnatz}FB{o&blsb2qykf{D1dbj>HQttD5l#WwilTI>R8wguMRDYjvKI?s`g|{K)En?UOua&u77xNP_t-nF|Gl!+JICQz`yfk?j<7X2^jha%uj%wU zEGSlVWET@RO#72fQyv@Ct=pi-rfi=2cG`{XBBS7g^YS72&He-L^VZH^$sKQVPUYNq uwSs5fcyHFM_uhD_5cfx?l1eJMko*RB4_G+K3Z-ZO0000Hlzfv77PGL>y$dB9*GD!M)=Dg-u)w{sU}Xjy zl8uz4q?AziB2kjh|6Q2Q`y4alnmOl~ck2DGXMWFb-j6fSdES>XD^{#nv0^1sf+|!+ zp7I^;B1#)oxC4L)(&oyMqm62!{GweQY0Bo;Mm6r?FZZU^Mvb7nid8|oCK8lm5o>a7 z)C$Tgh-Hj1#9~Fzt~I@~skH+un^qfjg7UJc?A2ZtwChZ-Y&vZpWkWqx|rGWk1>vAFhptV3qx9H-t~w{XS){wmU4^p(}??TTVGF+9(nF<)z@2 zz1mAczg?nJIS*HYvOQ#yUC_Qlo-XBh9I8?FqkV{YJ<_wJ$cCJ4oR*u6dhu^}fjO)ZL=bj=?t@I!{BF#$4&4fIt5}bq^4qjA#;Vp9Z4U*Jh z`#AOqxyq$;@x=Lks-Q9W%b`agcJUe)h?2+Ukee_?n{*1f8FS=uKR9fiX$;nRo$vCnVGirnD&5QL49mmZ z+Ij=Aj?vq=6V8TbJ#U(+LUd$=5>lyEJem3tW2A985xqPSX#*=%pq;kL&jrMHNZA9nXqe7 zwv(w!n;K*?`B&`FBHcj-zsahgGe$F`cnZWALmX+!X4GMwWD3-;T)Lmoohrc|vhZap zRn8=fok#7_$RiuiEp`1K9M~co=RDOXafF=2X=T)DLLE_mhbNML59m_D>>|V?BvCw-F*f1urelmT*s8DJRsUcBPu_kavna&`Zj0yqZ z1TI7eNpRsrV9W(a2t_*v~8=7 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurLinear.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurLinear.png deleted file mode 100644 index 12235381179eb0f283eb87ed9797076b55aed88d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0D98VX=kP61P*N!tb8}K+>oU=zn zP9U!$ptAKmQ;CPu&-Y#vpRDR%=OfhVw83rZgl+6EZZ5hjr_iwH)mfe+-xvr9P zIQW%$P2pb#pBs P+RNbS>gTe~DWM4fB*;OE diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurLinear@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurLinear@2x.png deleted file mode 100644 index e3f67c444953fb9903be091cf42c3128e798ab2f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 276 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcgZhN{ohEy=Vy``FTG(d#m;_A3B z{b$9P*WFE&+#a-U)~Y7$yYh1uCou_s)ll)A1Vl^bFS<~C#@6zk<+9~RA~JTU-8VfO zQU8C|-yI93lov2Rm^#lYDB$vEE(deB1BMLFOCAX{JT_#CV_cyuYRaIW%);=YaPEWG zo3{xkI4nBLE^%PKWP*bdGmpUm1_Y6w!e*gvmT-_!Z@u(}FSeV0KYbS@*R$RGX8jxC z_e!k0`)eQ7^)z%ze|tPF>twoWUPh9R2-~?zh2zZ6d8SN&xO3ZMUPd|2XYN|-_<-JI N@O1TaS?83{1OUyxYTp0= diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurLinear@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurLinear@3x.png deleted file mode 100644 index eb6279040ce9a04435623e10c0352cadd775e490..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 402 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q1xWh(YZ)^zFh+X1IEGX(zP+=xREANc?c(;0 z8+r3};y4PGftkwNW-M{#)N%FRAqnqbu zT#l)Z`kOM-Tm9zRld0y%cWzlzS2WK%`K(g1-rR8epL4u#n|9|sz4ZK*`t(bclCxM( zsa!Lk;K0PGGGX%!Fy-*`HH(mkLL*C&m@tR}v(boIJq}Ejs})i7>Az)#YWuBQY5Y6> z{OrB|tL*Z=-2dbHb@JaBt9iAb4%K~~EMA^go^v&2(^NzCo!|D<&3~!?jQ#HFpEDi4 z&NfP!`g4s@NO|Ow%4s`KO!s*n+qdb=XPqorShz4Sd=O^Zr`zC@u!A2Y=IQF^vd$@? F2>^KJrwIT6 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurOff.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurOff.png deleted file mode 100644 index 037d980c35336e6c3b4a7755cdf1b6ee617c1e60..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 146 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0DNKY5XkP61P*LE^CC+ uEfHa8RIPAM?$_gOTbHhjh?eu2l(uP2^m4`Ie^Ee77(8A5T-G@yGywp?a4-G< diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurOff@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurOff@2x.png deleted file mode 100644 index 0dc203196e4a65b6db64631ae51a8289ca350079..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcg&Uv~xhEy=Vy``RX#6X1YVSCD+ zMf(iwy>+*1?rd}WQtmNH#S@6^T@xS7NiVV~KIhPxyzuF~n(teV z@A_NK_qg$y1fwm(e4Z;Fj;RlX8~#Z!K4<8e*cHrhu3zv2r$cW@2!mapAj5$t?@bjt z8QCNf8gLN@E}3t7{&d|G_2bc+?SK9Dbc?+CX8p0Cr=g9V@A1U6lmESJE*#q!AhGjV mtBih(aZr*q*kzNJ=%3@^+4^J$>Z7(8A5T-G@yGywpJi)SnV diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurOff@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurOff@3x.png deleted file mode 100644 index 1de339b991ebd1c10eae21cd56e025824d0d6c82..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 388 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q1xWh(YZ)^zFnW8sIEGX(zP+=(P{vW9?V{am zqn=cuD~ImCDNqw?tdw+6X3Ns8i<%&J)lc|q97}L~@9laerHWxp3SjZSNF+sdERw_ol}G7ubw~W)YqzJ z2PRIH30R3*4jdBLb$m(tarN`rd*SDQ_r81PziNKY^DF;8JZ*jZN?m_lPWhdvlAwfh zj^}LG-%tO0wC=**U%X-~s!mMtJ$5r?)w@lnKCdaBq#t>1_nXwY&m*sv!a{<9;eh`- W4i@)Sm#uLLcZ&LJ=6%-T{ zLQDVcgarDWhsYhszBxaXYpE7*}i811ep947A*iwE)MiR-p$}yZ|_HwK_eZ{h6O= z{`M#8^7W9D@{pTtxc`tR^nmQEuW42ffD!3QVK}wHkd&Tb@M9Idg|vz^aLynl4@OJG z?9x8$dRy#zf;P&jrHcu%>m9va>*wl^OuB)+LLd6k=dLaL`fE#2P*BiM&^539VJM8A Rb2k70002ovPDHLkV1l_ypo;(i diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurRadial@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurRadial@2x.png deleted file mode 100644 index e689c5f6fdc42cc39c5417bb806113dbc0473bf7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 875 zcmV-x1C;!UP)_?^$pNm|Z1=bUrSIp>^n&M}F3?4(6DTI^&VlO!)ZP9NFpo(iBRGh-eWbta0ARgyf}K@2m$zl28olb;xQQ!kFtW3B$|9#m;fx`7V0YNnJ!~u z8tb`=y2YYG1Yi+~qr57q@G3`1ERG(4&$)&Ai;4u4sj;2ITmTvzW;-=X5>VkU)Ga=b z8i1E*qW)r<7|Lwo62o0$BV{p6vj|OIjv3$|)KN-e_=Yo#?hN0Ep~O+tzcB--E4*e` zcd;2vAB%a1$C$)pyu%{;z-;0!QNn9n0f-%7oftNdIKjuaGgi(Y%A(0Gh|H6 z;0S7~T|dJ0m;rvVW0^~+4`p0@fVxCE)QA{hl^tuSUP*;sR4vqq7~p+7)=`Tk6&9oF zp+>|2PuuYT>K#diH&F-d>Y11UX4$cUdQ4KGf@*{s@%sT1lWwm@{Ab|N2|WYNP^07C z18+oq4`lEuw5T|rLaXdJ8`UGJ(2bfMY82?3_=8USCce%icD8MTzlFBN|1C85*XY9& z`!yPZuPR{9lQF z9+$i@iTQNVCL3+Kn9n3}&N=6tbIv*EoOAB~<3CID^F|%tHe~<+002ovPDHLkV1jvm BoiG3Z diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurRadial@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorBlurRadial@3x.png deleted file mode 100644 index a6601bfdb3747e197f6cfc98b201184f47dffded..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1299 zcmV+u1?>8XP)|_<4wcegsqwes0 z*Rxi%2+y`1jXl$~_#I#RRb$ZI>8ko}enI=a&c8mt_sSb^8-BhgMEVHvJ$`QYf;g9P z4Cgq;W$u>eW=3(AQEql~>lwy*hF#i<$lz_(vA}iN;TsDFSt(`H7YUJ+$x>noc7G;wdyc zC{JoJ*n{S2&kMu~G~39C(E%HIiXD8$0Mkq}z-R2>DH_R)Iht)lv(nQ7aTybYc{1uZ zXW`>F;_(|k&WhpbNy1EUnU@86pD@0N?^n@5h}j6yK~vtraNMoA2mTB zpL)HVFeg|uC%bDn5qI6=^S(gS)T%4qr{q~OXUj{JL<7{=y5Y3f1=^urbrELmylk(H z+s%Sr7w92*&N)~J!FgMM6T#vf_5Oq27HEq67^~kQ>gR2}j-gmv*aWaWO&&xe0s7 zjU8GxqXnf{AVXRZwQ1;LXP7aIeU8wQ;z9Zv1J*$)n&#Ic>@Z~=v>^=(MNhA!kH|Bc zQn1wsAv9_qM(pNOuvy)pH>;-X=HbDZ#~pRa9e0>>9t1%ZW)7v~z$~Q0(F9F8lkP~# zk!zPxXVSVuP(^>zhxYxpAd=6pxEL#v4*RUK#l=R!8|d4u{{hUPaA5K97n17q{# zMuna?P#q^LaYIz-IoB4OKWU0U@GZqEdEpRtEcUaGCThtchgzCg$9^pA9MH)N6shbE z)AEDJp_}>AO^%8AK_A4+Fk{8M5~x13QyspSGipLGeQ50B-W-A#H zNt|u`K|KDTjkBVX@3t6{cyu!W7Yb$i+rh94^$XjyhiTT1$qhL8^`aw z@RAz^x;x_D9VKbKrNAP-CCpt(7+bje%fkJGE_Ygqg*#9s4wpIF(cb2=)7%aj+(m#N zu}B}|d`*D6Tsrpr*&ZAV000004Dz=g!~O~Y0000000000fGb$xpEP-8Nm>8^002ov JPDHLkV1mrSUt9nH diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorCaption.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorCaption.png deleted file mode 100644 index 112471166029138cae9d4b145f041dec1690c4c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 87 zcmeAS@N?(olHy`uVBq!ia0vp^+(697!2%?MGxX$ul$@uFV@L&K@{jmF)@6o&jzopr02lEV^8f$< diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorCaption@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorCaption@2x.png deleted file mode 100644 index 6ed8cb0d450c214f5031183749015ce029cb7cf8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 111 zcmeAS@N?(olHy`uVBq!ia0vp^Vn8gz!2%@DtF>PPQf8hmjv*C{$v^V{+;8>BIP;FAt2f_eIm4p5+D{Y3x!`LpuV Rm4Svac)I$ztaD0e0suZkC@la0 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorCrop@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorCrop@2x.png deleted file mode 100644 index a6ed7807f2aa21cd6a16a276b3c2df9b71d91af4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 194 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw0wgDV75oXLIz3$+Ln02pytPEept4oS>9(&%V-7{?M_AD6!--_uG39hB2}Wh#D{)I&`QqP5puF@0kBS z%QvPyEPS({hk45%X35|OaRtXF=e2Htf)Bg}_W!s3`J~@lQtUsQ>F|j|+HZ5N25WCS nD=fCI<#bwO=w<)pd9%d5&R=-MEBas~&`}JYu6{1-oD!MIC~ diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorCrop@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorCrop@3x.png deleted file mode 100644 index 1490c67dcadb57986c6aa7f207499a1a71fb96b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 274 zcmeAS@N?(olHy`uVBq!ia0vp^Q6S900wgCb?CbN!f zPek?VoML(X2U^@S^|YK8daO45m6)cfC-+de>Bu@`W8=-T7bnj=@nzzLndO#3yL4U% zaqd-%+LCc`k!!bD?8hIG52Ooz-;D27Y5R5jeDOsFkIEL7RU?f!gL`sUVOgrc;owBw_o&!dvE=1y(H~L)%S9V8PbcEM=^i0IkYcj>GZ39 z)#<+{&D{6cP6cMdUuLT(Uq4O||El~?C^0RqY;oL@g72T|b>n6LJ;~td>gTe~DWM4f D9AbJU diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorCurvesIcon@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorCurvesIcon@2x.png deleted file mode 100644 index 568807854e04472418ddff7a9975073647c573f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 589 zcmV-T0Vgrc-s4r;Au&v?A;vxn8we(SkB-`~aadP#YCd3hl*lf{%PUTot&KYfXCQVg~VR$3&onmGDfhi z3WwX+VP)V9_EMoxOaiM^1}YfAHYyC(WBrHuH=&O@k)vp5jI|mSnEtMjy6A zapO34MR8*-HbjAPfew;n)1qk*6e$8*u!jnPk65iDum|f@2()9}ioh}Kv_fDxHp)UxK_|9PVbF^m z(Gu+J1K1C>~UB85RQLs-2sa1gtraA?IoQKU%}Fn~2E9Of{Hozx_nvG0^B zBo1IHc54E4jA2I=8n>_%H#timY0sIh(3sB$GQFo-aiE-T{z-6=GR21#G|eU&Z{ZZAC1-+%-J6a!|)#|C}#hS^bbK?3f=4vgXK7c{apmw#2-QZ zH)#IRA6kULBIHmJ#6PCeA7dCN+Fz+z#KorP<})1McOPqa_r2X8em-CLJ|0pkl}e>j zsZ=Vpj4W@klaD#b5Nj1aHgcTbappP7a|#!2j8SE!GQA2D9ehtccj-}x_>xBESf|iX z;Asn-=)}y^t_C=axgx)K4fC@aViQh}eBvFpD1D`6oYP@Zu!FqW<;@=!Hmfta+G87NDa;8yD|As}k<}Vigk6}MiqOU#R&S9K zU1|m;T5(Ph@;t)yE5anLDXAGeq!m?iif{o_RD_+h=AoKFiPr2;gd*mGBIKyjijtZ^ z7bO;1y-7vbh98Mvr zcNYtSQb^>&|5F!1bQVE$zm@ldTp!&B5**i*$HKI_4<#G^sBb=XAIccW<<)&45%B?{ zgErEAD19N9L-&D%Rcq z=ndR3O$IU+qUY-8qjD9zu(%zSF&rCl8^7=XJ246AJ$dtW9M@4o*_HqkunAi{F$Z}J zo^vV4r4kz|K`y4rVWh@UgI_W&K@4}+m;}*&W!o8;>Au194ufA1RTUdXLiEt&FnZt@ z)ExK>_d1Wz$~vbZ`k}nj{tYuNHF5qEq_0b(ivPGCqID(~%L9jcGRT84(#^dszCvz> zver3>eoOy71mw;ky9W|@@ss=D@_#r4(R7201jSXzHT7Ws%*xl3uVMGXKo0uFqwN)l zh8jGkGvwAAIHo;BCv9Zafjon#lfh%QK`xbvuRi-Bj+F-@-;^5~Jm$Xg9Bw)*599+x zEez}*T6r)%><0re(hU^$iGkcT^I0SNq=novC;Jt}E?ia|#{`7-p@GQF_KAU}pK%l`a15`Z_6K?V zc_1qwy6#hp21aLmh0zWpm$J@sh^{Kz9zitAht4~w@`7}PPd_jx#9~~>Z>YV(RHSus zd|CX01KpKvgT?10KJiLax;(jDzWJ;b4Czn;X%N=L19cK7+fpK`51!+0h@K#j&fm$T zhFmY3&M7ZMzaxsy!^i>$M00e%bsSM%OvW>MU0bv+z@E2a~7gnJ_K)H2XgxUV$7kd6vKzpFp+XDcCSjmK5ytcUj0000^ diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorGif@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorGif@3x.png deleted file mode 100644 index cbc638ee954b3b344c679d04bda9e7ec84310980..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1943 zcmV;I2Wa?-P)EGi*Q*^CY46*!fLS@;Kya5{37E#^bXz&1ouE=J)+G*Gsf4Q4mI zG!d`huvESw({KY?p#@IyVV@tvuX^K>R2#@Gn2ZD4j=DbV|2lkzmKcax*o0`CfV+^9 z%mcXt)8W)pF+6@5T#T2|0m~3c3vg1h4do~dN4TyJ`1@*r7cmxYnv*O8$;R8rMYvib z&EWT17tdifLRCB&Ug*t4xQ5}fIQqWRaRWv`HagLV@(c4+b2#TS1zE~wbTBVN*SpGQbTFBi z2#UwMH2dyIUVNV0vBP;2x~@|;<9BJ3A)9QM?wTLYmC$v&vKb%FFvw=x(<0^va{+YS zplrs6(-*QX%4U2pmqC_~YRYDOsqkXRUJUnzC2%b+j@eT=JDj&6n;q`VFZ4 z7RzyqAUo0N3torpN@a`1aQZ{`TqMu4Z;SC&U`OG6+=P2^E-HK2XAZ8!jVK?-gLxLR zo=%S~d5|3ygX>h9pc}Tpsf`$oA8~@qeV4{m>}@rUc33$6Hilpo)<$R*I^lMYizH>+ zktH|09J0+w^Kl?=d$_u*2Wp2o#!Ha3*KGGS{3s9AJv=*G2iduD!&f2e>(fw9#XJnU@^ zYRU5j1&~$pcn)F;bnU{EE}pTyjRNSp(C5MYXz1BlMKr?;sHwZQMYh4OMS-F#V+)L`C#>^%?r%Y|&ZqPQ50_m-o05QBLEvQMMjS83?#;_^BDV`zak8m;j? zox%k>qaN9hTHZ+(b92Uf29)j!-5Btl5Y>Fi;DE8RZ$ixXT65lL?)`?In$A)DmKibGM2Fke>=SK)R1Ak2a6 zvt%Dk4ahe5u?j?Vmxq1+n~H-;M;>H3QSR?N=$eB}JD3R4yhXnQ86Fl{%!95+RYcjr z+=4>v?Nz^?>4}!(a61?xj(at}#uLbP+UQs`#JN6QtTPk3w&DH=-dX+t8z6fvVF#l> zwcI?&-yXXaPIbiNI0GdV@#iWy3-_ZV3gFc32|gHkcVCDyK^^=CiQ z>c`7d^h&q{cc3wv;0Bz4avqlA-iOCfJH&QJq9JZWcEJDL&qFp<*^GbA%_9AYNt4;Z z+yq&n`MWVYn8Er}EGDx<-BK__6cS*sghZH(S}lUD`ewvV0uv#{mulMYt%? z4(2=P`o_;+Ofx5~*^+8KuI&{rORi(%d=VB~CKH8y7P@hq}9J;32pPYkN zxte(4v$1Ad#SvNKYPUYb( zWGS1GPbY7QP)$Z%Wh6VGSCJ2=#wXATuC!!)+?fKWipBA|uj|kQx!8n9l5IFycw4hx zd1f4buhsB6mO@s5LzDIM{s*HFQ*eA7eP1tQ2=WoC80pGH-5mUcn@FVceF)sjKO9^+dN#VTxAFIJz`ltI^wd(e#-4&wj&lTz*}D5 z9k(AY?Y&*-jb=Dp*?jq>M7fBhZ5V?;@f3@TySA=Qd6U_hs002ovPDHLkV1mQ-qGJF6 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorGifShadow@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorGifShadow@2x.png deleted file mode 100644 index 43c6612c0c522af18d27fcea32e155a9052ee232..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5268 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 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorGifShadow@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorGifShadow@3x.png deleted file mode 100644 index 9dca9739b5bacdeaf274da9ef82d058da9dfb0d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4610 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 BFvS1> diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorPaint@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorPaint@2x.png deleted file mode 100644 index 41f3d9765ded42071c18979f2b1de0ac7c634ca3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 509 zcmVd{#Li%+c`Y)YcjoMFR?+*FGsSbWyLTI6Oq@7zetSr=N`)L=b zk3F+U``CgpYf>F~(4kiC2Gyy(Fo7q`tB(0IH<^ zD4P#iYfx_9=KVtLBtTAL|AM5m5+go9Z!ko5gZ`ztF`<1rH2I#s~ zHbCpJWN>NFq)7vpOeh^SOOi5g`13~D|I3M@4tq{m&I5Ed`b91abb&*fG!7S1DQg~` zj4X1AgjY*Yk_FG`!LCf32vid?wW|j=0B}0$4gd{3xCubIqn-w!sl}!Mcn;|d>cZ0i z+=U)GfO{?Y1c2?3&KdxRI_$b!^phQ(9v%Q#h#nndSMHnrknRQmPYgzj4pZe-zD_p` zbo3YHk(Q&McZL^%kC+H_M%nTH$LZGC-&r2L>);lb73Nvv*n6OBhO|!f2zz{&1Nx0- zn4%)zuFqUCXKaK%99D4IXNx7qO`JG!esA6Z##MV!>oS-500000NkvXXu0mjf69(Y+ diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorPaint@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorPaint@3x.png deleted file mode 100644 index fb8c602ad190f63e945bf6c1d283947b978ff53f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 674 zcmV;T0$u%yP)4_qYx4Yu}i^NI`}8V&Gi3BX*Lm>SUPlW3e_d3gM(ASB@PBUR7f{L z2b0wbZbF(s6=UBH!aeuodF~7dy*v8-toIpST)xje2YI4MB9TZW5{cx0LWLe<`mA#) z6mpX!2h4{+-XNX#-m^1g|Jk`@zu8mdJ$`u4o+58Y5f4)A1Mg0fEIEoY?DYW18FoJi zauh`odunAI3VB;w>xD;#N_gaEc;pQspI34#{9SIzE(5 z+EcQP?J?QJ_MDu@4uG7)4uNc8`%E^lU6LtMqr-p^BL;M+QJjJ8j!c0zlgu7YXj8DV z9g?ezjE~res*&xGT;~*9PO0azo$j)o{Fhzz=`1Lu2IH6pWnyB=G&oKTNx>ge{%IYE3NUrQ$1(wd*8b#~}Q#rbS$EqFB^tSQbrOKU~7_T7^&@KJFd zS$Z#2Yu7!xuD$K<7+cr*?#&G?%xS#v@ZE1r6hg@|#&#yDP z-KW6{_qajK0#%-CCkDWgv(eDb=O#ayJxAR2Fn^j)&fp45JV!%GTRGhy3Boc{4B9VleKhf^I!@Eg482|tP07*qo IM6N<$f^GCZv;Y7A diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorQuality@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorQuality@2x.png deleted file mode 100644 index fff3a37e75d54d162da8575e5ea3d77481fc4d38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 144 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw0wgDV75oXL!aZFaLn02py|Iz^fB_G)WB9z- z$yvP1OfIQ4+_|G)z-qlt)wBMT-%{hi<(v3pX0GA8v$#Os!qdp;RWwuc!2|;d9ySOy nuVwvQ{p;_RMYGRVseQ@#TF|+3WA_dZpcM?Bu6{1-oD!Mz@qLo)8Yy|t0|uz>)JquH`! zPu4|<>|SubGtprhQ|dG6&7wSZKVC#lR`I-achl1Jl%sA{+q6H;OApISvyZP#`}*wq z*2}>Q>s7|nUi2j(d~ z?7;M~S|h?39$@a0Eq@fziK)?uF_lhCwfu1e^MD+Mz%EQHx$;9EuQ8Phg(R(*D*0g* zrb(f35K}Kd)MNH3H0EPo$PX7W%M=<}yv2-@51KJ0@<1b|R6gj%B;|ny%rg0)8#75B zIEPs!AGBj;%L9)vi{*nGm`Zt|3o}hVIF31}(3pYgAWJ@2hiO)59Kf8GAM)wJEL12Y zc#f%(FHT{ukfjjVgn34`d{Ig-W{XCQ65eC#ln(Y_I+>{vA<1>jUGkI;a=C|TXRiK= ziQL3|pj7Fij1J5@Dl{x+(L%~rMS(KfFg>i%A2FNPn2&5!RG3aP<};NV5{0y3-cYV6 zF`0*$CXyNg$1ty$rKnLrJEmH{p@2TjQpJJom?s1T1Ox;G1Ox5b`Oen55!EfN>gx0OJ%N0*uoj1Q@6I za1yguKOv7hm=%f-8!-LUlC7^OpaIj(1jUCO8c1p65ZgGxOHwu~UX0=rzv`z(@gu=* udKl0`h5i-BQbjE%s9^yKWn^UhPhS93QdV7&vuulpk diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorTintIcon@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorTintIcon@3x.png deleted file mode 100644 index 133880fe7c1b5d8483f84a08cededbddeb2b10da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 977 zcmV;?11|iDP)F^HENX3H5hGk?%%tM_@3WcXU%hVe$P42#q)Yei9{liNW>pi zG_i`Od6^e^o`+aKwc?5tt9X}gvW;?*o!p~%;a>LB$F-cNjg;bmJNSg$g{-4Yr9>TX zGfKWrvqYuB0=md{m5?L6M?3rYl<)YRY*%?grNBCdn5>WeJV>SfgBD)mIO9yVn+g>d z?M&9idQzGOEqu;oUsI*x;T1Cd#b#zH2Q1?RnLegW#lfRwI!V29Mv8aH^qPu+PM*EXFXk@{O~YW%7oFm@fH8C+1ao!wZqT-w-g;}>B01H zi)M^~0ZcD-iV_=ferAqlgeHE)c}h{^3!D?wDQ~pWhw~+6iW)c3jdOv!lo!@9jB|lG zDh3wOkJC@9a>f=i_0pnZVL5|1L#$R#c$Q3;nXh7^m0p|?R_dB~gbAE;G^^NX2je1jQbw*D7&3}ZSeS1HlJ70f0A0s;a80s;a8 z0s;a8Hem*st5RbZ`Prq?<394ULZwHFVRAP{rQ(2Ya@VVP;44BxLPA19LPA19LPA19 zLPA19LPA20Dv?Me(n!;kNK<@}rYVu8_#jPFB2DpuQ?4wOlcxCK5~f{QXvbVqd~gt_ zgBqn#LkG@5#RrQS$LV4RYq^vAd7UntaTY61*v7SOQ{1qf>1|gWv4KIRHpm9W74tYm zwnNNQywSjV_V6v2`Hc_R$n8ob5{X12k@(j?r$3Fo6e;Ik00000NkvXXu0mjfgVMaR diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorTintTool@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorTintTool@2x.png deleted file mode 100644 index fb64ec8327a70e56591eda6cbd6d1c73f7f10f16..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 418 zcmV;T0bTxyP)dRqj&3+cU-%WIwz*!dJ?IR7%m8J;6f$87nJ|S+m_jB@Arq#M2~)_1v6%-FY*XJEVjf7an7o7V z1i)p;8kYb(4Uba&nw%NTa}&0lK0T zG)i3gA;r9qVg|^7DP+I|qDj+&2~^`VpQ&ZX1gdflz&X{tn2Zr^y0x>8nLsmqquV!T zvSB*w*kQ1pT(eQ3I%)MBm_Q-0MB37StuuinK9ctFzZSJX5_hEC{gF~kA&nK%R{kt0 zrjW!OKN;*Nb0PdKc9{HQI#g&dS_9ZmTGl^jEU?A{53I2eH0S@oUrdidu;8G<`2YX_ M07*qoM6N<$f_Po7Jpcdz diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorTools@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/PhotoEditorTools@2x.png deleted file mode 100644 index c814f6114a98bb3617242213ae8ea0f34e60ba85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 175 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw0wgDV75oXL$~;{hLn02po#x1OK!NALpFek+ zZNE;5Rp*(b5S&(|zc9cnNNA$3LhuRWBaBCQ3>msawcpi>9_&>&{Oj`hZ@{Zg$0Uu_ zd2d3s!~R5n-123nXtmo0!8H*dPbHnR`gZT4&!Gn|&fIo<^l#7KoaFUU8sK7->C3L;iO1k}Zg{x*=3|9LhWC8{y z;V(2UPP^<{!<=Wodx2)umE`mt{}+CruaNwP$@ZP|exrRaZylYbx6LL43|>giEt)pH zC~H=soi6uj^*Pm>zv#ENfxti2s@yBpdvd?1F21*Q;ji8ouh;44xxL@BFGKQv$;%|) t@Mt-RjbAdibocMRaP?@rif8{@UfJ4NQQ|Xig#-P>;OXk;vd$@?2>=LFYrg;h diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/RecordVideoIconOverlay@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/RecordVideoIconOverlay@3x.png deleted file mode 100644 index 7a571bb99880c0a1786a2fc48e939c5404305438..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2553 zcmbtWdpJ~EAD)PkkXuFin#Ltz%xq@NrEq4z{IDy7?mQb?4F985QIIWAqKi~43No%6@{oPWOkJbSOTe$V^9>s`O~TkF|re!i>p z=9texAP{<9o-~%KU9Wy;YpcG*lN1eAV+PaNu)ib>j^WB61cfIFg^*q%ZaBn(xV$Zq zcc7IBgr<)mfDN;mK4efLa^$KpjxyV?NP#i^$bwz#CC9C@CFb0ME z27x17QQu9mnSMwQi3~#G9bM2M;7mjkNR9xWM0CPAAf2#)3kFNV05~)jAY(~nEP(v+ zpj5NTcwuA~jqzhH)yNgahhZrhgNccWag1?xl*qy{0EtAxV4W~dPG}VZ9koRab7Rrs zD9dRD8WaV}1X5Ta5hK-#+)zn0?21x3{k{Z|l*#-lEROn-C{@ZZv0NzzaKvInBK5ky zp`&0H^p}nQiH-``B84z4C`uA716BJGW;sn(-X6A6vy5eaAjAaKz{5KBTs#84vW#3P2{2{_abH5K<~KK>6i zjLI-ZT>^hAiRqB4&eYwX1+E(WJR*=-buMJ81MoDIGJ!y7dw9_(0kKbpLsknn&`lOs zAGAki@84NuBRI_LO2scVjJC%!%92uF7Y=(S*Y6C3+u$ry&mj1rUS>zdV3BTPiC5w; zo-RrBC!RQH_v@f@GnUy7E@MsR8Z}>SJYUg#`0@MP-1h?(1D)k;9ipuSK2? zJfovK)d5;pP&X8!OIri^_UDpKpUe?)lQZq^r*v)AXCwOLt_n+qi!z?W@Xy;ZqguX4 zenw%fw5XW-xvpK|uYEyj`vNEsa#dPYSca9ri66I{PR1Na9?|HTIdSWcm~O31g#8+mnj7=^|}z`bQSrHVT-EP8$WK zELP$5HmmrVd1C6VfEWNk|Zs$&BVKcy5+PlX;?Ds zuUx+~d1En9(?(4jP#m4ov?<5{GFO;`os#tKU0R(fvB~_@eMjdltpDl_`dr$RwuQ6u zll9Yyr}ACajo7O8Q~dOh42}MTUw<1JPbxEeXtL-OR-}LFY~Akz3ptJ0IVYT2{#_jM z5_i5IirQNeQF1CXzc&6Mzx3|yp^7$FpUx{q@?ov{^6G>J)ApGBK|5Br9d?wJrJyd! zu0NPqWIBl-E7I$iaL$a15YfZ2I+zWGov;@a?-dy@%hoAvxmb*Gnp#v+!0U#f@RDgBJN+A)FqM?OSRXDMsf9s;{Gc4zFE2&ex}` z+|tH>o?nQCj63^JsIGPjY&>!G^4(I$ zv2iz>j%_Dy8$M%|*H0EEBUZcjnkVhsO0Wy6-ED6Y)@{`CMf{klAmjBf zOB#lp?lIL!ZT~P-(A7FM3m2msu6Hg^?+!27=IwgVrc$b>FA-OGo!gkAcW#Bz{mT2| z8(G)18sw1%q;mfH?Z-}zgf;8l9W_lssn0VC_7j_ox?jhS95e~pV6@FnVRBydFPCnGPmO%R zqTRX2FfQ3#?{-07P%fr;*Y*t z?!3a*yPeS*Ul2ODv27o-ruM+8+4yG;TRlRn5<}Amdsu$!7WiK{U1#P9K+8;ZDlIqr zYx?e8u9L2HIwF5CP;Tsq*AbFags7UYw70}7>j6*w(F*0Jvy*8SFAt%XmIorkaaQ`b zurV)n)Mgg3Q5V{Q&SL5BF8-v#IT_rwc%jT194%h<1)aJLx3q4^*8Sq)ES zrhX-PTf_;3!R*Ib?iHBsrZ!*SYnM;`(Xsk{hr-IghiO>lqd{wFW!L21vq?TuHNGwG zDNeekvS7-gFMKnnw|w=j3!dPf<~8nq*N^tiR^yO)E=3 zI!oW~;=`6F&pVp)w}u-mY!?=58NaDm6=oN_YQ@ueQbvadC!6e{@2_wP6K1?mQN;aSz4t!ob_jh7=d5eX7D?|k};A@$Fg7u}auM&<1M EFV9>#(EtDd diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardFavoriteTab@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardFavoriteTab@2x.png deleted file mode 100644 index d30bef49559d316a42c2f5367bd16342d760ff5f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2181 zcmV;02zvL4P)Px-KS@MERA>e5T5D`nMHHTy-K9!Q6fi`Cs6^T*qC(IF^pE|a(HJGZs$fugbQh`8 z2gG(4(D>-K_~=qzvb%_{2nLJ~5~7LG`a=yrFd9*eEh35}nh2FBg|d6^_?^3Zws-4p zyLVsuV{g))nKS40otZiJ-nlD8<*H<$l7UJFDjE3yWymHGw}@|43=1vlRRpd zL(bG6mlp1ao;}1yi(D!%f|& z;BYuRR>Z|N1e>rg#h#HKEUYoeB*7`twQLj{Z7QH58eY3TI{Vm3@fr5x95O4V7<6gb zI;sohY9m>aBVDpVwno)+D3I5KM^8_Wd+&iCFO_G^YE$ZJVajSDbq(O5Na>60F(@S) z{7v4?c3!r2dnno-zS+|*J6u~^8y_Y+YIjt?o!#M! zO;g+kOEp@EYN;)7Q!opjk*ve;DdAELfyVk*Mv@yo7VM5L6o$D8zRns{jF(lz9 zEp;D!^W0x3OyHzoxuDYsEI(gw>5ho9D1Nh*UAdGqbsu16#Auf@kB3a>?k%{AD)DfVQDQj zfbE?!>D=DBx;i71o>Sh=ojYAW9X(M4&^5GmQ1!9G1hx-WnGlm`QZm_8LO$Ye@ovd9 z=FY?<9#VCUNWR3;tO+e%!0n^Y1h@%jn+JV9-#|9qV)2uS`yTe_FYTf#{>LdbRUrv@ z+d>k=N?r|E=2xc)+d5eRW3PUUj4mZvGKAtY5yhv|ru&~ZlL`L@L44D(F4AS1+P3u7 zC)t9_xFlFO*cI6U(D!p6Grb9*AIr8sSgu@@mUJ)_MOD|!*eABvTY(nuJnj#tBNn4M zGpiQ>(-G7kwF<`C;Z^S?`!S>AVHSs>p12G)k5G z;L$(dKukl+R?1fcP4$ZrQ?krvw~`ZJQilT>To>7bYVBonaPanov3foVNQ`-fM~X|jx#HaY=I zq2&yige}l5R+a9ezIACm_u$d~p+57AOf4Vq#byyp7pk%2J4Vh+njJ9>t_yc)Q?zkk zNmc7_uK$$##iXdlH=5e)VVhEk&OnpT&wVG<(G1%SlS8VE%)?S!!R=yGyKVBBFIb8z zZ@{E1<(O5eVj=ZSR8)vx%*(0|uuV3}7x^s2enEi!%?l5seE&cJ;Gv|df6!g@1Gq!K z{dEP|wm`y{<+A|91p&7FN^yeyDmk5W<_wr_ zUyg2JHrr`F^8lRn#3M&rDZtV`3mKF%%$QB}%rI60=Th4*4I)BHf*dY!}rMcR{DvgqvscTM0?Z*Q8tQ203H#}Uu%R+C$o z*Z*oC&$XTR9yV?J7g@*G{KQ2+O~P5&RzNxcpmhuuUgTr-hj~Ma3Jy%2iFi7wxjS zw)5Y^T3o_TPM(hv*K8JZk5$s1U?FzIuFWzV84{s+EarfG;m#;OX5k%6gmjy~3 z+RZ}8>hbXL17_K}@N1Y$6D{Ze^9QW--+WMypk}4JmV1?yey8uptu0n!Zf@@m*9t=h zvB(o&50OX|x*;FrJI^a`z*Qd4=D{;DA7;TSB;+6aW4};xHI7~Qi+)~Vt!ni3KyePv z(C)x8eik!}AI2muEc1Ty&3&gd?>$V8=vOy7CLTgSKqUi}3{*1k-)7(+tNc7EYtMK600000NkvXX Hu0mjfC>0cC diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardFavoriteTab@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardFavoriteTab@3x.png deleted file mode 100644 index 64706d76810bbecd16d0bfdd0bb694c3e4c98408..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3482 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 IM6N<$g6K=P_5c6? diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardGifIcon@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardGifIcon@2x.png deleted file mode 100644 index 382c35e0335b2625cac33a8ebc30ea1b6fbb2cd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1264 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 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardRecentTab@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardRecentTab@2x.png deleted file mode 100644 index 95cc50e35f68bfa767bb5a95434a6353b4d081a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 698 zcmV;r0!96aP)Abrw>6yANs z6w61#{rTRy$H>g~rh12b+I0fE~1fR?yo1y|Zg?AN=;w zyi+f*edzw3jXoRD5X%0*CxeFen`id3HTreKj-XfC*b_8?8iH@bJf6t=6&lrb3omFh zFVGxn23)6Uo-ef40!mK_yQK{rpiYHrcAx{Td27&>121XeEz~-}x~+Hq(2L5SSz2%n zB`1885@=0(7*&>yDM4)oSQUCpiL776b9+zEY)ja1Zc2pP`#`U(G$intvT;Z7%1d6k zlE^4~kAszqR6)%}znhZRjp#L}itH)`@QjLzrX%1c6(=(pm<|FH-A@N5ze)MPAs_Lm zHf}fsZcy#rRm_T#(T1;k05;D}$+J+5_9dgCW8h)QbFZ{zj-~T#<`_6Dou`jb`(I3Y zS~Adqh2+{(3xwSn0Pm!N#yX0eu-pPu;+m=%dQ}nd4=4%byP`}j0j~oBf2QNz_Ylx@ zY%Dz8(uqOp(Aq66BrONfl(eqHzm}Xq>#rrb@X(=!!Xpb`S~`NJ((_!{M>Tqc`!whu*}~+q8P9ZCaO&cs=AseEifBKc>;5 zi%a-i%FpxdC43NP=w*!~4@)SGLoIP^$eu9i2wiq diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardRecentTab@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardRecentTab@3x.png deleted file mode 100644 index 045a394615bb1094e389f078110a86586251192a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1082 zcmeAS@N?(olHy`uVBq!ia0vp^Q6S903?%u>HW~n_GXXv!uK)l4Z|$2oJP_yn-%o-5 zaw!S&3ufTd3y9CDWYo#q@ZjHn!@lRNiI=k0z-2GWj=$rYoJq!#?H$7b(Ln;{G%xLXg zvGHf4KmYA*D>v;a%YU?wqx#6KC#OCwXkWME;8bn7_2=a|*qH0)Uw8iB8(<;Sd-SOK z#|RT4zKc)qs7!KlG%9o!pXim|GR?;-Rd3GO&dpCgwLNNG^kY%Tx{&OzRcoU(rymhN z%4E6xqKN#KTXXaJ?Ov8zzrD76<4uM3FZS<~3}i0KyB+@ceC?N$f|FlXFF5;bNupgf z|B07JJXQ2tj^6N2|4=u_Ceiv-u=l|=e;!PqP_H^8_0+SO_osGeH?8S@f9u=1xdJ|^ zE@l#;ER#1pbv&4}Ev5Udn}KlCm$f%eOwRojHs^pu&XYC9lbP2PKM!~pVHt6A67x1u zZGFeP8g=%^9{U?aO9qPntf*d-C+`&{-t~+hT{lCuSohDPCvX^rmwiSQny<}(3 z{nuULUxi+-T9?DNWMNrniEo|2g{hCNCe>A_=$7ieXuGtAcZsjwlaGuU*?KHH1T&b; ze>r?e%;mG2f9L_LX7g6d)IHyXWwRf u?J_ODc@eiA)ckYSNJ?ffxE<7xU}bPGEK9ByPDlV|8U{~SKbLh*2~7ZtP7A~U diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardSettingsIcon@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardSettingsIcon@2x.png deleted file mode 100644 index d0dc89b9ff65b0853b23098b9179450d2e204c4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1152 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw3=&b&bYNg$6c6wTaRqWGO4S?&F^=Fgws zHgR@q|IEHst3ZbI&Hn%YKadMDvv20ARjZ~>UDe({y920wB3KY;3&>cYAv4=1fY=>< zK&$5fEdq*kOax0!nB5O{4A8)iNpr!*&IH;8WPo&m5ztH^w|&Cwwh2HJ=70o&=1iE? zK5-7%g)`eHfVF@OpVbO9b|O#&Wzr%J0U0EpMCYv^52?V7GD-HFfi@* zba4!+V0=5Rb<$%ufwtRc?jO>5KWo~|nUZHD>i$3Xu+d6Q^_;pqv1i^KSZDTa6T?m0+8eE&hMW1>7g@4c zh@54V`CGW=i@UDu;ZD2x^XAT& ze$A)367Iz{J6X3sdL;Hvum56Cb@p4iO@BWa6B*4PS&CC8ulu__XWqw_kE4JJS^&z51&$GxFu* z#VyPJDAt}y>tOpeUF)1!{AjjgLXnrlJ@i}(7qFAi*NI{?=1Yj` zce=99$^0!EwQWD^`db#vA%=?o*5n=Bx$WM9%xdW}|M`cnt?KyrC^zHAJ+(bM_00B_ z-ThXdUibDQXZnG-1=j?9x3j(9$5^~H>+|=JsSDN~zMJWMbGBCT#4WRUohQyX{kb~7 zQc8Mp&$1`iC7w;Isjt0VSNk#Zq++asxdS7rZ& g_8X1rAK!l-USFCWY$5Cu4a_eLp00i_>zopr0Pw&&*#H0l diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardSettingsIcon@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/StickerKeyboardSettingsIcon@3x.png deleted file mode 100644 index 54b04299e54072494572f46b87b62c5f938c1e07..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1807 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 Q20tN5upya$E>2STFGr$$RR910 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/TrackingHeading@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/TrackingHeading@2x.png deleted file mode 100644 index be5ecb85d3279fc55a2111d32fbb84116e273fa5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 598 zcmV-c0;&CpP)1`w`Idyr?8jBMOatv&ppDO_tFr1zn!pTu{RL*|Y{u${{2=i@ zub;rDEugst`uGDo<5js>ht1R+XMB=hIX@a^j)iWoADQ$c5XVa!q@gj<Zh(YJ?=E(?%0Ns$Gh(^Cp{H*` zPm>MZ1y6g?(u~C^TCB3s)aTudXo1b{f|)!V2Vunk$7#9B5+mn5Y|$K_Ng%sBSn;|r zG5paJjh)%UwzrYuMK9Z23v_Y`j43uTIFR6bG={$M(KzlrR;hHv@i5NcyC+HCG6V+1 zLUa6f{$-0mqu5xv!+^Cf_Iz-hSPXM|_wI@DV_WrlOa6f!8jZ$9$E^DAWB6rZH>PU& z3yg67Wy{p(<1Fmj1^@s6 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/TrackingHeading@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/TrackingHeading@3x.png deleted file mode 100644 index a365339ceb92c4d6da3122b4a4d5192cf6925926..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 840 zcmV-O1GoH%P)T?cmwLvlTqAZQJ&4Rjq9!THCg52kWgnTHC$p*-8Bxv-Kq>9Spx|+`6|1 zhJaI7aJuZ@+8Qozf=SK4wKKW|6_eqJa6~vF91)HPM}#B7DX7d?VmmlEI5;>k*}##| z$@d2s-NIDu5xW;uQ~U*$pnqXoditINqbmUs<6&C_)mG~aT}W^DGq5F`cIXmR1eJ&F z=;ZxM2~eTMcHA3=2N7`xT|IBWHVAqeoG#{&ph8Vx8j9P#S&4i^GsXYcp?$|}h8xZGTgk|VR#bTA9BB&-T z1Ea-pi(s@CmY@s015S4n5OL4{8m323r+6i(2x<#cqj#pcJe9BrMh9VPggbwt5>z_T zH!v++&PkdGPW@p@y87M%r`t&s;WFnCh*7&_Nl@uX|G-q}y#z)_lP-eOIGBo#@~@;z zFy#=4(bO1z<<8(VD+U?mU<$gqUIUjmqb!u#t3_F~R~Sx<%+j1~9;JlV$d2BGVKhJT zbImdYV)Ah0FXL(!vZu*tVH6S@!_Wx&J+cI96tTe@akWa@VQ4sw3%iPBu6of4)t&^G z%gi|h>VDxRaCtqn1geEt=%+meE?0yR(Z#qoga!G)fnG$l1ct?{%ryjJv^Tf}S0yBZ zUO;hL6JoFU6^5dd`-fncxug|8!uu>ZtqUSz1Pq0sF}e1H+hFceNx$)o%MHdH0;vy3 zm$U5&w;)`_QzQKB^Wbt*t`%t!qwEbeb4sAXNF_bay#P*Ivh95{Urs{!V#j zP?g_Ju={)NIk4USPr|?mdC$=NLUEvm>Qfk+pL-3G0$T*=o+x@-i>S(m2><}ZQ~C@G SOnhixhN38p<0nEQ5JUkfAOH%0kU#;@01yQT;N7z=5sCr?1OZSq83I572!V<2 zd3#%h6-4cIymTz(>bdRiyvqlmUyuGrmF65EUGPSAL$Nsz#-2h%T`=*nVra6+$V-T9 z`Z)$yTQjw#iA%+NJP-SmFZZ(yV)4bTyY;&p~L1oqpEz0JP< zz}{|qjGY?%>Hy&(6fll_80-}b{K7}|q~UNS_U89E3DttQie zbOgq}=7sXQfl?+{=>#Hr>-~$*KdSW^nk?`SI?I4w(EKU$yh_#&>X$OdRVvde7`px$ zd-sB+Os-NyCFfQ0o}?_mRq~&tEW}mvm`BRwDj`+mDg_(W@?RySefL%JpMT1*Jqt*6 zF!UY}=#esPO#nVl^=k~e{{wmx)I39X{wdQ0mXzrSOUm?v-6>NH=9K9NyHlnZEGg3u zmXzrSyHlnTEGg3ucBf1+m{X=7>`s|tu%t{s*qt(!V2ls-V+Bmz>_3}gfa8S0btud; p^b8m;7YW>Or%c-`CnfmD_W?u#nTHS9ld1p!002ovPDHLkV1frR+4TSb diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/TrackingLocation@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/TrackingLocation@3x.png deleted file mode 100644 index 7a78214280cac49686b4b8867927fc2263d55e66..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 605 zcmV-j0;2tiP)#Qa2r3AW1eCt_YyWHp zqNu++%B;^;7!AFOY@?)gSu_C!FLbp@uF?^fVHjK}%^a|Ncj-K{_(gfb_41=h$Yb9QuuUx9x?nLavz zZN*~>7Ej3%0?PC_#jHR9WfCiJOA;@)`di>7W(8^}v#vnPSAXUM@sI+_tSivsIk9OIpICt+%Jik9u=0#pfg;MZk0)U9ZUV~oD^rQhD6<{H zN`e}+GS#4zsR*S^MF?eTLMT%cLYbNn%G88VrY3|kH6fI#3873)2xV&0t4ts7YKQ2Q zsZXCW+aWw2VMq|l6lFtYwnI#}LlDZ8fKa9;gfcZDl&J}!Oik7+vmIg@?GUkAmDvvA rpB6B9EWQ)U6ePu~`qS{y6t;mMN!z515HW;t00000NkvXXu0mjfyR8dj diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/TrackingLocationOff@2x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/TrackingLocationOff@2x.png deleted file mode 100644 index 01f4da7cbc978ad04117f9741c6cb5f4cc267c6c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 649 zcmV;40(Sk0P)x1Ys0DwQakNYa^&_yAA3FHD>Tw}i-d}kqf4T!VC>5yLsQtg4@pOC!FVbCW{AowJN`W3kGPt15)0Z!%DuQVX; z0KpeEqdNL~cN?~OHj9^|z`Tp_hte=njcoAIO^h}T1^F9zsg5H~`6 zA@hRQrc=5kh zGH-g6nNxI|`JzOu`$DQmNmCg;EpN6`*lsiYGNDl!JuM7+Q9Nunp&r}7|EWx00000NkvXXu0mjfQ!XH8 diff --git a/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/TrackingLocationOff@3x.png b/submodules/LegacyComponents/Resources/LegacyComponentsResources.bundle/TrackingLocationOff@3x.png deleted file mode 100644 index be8ac1a6abfc77cfd1e67116959530473300fde9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 796 zcmV+%1LOROP)Fmy7{@_}yBp_kHtaeBk#E21`@ASQA(m5QrPVP&IM)53@z#2( zE$93?Vi_YNpTmXWv2u%Q$=J*$V!24heeJxsydmp`$;xcRB7)gI( zrVi9cnc;#)9)STSiCa4fVdM!=W=0jrelV%P^zyUu)fj1QrNtO&ZwJcEqypIwr4^W7 zCjN6AZEya&G36#uW~LQrQD*lFWOoNwAf_i}8hO_5?*fm) z3S_y8D-e^9GD8I#cVh0m>t2CW6ls# z&&N|?H2k3uFAN_HKMwkrw=q0}QlLhHFhV$j@L#}!*Nvsn5Q&f&iIW73IQ$hQVZfX4 zI>`tlAdjc4Wh7JU1)|4k=VDb%fscoJYJ9g-UYUY5iJSw zJ})y7f+RNE{x+v#*(e+YG_~5YS@g4y`&e}ZwO1q2nKm~p9e27w?;zSNcsjs6UCGCE zMF0+}uV>t`<^1L((NPYx*~BtW(-DEcH8{9e0Q+FW=$)==SUT?Yf)h1nGqWc2?~&*I zPmdPU#q_iOrB7gA%{&r<{jgbLWlVC|g@2AMoG3}sEDxj3eg>xMMK;fh3;48`gXz{0 zV#wHYZDcFi`dz2^?W+kC!vcf1H%^NSuC)Tl^e;V=rV3FQB3nobM)UG1$s~iTY=Vnv zSO4-AfA@+jZuJ0yW?rf=q<|w5c>a(${dfSx2(lxYE1pPOgS|A{V#HV&bO&oBcDq}g zUK#Zh0eE{L4ompeBOhs8@H2;I*t3ksdq~Z2kN*DSbZ%xpdgx zD5f_jQQ`AoZ^$kN9y7Dpv^l=qZsk4S`kOX!zLdMZ2hawLBuUP;-|hV2L$uc~7S0MP z|Ji57GONa6bww%n{a(z!B;pfbFRL*E7z66BK1VFuV(@w_SF=*CFm!PTz?%TBV`K+q zi!qkJ+AjX+ZB7!yi>HdqX~N(yMjsB|>Y3}le*o)ZK&XrSsQS`~_>%{Rt;jHKju72> z<4N%!wMv1z7;AR^nfDCMQKK3f<5&W-$VkeOakB#*=;Jo?3zeiE4%P}LT*JiU0mXr0 zG+TEcX}-~0n-nf-QqE8BvTU$jm>|v1J{MQ5oLSATj4d8r*snTIxQSn$bl5EFjB9?} zBV$PmL^JD#G-o$du{@UZzwNVbK+}E6)vV(-iAnvNN9}enwb!!B1)1c^`I)`4A0T$v ze4t{hW2H6}8`Wm0bUNl#5U}y-U2->cWheJSl^)sDP_Y^B3s%=EMC7#Rq7o*UgwA?!)SCgN23o_Ku2czfZBbW1c z`+riBV*XGqGB`Tnn;l9On<`CJaH*!Y+BL}GERj%NXb_}u(9X4bMR1}un#R{!mp`kR1)YmxH`3m&@H_*!O*8lhO4!hv~3y}iB2$jHFJz{A7C!otGJ%F52p&ezx1 z;o;%z?ChVPpM8COc6N4YX=&!>=H=z(<>lq=?d|sV_WAkw_V)Jo_xJbr_xk$!`~3X> z|Ns5{{rdX)@9*#G>gwm`=i=hx`1ts)uC6dJFyG(b2L}iA^z<7W8`jp=n3$Nfw6y#C z`^w77@$vCtVPWv_@UXD3Z*On4wYAmN)#T*l_V)I;xVX>H&q+y1MpAGmnV2>J0032V zQchC<0RjUC2@DYx7a1KNAtNOwD>gbnK1o(zWovJ4a)OVXpQf*|vT9L3Kf%-BxK7n}G4>?e2jUvndRQpzOf$6<%@O|9i}2lETc1m}z%ry8AsZNY;K{m-5w4CBMbt zrv`=khzRXB=ifr_PnUuMiuV22_FL&A)WaHMx@A4R9APj8P~}u7Eyft?PIJzQ80kaz zP4E4)bXn#WCV} zxdW8|7>47Lbnb{+`SEwtw2m}0>ZzAb{7jp3LXUdDSWd;jg{*bgDr)AQ-87;&o1wHx zh!I?_bO^1$g^bAzwcD`PdR)-kYsY|=g^gfL<^X&VA{VnZF90d{L*oVX(~7oCxk!3z z*?Xtw^VZgg0$a@xxR4mr04O#+{WzGTA8zVH;BDFEA||yKoCZHuDUezN z)_i_vTfo11Hz*e}GQV&H;G6Uj&G|#e(@o%~NiMc#j17*cp>n|duC>8PvT1}OW<=5D?2#y%T z+ANTKB}Rhyql+h zPF{cHa;n5{I{z|7=7qsp>um{Od;cDr-JIS3WF!%~WOnP@)o)ifwybb!!3Yk}xI8_k z;2uia0?L*eyZFIDJ7W{gP&8Y9btZPpK3=(76y>A$>cgE`rmp;79Ma8!|)`@paPms1dS2$4;3yQ0y`gy#c95) z_jjB0b99C9@MZ?ivp(p!%^^pfc+teb1(-Z~JDSA{HOrZF>kE5>+{6#nPpESGdUBB2S1B;7AZ7qRcjcJqUW5R;mt8Q}qFG z*GWhcpb98T&wDrMQ9a-Sv&jSc>;o~V3P#Z9jG*%efL&J=F-lwHX=#j2046rxyZVd* z**io!Z1Uda<84kYDueAUgX+tn_0fIdytj6f%wG*5h!}w#YY89h**N=sP-9F^o5aZA zv=}d~15}raX%CS7R|pyb`qaG^!t#CwXkG>d{8u3;jTGQ$B+*%VbSW~}ycOfia<#=@-Qhf0tk(YT zK~Y)zb`F@BrlxhbdAM@7kkoyb_R{nzX?T4(6He)VGy2H&eL7@R=}`^BdBzGI2MJcH zO1P9RixoP=IdP4@K`U<)`Qj2lF?l<)RjX)~CO2g|DyyI38(`}Yk8oE(5^6&z>W zsKCTg4iHwdxA^#n8%GmgjRMb{aP6B>;BapClKm`_{4%Aq6|+~(7k+Ws%)}!{S8Gcn zLQkF>0XVD_K+;s)oi8L-mDjRVkThFNKaZsk#ozu5Kn%^$$gg|OWJdt0(xye29^X;a z16YGp3P_^Fa$;}cSUDBv4`k0wmP*gahpmNfW2NvlE_ifd$7a_V+GcfYAv zhN8y4Qc|<{?A$1~Kd^}jJNbQ(UCpG9glR#jCUX|eLp??!4=eRI`&0Lzdf zn>QwHNlnByX77~&z%Z<;SSsx9m{0>5+ur@~Ug2pIhL@z)E;N(N2gVqy0?HplKs9Qd zX{Gsc>3!v?Ee-3Okvkun*#j{~I*^3vJtk2&8l7ULLDw|=!Wf4W`%LXpX-90orZ?Zd zud%9>8q>g7W5oanf&hyj+-4aBg!jH@YnCp77w#!2EV874LZl;x5F)39+Su;iqWgth juzCehR3CrE$T|NHQ2n1`xj8#|00000NkvXXu0mjf+}KN@ diff --git a/submodules/LegacyComponents/Sources/AVAsset+CBExtension.h b/submodules/LegacyComponents/Sources/AVAsset+CBExtension.h deleted file mode 100755 index eb5cb5c3f4..0000000000 --- a/submodules/LegacyComponents/Sources/AVAsset+CBExtension.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// AVAsset+Extension.h -// CoubPlayer -// -// Created by Pavel Tikhonenko on 19/10/14. -// Copyright (c) 2014 Pavel Tikhonenko. All rights reserved. -// - -#import - -@interface AVAsset (CBExtension) - -@property (nonatomic, readonly) AVAssetTrack *anyVideoTrack; -@property (nonatomic, readonly) AVAssetTrack *anyAudioTrack; - -@end diff --git a/submodules/LegacyComponents/Sources/AVAsset+CBExtension.m b/submodules/LegacyComponents/Sources/AVAsset+CBExtension.m deleted file mode 100755 index 4ecf0fe334..0000000000 --- a/submodules/LegacyComponents/Sources/AVAsset+CBExtension.m +++ /dev/null @@ -1,25 +0,0 @@ -// -// AVAsset+Extension.m -// CoubPlayer -// -// Created by Pavel Tikhonenko on 19/10/14. -// Copyright (c) 2014 Pavel Tikhonenko. All rights reserved. -// - -#import "AVAsset+CBExtension.h" - -@implementation AVAsset (CBExtension) - -- (AVAssetTrack *)anyVideoTrack -{ - NSArray *videoTracks = [self tracksWithMediaType:AVMediaTypeVideo]; - return [videoTracks count] ? videoTracks[0] : nil; -} - -- (AVAssetTrack *)anyAudioTrack -{ - NSArray *audioTracks = [self tracksWithMediaType:AVMediaTypeAudio]; - return [audioTracks count] ? audioTracks[0] : nil; -} - -@end diff --git a/submodules/LegacyComponents/Sources/CBAssetDownloadManager.h b/submodules/LegacyComponents/Sources/CBAssetDownloadManager.h deleted file mode 100755 index 5b91844ea5..0000000000 --- a/submodules/LegacyComponents/Sources/CBAssetDownloadManager.h +++ /dev/null @@ -1,66 +0,0 @@ -// -// Created by Tikhonenko Pavel on 23/05/2014. -// Copyright (c) 2014 Coub. All rights reserved. -// - -#import -#import "CBCoubAsset.h" - -@protocol CBDownloadOperationDelegate; - -typedef NS_ENUM(NSInteger, CBDownloadProcessType) -{ - CBDownloadProcessTypeCoub, - CBDownloadProcessTypeChunks, -}; - -@interface CBAssetDownloadManager : NSObject - -- (void)downloadCoubWithoutChunks:(id)coub - tag:(NSInteger)tag - withDelegate:(id)delegate - downloadSucces:(void (^)(id coub, NSInteger tag))success downloadFailure:(void (^)(id coub, NSInteger tag, NSError *error))failure; - -- (void)downloadCoub:(id)coub - tag:(NSInteger)tag - withDelegate:(id)delegate - withChunks:(BOOL)withChunks - downloadSucces:(void (^)(id coub, NSInteger tag))success downloadFailure:(void (^)(id coub, NSInteger tag, NSError *error))failure; - -#pragma mark - -#pragma mark Downloading video and first chunk - -//- (void)downloadCoub:(id)coub -// tag:(NSInteger)tag -// withDelegate:(id)delegate -// downloadSucces:(void (^)(id coub, NSInteger tag))success downloadFailure:(void (^)(id coub, NSInteger tag, NSError *error))failure; - -- (void)downloadNextCoub:(id)coub - tag:(NSInteger)tag - downloadSucces:(void (^)(id coub, NSInteger tag))success downloadFailure:(void (^)(id coub, NSInteger tag, NSError *error))failure; - -- (void)cancelDownloadingForCoub:(id)coub; - -#pragma mark - -#pragma mark Downloading remaining chunks - -- (void)downloadChunkWithCoub:(id)coub - tag:(NSInteger)tag - chunkIdx:(NSInteger)chunkIdx - downloadSucces:(void (^)(id coub, NSInteger tag))success - downloadFailure:(void (^)(id coub, NSInteger tag, NSError *error))failure; - -- (void)downloadNextChunkWithCoub:(id)coub - downloadSucces:(void (^)(id coub, NSInteger tag))success - downloadFailure:(void (^)(id coub, NSInteger tag, NSError *error))failure; -//- (void)downloadRemainingChunksWithCoub:(id)coub -// tag:(NSInteger)tag -// downloadChunkSucces:(void (^)(id coub, NSInteger tag, NSInteger chunkIdx))chunkDownloaded -// downloadSucces:(void (^)(id coub, NSInteger tag))success -// downloadFailure:(void (^)(id coub, NSInteger tag, NSError *error))failure; - -- (void)stopAllDownloads; - -+ (instancetype)sharedManager; - -@end \ No newline at end of file diff --git a/submodules/LegacyComponents/Sources/CBAssetDownloadManager.m b/submodules/LegacyComponents/Sources/CBAssetDownloadManager.m deleted file mode 100755 index 36792d0480..0000000000 --- a/submodules/LegacyComponents/Sources/CBAssetDownloadManager.m +++ /dev/null @@ -1,290 +0,0 @@ -// -// Created by Tikhonenko Pavel on 23/05/2014. -// Copyright (c) 2014 Coub. All rights reserved. -// - -#import "CBAssetDownloadManager.h" -#import "CBCoubDownloadOperation.h" -#import "CBChunkDownloadOperation.h" -#import "CBDownloadOperation.h" -#import "CBDownloadOperationDelegate.h" - - -@interface CBAssetDownloadManager () - -@property (nonatomic, strong) CBCoubDownloadOperation *currentCoubDownloadingOperation; -@property (nonatomic, strong) CBCoubDownloadOperation *pausedCoubDownloadingOperation; -@property (nonatomic, strong) CBCoubDownloadOperation *nextCoubDownloadingOperation; -@property (nonatomic, strong) CBChunkDownloadOperation *currentChunksDownloadingOperation; - -- (void)resumeCoubDownloading; -- (void)destroyDownloadOperation:(id)downloadOperation; - -- (id)operationWithType:(CBDownloadProcessType)type - coub:(id)coub tag:(NSInteger)tag - downloadSucces:(void (^)(id coub, NSInteger tag))success - downloadFailure:(void (^)(id coub, NSInteger tag, NSError *error))failure; -@end - -@implementation CBAssetDownloadManager - -- (id)init -{ - self = [super init]; - - if(self) - { - } - - return self; -} - -- (void)downloadCoubWithoutChunks:(id)coub - tag:(NSInteger)tag - withDelegate:(id)delegate - downloadSucces:(void (^)(id coub, NSInteger tag))success downloadFailure:(void (^)(id coub, NSInteger tag, NSError *error))failure -{ - if(_currentChunksDownloadingOperation) - { - //_pausedCoubDownloadingOperation = _currentChunksDownloadingOperation; - [self destroyDownloadOperation:_currentChunksDownloadingOperation]; - _currentChunksDownloadingOperation = nil; - } - - [self downloadCoub:coub tag:tag withDelegate:delegate queuePriority:NSOperationQueuePriorityNormal withChunks:NO downloadSucces:success downloadFailure:failure]; -} - - -#pragma mark - -#pragma mark Downloading video and first chunk - -- (void)downloadCoub:(id)coub - tag:(NSInteger)tag - withDelegate:(id)delegate - withChunks:(BOOL)withChunks - downloadSucces:(void (^)(id coub, NSInteger tag))success downloadFailure:(void (^)(id coub, NSInteger tag, NSError *error))failure -{ - if(_currentChunksDownloadingOperation) - { - //_pausedCoubDownloadingOperation = _currentChunksDownloadingOperation; - [self destroyDownloadOperation:_currentChunksDownloadingOperation]; - _currentChunksDownloadingOperation = nil; - } - - [self downloadCoub:coub tag:tag withDelegate:delegate queuePriority:NSOperationQueuePriorityNormal withChunks:withChunks downloadSucces:success downloadFailure:failure]; -} - -- (void)downloadCoub:(id)coub - tag:(NSInteger)tag - withDelegate:(id)delegate - queuePriority:(NSOperationQueuePriority)queuePriority - withChunks:(BOOL)withChunks - downloadSucces:(void (^)(id coub, NSInteger tag))success downloadFailure:(void (^)(id coub, NSInteger tag, NSError *error))failure -{ - if(_currentCoubDownloadingOperation && _currentCoubDownloadingOperation.coub == coub && !_currentChunksDownloadingOperation.comleted) - { - _currentCoubDownloadingOperation.operationViewDelegate = delegate; - [_currentCoubDownloadingOperation setClientSuccess:success]; - [_currentCoubDownloadingOperation setClientFailure:failure]; - return; - } - - if(_nextCoubDownloadingOperation && _nextCoubDownloadingOperation.coub == coub && !_nextCoubDownloadingOperation.comleted) - { - [self destroyDownloadOperation:_nextCoubDownloadingOperation]; - } - - if(_currentCoubDownloadingOperation) - [self destroyDownloadOperation:_currentCoubDownloadingOperation]; - - id downloadOperation = [self operationWithType:CBDownloadProcessTypeCoub - coub:coub tag:tag downloadSucces:success downloadFailure:failure]; - downloadOperation.queuePriority = queuePriority; - - _currentCoubDownloadingOperation = downloadOperation; - _currentCoubDownloadingOperation.chunkDownloadingNeeded = withChunks; - [_currentCoubDownloadingOperation setOperationViewDelegate:delegate]; - [_currentCoubDownloadingOperation start]; -} - -- (void)downloadNextCoub:(id)coub - tag:(NSInteger)tag - downloadSucces:(void (^)(id coub,NSInteger tag))success downloadFailure:(void (^)(id coub,NSInteger tag, NSError *error))failure -{ - if(_currentChunksDownloadingOperation && _currentChunksDownloadingOperation.coub == coub && !_currentChunksDownloadingOperation.comleted) - { - failure(self, 0, nil); - return; - } - - - if(_nextCoubDownloadingOperation) - [self destroyDownloadOperation:_nextCoubDownloadingOperation]; - - - id downloadOperation = [self operationWithType:CBDownloadProcessTypeCoub - coub:coub tag:tag downloadSucces:success downloadFailure:failure]; - downloadOperation.queuePriority = NSOperationQueuePriorityVeryLow; - - _nextCoubDownloadingOperation = downloadOperation; - [_nextCoubDownloadingOperation setOperationViewDelegate:nil]; - [_nextCoubDownloadingOperation start]; -} - -- (void)cancelDownloadingForCoub:(id)coub -{ - if(_currentCoubDownloadingOperation && _currentCoubDownloadingOperation.coub == coub) - [self destroyDownloadOperation:_currentCoubDownloadingOperation]; -} - -#pragma mark - -#pragma mark Downloading remaining chunks - -- (void)downloadChunkWithCoub:(id)coub - tag:(NSInteger)tag - chunkIdx:(NSInteger)chunkIdx - downloadSucces:(void (^)(id coub, NSInteger tag))success - downloadFailure:(void (^)(id coub, NSInteger tag, NSError *error))failure -{ - [self destroyDownloadOperation:_currentChunksDownloadingOperation]; - - _currentChunksDownloadingOperation = [self operationWithType:CBDownloadProcessTypeChunks coub:coub - tag:tag downloadSucces:success downloadFailure:failure]; - - __weak typeof(self) wSelf = self; - - _currentChunksDownloadingOperation.chunkIdx = chunkIdx; - [_currentChunksDownloadingOperation setCompletionBlock:^(id process, NSError *error) { - [wSelf destroyDownloadOperation:process]; - [wSelf resumeCoubDownloading]; - }]; - - [_currentChunksDownloadingOperation start]; -} - -- (void)downloadNextChunkWithCoub:(id)coub - downloadSucces:(void (^)(id coub, NSInteger tag))success - downloadFailure:(void (^)(id coub, NSInteger tag, NSError *error))failure -{ - NSInteger chunkIdx = 0; - [self downloadChunkWithCoub:coub tag:chunkIdx chunkIdx:chunkIdx downloadSucces:success downloadFailure:failure]; -} - -- (void)downloadRemainingChunksWithCoub:(id)coub tag:(NSInteger)tag - downloadChunkSucces:(void (^)(id coub, NSInteger tag, NSInteger chunkIdx))chunkDownloaded - downloadSucces:(void (^)(id coub,NSInteger tag))success - downloadFailure:(void (^)(id coub, NSInteger tag, NSError *error))failure -{ - [self destroyDownloadOperation:_currentChunksDownloadingOperation]; - - _currentChunksDownloadingOperation = [self operationWithType:CBDownloadProcessTypeChunks coub:coub - tag:tag downloadSucces:success downloadFailure:failure]; - - __weak typeof(self) wSelf = self; - - _currentChunksDownloadingOperation.chunkDownloadedBlock = chunkDownloaded; - [_currentChunksDownloadingOperation setCompletionBlock:^(id process, NSError *error) { - [wSelf destroyDownloadOperation:process]; - [wSelf resumeCoubDownloading]; - }]; - - [_currentChunksDownloadingOperation start]; -} - -- (void)stopAllDownloads -{ - [self destroyCurrentOperations]; - - _pausedCoubDownloadingOperation = nil; -} - -#pragma mark - -#pragma mark private method - -- (void)resumeCoubDownloading -{ - if(_pausedCoubDownloadingOperation) - { - _currentCoubDownloadingOperation = _pausedCoubDownloadingOperation; - [_currentCoubDownloadingOperation start]; - } -} - -- (void)destroyCurrentOperations -{ - [self destroyDownloadOperation:_currentCoubDownloadingOperation]; - - [self destroyDownloadOperation:_currentChunksDownloadingOperation]; - - //_pausedCoubDownloadingOperation = nil; -} - -- (void)destroyDownloadOperation:(id)downloadOperation -{ - if(downloadOperation) - [downloadOperation cancel]; - - if(downloadOperation == _currentCoubDownloadingOperation) - _currentCoubDownloadingOperation = nil; - - if(downloadOperation == _currentChunksDownloadingOperation) - _currentChunksDownloadingOperation = nil; -} - -#pragma mark - -#pragma mark Factory method - -- (id)operationWithType:(CBDownloadProcessType)type - coub:(id)coub tag:(NSInteger)tag - downloadSucces:(void (^)(id, NSInteger tag))success - downloadFailure:(void (^)(id, NSInteger tag, NSError *error))failure -{ - id downloadOperation; - - switch(type) - { - case CBDownloadProcessTypeCoub: - { - downloadOperation = [CBCoubDownloadOperation new]; - break; - } - - case CBDownloadProcessTypeChunks: - { - downloadOperation = [CBChunkDownloadOperation new]; - break; - } - } - - [downloadOperation setTag:tag]; - [downloadOperation setCoub:coub]; - [downloadOperation setClientSuccess:success]; - [downloadOperation setClientFailure:failure]; - - __weak typeof(self) wSelf = self; - - [downloadOperation setCompletionBlock:^(id operation, NSError *error) { - [wSelf destroyDownloadOperation:operation]; - [wSelf resumeCoubDownloading]; - }]; - - return downloadOperation; -} - -#pragma mark - -#pragma mark Singleton implementation - -static CBAssetDownloadManager *instance = nil; - -+ (instancetype)sharedManager -{ - if(instance != nil) return instance; - - static dispatch_once_t onceToken = 0; - dispatch_once(&onceToken, ^{ - instance = [[self alloc] init]; - }); - return instance; -} - -@end \ No newline at end of file diff --git a/submodules/LegacyComponents/Sources/CBChunkDownloadOperation.h b/submodules/LegacyComponents/Sources/CBChunkDownloadOperation.h deleted file mode 100755 index d7439ca0d3..0000000000 --- a/submodules/LegacyComponents/Sources/CBChunkDownloadOperation.h +++ /dev/null @@ -1,14 +0,0 @@ -// -// Created by Tikhonenko Pavel on 23/05/2014. -// Copyright (c) 2014 Coub. All rights reserved. -// - -#import "CBGenericDownloadOperation.h" - -@interface CBChunkDownloadOperation : CBGenericDownloadOperation - -@property (nonatomic, assign) NSInteger chunkIdx; - -@property(nonatomic, copy) void (^chunkDownloadedBlock)(id, NSInteger tag, NSInteger chunkIdx); - -@end \ No newline at end of file diff --git a/submodules/LegacyComponents/Sources/CBChunkDownloadOperation.m b/submodules/LegacyComponents/Sources/CBChunkDownloadOperation.m deleted file mode 100755 index 467bd77c95..0000000000 --- a/submodules/LegacyComponents/Sources/CBChunkDownloadOperation.m +++ /dev/null @@ -1,65 +0,0 @@ -// -// Created by Tikhonenko Pavel on 23/05/2014. -// Copyright (c) 2014 Coub. All rights reserved. -// - -#import "CBChunkDownloadOperation.h" - -#import "LegacyComponentsInternal.h" -#import "LegacyHTTPRequestOperation.h" - -@implementation CBChunkDownloadOperation -{ - -} - -- (void)start -{ - [super start]; - [self downloadChunk]; -} - -- (void)downloadChunk -{ - NSURL *localURL = [self.coub localAudioChunkWithIdx:_chunkIdx]; - - NSURL *remoteURL = [self.coub remoteAudioChunkWithIdx:_chunkIdx+1]; - - NSURLRequest *downloadRequest = [NSURLRequest requestWithURL:remoteURL]; - - self.downloadOperation = [[LegacyComponentsGlobals provider] makeHTTPRequestOperationWithRequest:downloadRequest]; - self.downloadOperation.queuePriority = self.queuePriority; - self.downloadOperation.outputStream = [NSOutputStream outputStreamToFileAtPath:localURL.path append:NO]; - //[self.downloadOperation setShouldExecuteAsBackgroundTaskWithExpirationHandler:nil]; - - __weak typeof(self) wSelf = self; - - [self.downloadOperation setCompletionBlockWithSuccess:^(__unused id operation, __unused id responseObject) { - [wSelf successChunkDownload]; - } failure:^(__unused id operation, __unused NSError *error) { - [wSelf failureDownloadWithError:error]; - }]; - - [self.downloadOperation start]; -} - -- (void)successChunkDownload -{ - //NSLog(@"successChunkDownload"); - - [self successDownload]; -} - -- (instancetype)clone -{ - CBChunkDownloadOperation *clone = [CBChunkDownloadOperation new]; - [clone setTag:self.tag]; - [clone setCoub:self.coub]; - [clone setCompletionBlock:self.completionBlock]; - [clone setClientSuccess:self.clientSuccess]; - [clone setClientFailure:self.clientFailure]; - [clone setChunkDownloadedBlock:self.chunkDownloadedBlock]; - return clone; -} - -@end diff --git a/submodules/LegacyComponents/Sources/CBConstance.h b/submodules/LegacyComponents/Sources/CBConstance.h deleted file mode 100755 index f448703234..0000000000 --- a/submodules/LegacyComponents/Sources/CBConstance.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// CBConstance.h -// CoubPlayer -// -// Created by Pavel Tikhonenko on 19/10/14. -// Copyright (c) 2014 Pavel Tikhonenko. All rights reserved. -// - -#import - -typedef void (^CBSuccessBlock)(id result); -//typedef void (^CBSuccessWithUserInfoBlock)(id result, id userInfo); -typedef void (^CBFailureBlock)(NSError *error); - -extern NSString * const kCBServerURL; - -extern NSString * const CBCoubLoopErrorDomain; -enum { - CBCoubLoopErrorUnknown = 1, - CBCoubLoopErrorNoSuchFile, - CBCoubLoopErrorUnsupportedAudioFormat, - CBCoubLoopErrorUnreadableAudioTrack, - CBCoubLoopErrorNoVideoTracks, - CBCoubLoopErrorCanceled, -}; - - -extern NSString *const CBPlayerInterruptionDidBeginNotification; -extern NSString *const CBPlayerInterruptionDidEndNotification; - -@interface CBConstance : NSObject - -@end diff --git a/submodules/LegacyComponents/Sources/CBConstance.m b/submodules/LegacyComponents/Sources/CBConstance.m deleted file mode 100755 index 8528fb4e1c..0000000000 --- a/submodules/LegacyComponents/Sources/CBConstance.m +++ /dev/null @@ -1,21 +0,0 @@ -// -// CBConstance.m -// CoubPlayer -// -// Created by Pavel Tikhonenko on 19/10/14. -// Copyright (c) 2014 Pavel Tikhonenko. All rights reserved. -// - -#import "CBConstance.h" - -NSString *const kCBServerURL = @"http://coub.com"; - -NSString *const CBCoubLoopErrorDomain = @"com.coub.loop.ErrorDomain"; - -NSString *const CBPlayerInterruptionDidBeginNotification = @"CBPlayerInterruptionDidBeginNotification"; -NSString *const CBPlayerInterruptionDidEndNotification = @"CBPlayerInterruptionDidEndNotification"; - - -@implementation CBConstance - -@end diff --git a/submodules/LegacyComponents/Sources/CBCoubAsset.h b/submodules/LegacyComponents/Sources/CBCoubAsset.h deleted file mode 100755 index bb921e8773..0000000000 --- a/submodules/LegacyComponents/Sources/CBCoubAsset.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// Created by Tikhonenko Pavel on 04/04/2014. -// Copyright (c) 2014 Coub. All rights reserved. -// - -#import -#import "CBCoubPlayerContance.h" - -@protocol CBCoubAsset - -@property(nonatomic, readonly) NSString *assetId; //permalink -@property(nonatomic, readonly) NSURL *localVideoFileURL; -@property(nonatomic, readonly) CBCoubAudioType audioType; -@property(nonatomic, readonly) NSURL *externalAudioURL; //may be nil -@property(nonatomic, readonly) NSURL *largeImageURL; - -- (BOOL)failedDownloadChunk; - -- (NSURL *)remoteVideoFileURL; - -- (NSURL *)localAudioChunkWithIdx:(NSInteger)idx; -- (NSURL *)remoteAudioChunkWithIdx:(NSInteger)idx; - - -@end \ No newline at end of file diff --git a/submodules/LegacyComponents/Sources/CBCoubAudioSource.h b/submodules/LegacyComponents/Sources/CBCoubAudioSource.h deleted file mode 100755 index a9161dab91..0000000000 --- a/submodules/LegacyComponents/Sources/CBCoubAudioSource.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// CBCoubAudioSource.h -// Coub -// -// Created by Tikhonenko Pavel on 18/11/2013. -// Copyright (c) 2013 Coub. All rights reserved. -// - -#import - -@interface CBCoubAudioSource : NSObject - -@property (nonatomic, strong) NSString *cover; -@property (nonatomic, strong) NSString *title; -@property (nonatomic, strong) NSString *artist; -@property (nonatomic, strong) NSString *itunesURL; -@property (nonatomic, strong) NSString *songName; - -+ (CBCoubAudioSource *)sourceFromData:(NSDictionary *)dict; - -@end diff --git a/submodules/LegacyComponents/Sources/CBCoubAudioSource.m b/submodules/LegacyComponents/Sources/CBCoubAudioSource.m deleted file mode 100755 index be04846066..0000000000 --- a/submodules/LegacyComponents/Sources/CBCoubAudioSource.m +++ /dev/null @@ -1,32 +0,0 @@ -// -// CBCoubAudioSource.m -// Coub -// -// Created by Tikhonenko Pavel on 18/11/2013. -// Copyright (c) 2013 Coub. All rights reserved. -// - -#import "CBCoubAudioSource.h" - -@implementation CBCoubAudioSource - -+ (CBCoubAudioSource *)sourceFromData:(NSDictionary *)dict -{ - if(!dict.count) return nil; - - - NSDictionary *meta = dict[@"meta"]; - - CBCoubAudioSource *source = [[CBCoubAudioSource alloc] init]; - source.cover = dict[@"image"]; - source.itunesURL = dict[@"url"]; - source.songName = meta[@"title"]; - source.title = source.songName; - source.artist = meta[@"artist"]; - if(source.title == nil || source.itunesURL == nil) - return nil; - - return source; -} - -@end diff --git a/submodules/LegacyComponents/Sources/CBCoubAuthorVO.h b/submodules/LegacyComponents/Sources/CBCoubAuthorVO.h deleted file mode 100755 index 2d1ca547ae..0000000000 --- a/submodules/LegacyComponents/Sources/CBCoubAuthorVO.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// CBCoubAuthorVO.h -// Coub -// -// Created by Tikhonenko Pavel on 21/11/2013. -// Copyright (c) 2013 Coub. All rights reserved. -// - -#import - -@interface CBCoubAuthorVO : NSObject - -@property (nonatomic, strong) NSString *avatarURL; -@property (nonatomic, strong) NSString *largeAvatarURL; -@property (nonatomic, assign) NSInteger followersCount; -@property (nonatomic, assign) NSInteger viewsCount; -@property (nonatomic, strong) NSString *userId; -@property (nonatomic, strong) NSString *name; -@property (nonatomic, strong) NSString *permalink; - -+ (CBCoubAuthorVO *)coubAuthorWithAttributes:(NSDictionary *)attributes; -+ (CBCoubAuthorVO *)currentUser; -@end diff --git a/submodules/LegacyComponents/Sources/CBCoubAuthorVO.m b/submodules/LegacyComponents/Sources/CBCoubAuthorVO.m deleted file mode 100755 index cd54782c86..0000000000 --- a/submodules/LegacyComponents/Sources/CBCoubAuthorVO.m +++ /dev/null @@ -1,42 +0,0 @@ -// -// CBCoubAuthorVO.m -// Coub -// -// Created by Tikhonenko Pavel on 21/11/2013. -// Copyright (c) 2013 Coub. All rights reserved. -// - -#import "CBCoubAuthorVO.h" - -@implementation CBCoubAuthorVO - -+ (CBCoubAuthorVO *)coubAuthorWithAttributes:(NSDictionary *)attributes -{ - CBCoubAuthorVO *author = [CBCoubAuthorVO new]; - author.avatarURL = attributes[@"avatar"]; - author.largeAvatarURL = attributes[@"large_avatar"]; - author.followersCount = [attributes[@"followers_count"] integerValue]; - author.userId = [attributes[@"id"] stringValue]; - author.name = attributes[@"name"]; - author.permalink = attributes[@"permalink"]; - author.viewsCount = [attributes[@"views_count"] integerValue]; - //author.viewsCount; - return author; -} - -//+ (CBCoubAuthorVO *)currentUser -//{ -// CBUserNew *curUser = [CBUserNew currentUser]; -// -// CBCoubAuthorVO *author = [CBCoubAuthorVO new]; -// author.avatarURL = curUser.mediumAvatar; -// author.largeAvatarURL = curUser.largeAvatar; -// author.followersCount = curUser.followerCount; -// author.userId = curUser.coubID; -// author.name = curUser.fullName; -// author.permalink = curUser.permalink; -// author.viewsCount = curUser.viewsCount; -// return author; -//} - -@end diff --git a/submodules/LegacyComponents/Sources/CBCoubDownloadOperation.h b/submodules/LegacyComponents/Sources/CBCoubDownloadOperation.h deleted file mode 100755 index 6fcc7eb0a5..0000000000 --- a/submodules/LegacyComponents/Sources/CBCoubDownloadOperation.h +++ /dev/null @@ -1,12 +0,0 @@ -// -// Created by Tikhonenko Pavel on 23/05/2014. -// Copyright (c) 2014 Coub. All rights reserved. -// - -#import "CBGenericDownloadOperation.h" - -@interface CBCoubDownloadOperation : CBGenericDownloadOperation - -@property (nonatomic, assign) NSInteger neededChunkCount; - -@end \ No newline at end of file diff --git a/submodules/LegacyComponents/Sources/CBCoubDownloadOperation.m b/submodules/LegacyComponents/Sources/CBCoubDownloadOperation.m deleted file mode 100755 index eadca4f671..0000000000 --- a/submodules/LegacyComponents/Sources/CBCoubDownloadOperation.m +++ /dev/null @@ -1,190 +0,0 @@ -// -// Created by Tikhonenko Pavel on 23/05/2014. -// Copyright (c) 2014 Coub. All rights reserved. -// - -#import "CBCoubDownloadOperation.h" -#import "CBDownloadOperationDelegate.h" - -#import "LegacyComponentsInternal.h" - -@implementation CBCoubDownloadOperation -{ - BOOL _isVideoDownloaded; - NSInteger _currentChunkIdx; -} - -- (void)start -{ - [super start]; - - _neededChunkCount = NSNotFound; - _currentChunkIdx = 0; - - [self downloadVideo]; -} - -- (void)downloadVideo -{ - NSURL *remoteURL = [self.coub remoteVideoFileURL]; - NSURL *localURL = [self.coub localVideoFileURL]; - - _isVideoDownloaded = [[NSFileManager defaultManager] fileExistsAtPath:[localURL path]]; - if(_isVideoDownloaded) - { - [self successVideoDownload]; - return; - }else{ - //KALog(@"video doesn't %i", _currentChunkIdx); - } - - NSURLRequest *downloadRequest = [NSURLRequest requestWithURL:remoteURL]; - - __weak typeof(self) wSelf = self; - - self.downloadOperation = [[LegacyComponentsGlobals provider] makeHTTPRequestOperationWithRequest:downloadRequest]; - self.downloadOperation.queuePriority = self.queuePriority; - self.downloadOperation.outputStream = [NSOutputStream outputStreamToFileAtPath:localURL.path append:NO]; - //[self.downloadOperation setShouldExecuteAsBackgroundTaskWithExpirationHandler:nil]; - [self.downloadOperation setDownloadProgressBlock:^(__unused NSInteger bytesRead, NSInteger totalBytesRead, NSInteger totalBytesExpectedToRead) { - float progress = totalBytesRead / (float) totalBytesExpectedToRead; - [wSelf progressDownload:progress]; - }]; - - [self.downloadOperation setCompletionBlockWithSuccess:^(__unused id operation, __unused id responseObject) { - [wSelf successVideoDownload]; - } failure:^(__unused id operation, NSError *error) { - - if([[NSFileManager defaultManager] fileExistsAtPath:[localURL path]]) - [[NSFileManager defaultManager] removeItemAtPath:[localURL path] error:nil]; - - [wSelf failureDownloadWithError:error]; - }]; - - [self.downloadOperation start]; -} - -- (void)downloadChunk -{ - NSURL *localURL = [self.coub localAudioChunkWithIdx:_currentChunkIdx]; - - //int fileExist = [[CBLibrary sharedLibrary] isCoubChunkDownloadedByPermalink:self.coub.permalink idx:_currentChunkIdx]; - int fileExist = [[NSFileManager defaultManager] fileExistsAtPath:[localURL path]]; - - if(fileExist || (_neededChunkCount == NSNotFound && _currentChunkIdx > 1)) - { - [self successDownload]; - return; - } - - NSURL *remoteURL = [self.coub remoteAudioChunkWithIdx:_currentChunkIdx + 1]; - NSURLRequest *downloadRequest = [NSURLRequest requestWithURL:remoteURL]; - - //NSLog(@"chunk idx = %i, remoteURL = %@", _currentChunkIdx, remoteURL); - - __weak typeof(self) wSelf = self; - - self.downloadOperation = [[LegacyComponentsGlobals provider] makeHTTPRequestOperationWithRequest:downloadRequest]; - self.downloadOperation.queuePriority = self.queuePriority; - self.downloadOperation.outputStream = [NSOutputStream outputStreamToFileAtPath:localURL.path append:NO]; - //[self.downloadOperation setShouldExecuteAsBackgroundTaskWithExpirationHandler:nil]; - [self.downloadOperation setDownloadProgressBlock:^(__unused NSInteger bytesRead, NSInteger totalBytesRead, NSInteger totalBytesExpectedToRead) { - - if(wSelf.neededChunkCount == NSNotFound) - { - //NSLog(@"totalBytesExpectedToRead = %llu", totalBytesExpectedToRead); - - wSelf.neededChunkCount = MIN((int) ((1024*1024)/totalBytesExpectedToRead), 4); - wSelf.neededChunkCount = MAX(wSelf.neededChunkCount, 1); - } - - float progress = totalBytesRead / (float) totalBytesExpectedToRead; - [wSelf progressDownload:progress]; - }]; - - [self.downloadOperation setCompletionBlockWithSuccess:^(__unused id operation, __unused id responseObject) { - //[wSelf.coub setFailedDownloadChunk:NO]; - [wSelf successChunkDownload]; - } failure:^(__unused id operation, NSError *error) { - - if([[NSFileManager defaultManager] fileExistsAtPath:[localURL path]]) - [[NSFileManager defaultManager] removeItemAtPath:[localURL path] error:nil]; - - if(error.code == -1011) - { - //NSLog(@"failed download"); - - //[wSelf.coub setFailedDownloadChunk:YES]; - [wSelf successDownload]; - - return; - } - //NSLog(@"failed download unknown"); - - [wSelf failureDownloadWithError:error]; - }]; - - [self.downloadOperation start]; -} - -- (void)successVideoDownload -{ - //[[CBLibrary sharedLibrary] markCoubAsset:self.coub asDownloaded:YES]; - - _isVideoDownloaded = YES; - - if(self.starting) - { - if(self.chunkDownloadingNeeded && [self.coub audioType] == CBCoubAudioTypeExternal) - [self downloadChunk]; - else - [super successDownload]; - } -} - -- (void)successDownload -{ - _currentChunkIdx++; - - if([self.coub audioType] != CBCoubAudioTypeExternal || _currentChunkIdx >= MIN(4, _neededChunkCount)) - { - [super successDownload]; - } - else - [self downloadChunk]; -} - -- (void)successChunkDownload -{ - [self successDownload]; -} - -- (void)progressDownload:(float)progress -{ - if(self.starting && self.operationViewDelegate) - { - float newProgress; - - if(_isVideoDownloaded) - { - newProgress = .5f + (_currentChunkIdx * 1/(float)_neededChunkCount + progress/(float)_neededChunkCount)*.5f; - }else{ - newProgress = progress/2.0f; - } - [self.operationViewDelegate downloadDidReachProgress:newProgress]; - } -} - -- (instancetype)clone -{ - CBCoubDownloadOperation *clone = [CBCoubDownloadOperation new]; - [clone setOperationViewDelegate:self.operationViewDelegate]; - [clone setTag:self.tag]; - [clone setCoub:self.coub]; - [clone setCompletionBlock:self.completionBlock]; - [clone setClientSuccess:self.clientSuccess]; - [clone setClientFailure:self.clientFailure]; - return clone; -} - -@end diff --git a/submodules/LegacyComponents/Sources/CBCoubLoopCompositionMaker.h b/submodules/LegacyComponents/Sources/CBCoubLoopCompositionMaker.h deleted file mode 100755 index e45269c609..0000000000 --- a/submodules/LegacyComponents/Sources/CBCoubLoopCompositionMaker.h +++ /dev/null @@ -1,41 +0,0 @@ -// -// Created by Tikhonenko Pavel on 26/11/2013. -// Copyright (c) 2013 Coub. All rights reserved. -// - - -#import -#import "CBCoubAsset.h" - -#import - -@class CBCoubLoopCompositionMaker; -@protocol CBCoubAsset; - -@protocol CBCoubLoopDelegate - -@required -- (void)coubLoopDidFinishPreparing:(CBCoubLoopCompositionMaker *)loop; -- (void)coubLoop:(CBCoubLoopCompositionMaker *)loop didFailToLoadWithError:(NSError *)error; - -@end - -@interface CBCoubLoopCompositionMaker : NSObject - -@property (nonatomic, weak) id delegate; -@property (nonatomic, strong) id asset; - -@property (nonatomic, strong) AVAsset *videoAsset; -@property (nonatomic, strong) NSError *error; -@property (nonatomic, readonly) BOOL hasAudio; - -@property (nonatomic, assign, getter=isLoopReady) BOOL loopReady; - -- (void)prepareLoop; -- (void)cancelPrepareLoop; - -- (void)notifyObservers; - -+ (instancetype)coubLoopWithAsset:(id)asset; - -@end \ No newline at end of file diff --git a/submodules/LegacyComponents/Sources/CBCoubLoopCompositionMaker.m b/submodules/LegacyComponents/Sources/CBCoubLoopCompositionMaker.m deleted file mode 100755 index 6d552e1839..0000000000 --- a/submodules/LegacyComponents/Sources/CBCoubLoopCompositionMaker.m +++ /dev/null @@ -1,322 +0,0 @@ -// -// Created by Tikhonenko Pavel on 26/11/2013. -// Copyright (c) 2013 Coub. All rights reserved. -// - - -#import -#import "CBCoubLoopCompositionMaker.h" -#import "CBCoubAsset.h" -#import "CBConstance.h" -#import "AVAsset+CBExtension.h" - -#pragma mark - -#pragma mark CBCoubLoopOperation - -static AVURLAsset *gDigitalSilenceAsset = nil; - -@interface CBCoubLoopOperation : NSOperation - -- (id)initWithCoubAsset:(id)asset loop:(CBCoubLoopCompositionMaker *)loop; - -- (void)prepareOperation; -- (void)makeLoop; -- (AVComposition *)makeLoopComposition; - -- (BOOL)checkAssetURL:(NSURL *)assetURL; - -- (void)completeWithError:(NSError *)error; - -@end - -@implementation CBCoubLoopOperation -{ -@private - id _asset; - CBCoubLoopCompositionMaker *_loop; - AVAssetExportSession *_exportSession; - - NSURL *_assetURL; - BOOL _hasExternalAudio; -} - -- (id)initWithCoubAsset:(id)asset loop:(CBCoubLoopCompositionMaker *)loop -{ - self = [super init]; - if(self) - { - _asset = asset; - _loop = loop; - } - return self; -} - -- (void)main -{ - if([self isCancelled]) - return; - - [self prepareOperation]; -} - -- (void)prepareOperation -{ - if(![self checkAssetURL:_asset.localVideoFileURL]) - return; - - _assetURL = _asset.localVideoFileURL; - _hasExternalAudio = _asset.externalAudioURL != nil; - - [self makeLoop]; -} - -- (void)makeLoop -{ - AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:_assetURL options:@{AVURLAssetPreferPreciseDurationAndTimingKey : @YES}]; -// _loop.videoAsset = avAsset; -// [self completeWithError:nil]; -// return; - if(_asset.audioType == CBCoubAudioTypeInternal) - { - AVComposition *composition = [self makeLoopComposition]; - if(![self isCancelled]) - { - _loop.videoAsset = composition; - [self completeWithError:nil]; - }else{ - - } - - }else{ - _loop.videoAsset = avAsset; - [self completeWithError:nil]; - } - -} - -- (AVComposition *)makeLoopComposition -{ - AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:_assetURL options:@{AVURLAssetPreferPreciseDurationAndTimingKey : @YES}]; - NSArray *videoTracks = [avAsset tracksWithMediaType:AVMediaTypeVideo]; - if([videoTracks count] == 0) - { - - //TODO: remove cache file and download again - - NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain - code:CBCoubLoopErrorNoVideoTracks - userInfo:_assetURL ? @{NSURLErrorKey : _assetURL} : nil]; - - [self completeWithError:error]; - - return nil; - } - - if([self isCancelled]) - return nil; - - AVAssetTrack *originalVideoTrack = videoTracks[0]; - AVAssetTrack *originalAudioTrack = _hasExternalAudio ? nil : avAsset.anyAudioTrack; - - if(originalVideoTrack == nil) - { - NSError *error = [NSError errorWithDomain:CBCoubLoopErrorDomain - code:CBCoubLoopErrorNoVideoTracks - userInfo:nil]; - [self completeWithError:error]; - return nil; - } - - CMTimeRange videoTrackTimeRange = originalVideoTrack.timeRange; -// videoTrackTimeRange.start.value = 1; -// videoTrackTimeRange.duration.value -= 2; - - CMTimeRange audioTrackTimeRange = originalAudioTrack ? originalAudioTrack.timeRange : kCMTimeRangeZero; -// if(originalAudioTrack) -// { -// audioTrackTimeRange.start.value = 1; -// audioTrackTimeRange.duration.value -= 2; -// } - - // Calculate the minimum duration of our composition - CMTime minimumCompositionDuration = CMTimeMake(60*audioTrackTimeRange.start.timescale, audioTrackTimeRange.start.timescale); - - if(!_hasExternalAudio) - { - if(originalAudioTrack) - audioTrackTimeRange = CMTimeRangeGetIntersection(audioTrackTimeRange, videoTrackTimeRange); - } - - AVAssetTrack *silence = nil; - CMTimeRange silenceTimeRange = kCMTimeRangeZero; - - if([self isCancelled]) - return nil; - - AVMutableComposition *composition = [AVMutableComposition composition]; - AVMutableCompositionTrack *videoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; - AVMutableCompositionTrack *audioTrack = originalAudioTrack ? [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid] : nil; - - CMTime videoTrackDuration = kCMTimeZero; - NSError *error = nil; - while(CMTIME_COMPARE_INLINE(videoTrackDuration, <, minimumCompositionDuration)) - { - if([self isCancelled]) - return nil; - - if(![videoTrack insertTimeRange:videoTrackTimeRange ofTrack:originalVideoTrack atTime:videoTrackDuration error:&error]) - { -// KAObjectLogError(@"Failed to insert %@ of video track %@ at %@: %@", CBStringFromTimeRange(videoTrackTimeRange), originalVideoTrack, CBStringFromTime(videoTrackDuration), error); - [self completeWithError:error]; - return nil; - } - if(audioTrack) - { - if(![audioTrack insertTimeRange:audioTrackTimeRange ofTrack:originalAudioTrack atTime:videoTrackDuration error:&error]) - { - -// KAObjectLogError(@"Failed to insert %@ of audio track %@ at %@: %@", CBStringFromTimeRange(audioTrackTimeRange), originalAudioTrack, CBStringFromTime(videoTrackDuration), error); - [self completeWithError:error]; - return nil; - } - } - if(silence) - { - if(![audioTrack insertTimeRange:silenceTimeRange ofTrack:silence atTime:CMTimeAdd(videoTrackDuration, audioTrackTimeRange.duration) error:&error]) - { - [self completeWithError:error]; - return nil; - } - } - videoTrackDuration = CMTimeAdd(videoTrackDuration, videoTrackTimeRange.duration); - } - - videoTrack.preferredTransform = originalVideoTrack.preferredTransform; - return composition; -} - -- (BOOL)checkAssetURL:(NSURL *)assetURL -{ - if (assetURL == nil || ([assetURL isFileURL] && ![[NSFileManager defaultManager] fileExistsAtPath: [assetURL path]])) - { - NSLog(@"File doesn't exist: %@", assetURL); - //TODO: remove cache file and download again - - NSError *error = [NSError errorWithDomain:CBCoubLoopErrorDomain - code:CBCoubLoopErrorNoSuchFile - userInfo:assetURL ? @{NSURLErrorKey : assetURL} : nil]; - [self completeWithError:error]; - return NO; - }else{ - return YES; - } -} - -- (void)cancel -{ - [_exportSession cancelExport]; - [super cancel]; -} - -- (void)completeWithError:(NSError *)error -{ - dispatch_async(dispatch_get_main_queue(), ^ - { - [_exportSession cancelExport]; - - _loop.error = error; - [_loop notifyObservers]; - }); -} -@end - -#pragma mark - -#pragma mark CBCoubLoop - -static NSOperationQueue *gOperationQueue = nil; - -@implementation CBCoubLoopCompositionMaker -{ -@private - CBCoubLoopOperation *_operation; -} - -+ (void)initialize -{ - if(!gOperationQueue) - { - gOperationQueue = [NSOperationQueue new]; - [gOperationQueue setMaxConcurrentOperationCount:1]; - } -} - -- (id)initWithAsset:(id)asset -{ - self = [super init]; - - if(self) - { - _asset = asset; - } - - return self; -} - -- (BOOL)hasAudio -{ - return !(_asset.audioType == CBCoubAudioTypeNone); -} - -- (void)prepareLoop -{ - if(gOperationQueue.operations.count) - [gOperationQueue cancelAllOperations]; - - if(!_operation) - { - self.error = nil; - - CBCoubLoopOperation *operation = [[CBCoubLoopOperation alloc] initWithCoubAsset:_asset loop:self]; - [gOperationQueue addOperation:operation]; - - _operation = operation; - //[_operation start]; - } -} - -- (void)cancelPrepareLoop -{ - self.videoAsset = nil; - - [_operation cancel]; - _operation = nil; - - self.error = [NSError errorWithDomain:CBCoubLoopErrorDomain - code:CBCoubLoopErrorCanceled - userInfo:nil]; - [_delegate coubLoop:self didFailToLoadWithError:self.error]; - -} - -- (void)notifyObservers -{ - NSAssert([NSThread isMainThread], @"%s must be called on the main thread", __PRETTY_FUNCTION__); - - if(self.error) - [_delegate coubLoop:self didFailToLoadWithError:self.error]; - else - { - _loopReady = YES; - [_delegate coubLoopDidFinishPreparing:self]; - } - - _operation = nil; -} - -+ (instancetype)coubLoopWithAsset:(id)asset -{ - CBCoubLoopCompositionMaker *instance = [[CBCoubLoopCompositionMaker alloc] initWithAsset:asset]; - return instance; -} - -@end diff --git a/submodules/LegacyComponents/Sources/CBCoubNew.h b/submodules/LegacyComponents/Sources/CBCoubNew.h deleted file mode 100755 index 19b534278a..0000000000 --- a/submodules/LegacyComponents/Sources/CBCoubNew.h +++ /dev/null @@ -1,70 +0,0 @@ -// -// CBCoubNew.h -// Coub -// -// Created by Tikhonenko Pavel on 18/11/2013. -// Copyright (c) 2013 Coub. All rights reserved. -// - -#import -#import "CBCoubAuthorVO.h" -#import "CBCoubAudioSource.h" -#import "CBCoubVideoSource.h" -#import "CBCoubAsset.h" - -@interface CBCoubNew : NSObject - -@property(nonatomic, strong) NSString *coubID; -@property(nonatomic, strong) NSString *permalink; -@property(nonatomic, strong) NSString *originalPermalink; -@property(nonatomic, strong) NSString *visibility; // kCBCoubVisibility*, see above -@property(nonatomic, assign) BOOL isDone; - -@property(nonatomic, strong) CBCoubAuthorVO *author; -@property(nonatomic, strong) CBCoubAuthorVO *recouber; - -@property(nonatomic, strong) NSString *title; -@property(nonatomic, strong) NSDate *creationDate; -@property(nonatomic, strong) NSDate *originalCreationDate; -@property(nonatomic, strong) NSArray *tags; //CBTagNew - -//Stats -@property(nonatomic, assign) NSUInteger viewCount; -@property(nonatomic, assign) NSUInteger likeCount; -@property(nonatomic, assign) NSUInteger recoubCount; -@property(nonatomic, assign) BOOL liked; // whether the current user likes the coub; does not update likeCount -@property(nonatomic, assign) BOOL recoubed; -@property(nonatomic, assign) BOOL cotd; -@property(nonatomic, assign) BOOL flagged; -@property(nonatomic, assign) BOOL deleted; - -@property(nonatomic, assign) CBCoubAudioType audioType; - -@property(nonatomic, strong) NSString *externalDownloadType; -@property(nonatomic, strong) NSString *externalDownloadSource; // youtube/vimeo URL - -//@property (nonatomic, readonly) NSOrderedSet *recoubersOthenThanCurrentUser; -@property (nonatomic, readonly) NSURL *coubWebViewURL; -@property(nonatomic, readonly) NSURL *mediumImageURL; -@property(nonatomic, readonly) NSURL *largeImageURL; -@property(nonatomic, readonly) BOOL isRecoub; -@property(nonatomic, readonly) BOOL isMyCoub; - -@property(nonatomic, retain) NSURL *customLocalVideoFileURL; -@property(nonatomic, retain) NSString *remoteVideoLocation; -@property(nonatomic, retain) NSString *remoteAudioLocation; -@property(nonatomic, retain) NSString *remoteAudioLocationPattern; -@property(nonatomic, retain) NSString *mediumPicture; -@property(nonatomic, retain) NSString *largePicture; -@property(nonatomic, retain) NSString *creationDateAsString; -@property(nonatomic, retain) NSString *originalCreationDateAsString; - -@property(nonatomic, readonly) NSURL *remoteVideoFileURL; - -@property(nonatomic, assign) BOOL isCoubSourcesAvailable; -@property(nonatomic, strong) CBCoubAudioSource *audioSource; -@property(nonatomic, strong) CBCoubVideoSource *videoSource; - -+ (CBCoubNew *)coubWithAttributes:(NSDictionary *)attributes; - -@end diff --git a/submodules/LegacyComponents/Sources/CBCoubNew.m b/submodules/LegacyComponents/Sources/CBCoubNew.m deleted file mode 100755 index 36c1db6f10..0000000000 --- a/submodules/LegacyComponents/Sources/CBCoubNew.m +++ /dev/null @@ -1,199 +0,0 @@ -// -// CBCoubNew.m -// Coub -// -// Created by Tikhonenko Pavel on 18/11/2013. -// Copyright (c) 2013 Coub. All rights reserved. -// - -#import "CBCoubNew.h" -//#import "Formatters.h" -//#import "NSDictionary+Extensions.h" -#import "CBLibrary.h" -#import "CBJSONCoubMapper.h" -#import "CBConstance.h" - -@interface CBCoubNew () -{ - BOOL _failedDownloadChunks; -} -@end - -@implementation CBCoubNew - -//- (void)setNaturalVideoSize:(CGSize)size -//{ -// _naturalVideoSize = size; -//} - -- (BOOL)isDraft -{ - return NO; -} - -//- (NSDate *)creationDate -//{ -// if(!_creationDate) -// _creationDate = [[NSDateFormatter sharedCoubJSONDateFormatter] dateFromString:_creationDateAsString]; -// -// return _creationDate; -//} - -//- (NSDate *)originalCreationDate -//{ -// if(!_originalCreationDate) -// _originalCreationDate = [[NSDateFormatter sharedCoubJSONDateFormatter] dateFromString:_originalCreationDateAsString]; -// -// return _originalCreationDate; -//} - -- (NSURL *)mediumImageURL -{ - NSString *remoteImageFilePath = self.mediumPicture; - if(remoteImageFilePath) - return [NSURL URLWithString:[remoteImageFilePath hasPrefix:@"http://"] ? remoteImageFilePath : [[@"http://" stringByAppendingString:kCBServerURL] stringByAppendingPathComponent:remoteImageFilePath]]; - return nil; -} - - -- (NSURL *)largeImageURL -{ - NSString *remoteImageFilePath = self.largePicture; - if(remoteImageFilePath) - return [NSURL URLWithString:[remoteImageFilePath hasPrefix:@"http://"] ? remoteImageFilePath : [[@"http://" stringByAppendingString:kCBServerURL] stringByAppendingPathComponent:remoteImageFilePath]]; - return nil; -} - -- (BOOL)isRecoub -{ - return _recouber != nil ? YES : NO; -} - -//- (CBCoubStatusFlags)statusFlags -//{ -// CBCoubStatusFlags statusFlags = 0; -// -// if([_visibility isEqualToString:kCBCoubVisibilityFriends]) -// statusFlags |= CBCoubStatusFriendsOnly; -// else if([_visibility isEqualToString:kCBCoubVisibilityPrivate]) -// statusFlags |= CBCoubStatusPrivate; -// else if([_visibility isEqualToString:kCBCoubVisibilityUnlisted]) -// statusFlags |= CBCoubStatusUnlisted; -// switch(_audioType) -// { -// case CBCoubAudioTypeExternal: -// statusFlags |= CBCoubStatusExternalAudio; -// break; -// case CBCoubAudioTypeInternal: -// statusFlags |= CBCoubStatusHasAudioTrack; -// break; -// default: -// break; -// } -// -// return statusFlags; -//} - -- (NSURL *)remoteVideoFileURL -{ - NSURL *url = nil; - - NSString *remoteFilePath = self.remoteVideoLocation; - if([remoteFilePath isKindOfClass:[NSString class]] && remoteFilePath.length > 0) - { - url = [NSURL URLWithString:[remoteFilePath hasPrefix:@"http://"] ? remoteFilePath : [[@"http://" stringByAppendingString:kCBServerURL] stringByAppendingPathComponent:remoteFilePath]]; - if(!url) - [NSException raise:NSInternalInconsistencyException format:@"Could not make a URL from \"%@\"", remoteFilePath]; - } - return url; -} - -- (NSURL *)externalAudioURL -{ - NSURL *url = nil; - - NSString *remoteFilePath = self.remoteAudioLocation; - if([remoteFilePath isKindOfClass:[NSString class]] && remoteFilePath.length > 0) - { - url = [NSURL URLWithString:[remoteFilePath hasPrefix:@"http://"] ? remoteFilePath : [[@"http://" stringByAppendingString:kCBServerURL] stringByAppendingPathComponent:remoteFilePath]]; - if(!url) - [NSException raise:NSInternalInconsistencyException format:@"Could not make a URL from \"%@\"", remoteFilePath]; - } - return url; -} - -- (NSURL *)localVideoFileURL -{ - if (self.customLocalVideoFileURL != nil) - return self.customLocalVideoFileURL; - - if(self.permalink == nil) - return nil; - - - NSString *fileNameExtension = [self.remoteVideoLocation pathExtension] ?: @"mp4"; - NSString *localFileName = [[@"coub " stringByAppendingString:self.permalink] stringByAppendingPathExtension:fileNameExtension]; - NSString *path = [[CBLibrary sharedLibrary].mediaDirectory.path stringByAppendingPathComponent:localFileName]; - return [NSURL fileURLWithPath:path isDirectory:NO]; -} - -- (NSURL *)localAudioFileURL -{ - if(self.permalink == nil) - return nil; - - NSString *fileNameExtension = @"m4a"; - NSString *localFileName = [[@"coub " stringByAppendingString:self.permalink] stringByAppendingPathExtension:fileNameExtension]; - return [NSURL fileURLWithPath:[[CBLibrary sharedLibrary].mediaDirectory.path stringByAppendingPathComponent:localFileName] isDirectory:NO]; -} - -- (NSString *)assetId -{ - return self.permalink; -} - -- (BOOL)isAudioAvailable -{ - return (_audioType != CBCoubAudioTypeNone && !_failedDownloadChunks); -} - -- (BOOL)isEqualToCoub:(CBCoubNew *)coub -{ - return [coub.permalink isEqualToString:self.permalink]; -} - -+ (CBCoubNew *)coubWithAttributes:(NSDictionary *)attributes -{ - return [CBJSONCoubMapper coubFromJSONObject:attributes]; -} - -- (NSURL *)remoteAudioChunkWithIdx:(NSInteger)idx -{ - //NSLog(@"remoteAudioChunkWithIdx = %@ ", [NSURL URLWithString:[NSString stringWithFormat:_remoteAudioLocationPattern, idx]]); - - //NOTE: sometimes _remoteAudioLocationPattern - return [NSURL URLWithString:[NSString stringWithFormat:_remoteAudioLocationPattern, idx]]; -} - -- (NSURL *)localAudioChunkWithIdx:(NSInteger)idx -{ - //NSLog(@"localAudioChunkWithIdx = %i", idx); - - NSString *fileNameExtension = @"mp3"; - NSString *fileName = [[NSString stringWithFormat:@"coub mp3 chunk %i ", idx] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - NSString *localFileName = [[fileName stringByAppendingString:self.permalink] stringByAppendingPathExtension:fileNameExtension]; - - return [NSURL fileURLWithPath:[[CBLibrary sharedLibrary].mediaDirectory.path stringByAppendingPathComponent:localFileName] isDirectory:NO]; -} - -- (BOOL)failedDownloadChunk -{ - return _failedDownloadChunks; -} - -- (void)setFailedDownloadChunk:(BOOL)failed -{ - _failedDownloadChunks = failed; -} - -@end diff --git a/submodules/LegacyComponents/Sources/CBCoubPlayer.h b/submodules/LegacyComponents/Sources/CBCoubPlayer.h deleted file mode 100755 index b212174afe..0000000000 --- a/submodules/LegacyComponents/Sources/CBCoubPlayer.h +++ /dev/null @@ -1,96 +0,0 @@ -// -// CBCoubPlayer.h -// Coub -// -// Created by Pavel Tikhonenko on 12/08/14. -// Copyright (c) 2014 Coub. All rights reserved. -// - -#import - -@class CBCoubPlayer; -@protocol CBCoubAsset; -@class AVPlayerLayer; - -typedef enum -{ - CBCoubPlayerStateReadyToPlay, - CBCoubPlayerStateRunning = 1, - CBCoubPlayerStatePlaying = (1 << 1) | CBCoubPlayerStateRunning, - CBCoubPlayerStatePaused = (1 << 2) | CBCoubPlayerStatePlaying, - CBCoubPlayerStateInterrupted = (1 << 3) | CBCoubPlayerStatePlaying, - CBCoubPlayerStateStopped = (1 << 4), - CBCoubPlayerStatePseudoStopped = (1 << 5) | CBCoubPlayerStateStopped, - CBCoubPlayerStateError = (1 << 6) | CBCoubPlayerStateStopped, - CBCoubPlayerStatePrepairing = (1 << 7) | CBCoubPlayerStateRunning, - CBCoubPlayerStateUnknown = NSNotFound, -} -CBCoubPlayerState; - -typedef enum -{ - CBCoubPlayerVideoPlayMethodDefault, - CBCoubPlayerVideoPlayMethodStream -} -CBCoubPlayerVideoPlayMethod; - -#pragma mark - -#pragma mark CBCoubPlayerDelegate - -@protocol CBCoubPlayerDelegate -@required -- (void)playerReadyToPlay:(CBCoubPlayer *)player; -- (void)playerDidStartPlaying:(CBCoubPlayer *)player; -- (void)playerDidPause:(CBCoubPlayer *)player withUserAction:(BOOL)isUserAction; -- (void)playerDidResume:(CBCoubPlayer *)player; -- (void)playerDidStop:(CBCoubPlayer *)player; -- (void)playerDidFail:(CBCoubPlayer *)player error:(NSError *)error; -- (void)player:(CBCoubPlayer *)player didReachProgressWhileDownloading:(float)progress; -@end - -#pragma mark - -#pragma mark CBCoubPlayer - -@interface CBCoubPlayer : NSObject - -@property (nonatomic, weak) id delegate; - -/// indicate whether player is playing -@property(nonatomic, readonly) BOOL isPlaying; -/// indicate whether player was paused -@property(nonatomic, readonly) BOOL isPaused; -/// indicate whether player was interrupted by system -@property(nonatomic, readonly) BOOL isInterrupted; -/// If Yes then this instance is current/active player -@property(nonatomic, readonly) BOOL isActivePlayer; -/// set/get current player state -@property(nonatomic, assign) CBCoubPlayerState state; - -/// set/get whether player playback only video -@property(nonatomic, assign) BOOL withoutAudio; //Default NO - -//Temp later move back to private var -@property(nonatomic, strong) id asset; - -@property(nonatomic, assign) CBCoubPlayerVideoPlayMethod videoPlayMethod; - - - -- (instancetype)initWithVideoLayer:(AVPlayerLayer *)layer; - -- (void)playAsset:(id)asset; -- (void)pause; -- (void)resume; -- (void)stop; - -// pause video and mute audio -- (void)pseudoStop; - -- (BOOL)isVideoLayerPlaying:(AVPlayerLayer *)layer; -- (BOOL)coubPlaying:(id)coub; -- (BOOL)coubPrepairing:(id)coub; - -+ (instancetype)activePlayer; -+ (instancetype)setActivePlayer:(CBCoubPlayer *)player; - -@end diff --git a/submodules/LegacyComponents/Sources/CBCoubPlayer.m b/submodules/LegacyComponents/Sources/CBCoubPlayer.m deleted file mode 100755 index 4c2d059adc..0000000000 --- a/submodules/LegacyComponents/Sources/CBCoubPlayer.m +++ /dev/null @@ -1,585 +0,0 @@ -// -// CBCoubPlayer.m -// Coub -// -// Created by Pavel Tikhonenko on 12/08/14. -// Copyright (c) 2014 Coub. All rights reserved. -// - -#import -#import "CBCoubPlayer.h" -#import "CBCoubAsset.h" -#import "CBVideoPlayer.h" -#import "CBCoubLoopCompositionMaker.h" -#import "CBAssetDownloadManager.h" -#import "STKAudioPlayer.h" -#import "CBLibrary.h" -#import "CBConstance.h" -#import "CBDownloadOperationDelegate.h" - -static CBCoubPlayer *gActivePlayer = nil; -static NSLock *gLock = nil; -static BOOL gPlaybackIsInterrupted = NO; - -@interface CBCoubPlayer () -{ - BOOL _shouldPlayWhenReady; - BOOL _shouldResumeWhenAppIsActive; - BOOL _shouldResumeWhenInterruptionEnds; - BOOL _shouldPlayAfterStop; - NSInteger _currentPlayingChunk; - double _startTime; -} - - -@property(nonatomic, strong) CBVideoPlayer *videoPlayer; -@property(nonatomic, strong) STKAudioPlayer *audioPlayer; -@property(nonatomic, strong) CBCoubLoopCompositionMaker *loopMaker; - - -@end - -@implementation CBCoubPlayer - -+ (void)initialize -{ - if(!gLock) - { - NSError *categoryError = NULL; - NSError *activeError = NULL; - - [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&categoryError]; - [[AVAudioSession sharedInstance] setActive:YES error:&activeError]; - - Float32 bufferLength = 0.1; - AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(bufferLength), &bufferLength); - - gLock = [[NSLock alloc] init]; - - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pauseActivePlayer:) name:UIApplicationWillResignActiveNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resumeActivePlayer:) name:UIApplicationDidBecomeActiveNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pauseActivePlayer:) name:CBPlayerInterruptionDidBeginNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resumeActivePlayer:) name:CBPlayerInterruptionDidEndNotification object:nil]; - } -} - -- (instancetype)initWithVideoLayer:(AVPlayerLayer *)layer -{ - return [self initWithVideoLayer:layer videoPlayMethod:CBCoubPlayerVideoPlayMethodDefault]; -} - -- (instancetype)initWithVideoLayer:(AVPlayerLayer *)layer videoPlayMethod:(CBCoubPlayerVideoPlayMethod)videoPlayMethod -{ - self = [super init]; - - if(self) - { - _currentPlayingChunk = -1; - _videoPlayMethod = videoPlayMethod; - _state = CBCoubPlayerStateUnknown; - - [self createVideoPlayerWithLayer:layer]; - - } - - return self; -} - -#pragma mark - -#pragma mark Getter/Setter - -- (BOOL)isPlaying -{ - return _state == CBCoubPlayerStatePlaying; -} - -- (BOOL)isPaused -{ - return _state == CBCoubPlayerStatePaused; -} - -- (BOOL)isActivePlayer -{ - return (gActivePlayer == self); -} - -#pragma mark - -#pragma mark Public methods - -- (void)playAsset:(id)asset -{ - NSLog(@"playAsset"); - - if(_state == CBCoubPlayerStateRunning && self.asset == asset) - return; - - if(gActivePlayer == self && self.asset == asset && gActivePlayer.state == CBCoubPlayerStatePlaying) - return; - - [[NSNotificationCenter defaultCenter] postNotificationName:@"interruptDownloading" object:nil]; - - //_startTime = [CBUtils timestamp]; - - if(gActivePlayer == self) - { - [_videoPlayer stop]; - [_audioPlayer dispose]; - }else{ - [self stopActivePlayer]; - [self becomeActivePlayer]; - } - - gPlaybackIsInterrupted = NO; //NOTE: note note note - _shouldPlayWhenReady = YES; - self.state = CBCoubPlayerStateRunning; - - self.asset = asset; - - [self downloadMediaAssetsWithCompletion:^(__unused id result) { - [self prepareLoopCompostion]; - }failure:^(NSError *error) { - [self failPlaybackWithError:error]; - }]; -} - -- (void)pause -{ - _shouldPlayWhenReady = NO; - - if(!self.isPlaying) - return; - - self.state = CBCoubPlayerStatePaused; - - [_videoPlayer pause]; - - if(_asset.audioType == CBCoubAudioTypeExternal) - [_audioPlayer pause]; - - if([_delegate respondsToSelector:@selector(playerDidPause:withUserAction:)]) - [_delegate playerDidPause:self withUserAction:YES]; -} - -- (void)resume -{ - _shouldPlayWhenReady = YES; - -// if(_state == CBCoubPlayerStateReadyToPlay) -// { -// [self startPlayingIfPossible]; -// } - if(self.state == CBCoubPlayerStatePaused){ - self.state = STKAudioPlayerStatePlaying; - - [_videoPlayer play]; - - if(_asset.audioType == CBCoubAudioTypeExternal) - [_audioPlayer resume]; - } - - if([_delegate respondsToSelector:@selector(playerDidResume:)]) - [_delegate playerDidResume:self]; -} - -- (void)stop -{ - _shouldPlayWhenReady = NO; - - if(self.state == CBCoubPlayerStateStopped || self.state == NSNotFound) - return; - - //KAObjectLog(@"stop player"); - - //[[CBAssetDownloadManager sharedManager] cancelDownloadingForCoub:_asset]; - - if([_delegate respondsToSelector:@selector(playerDidStop:)]) - [_delegate playerDidStop:self]; - -// [_audioPlayer pause]; - if(_asset.audioType == CBCoubAudioTypeExternal) - { - _audioPlayer.delegate = nil; - [_audioPlayer dispose]; - _audioPlayer = nil; - } - - [_videoPlayer stop]; - -// dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ -// -// }); - - self.state = CBCoubPlayerStateStopped; - - [self resignActivePlayer]; -} - -- (void)pseudoStop -{ - _shouldPlayWhenReady = NO; - - if(self.isPlaying) - { - if(_asset.audioType == CBCoubAudioTypeExternal) - [_audioPlayer pause]; - else - [_videoPlayer pause]; - } - - self.state = CBCoubPlayerStatePseudoStopped; -} - -- (void)stopActivePlayer -{ - [gActivePlayer stop]; -} - -- (void)resetCurrentPlayer -{ - self.state = NSNotFound; - _shouldPlayWhenReady = YES; - _currentPlayingChunk = -1; - [self.loopMaker cancelPrepareLoop]; -} - -#pragma mark - -#pragma mark Private methods - -- (void)createVideoPlayerWithLayer:(AVPlayerLayer *)layer -{ - self.videoPlayer = [[CBVideoPlayer alloc] initWithVideoLayer:layer]; -} - -- (void)prepareVideoPlayer -{ - [_videoPlayer prepareWithAVAsset:self.loopMaker.videoAsset completion:^(NSError *error) { - if(error) - [self failPlaybackWithError:error]; - else{ - if([_delegate respondsToSelector:@selector(playerReadyToPlay:)]) - [_delegate playerReadyToPlay:self]; - - [self startPlayingIfPossible]; - } - }]; - - [self.loopMaker cancelPrepareLoop]; -} - -- (void)playVideoPlayer -{ - [_videoPlayer play]; - - if(_shouldPlayWhenReady == NO) - [self pause]; -} - -- (void)createAudioPlayer -{ - self.audioPlayer = [[STKAudioPlayer alloc] init]; - _audioPlayer.delegate = self; -} - -- (void)prepareAudioPlayer -{ - _currentPlayingChunk = -1; - -// STKAudioPlayerState state = _audioPlayer.state; - - [self startPlayingFirstAudioChunk]; -} - -- (void)startPlayingFirstAudioChunk -{ -// NSFileManager *fileManager = [NSFileManager defaultManager]; -// NSDictionary *attributes = [fileManager attributesOfItemAtPath:[_asset localAudioChunkWithIdx:0].path error:nil]; - - _shouldPlayAfterStop = NO; - - NSURL * url = [_asset localAudioChunkWithIdx:0]; - - if (url) { - [_audioPlayer playURL:url]; - } -} - -- (void)startPlayingIfPossible -{ - if(self.state == CBCoubPlayerStatePlaying) - return; - - self.state = CBCoubPlayerStateReadyToPlay; - - if(gPlaybackIsInterrupted && _shouldPlayWhenReady) - [self pauseWhileInterrupted]; - - if(!_shouldPlayWhenReady) - return; - - if(!_withoutAudio && _asset.audioType == CBCoubAudioTypeExternal && _audioPlayer.state != STKAudioPlayerStatePlaying) - { - [self createAudioPlayer]; - [self prepareAudioPlayer]; - return; - } - - [[NSNotificationCenter defaultCenter] postNotificationName:@"resumeDownloading" object:nil]; - - self.state = CBCoubPlayerStatePlaying; - - if([_delegate respondsToSelector:@selector(playerDidStartPlaying:)]) - [_delegate playerDidStartPlaying:self]; - - - [self playVideoPlayer]; - -// NSNumber *number = [NSNumber numberWithDouble:[CBUtils timestamp] - _startTime]; -// NSString *curPlace = [CBAnalyticManager sharedManager].currentPlayerPlace; -// NSString *assetId = _asset.assetId; -// -// NSDictionary *dict = @{@"loading_time":number, -// @"coubId":assetId, -// @"place": curPlace}; -// -// [[CBAnalyticManager sharedManager] track:@"player_started" -// properties:dict -// method:CBAnalyticManagerMethodCES]; -} - -- (void)downloadMediaAssetsWithCompletion:(CBSuccessBlock)success failure:(CBFailureBlock)failure -{ - [[CBAssetDownloadManager sharedManager] downloadCoub:_asset tag:-1 - withDelegate:self - withChunks:!_withoutAudio - downloadSucces:^(__unused id coub, __unused NSInteger tag) { - success(nil); - }downloadFailure:^(__unused id coub, __unused NSInteger tag, NSError *error) { - failure(error); - }]; -} - -- (void)downloadChunk:(NSInteger)idx -{ - if(_asset.audioType != CBCoubAudioTypeExternal) - return; - - [[CBAssetDownloadManager sharedManager] downloadChunkWithCoub:_asset tag:NSNotFound chunkIdx:idx downloadSucces:^(id __unused coub, NSInteger __unused tag) { - [_audioPlayer queueURL:[_asset localAudioChunkWithIdx:idx]]; - } downloadFailure:^(__unused id coub, __unused NSInteger tag, __unused NSError *error) { - - }]; - -// [[CBAssetDownloadManager sharedManager] downloadNextChunkWithCoub:_asset downloadSucces:^(id coub, NSInteger tag) { -// [_audioPlayer queueURL:[_asset localAudioChunkWithIdx:tag]]; -// } downloadFailure:^(id coub, NSInteger tag, NSError *error) { -// -// }]; -} - -- (void)prepareLoopCompostion -{ - if(self.state == CBCoubPlayerStateStopped) - return; - - self.loopMaker = [CBCoubLoopCompositionMaker coubLoopWithAsset:_asset]; - _loopMaker.delegate = self; - [_loopMaker prepareLoop]; -} - -- (void)failPlaybackWithError:(NSError *)error -{ - if(self.state == CBCoubPlayerStateStopped) - return; - - self.state = CBCoubPlayerStateError; - - if([_delegate respondsToSelector:@selector(playerDidFail:error:)]) - [_delegate playerDidFail:self error:error]; -} - -#pragma mark - - -- (void)becomeActivePlayer -{ - [gLock lock]; - if(gActivePlayer != self) - { - //[gActivePlayer pause]; - gActivePlayer = self; - } - [gLock unlock]; -} - - -- (void)resignActivePlayer -{ - [gLock lock]; - if(gActivePlayer == self && self.isPlaying == NO) - gActivePlayer = nil; - [gLock unlock]; -} - -#pragma mark - -#pragma mark Audio Player Delegate methods - -- (void)audioPlayer:(STKAudioPlayer *)audioPlayer stateChanged:(STKAudioPlayerState)state previousState:(STKAudioPlayerState)previousState -{ - if(state == STKAudioPlayerStateStopped && _shouldPlayAfterStop) - { - [self startPlayingFirstAudioChunk]; - return; - } - - if(state == STKAudioPlayerStatePlaying && self.state != CBCoubPlayerStatePlaying) - { - //KAObjectLog(@"STKAudioPlayerStatePlaying"); - - [self startPlayingIfPossible]; - } -} - -- (void)audioPlayer:(STKAudioPlayer *)audioPlayer unexpectedError:(STKAudioPlayerErrorCode)errorCode -{ - [self failPlaybackWithError:nil]; -} - -- (void)audioPlayer:(STKAudioPlayer *)audioPlayer didStartPlayingQueueItemId:(NSObject *)queueItemId -{ - if(_currentPlayingChunk == 3) - _currentPlayingChunk = -1; - - _currentPlayingChunk++; - - NSInteger nextItem = _currentPlayingChunk+1; - nextItem = nextItem > 3 ? 0 : nextItem; - - if([[CBLibrary sharedLibrary] isCoubChunkDownloadedByPermalink:_asset.assetId idx:nextItem]) - [_audioPlayer queueURL:[_asset localAudioChunkWithIdx:nextItem]]; - else - [self downloadChunk:nextItem]; -} - -- (void)audioPlayer:(STKAudioPlayer *)audioPlayer didFinishBufferingSourceWithQueueItemId:(NSObject *)queueItemId -{ - -} - -- (void)audioPlayer:(STKAudioPlayer *)audioPlayer didFinishPlayingQueueItemId:(NSObject *)queueItemId withReason:(STKAudioPlayerStopReason)stopReason andProgress:(double)progress andDuration:(double)duration -{ - -} - -- (void)audioPlayer:(STKAudioPlayer *)audioPlayer logInfo:(NSString *)line -{ - //KAObjectLog(@"%@", line); -} - -#pragma mark - -#pragma mark Download Manager Delegate methods - -- (void)downloadDidReachProgress:(float)progress -{ - if([_delegate respondsToSelector:@selector(player:didReachProgressWhileDownloading:)]) - [_delegate player:self didReachProgressWhileDownloading:progress]; -} - -- (void)downloadHasBeenCancelledWithError:(NSError *)error -{ - if(error == nil) - return; - - [self failPlaybackWithError:error]; -} - -#pragma mark - -#pragma mark Loop Composition Maker Delegate methods - -- (void)coubLoopDidFinishPreparing:(CBCoubLoopCompositionMaker *)loop -{ - [self prepareVideoPlayer]; -} - -- (void)coubLoop:(CBCoubLoopCompositionMaker *)loop didFailToLoadWithError:(NSError *)error -{ - if(error.code == CBCoubLoopErrorCanceled) - return; - - [self failPlaybackWithError:error]; -} - -#pragma mark - - -+ (void)pauseActivePlayer:(NSNotification *)notification -{ - //KAObjectLog(@"pauseActivePlayer %p", gActivePlayer); - - if([[notification name] isEqualToString:UIApplicationWillResignActiveNotification]) - { - [gActivePlayer pauseWhileInBackground]; - }else - { - gPlaybackIsInterrupted = YES; - [gActivePlayer pauseWhileInterrupted]; - } -} - - -+ (void)resumeActivePlayer:(NSNotification *)notification -{ - //KAObjectLog(@"resumeActivePlayer %p", gActivePlayer); - - NSLog(@"resumeActivePlayer"); - - if([[notification name] isEqualToString:UIApplicationDidBecomeActiveNotification]) - { - [gActivePlayer resumeIfPausedWhileInBackground]; - }else - { - gPlaybackIsInterrupted = NO; - [gActivePlayer resumeIfPausedWhileInterrupted]; - } -} - -- (void)pauseWhileInBackground -{ - _shouldResumeWhenAppIsActive = self.isPlaying || _shouldPlayWhenReady; - [self pause]; -} - - -- (void)resumeIfPausedWhileInBackground -{ - NSLog(@"resumeIfPausedWhileInBackground"); - - if(_shouldResumeWhenAppIsActive) - [self resume]; -} - - -- (void)pauseWhileInterrupted -{ - _shouldResumeWhenInterruptionEnds = self.isPlaying || _shouldPlayWhenReady; - [self pause]; -} - - -- (void)resumeIfPausedWhileInterrupted -{ - if(_shouldResumeWhenInterruptionEnds) - [self resume]; -} - -#pragma mark - - -+ (instancetype)activePlayer -{ - return gActivePlayer; -} - -- (void)dealloc -{ - _audioPlayer.delegate = nil; - [_audioPlayer dispose]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/CBCoubPlayerContance.h b/submodules/LegacyComponents/Sources/CBCoubPlayerContance.h deleted file mode 100755 index 935c8e4685..0000000000 --- a/submodules/LegacyComponents/Sources/CBCoubPlayerContance.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// CBCoubPlayerContance.h -// CoubPlayer -// -// Created by Pavel Tikhonenko on 19/10/14. -// Copyright (c) 2014 Pavel Tikhonenko. All rights reserved. -// - -#import - -typedef NS_ENUM(UInt16, CBCoubAudioType) -{ - CBCoubAudioTypeNone = 0, - CBCoubAudioTypeInternal, - CBCoubAudioTypeExternal, -}; - -@interface CBCoubPlayerContance : NSObject - -@end diff --git a/submodules/LegacyComponents/Sources/CBCoubPlayerContance.m b/submodules/LegacyComponents/Sources/CBCoubPlayerContance.m deleted file mode 100755 index d2850886ff..0000000000 --- a/submodules/LegacyComponents/Sources/CBCoubPlayerContance.m +++ /dev/null @@ -1,13 +0,0 @@ -// -// CBCoubPlayerContance.m -// CoubPlayer -// -// Created by Pavel Tikhonenko on 19/10/14. -// Copyright (c) 2014 Pavel Tikhonenko. All rights reserved. -// - -#import "CBCoubPlayerContance.h" - -@implementation CBCoubPlayerContance - -@end diff --git a/submodules/LegacyComponents/Sources/CBCoubVideoSource.h b/submodules/LegacyComponents/Sources/CBCoubVideoSource.h deleted file mode 100755 index a07b1d4c4c..0000000000 --- a/submodules/LegacyComponents/Sources/CBCoubVideoSource.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// CBCoubVideoSource.h -// Coub -// -// Created by Tikhonenko Pavel on 18/11/2013. -// Copyright (c) 2013 Coub. All rights reserved. -// - -#import - -@interface CBCoubVideoSource : NSObject - -@property (nonatomic, strong) NSString *yourtubeURL; -@property (nonatomic, strong) NSString *title; -@property (nonatomic, strong) NSString *thumbnail; -@property (nonatomic, readonly) BOOL isYouTube; - -+ (CBCoubVideoSource *)sourceFromData:(NSDictionary *)dict; - -@end \ No newline at end of file diff --git a/submodules/LegacyComponents/Sources/CBCoubVideoSource.m b/submodules/LegacyComponents/Sources/CBCoubVideoSource.m deleted file mode 100755 index 7226506f97..0000000000 --- a/submodules/LegacyComponents/Sources/CBCoubVideoSource.m +++ /dev/null @@ -1,33 +0,0 @@ -// -// CBCoubVideoSource.m -// Coub -// -// Created by Tikhonenko Pavel on 18/11/2013. -// Copyright (c) 2013 Coub. All rights reserved. -// - -#import "CBCoubVideoSource.h" - -@implementation CBCoubVideoSource - -- (BOOL)isYouTube -{ - return [_yourtubeURL rangeOfString:@"youtube"].length != 0; -} - -+ (CBCoubVideoSource *)sourceFromData:(NSDictionary *)dict -{ - if(!dict.count) return nil; - - CBCoubVideoSource *source = [[CBCoubVideoSource alloc] init]; - source.yourtubeURL = dict[@"url"]; - source.title = dict[@"title"]; - source.thumbnail = dict[@"image"]; - - if(source.yourtubeURL == nil) - return nil; - - return source; -} - -@end diff --git a/submodules/LegacyComponents/Sources/CBDownloadOperation.h b/submodules/LegacyComponents/Sources/CBDownloadOperation.h deleted file mode 100755 index fb98a3edfb..0000000000 --- a/submodules/LegacyComponents/Sources/CBDownloadOperation.h +++ /dev/null @@ -1,37 +0,0 @@ -// -// CBDownloadOperation.h -// CoubPlayer -// -// Created by Pavel Tikhonenko on 19/10/14. -// Copyright (c) 2014 Pavel Tikhonenko. All rights reserved. -// - -#import -@protocol CBCoubAsset; -@protocol CBDownloadOperationDelegate; - -@protocol CBDownloadOperation - -@required -- (void)setTag:(NSInteger)tag; -- (NSInteger)tag; - -- (void)setCoub:(id)coub; -- (id)coub; - -- (void)setQueuePriority:(NSOperationQueuePriority)queuePriority; -- (NSOperationQueuePriority)queuePriority; - -//- (void)setDelegate:(id)delegate; - -- (void)setClientSuccess:(void (^)(id operation, NSInteger tag))success; -- (void)setClientFailure:(void (^)(id operation, NSInteger tag, NSError *error))failure; - -- (void)setCompletionBlock:(void (^)(id operation, NSError *error))completion; - -- (void)start; -- (void)cancel; - -- (instancetype)clone; - -@end diff --git a/submodules/LegacyComponents/Sources/CBDownloadOperationDelegate.h b/submodules/LegacyComponents/Sources/CBDownloadOperationDelegate.h deleted file mode 100755 index 9639ef811b..0000000000 --- a/submodules/LegacyComponents/Sources/CBDownloadOperationDelegate.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// CBDownloadOperationDelegate.h -// CoubPlayer -// -// Created by Pavel Tikhonenko on 19/10/14. -// Copyright (c) 2014 Pavel Tikhonenko. All rights reserved. -// - -#import - -@protocol CBDownloadOperationDelegate - -@optional -- (void)downloadDidReachProgress:(float)progress; -- (void)downloadHasBeenCancelledWithError:(NSError *)error; - -@end diff --git a/submodules/LegacyComponents/Sources/CBGenericDownloadOperation.h b/submodules/LegacyComponents/Sources/CBGenericDownloadOperation.h deleted file mode 100755 index 6b55e97fd5..0000000000 --- a/submodules/LegacyComponents/Sources/CBGenericDownloadOperation.h +++ /dev/null @@ -1,28 +0,0 @@ -#import -#import "CBDownloadOperation.h" -#import "CBCoubAsset.h" -#import "CBDownloadOperationDelegate.h" -#import "LegacyHTTPRequestOperation.h" - -@interface CBGenericDownloadOperation : NSObject - -@property (nonatomic, strong) NSOperation *downloadOperation; -@property (nonatomic, readwrite) NSOperationQueuePriority queuePriority; - -@property (nonatomic, assign) NSInteger tag; -@property (nonatomic, assign) BOOL starting; -@property (nonatomic, assign) BOOL comleted; -@property (nonatomic, assign) BOOL chunkDownloadingNeeded; - -@property (nonatomic, weak) id coub; -@property (nonatomic, weak) id operationViewDelegate; - -@property(nonatomic, copy) void (^clientSuccess)(id, NSInteger tag); -@property(nonatomic, copy) void (^clientFailure)(id, NSInteger tag, NSError *error); - -@property (nonatomic, copy) void (^completionBlock)(id process, NSError *error); - -//protected -- (void)successDownload; -- (void)failureDownloadWithError:(NSError *)error; -@end diff --git a/submodules/LegacyComponents/Sources/CBGenericDownloadOperation.m b/submodules/LegacyComponents/Sources/CBGenericDownloadOperation.m deleted file mode 100755 index a86dfc3b8c..0000000000 --- a/submodules/LegacyComponents/Sources/CBGenericDownloadOperation.m +++ /dev/null @@ -1,89 +0,0 @@ -// -// Created by Tikhonenko Pavel on 27/05/2014. -// Copyright (c) 2014 Coub. All rights reserved. -// - -#import "CBGenericDownloadOperation.h" -#import "CBCoubAsset.h" - -@implementation CBGenericDownloadOperation -{ - NSOperationQueuePriority _queuePriority; -} - -- (NSOperationQueuePriority)queuePriority -{ - return _queuePriority; -} - -- (void)setQueuePriority:(NSOperationQueuePriority)queuePriority -{ - _queuePriority = queuePriority; - - if(_downloadOperation) - _downloadOperation.queuePriority = queuePriority; -} - -- (void)start -{ - self.starting = YES; -} - -- (void)cancel -{ - self.starting = NO; - - NSError *cancelError = nil; - - if (!_downloadOperation.isFinished && !_downloadOperation.isCancelled) - { - //cancelError = [NSError errorWithDomain:kCBAssetDownloadManagerErrorDomain code:99 userInfo:nil]; - [_downloadOperation cancel]; - } - - [_operationViewDelegate downloadHasBeenCancelledWithError:cancelError]; - - self.clientSuccess = nil; - self.clientFailure = nil; -} - -- (void)successDownload -{ - if(self.starting) - { - self.starting = NO; - self.comleted = YES; - - if(self.operationViewDelegate != nil)[self.operationViewDelegate downloadHasBeenCancelledWithError:nil]; - if(self.clientSuccess != nil) self.clientSuccess(self.coub, self.tag); - if(self.completionBlock != nil) self.completionBlock(self, nil); - - self.downloadOperation = nil; - } -} - - -- (void)failureDownloadWithError:(NSError *)error -{ - if(self.starting) - { - self.starting = NO; - self.comleted = YES; - - if(self.operationViewDelegate != nil)[self.operationViewDelegate downloadHasBeenCancelledWithError:error]; - if(self.clientFailure != nil) self.clientFailure(self.coub, self.tag, error); - if(self.completionBlock != nil) self.completionBlock(self, error); - } -} - -- (instancetype)clone -{ - return nil; -} - -- (void)dealloc -{ - self.completionBlock = nil; -} - -@end diff --git a/submodules/LegacyComponents/Sources/CBJSONCoubMapper.h b/submodules/LegacyComponents/Sources/CBJSONCoubMapper.h deleted file mode 100755 index 6effbcbaec..0000000000 --- a/submodules/LegacyComponents/Sources/CBJSONCoubMapper.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// Created by Tikhonenko Pavel on 29/11/2013. -// Copyright (c) 2013 Coub. All rights reserved. -// - - -#import - -@class CBCoubNew; - - -@interface CBJSONCoubMapper : NSObject - -+ (CBCoubNew *)updateCoubFromCoub:(CBCoubNew *)newCoub coub:(CBCoubNew *)coub; -+ (CBCoubNew *)updateCoubFromJSONObject:(NSDictionary *)jsonObj coub:(CBCoubNew *)coub; -+ (CBCoubNew *)coubFromJSONObject:(NSDictionary *)jsonObj; - -@end \ No newline at end of file diff --git a/submodules/LegacyComponents/Sources/CBJSONCoubMapper.m b/submodules/LegacyComponents/Sources/CBJSONCoubMapper.m deleted file mode 100755 index ebdc9e9dcf..0000000000 --- a/submodules/LegacyComponents/Sources/CBJSONCoubMapper.m +++ /dev/null @@ -1,254 +0,0 @@ -// -// Created by Tikhonenko Pavel on 29/11/2013. -// Copyright (c) 2013 Coub. All rights reserved. -// - - -#import "CBJSONCoubMapper.h" -#import "CBCoubNew.h" -#import "NSDictionary+CBExtensions.h" -#import "CBCoubVideoSource.h" -#import "CBCoubAudioSource.h" -#import "CBTagNew.h" - - - -@implementation CBJSONCoubMapper -{ - -} - -+ (CBCoubNew *)updateCoubFromCoub:(CBCoubNew *)newCoub coub:(CBCoubNew *)coub -{ - coub.title = newCoub.title; - coub.liked = newCoub.liked; - coub.visibility = newCoub.visibility; - coub.recoubed = newCoub.recoubed; - coub.likeCount = newCoub.likeCount; - coub.recoubCount = newCoub.recoubCount; - coub.cotd = newCoub.cotd; - coub.flagged = newCoub.flagged; - coub.creationDate = coub.creationDate; - coub.creationDateAsString = coub.creationDateAsString; - -// if(newCoub.isDone) -// coub.state = CBCoubDraftCompleted; - - return coub; -} - -+ (CBCoubNew *)updateCoubFromJSONObject:(NSDictionary *)attributes coub:(CBCoubNew *)coub -{ - static NSDictionary *kCoubJSONKeys = nil; - if(!kCoubJSONKeys) - { - kCoubJSONKeys = @{ - //@"permalink" : @"permalink", - @"title" : @"title", - @"visibility_type" : @"visibility", - //@"created_at" : @"creationDateAsString", - //@"external_download" : @"externalDownloadAsDictionary", - @"like" : @"liked", - @"recoub" : @"recoubed", - @"likes_count" : @"likeCount", - @"views_count" : @"viewCount", - @"recoubs_count" : @"recoubCount", - @"cotd" : @"cotd", - @"flag" : @"flagged", - }; - } - - if ([attributes[@"title"] isKindOfClass:[NSString class]]) - { - NSString *title = attributes[@"title"]; - coub.title = title; - } - - NSDictionary *recoubInfo = nil; - - if(attributes[@"permalink"]) - coub.permalink = attributes[@"permalink"]; - - if(attributes[@"id"]) - coub.coubID = [attributes[@"id"] stringValue]; - - coub.originalPermalink = attributes[@"permalink"]; - coub.originalCreationDateAsString = attributes[@"created_at"]; - - if (coub.author == nil) - { - coub.author = [CBCoubAuthorVO coubAuthorWithAttributes:attributes[@"user"]]; - //coub.authorCD = [CBUserNewuserWithAttributes:attributes[@"user"]]; - } - - if (coub.author.name.length == 0) - { - NSDictionary *channel = attributes[@"channel"]; - if ([channel respondsToSelector:@selector(objectForKey:)]) - coub.author.name = channel[@"title"]; - } - - if(attributes[@"is_done"]) - coub.isDone = [attributes[@"is_done"] boolValue]; - - NSDictionary *fileVersions = attributes[@"file_versions"]; - NSString *remoteVideoLocation = attributes[@"explicitVideoLocation"]; - if (remoteVideoLocation) - { - remoteVideoLocation = [remoteVideoLocation stringByReplacingOccurrencesOfString:@"muted_mp4_med_" withString:@"mp4_med_"]; - remoteVideoLocation = [remoteVideoLocation stringByReplacingOccurrencesOfString:@"_muted_med" withString:@"_med"]; - coub.remoteVideoLocation = remoteVideoLocation; - } - else - { - if (fileVersions) - remoteVideoLocation = fileVersions[@"iphone"][@"url"]; - if(!remoteVideoLocation) - remoteVideoLocation = attributes[@"file"]; - if(!remoteVideoLocation || [remoteVideoLocation isEqual:[NSNull null]]) - remoteVideoLocation = fileVersions[@"html5"][@"video"][@"med"][@"url"]; - - if (remoteVideoLocation) - { - if ([remoteVideoLocation rangeOfString:@"muted_mp4"].location != NSNotFound) - { - remoteVideoLocation = [remoteVideoLocation stringByReplacingOccurrencesOfString:@"muted_mp4_med_" withString:@"mp4_med_"]; - remoteVideoLocation = [remoteVideoLocation stringByReplacingOccurrencesOfString:@"_muted_med" withString:@"_med"]; - coub.remoteVideoLocation = remoteVideoLocation; - } - else - { - NSRange r1 = [remoteVideoLocation rangeOfString:@"iphone_"]; - NSRange r2 = [remoteVideoLocation rangeOfString:@"_iphone"]; - - if (r1.location == NSNotFound) - { - r1 = [remoteVideoLocation rangeOfString:@"gifv_"]; - r2 = [remoteVideoLocation rangeOfString:@"_gifv"]; - } - - if (r1.location != NSNotFound) - { - NSInteger loc = r1.length+r1.location; - NSString *someVideoMetadataString = [remoteVideoLocation substringWithRange:NSMakeRange(loc, r2.location - loc)]; - - remoteVideoLocation = fileVersions[@"web"][@"template"]; - NSRange r3 = [remoteVideoLocation rangeOfString:@"%{"]; - - remoteVideoLocation = [remoteVideoLocation substringToIndex:r3.location]; - remoteVideoLocation = [NSString stringWithFormat:@"%@mp4_med_size_%@_med.mp4", remoteVideoLocation, someVideoMetadataString]; - coub.remoteVideoLocation = remoteVideoLocation; - } - else if ([remoteVideoLocation rangeOfString:@"mp4_med_size_"].location != NSNotFound) - { - coub.remoteVideoLocation = remoteVideoLocation; - } - } - } - } - - NSString *remoteAudioLocation = [attributes[@"audio_versions"] coubURIFromVersionTemplateWithPreferredSubstitutions:@[@"low", @"mid", @"high"]]; - if(!remoteAudioLocation) - remoteAudioLocation = attributes[@"audio_file_url"]; - if(!remoteAudioLocation || [remoteAudioLocation isEqual:[NSNull null]]) - remoteAudioLocation = fileVersions[@"mobile"][@"mp3"]; - if(remoteAudioLocation) - coub.remoteAudioLocation = remoteAudioLocation; - - NSDictionary *chunks = attributes[@"audio_versions"][@"chunks"]; - - if(chunks) - { - NSString *audioTemplate = chunks[@"template"]; - audioTemplate = [audioTemplate stringByReplacingOccurrencesOfString:@"%{version}" withString:@"low"]; - audioTemplate = [audioTemplate stringByReplacingOccurrencesOfString:@"%{chunk}" withString:@"%i"]; - coub.remoteAudioLocationPattern = audioTemplate; - } - - // big, med, small, ios_large - //KALog(@"ff=%@", [attributes[@"first_frame_versions"][@"versions"] componentsJoinedByString: @", "]); - NSString *largePictureLocation = [attributes[@"first_frame_versions"] coubURIFromVersionTemplateWithPreferredSubstitutions:@[@"med", @"big", @"ios_large"]]; - if(largePictureLocation) - coub.largePicture = largePictureLocation; - - // micro, tiny, age_restricted, ios_large, ios_mosaic, big, med, small - NSString *mediumPictureLocation = [attributes[@"image_versions"] coubURIFromVersionTemplateWithPreferredSubstitutions:@[@"ios_mosaic", @"small", @"med"]]; - if(!mediumPictureLocation) - mediumPictureLocation = attributes[@"picture"]; // short JSON - if(mediumPictureLocation) - coub.mediumPicture = mediumPictureLocation; - - // Determine the type of audio based on the values of "has_sound" and "audio_file_url" - if(coub.remoteAudioLocation && ([coub.remoteAudioLocation isKindOfClass:[NSString class]] && [coub.remoteAudioLocation length] < 8)) - coub.remoteAudioLocation = nil; - - if(attributes[@"visibility_type"]) - { - coub.audioType = coub.remoteAudioLocationPattern ? CBCoubAudioTypeExternal : ([attributes[@"has_sound"] boolValue] ? CBCoubAudioTypeInternal : CBCoubAudioTypeNone); - } - // else a short JSON doesn't have any information on sound - - NSDictionary *mediaBlock = attributes[@"media_blocks"]; - - BOOL isCoubAudioSourceAvailable = mediaBlock[@"audio_track"] != nil; - BOOL isCoubVideoSourceAvailable = mediaBlock[@"external_video"] != nil; - - if(isCoubVideoSourceAvailable) - coub.videoSource = [CBCoubVideoSource sourceFromData:mediaBlock[@"external_video"]]; - if(isCoubAudioSourceAvailable) - coub.audioSource = [CBCoubAudioSource sourceFromData:mediaBlock[@"audio_track"]]; - - if(coub.audioSource || coub.videoSource) - coub.isCoubSourcesAvailable = YES; - - NSDictionary *externalDownloadInfo = attributes[@"external_download"]; - if([externalDownloadInfo isKindOfClass:[NSDictionary class]]) - { - coub.externalDownloadType = externalDownloadInfo[@"type"]; - coub.externalDownloadSource = externalDownloadInfo[@"url"]; - }else - { - // Coub API may return a boolean "false" as "external_download" value - coub.externalDownloadType = nil; - coub.externalDownloadSource = nil; - } - - NSArray *tags = attributes[@"tags"]; - if(tags) - { - NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:tags.count]; - [tags enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) - { - [mutableArray addObject:[CBTagNew tagWithAttributes:obj]]; - }]; - - coub.tags = [NSArray arrayWithArray:mutableArray]; - } - - - - if(recoubInfo) - { - coub.recouber = [CBCoubAuthorVO coubAuthorWithAttributes:recoubInfo[@"user"]]; - coub.liked = [recoubInfo[@"like"] boolValue]; - coub.recoubed = [recoubInfo[@"recoub"] boolValue]; - coub.flagged = [recoubInfo[@"flagged"] boolValue]; - } - - if(!coub.coubID) - [NSException raise:NSInternalInconsistencyException format:@"No coub id found in %@", attributes]; - if(!coub.permalink) - [NSException raise:NSInternalInconsistencyException format:@"No coub permalink found in %@", attributes]; - - NSArray *size = attributes[@"dimensions"][@"small"]; - - //coub.naturalVideoSize = CGSizeMake([size[0] floatValue], [size[1] floatValue]); - return coub; -} - -+ (CBCoubNew *)coubFromJSONObject:(NSDictionary *)jsonObj -{ - return [self updateCoubFromJSONObject:jsonObj coub:[CBCoubNew new]]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/CBLibrary.h b/submodules/LegacyComponents/Sources/CBLibrary.h deleted file mode 100755 index bc708069dd..0000000000 --- a/submodules/LegacyComponents/Sources/CBLibrary.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// CBLibrary.h -// Coub -// -// Created by Konstantin Anoshkin on 26.06.12. -// Copyright 2012 Coub. All rights reserved. -// - -#import -#import "CBCoubAsset.h" - -#if TARGET_IPHONE_SIMULATOR -// On iPhone Simulator NSTemporaryDirectory() returns a Mac OS X temporary directory which is outside our application sandbox. -// For consistency's sake we want to make it behave as on an honest-to-goodness iPhone device. -NSString *CBTemporaryDirectory (void); -#define NSTemporaryDirectory() CBTemporaryDirectory() -#endif - -NSString *CBDocumentsDirectory (void); -NSString *CBCachesDirectory (void); - -@interface CBLibrary : NSObject - -+ (CBLibrary *)sharedLibrary; - -- (void)markCoubAsset:(id)coub asDownloaded:(BOOL)downloaded; -- (BOOL)isCoubDownloadedByPermalink:(NSString *)permalink; - -- (void)markCoubChunk:(id)coub idx:(NSInteger)idx asDownloaded:(BOOL)downloaded; -- (BOOL)isCoubChunkDownloadedByPermalink:(NSString *)permalink idx:(NSInteger)idx; - -- (void)cleanUpMediaCache; - -@property (strong, nonatomic) NSURL *mediaDirectory; - -@end diff --git a/submodules/LegacyComponents/Sources/CBLibrary.m b/submodules/LegacyComponents/Sources/CBLibrary.m deleted file mode 100755 index 609349f176..0000000000 --- a/submodules/LegacyComponents/Sources/CBLibrary.m +++ /dev/null @@ -1,236 +0,0 @@ -// -// CBLibrary.m -// Coub -// -// Created by Konstantin Anoshkin on 26.06.12. -// Copyright 2012 Coub. All rights reserved. -// - -#define CBLIBRARY_IMPLEMENTATION_FILE - -#import "CBLibrary.h" -#import - - -#if TARGET_IPHONE_SIMULATOR -NSString *CBTemporaryDirectory (void) -{ - return [NSHomeDirectory() stringByAppendingPathComponent: @"tmp"]; -} -#endif - - -NSString *CBDocumentsDirectory (void) -{ - static NSString *sPath = nil; - if (!sPath) - sPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] copy]; - return sPath; -} - - -NSString *CBCachesDirectory (void) -{ - static NSString *sPath = nil; - if (!sPath) { - sPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] copy]; - if (![[NSFileManager defaultManager] fileExistsAtPath: sPath]) - [[NSFileManager defaultManager] createDirectoryAtPath: sPath withIntermediateDirectories: YES attributes: nil error: NULL]; - } - return sPath; -} - - -NSString *CBMediaDirectory (void) -{ - static NSString *sPath = nil; - if (!sPath) { - sPath = [[[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent: @"Media"] copy]; - } - return sPath; -} - -NSString *const kCBLibraryDatabaseFileNameExtension = @"sqlite"; -NSString *const kCBLibraryCurrentUserID = @"currentUserID"; - - -@implementation CBLibrary -{ -@private - NSURL *_mediaDirectory; - NSMutableDictionary *_cachedMediaFiles; -} - - -+ (CBLibrary *)sharedLibrary -{ - static id sSharedInstance = nil; - static dispatch_once_t onceToken = 0; - dispatch_once(&onceToken, ^ - { - sSharedInstance = [[self alloc] init]; - }); - return sSharedInstance; -} - - -- (id)init -{ - self = [super init]; - - if(self) - { - _cachedMediaFiles = [NSMutableDictionary new]; - } - - return self; -} - -#pragma mark - Paths & URLs - -- (void)setMediaDirectory:(NSURL *)mediaDirectory -{ - if (_mediaDirectory && ![mediaDirectory.absoluteString isEqualToString:_mediaDirectory.absoluteString]) { - [self cleanUpMediaCache]; - } - - if (mediaDirectory && ![mediaDirectory.absoluteString isEqualToString:_mediaDirectory.absoluteString]) { - _mediaDirectory = mediaDirectory; - [self createMediaDirectory]; - } else { - _mediaDirectory = mediaDirectory; - } -} - -- (NSURL *)mediaDirectory -{ - if(!_mediaDirectory) { - _mediaDirectory = [NSURL fileURLWithPath:CBMediaDirectory() isDirectory:YES]; - [self createMediaDirectory]; - } - return _mediaDirectory; -} - -- (void)createMediaDirectory -{ - NSError *error = nil; - NSString *mediaDirectoryPath = [[self mediaDirectory] path]; - if(![[NSFileManager defaultManager] fileExistsAtPath:mediaDirectoryPath]) - { - if(![[NSFileManager defaultManager] createDirectoryAtPath:mediaDirectoryPath withIntermediateDirectories:YES attributes:nil error:&error]) - { - NSLog(@"*** Could not recreate Media directory, %@", error); - return; - } - - if(&NSURLIsExcludedFromBackupKey) - { - if(![[self mediaDirectory] setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:&error]) - NSLog(@"*** Failed to set NSURLIsExcludedFromBackupKey for %@, %@", [self mediaDirectory], error); - }else - { - // Set the Do Not Backup extended attribute, http://developer.apple.com/library/ios/#qa/qa1719/_index.html - - - u_int8_t attrValue = 1; - if(setxattr([mediaDirectoryPath fileSystemRepresentation], "com.apple.MobileBackup", &attrValue, sizeof(attrValue), 0, 0)) - { - //KAObjectLogError(@"setxattr(%@) failed: %s (%d)", mediaDirectoryPath, strerror(errno), errno); - } - } - } - - - -} - -- (void)markCoubAsset:(id)coub asDownloaded:(BOOL)downloaded -{ - if(downloaded) - { - if([self isCoubDownloadedByPermalink:coub.assetId]) - return; - - NSError *error = nil; - NSDictionary *attrs = [[NSFileManager defaultManager] attributesOfItemAtPath:[coub.localVideoFileURL path] error:&error]; - if(attrs) - { - _cachedMediaFiles[coub.assetId] = [NSMutableDictionary dictionaryWithDictionary:@{@"coub" : coub, @"downloadedChunks": @0}]; - }else - { - //KAObjectLogError(@"Can't get attributes at %@: %@", coub.localVideoFileURL, error); - } - }else - { - [_cachedMediaFiles removeObjectForKey:coub.assetId]; - } -} - -- (BOOL)isCoubDownloadedByPermalink:(NSString *)permalink -{ - return _cachedMediaFiles[permalink] != nil; -} - -- (void)markCoubChunk:(id)coub idx:(NSInteger)idx asDownloaded:(BOOL)downloaded -{ - //NSLog(@"markCoubChunk %i", idx); - - NSMutableDictionary *mediaFile = _cachedMediaFiles[coub.assetId]; - - if(mediaFile) - { - NSInteger downloadedChunks = ((NSNumber *)mediaFile[@"downloadedChunks"]).integerValue; - NSInteger normalIdx = 1< - -@interface CBPlayerLayerView : UIView - -@end diff --git a/submodules/LegacyComponents/Sources/CBPlayerLayerView.m b/submodules/LegacyComponents/Sources/CBPlayerLayerView.m deleted file mode 100755 index 9e25cc8573..0000000000 --- a/submodules/LegacyComponents/Sources/CBPlayerLayerView.m +++ /dev/null @@ -1,20 +0,0 @@ -// -// CBPlayerLayerView.m -// Coub -// -// Created by Tikhonenko Pavel on 23/11/2013. -// Copyright (c) 2013 Coub. All rights reserved. -// - -#import "CBPlayerLayerView.h" - -#import - -@implementation CBPlayerLayerView - -+ (Class)layerClass -{ - return [AVPlayerLayer class]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/CBPlayerView.h b/submodules/LegacyComponents/Sources/CBPlayerView.h deleted file mode 100755 index 06350aee73..0000000000 --- a/submodules/LegacyComponents/Sources/CBPlayerView.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// CBPlayerView.h -// CoubPlayer -// -// Created by Pavel Tikhonenko on 17/10/14. -// Copyright (c) 2014 Pavel Tikhonenko. All rights reserved. -// - -#import - -#import - -#import "CBCoubPlayer.h" -#import "CBPlayerLayerView.h" - -@interface CBPlayerView : UIView - -@property (nonatomic, readonly) UIImageView *preview; -@property (nonatomic, readonly) CBPlayerLayerView *videoPlayerView; - -- (void)play; -- (void)stop; - -@end - -//@interface CBPlayerLayerView : UIView -//@end \ No newline at end of file diff --git a/submodules/LegacyComponents/Sources/CBPlayerView.m b/submodules/LegacyComponents/Sources/CBPlayerView.m deleted file mode 100755 index 9bda935f06..0000000000 --- a/submodules/LegacyComponents/Sources/CBPlayerView.m +++ /dev/null @@ -1,101 +0,0 @@ -// -// CBPlayerView.m -// CoubPlayer -// -// Created by Pavel Tikhonenko on 17/10/14. -// Copyright (c) 2014 Pavel Tikhonenko. All rights reserved. -// - -#import "CBPlayerView.h" - - - -@implementation CBPlayerView - -- (id)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - - if(self) - { - [self setupView]; - } - - return self; -} -- (void)setupView -{ - self.clipsToBounds = YES; - - _preview = [[UIImageView alloc] initWithFrame:self.bounds]; - _preview.contentMode = UIViewContentModeScaleAspectFill; - [self addSubview:_preview]; - - _videoPlayerView = [[CBPlayerLayerView alloc] initWithFrame:self.bounds]; - _videoPlayerView.hidden = YES; - ((AVPlayerLayer *) _videoPlayerView.layer).videoGravity = AVLayerVideoGravityResizeAspectFill; - [self addSubview:_videoPlayerView]; -} - -- (void)setContentMode:(UIViewContentMode)contentMode -{ - [super setContentMode:contentMode]; - - _preview.contentMode = contentMode; - ((AVPlayerLayer *)_videoPlayerView.layer).videoGravity = (contentMode == UIViewContentModeScaleAspectFit) ? AVLayerVideoGravityResizeAspect : AVLayerVideoGravityResizeAspectFill; -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - CGRect bounds = self.bounds; - - _videoPlayerView.frame = bounds; - _preview.frame = bounds; -} - -- (void)play -{ - _videoPlayerView.hidden = NO; -} - -- (void)stop -{ - _videoPlayerView.hidden = YES; -} - -//- (void) layoutSubviews -//{ -// // We need manual aspect fill/fit layout if we want fluid frame animations -// CGRect bounds = self.bounds; -// //_preview.frame = bounds; -// -// if (self.contentMode == UIViewContentModeScaleAspectFit) { -// CGRect viewFrame = bounds; -// -// CGSize size = _player.loop.videoTrackSize; -// if (size.width && size.height) { -// CGFloat scale = fminf(viewFrame.size.width / size.width, viewFrame.size.height / size.height); -// size.width = roundf(size.width * scale); -// size.height = roundf(size.height * scale); -// viewFrame = CGRectInset(viewFrame, 0.5f * (viewFrame.size.width - size.width), 0.5f * (viewFrame.size.height - size.height)); -// } -// -// _videoPlayerView.frame = viewFrame; -// } else -// _videoPlayerView.frame = bounds; -// -// CGPoint center = (CGPoint) { CGRectGetMidX(bounds), CGRectGetMidY(bounds) }; -// _spinner.center = center; -// _reloadButton.center = center; -//} - -@end - -//#pragma mark - -//#pragma mark CBPlayerLayerView -// -//@implementation CBPlayerLayerView -//+ (Class)layerClass { return [AVPlayerLayer class]; } -//@end diff --git a/submodules/LegacyComponents/Sources/CBTagNew.h b/submodules/LegacyComponents/Sources/CBTagNew.h deleted file mode 100755 index 6052d00c11..0000000000 --- a/submodules/LegacyComponents/Sources/CBTagNew.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// Created by Tikhonenko Pavel on 30/11/2013. -// Copyright (c) 2013 Coub. All rights reserved. -// - - -#import - - -@interface CBTagNew : NSObject -@property (nonatomic, strong) NSNumber *tagId; -@property (nonatomic, strong) NSString *title; -@property (nonatomic, strong) NSString *value; -@property (nonatomic, readonly) NSString *hashTag; - -+ (instancetype)tagWithAttributes:(NSDictionary *)attributes; - -@end \ No newline at end of file diff --git a/submodules/LegacyComponents/Sources/CBTagNew.m b/submodules/LegacyComponents/Sources/CBTagNew.m deleted file mode 100755 index 7229d24414..0000000000 --- a/submodules/LegacyComponents/Sources/CBTagNew.m +++ /dev/null @@ -1,29 +0,0 @@ -// -// Created by Tikhonenko Pavel on 30/11/2013. -// Copyright (c) 2013 Coub. All rights reserved. -// - - -#import "CBTagNew.h" - - -@implementation CBTagNew -{ - -} - -- (NSString *)hashTag -{ - return [@"#" stringByAppendingString:_title]; -} - -+ (instancetype)tagWithAttributes:(NSDictionary *)attributes -{ - CBTagNew *tag = [CBTagNew new]; - tag.tagId = attributes[@"id"]; - tag.title = attributes[@"title"]; - tag.value = attributes[@"value"]; - return tag; -} - -@end \ No newline at end of file diff --git a/submodules/LegacyComponents/Sources/CBVideoPlayer.h b/submodules/LegacyComponents/Sources/CBVideoPlayer.h deleted file mode 100755 index 7bc9cb7f0b..0000000000 --- a/submodules/LegacyComponents/Sources/CBVideoPlayer.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// CBVideoPlayer.h -// Coub -// -// Created by Pavel Tikhonenko on 12/08/14. -// Copyright (c) 2014 Coub. All rights reserved. -// - -#import -#import - -typedef enum -{ - CBVideoPlayerStatusInited, - CBVideoPlayerStatusPrepairing = 1, - CBVideoPlayerStatusReadyToPlay = 1 << 1, - CBVideoPlayerStatusFailed = 1 << 2, - CBVideoPlayerStatusUnknown = NSNotFound - -} -CBVideoPlayerStatus; - -@interface CBVideoPlayer : NSObject - -@property (nonatomic, assign) CBVideoPlayerStatus status; - -- (id)initWithVideoLayer:(AVPlayerLayer *)layer; - -- (void)prepareWithAVAsset:(AVAsset *)asset completion:(void (^)(NSError *error))completion; -- (void)stopPrepairing; - -- (void)play; -- (void)pause; -- (void)stop; - -@end diff --git a/submodules/LegacyComponents/Sources/CBVideoPlayer.m b/submodules/LegacyComponents/Sources/CBVideoPlayer.m deleted file mode 100755 index adae6c2cab..0000000000 --- a/submodules/LegacyComponents/Sources/CBVideoPlayer.m +++ /dev/null @@ -1,193 +0,0 @@ -// -// CBVideoPlayer.m -// Coub -// -// Created by Pavel Tikhonenko on 12/08/14. -// Copyright (c) 2014 Coub. All rights reserved. -// - -#import "CBVideoPlayer.h" - -static void *kPlayerItemContext = (void *) 1; -static void *kPlayerStatusContext = (void *) 2; - -static void *kPlayerLayerReadyToDisplayContext = (void *) 4; - -@interface CBVideoPlayer () - -@property (nonatomic, strong) AVPlayerLayer *layer; -@property (nonatomic, strong) AVPlayer *videoPlayer; -@property (nonatomic, strong) AVPlayerItem *nextItem; -@property (nonatomic, assign) BOOL hasBeenReseted; - -@property (nonatomic, copy) void (^prepairingCompletion)(NSError *error); - -@end - -@implementation CBVideoPlayer - -- (id)initWithVideoLayer:(AVPlayerLayer *)layer -{ - self = [super init]; - - if(self) - { - self.status = CBVideoPlayerStatusUnknown; - self.hasBeenReseted = YES; - - self.layer = layer; - - [self createVideoPlayer]; - - - self.status = CBVideoPlayerStatusInited; - } - - return self; -} - -#pragma mark - -#pragma mark Public methods - -- (void)prepareWithAVAsset:(AVAsset *)asset completion:(void (^)(NSError *error))completion -{ - self.prepairingCompletion = completion; - - self.status = CBVideoPlayerStatusPrepairing; - - if(!_hasBeenReseted) - [self resetPlayer]; - - _hasBeenReseted = NO; - - [self prepareVideoPlayer]; - [self prepareVideoLayer]; - - AVPlayerItem *item = [AVPlayerItem playerItemWithAsset:asset]; - [self.videoPlayer replaceCurrentItemWithPlayerItem:item]; - -} - -- (void)play -{ - [_videoPlayer play]; -} - -- (void)pause -{ - _videoPlayer.rate = 0; -} - -- (void)stop -{ - _videoPlayer.rate = 0; - - [self resetPlayer]; - [self.videoPlayer replaceCurrentItemWithPlayerItem:nil]; -} - -- (void)stopPrepairing -{ -} - -#pragma mark - -#pragma mark Private methods - -- (void)createVideoPlayer -{ - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(restartAVPlayer:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil]; - - self.videoPlayer = [AVPlayer new]; - _videoPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone; - -} - -- (void)prepareVideoPlayer -{ - [_videoPlayer addObserver:self forKeyPath:@"currentItem" options:NSKeyValueObservingOptionNew context:kPlayerItemContext]; - [_videoPlayer addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:kPlayerStatusContext]; -} - -- (void)prepareVideoLayer -{ - [_layer addObserver:self forKeyPath:@"readyForDisplay" options:NSKeyValueObservingOptionNew context:kPlayerLayerReadyToDisplayContext]; -} - -- (void)resetPlayer -{ - @try{ - [_videoPlayer removeObserver:self forKeyPath:@"currentItem" context:kPlayerItemContext]; - }@catch(id anException){} - - @try{ - [_videoPlayer removeObserver:self forKeyPath:@"status" context:kPlayerStatusContext]; - }@catch(id anException){} - - @try{ - [_layer removeObserver:self forKeyPath:@"readyForDisplay" context:kPlayerLayerReadyToDisplayContext]; - }@catch(id anException){} -} - -- (void)prerollPlayer -{ - [_videoPlayer prerollAtRate:1 completionHandler:^(BOOL finished) { - [_layer setPlayer:self.videoPlayer]; - }]; -} -- (void)completeVideoPrepairing -{ - [self resetPlayer]; - self.prepairingCompletion(nil); -} - -- (void)restartAVPlayer:(NSNotification *)notification -{ - AVPlayerItem *playerItem = [notification object]; - if (playerItem == _videoPlayer.currentItem) - [_videoPlayer seekToTime:kCMTimeZero]; -} - -#pragma mark - -#pragma mark Observe value - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context -{ - AVPlayer *player = (AVPlayer *) object; - - if(context == kPlayerLayerReadyToDisplayContext) - { - [self completeVideoPrepairing]; - } - - if(context == kPlayerStatusContext || context == kPlayerItemContext) - { - //KAObjectLog(@"%@ status: %i", player == self.videoPlayer ? @"videoPlayer" : @"audioPlayer", player.status); - - NSLog(@"status: %i", player.status); - if(context == kPlayerItemContext && player.currentItem == nil && _nextItem) - return; - - if(context == kPlayerItemContext && player.currentItem == nil) - return; - - if(player.status == AVPlayerStatusReadyToPlay) - { - [self prerollPlayer]; - }else if(player.status == AVPlayerStatusFailed) - { - //[self.delegate playerInitialzeProccess:self completeWithError:[NSError errorWithDomain:@"com.coub.player" code:99 userInfo:nil]]; - - }//else if(player.status == AVPlayerStatusUnknown) - //KAObjectLog(@"%@ AVPlayerStatusUnknown: %@", player == self.videoPlayer ? @"videoPlayer" : @"audioPlayer", player.error); - } -} - -- (void)dealloc -{ - @try{ - [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil]; - }@catch(id anException){} - - [self resetPlayer]; -} -@end diff --git a/submodules/LegacyComponents/Sources/NSDictionary+CBExtensions.h b/submodules/LegacyComponents/Sources/NSDictionary+CBExtensions.h deleted file mode 100755 index 285d40b3ba..0000000000 --- a/submodules/LegacyComponents/Sources/NSDictionary+CBExtensions.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// NSDictionary+Extensions.h -// Coub -// -// Created by Konstantin Anoshkin on 8.10.13. -// Copyright 2013 Coub. All rights reserved. -// - -#import - - -@interface NSDictionary (CBDictionaryExtensions) - -- (NSString *) coubURIFromVersionTemplateWithPreferredSubstitutions: (NSArray *) preferredVersions; - -@end diff --git a/submodules/LegacyComponents/Sources/NSDictionary+CBExtensions.m b/submodules/LegacyComponents/Sources/NSDictionary+CBExtensions.m deleted file mode 100755 index affd8281b4..0000000000 --- a/submodules/LegacyComponents/Sources/NSDictionary+CBExtensions.m +++ /dev/null @@ -1,38 +0,0 @@ -// -// NSDictionary+Extensions.m -// Coub -// -// Created by Konstantin Anoshkin on 8.10.13. -// Copyright 2013 Coub. All rights reserved. -// - -#import "NSDictionary+CBExtensions.h" - - -@implementation NSDictionary (CBDictionaryExtensions) - - -- (NSString *) coubURIFromVersionTemplateWithPreferredSubstitutions: (NSArray *) preferredVersions -{ - NSString *urlTemplate = self[@"template"]; - if (urlTemplate) { - NSArray *availableVersions = self[@"versions"]; - __block NSString *bestVersion = nil; - [preferredVersions enumerateObjectsUsingBlock: ^(NSString *version, __unused NSUInteger idx, BOOL *stop) { - if ([availableVersions containsObject: version]) { - bestVersion = version; - *stop = YES; - } - }]; - if (bestVersion) { - //KALog(@"%@", [urlTemplate stringByReplacingOccurrencesOfString: @"%{version}" withString: bestVersion]); - return [urlTemplate stringByReplacingOccurrencesOfString: @"%{version}" withString: bestVersion]; - } else { - //KAObjectLogError(@"Could not find appropriate URI version: {%@}", [preferredVersions componentsJoinedByString: @", "]); - } - } - return nil; -} - - -@end diff --git a/submodules/LegacyComponents/Sources/NSMutableArray+STKAudioPlayer.h b/submodules/LegacyComponents/Sources/NSMutableArray+STKAudioPlayer.h deleted file mode 100755 index 12ca8396b4..0000000000 --- a/submodules/LegacyComponents/Sources/NSMutableArray+STKAudioPlayer.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// NSMutableArray+STKAudioPlayer.h -// StreamingKit -// -// Created by Thong Nguyen on 30/01/2014. -// Copyright (c) 2014 Thong Nguyen. All rights reserved. -// - -#import - -@interface NSMutableArray (STKAudioPlayer) --(void) enqueue:(id)obj; --(void) skipQueue:(id)obj; --(void) skipQueueWithQueue:(NSMutableArray*)queue; --(id) dequeue; --(id) peek; -@end diff --git a/submodules/LegacyComponents/Sources/NSMutableArray+STKAudioPlayer.m b/submodules/LegacyComponents/Sources/NSMutableArray+STKAudioPlayer.m deleted file mode 100755 index 493868f45d..0000000000 --- a/submodules/LegacyComponents/Sources/NSMutableArray+STKAudioPlayer.m +++ /dev/null @@ -1,50 +0,0 @@ -// -// NSMutableArray+STKAudioPlayer.m -// StreamingKit -// -// Created by Thong Nguyen on 30/01/2014. -// Copyright (c) 2014 Thong Nguyen. All rights reserved. -// - -#import "NSMutableArray+STKAudioPlayer.h" - -@implementation NSMutableArray (STKAudioPlayer) - --(void) enqueue:(id)obj -{ - [self insertObject:obj atIndex:0]; -} - --(void) skipQueue:(id)obj -{ - [self addObject:obj]; -} - --(void) skipQueueWithQueue:(NSMutableArray*)queue -{ - for (id item in queue) - { - [self addObject:item]; - } -} - --(id) dequeue -{ - if ([self count] == 0) - { - return nil; - } - - id retval = [self lastObject]; - - [self removeLastObject]; - - return retval; -} - --(id) peek -{ - return [self lastObject]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/PGPhotoFilter.h b/submodules/LegacyComponents/Sources/PGPhotoFilter.h deleted file mode 100644 index eddd041ec5..0000000000 --- a/submodules/LegacyComponents/Sources/PGPhotoFilter.h +++ /dev/null @@ -1,19 +0,0 @@ -#import "PGPhotoEditorItem.h" - -@class PGPhotoFilterDefinition; -@class PGPhotoProcessPass; - -@interface PGPhotoFilter : NSObject -{ - PGPhotoProcessPass *_pass; -} - -@property (nonatomic, readonly) PGPhotoFilterDefinition *definition; -@property (nonatomic, retain) PGPhotoProcessPass *pass; -@property (nonatomic, readonly) PGPhotoProcessPass *optimizedPass; - -- (void)invalidate; - -+ (PGPhotoFilter *)filterWithDefinition:(PGPhotoFilterDefinition *)definition; - -@end diff --git a/submodules/LegacyComponents/Sources/PGPhotoFilter.m b/submodules/LegacyComponents/Sources/PGPhotoFilter.m deleted file mode 100644 index f37c7bef8d..0000000000 --- a/submodules/LegacyComponents/Sources/PGPhotoFilter.m +++ /dev/null @@ -1,242 +0,0 @@ -#import "PGPhotoFilter.h" - -#import "TGPhotoEditorGenericToolView.h" - -#import "PGPhotoFilterDefinition.h" - -#import "PGPhotoCustomFilterPass.h" -#import "PGPhotoLookupFilterPass.h" -#import "PGPhotoProcessPass.h" - -@interface PGPhotoFilter () -{ - PGPhotoProcessPass *_parameter; -} -@end - -@implementation PGPhotoFilter - -@synthesize value = _value; -@synthesize tempValue = _tempValue; -@synthesize parameters = _parameters; -@synthesize beingEdited = _beingEdited; -@synthesize shouldBeSkipped = _shouldBeSkipped; -@synthesize parametersChanged = _parametersChanged; -@synthesize disabled = _disabled; -@synthesize segmented = _segmented; - -- (instancetype)initWithDefinition:(PGPhotoFilterDefinition *)definition -{ - self = [super init]; - if (self != nil) - { - _definition = definition; - _value = @(self.defaultValue); - } - return self; -} - -- (instancetype)copyWithZone:(NSZone *)__unused zone -{ - PGPhotoFilter *filter = [[PGPhotoFilter alloc] initWithDefinition:self.definition]; - filter.value = self.value; - return filter; -} - -- (NSString *)title -{ - return _definition.title; -} - -- (NSString *)identifier -{ - return _definition.identifier; -} - -- (PGPhotoProcessPass *)pass -{ - if (_pass == nil) - { - switch (_definition.type) - { - case PGPhotoFilterTypeCustom: - { - _pass = [[PGPhotoCustomFilterPass alloc] initWithShaderFile:_definition.shaderFilename textureFiles:_definition.textureFilenames]; - } - break; - - case PGPhotoFilterTypeLookup: - { - _pass = [[PGPhotoLookupFilterPass alloc] initWithLookupImage:[UIImage imageNamed:[NSString stringWithFormat:@"%@.png", _definition.lookupFilename]]]; - } - break; - - default: - { - _pass = [[PGPhotoProcessPass alloc] init]; - } - break; - } - } - - [self updatePassParameters]; - - return _pass; -} - -- (PGPhotoProcessPass *)optimizedPass -{ - switch (_definition.type) - { - case PGPhotoFilterTypeCustom: - { - return [[PGPhotoCustomFilterPass alloc] initWithShaderFile:_definition.shaderFilename textureFiles:_definition.textureFilenames optimized:true]; - } - break; - - case PGPhotoFilterTypeLookup: - { - return [[PGPhotoLookupFilterPass alloc] initWithLookupImage:[UIImage imageNamed:[NSString stringWithFormat:@"%@.png", _definition.lookupFilename]]]; - } - break; - - default: - break; - } - - return [[PGPhotoProcessPass alloc] init]; -} - -- (Class)valueClass -{ - return [NSNumber class]; -} - -- (CGFloat)minimumValue -{ - return 0.0f; -} - -- (CGFloat)maximumValue -{ - return 100.0f; -} - -- (CGFloat)defaultValue -{ - return 100.0f; -} - -- (id)tempValue -{ - if (self.disabled) - { - if ([_tempValue isKindOfClass:[NSNumber class]]) - return @0; - } - - return _tempValue; -} - -- (id)displayValue -{ - if (self.beingEdited) - return self.tempValue; - - return self.value; -} - -- (void)setValue:(id)value -{ - _value = value; - - if (!self.beingEdited) - [self updateParameters]; -} - -- (void)setTempValue:(id)tempValue -{ - _tempValue = tempValue; - - if (self.beingEdited) - [self updateParameters]; -} - -- (NSArray *)parameters -{ - return _parameters; -} - -- (void)updateParameters -{ - -} - -- (void)updatePassParameters -{ - CGFloat value = ((NSNumber *)self.displayValue).floatValue / self.maximumValue; - - if ([_pass isKindOfClass:[PGPhotoLookupFilterPass class]]) - { - PGPhotoLookupFilterPass *pass = (PGPhotoLookupFilterPass *)_pass; - [pass setIntensity:value]; - } - else if ([_pass isKindOfClass:[PGPhotoCustomFilterPass class]]) - { - PGPhotoCustomFilterPass *pass = (PGPhotoCustomFilterPass *)_pass; - [pass setIntensity:value]; - } -} - -- (void)invalidate -{ - _pass = nil; - _value = @(self.defaultValue); -} - -- (void)reset -{ - [_pass.filter removeAllTargets]; -} - -- (id)itemControlViewWithChangeBlock:(void (^)(id newValue, bool animated))changeBlock -{ - __weak PGPhotoFilter *weakSelf = self; - - id view = [[TGPhotoEditorGenericToolView alloc] initWithEditorItem:self]; - view.valueChanged = ^(id newValue, bool animated) - { - __strong PGPhotoFilter *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - strongSelf.tempValue = newValue; - - if (changeBlock != nil) - changeBlock(newValue, animated); - }; - return view; -} - -- (UIView *)itemAreaViewWithChangeBlock:(void (^)(id newValue))__unused changeBlock -{ - return nil; -} - -- (BOOL)isEqual:(id)object -{ - if (object == self) - return YES; - - if (!object || ![object isKindOfClass:[self class]]) - return NO; - - return ([[(PGPhotoFilter *)object definition].identifier isEqualToString:self.definition.identifier]); -} - -+ (PGPhotoFilter *)filterWithDefinition:(PGPhotoFilterDefinition *)definition -{ - return [[[self class] alloc] initWithDefinition:definition]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/PGPhotoFilterDefinition.h b/submodules/LegacyComponents/Sources/PGPhotoFilterDefinition.h deleted file mode 100644 index 1c15ed0746..0000000000 --- a/submodules/LegacyComponents/Sources/PGPhotoFilterDefinition.h +++ /dev/null @@ -1,21 +0,0 @@ -#import - -typedef enum { - PGPhotoFilterTypePassThrough, - PGPhotoFilterTypeLookup, - PGPhotoFilterTypeCustom -} PGPhotoFilterType; - -@interface PGPhotoFilterDefinition : NSObject - -@property (readonly, nonatomic) NSString *identifier; -@property (readonly, nonatomic) NSString *title; -@property (readonly, nonatomic) PGPhotoFilterType type; -@property (readonly, nonatomic) NSString *lookupFilename; -@property (readonly, nonatomic) NSString *shaderFilename; -@property (readonly, nonatomic) NSArray *textureFilenames; - -+ (PGPhotoFilterDefinition *)originalFilterDefinition; -+ (PGPhotoFilterDefinition *)definitionWithDictionary:(NSDictionary *)dictionary; - -@end diff --git a/submodules/LegacyComponents/Sources/PGPhotoFilterDefinition.m b/submodules/LegacyComponents/Sources/PGPhotoFilterDefinition.m deleted file mode 100644 index f2f3b27995..0000000000 --- a/submodules/LegacyComponents/Sources/PGPhotoFilterDefinition.m +++ /dev/null @@ -1,35 +0,0 @@ -#import "PGPhotoFilterDefinition.h" - -@implementation PGPhotoFilterDefinition - -+ (PGPhotoFilterDefinition *)originalFilterDefinition -{ - PGPhotoFilterDefinition *definition = [[PGPhotoFilterDefinition alloc] init]; - definition->_type = PGPhotoFilterTypePassThrough; - definition->_identifier = @"0_0"; - definition->_title = @"Original"; - - return definition; -} - -+ (PGPhotoFilterDefinition *)definitionWithDictionary:(NSDictionary *)dictionary -{ - PGPhotoFilterDefinition *definition = [[PGPhotoFilterDefinition alloc] init]; - - if ([dictionary[@"type"] isEqualToString:@"lookup"]) - definition->_type = PGPhotoFilterTypeLookup; - else if ([dictionary[@"type"] isEqualToString:@"custom"]) - definition->_type = PGPhotoFilterTypeCustom; - else - return nil; - - definition->_identifier = dictionary[@"id"]; - definition->_title = dictionary[@"title"]; - definition->_lookupFilename = dictionary[@"lookup_name"]; - definition->_shaderFilename = dictionary[@"shader_name"]; - definition->_textureFilenames = dictionary[@"texture_names"]; - - return definition; -} - -@end diff --git a/submodules/LegacyComponents/Sources/PGPhotoFilterThumbnailManager.h b/submodules/LegacyComponents/Sources/PGPhotoFilterThumbnailManager.h deleted file mode 100644 index b215d589ce..0000000000 --- a/submodules/LegacyComponents/Sources/PGPhotoFilterThumbnailManager.h +++ /dev/null @@ -1,20 +0,0 @@ -#import -#import - -@class PGPhotoEditor; -@class PGPhotoFilter; - -@interface PGPhotoFilterThumbnailManager : NSObject - -@property (nonatomic, weak) PGPhotoEditor *photoEditor; - -- (void)setThumbnailImage:(UIImage *)image; -- (void)requestThumbnailImageForFilter:(PGPhotoFilter *)filter completion:(void (^)(UIImage *thumbnailImage, bool cached, bool finished))completion; -- (void)startCachingThumbnailImagesForFilters:(NSArray *)filters; -- (void)stopCachingThumbnailImagesForFilters:(NSArray *)filters; -- (void)stopCachingThumbnailImagesForAllFilters; -- (void)invalidateThumbnailImages; - -- (void)haltCaching; - -@end diff --git a/submodules/LegacyComponents/Sources/PGPhotoFilterThumbnailManager.m b/submodules/LegacyComponents/Sources/PGPhotoFilterThumbnailManager.m deleted file mode 100644 index c1594aa32e..0000000000 --- a/submodules/LegacyComponents/Sources/PGPhotoFilterThumbnailManager.m +++ /dev/null @@ -1,277 +0,0 @@ -#import "PGPhotoFilterThumbnailManager.h" - -#import -#import - -#import - -#import "PGPhotoEditor.h" -#import "PGPhotoFilter.h" -#import "PGPhotoFilterDefinition.h" -#import "PGPhotoProcessPass.h" -#import "PGPhotoEditorPicture.h" - -const NSUInteger TGFilterThumbnailCacheSoftMemoryLimit = 2 * 1024 * 1024; -const NSUInteger TGFilterThumbnailCacheHardMemoryLimit = 2 * 1024 * 1024; - -@interface PGPhotoFilterThumbnailManager () -{ - TGMemoryImageCache *_filterThumbnailCache; - SQueue *_cachingQueue; - - UIImage *_thumbnailImage; - PGPhotoEditorPicture *_thumbnailPicture; - - SQueue *_filteringQueue; - dispatch_queue_t _prepQueue; - - pthread_rwlock_t _callbackLock; - NSMutableDictionary *_callbacksForId; - - NSInteger _version; -} - -@end - -@implementation PGPhotoFilterThumbnailManager - -- (instancetype)init -{ - self = [super init]; - if (self != nil) - { - [self invalidateThumbnailImages]; - - _prepQueue = dispatch_queue_create("ph.pictogra.Pictograph.FilterThumbnailQueue", DISPATCH_QUEUE_CONCURRENT); - - _cachingQueue = [[SQueue alloc] init]; - _callbacksForId = [[NSMutableDictionary alloc] init]; - - _filteringQueue = [[SQueue alloc] init]; - pthread_rwlock_init(&_callbackLock, NULL); - } - return self; -} - -- (void)setThumbnailImage:(UIImage *)image -{ - [self invalidateThumbnailImages]; - _thumbnailImage = image; - - //_thumbnailPicture = [[PGPhotoEditorPicture alloc] initWithImage:_thumbnailImage]; -} - -- (void)requestThumbnailImageForFilter:(PGPhotoFilter *)filter completion:(void (^)(UIImage *image, bool cached, bool finished))completion -{ - if (filter.definition.type == PGPhotoFilterTypePassThrough) - { - if (completion != nil) - { - if (_thumbnailImage != nil) - completion(_thumbnailImage, true, true); - else - completion(nil, true, false); - } - - return; - } - - UIImage *cachedImage = [_filterThumbnailCache imageForKey:filter.identifier attributes:nil]; - if (cachedImage != nil) - { - if (completion != nil) - completion(cachedImage, true, true); - return; - } - - if (_thumbnailImage == nil) - { - completion(nil, true, true); - return; - } - - if (completion != nil) - completion(_thumbnailImage, true, false); - - NSInteger version = _version; - - __weak PGPhotoFilterThumbnailManager *weakSelf = self; - [self _addCallback:completion forId:filter.identifier createCallback:^ - { - __strong PGPhotoFilterThumbnailManager *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - if (version != strongSelf->_version) - return; - - [strongSelf renderFilterThumbnailWithPicture:strongSelf->_thumbnailPicture filter:filter completion:^(UIImage *result) - { - [strongSelf _processCompletionForId:filter.identifier withResult:result]; - }]; - }]; -} - -- (void)startCachingThumbnailImagesForFilters:(NSArray *)filters -{ - if (_thumbnailImage == nil) - return; - - NSMutableArray *filtersToStartCaching = [[NSMutableArray alloc] init]; - - for (PGPhotoFilter *filter in filters) - { - if (filter.definition.type != PGPhotoFilterTypePassThrough && [_filterThumbnailCache imageForKey:filter.identifier attributes:nil] == nil) - [filtersToStartCaching addObject:filter]; - } - - NSInteger version = _version; - - [_cachingQueue dispatch:^ - { - if (version != _version) - return; - - for (PGPhotoFilter *filter in filtersToStartCaching) - { - __weak PGPhotoFilterThumbnailManager *weakSelf = self; - [self _addCallback:nil forId:filter.identifier createCallback:^ - { - __strong PGPhotoFilterThumbnailManager *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - if (version != strongSelf->_version) - return; - - [strongSelf renderFilterThumbnailWithPicture:strongSelf->_thumbnailPicture filter:filter completion:^(UIImage *result) - { - [strongSelf _processCompletionForId:filter.identifier withResult:result]; - }]; - }]; - } - }]; -} - -- (void)stopCachingThumbnailImagesForFilters:(NSArray *)__unused filters -{ - -} - -- (void)stopCachingThumbnailImagesForAllFilters -{ - -} - -- (void)_processCompletionForId:(NSString *)filterId withResult:(UIImage *)result -{ - [_filterThumbnailCache setImage:result forKey:filterId attributes:nil]; - - NSArray *callbacks = [self _callbacksForId:filterId]; - [self _removeCallbacksForId:filterId]; - - for (id callback in callbacks) - { - void(^callbackBlock)(UIImage *image, bool cached, bool finished) = callback; - if (callbackBlock != nil) - callbackBlock(result, false, true); - } -} - -- (void)renderFilterThumbnailWithPicture:(PGPhotoEditorPicture *)picture filter:(PGPhotoFilter *)filter completion:(void (^)(UIImage *result))completion -{ - PGPhotoEditor *photoEditor = self.photoEditor; - if (photoEditor == nil) - return; - - NSInteger version = _version; - dispatch_async(_prepQueue, ^ - { - GPUImageOutput *gpuFilter = filter.optimizedPass.filter; - [_filteringQueue dispatch:^ - { - if (version != _version) - return; - - [picture addTarget:gpuFilter]; - [gpuFilter useNextFrameForImageCapture]; - [picture processSynchronous:true completion:^ - { - UIImage *image = [gpuFilter imageFromCurrentFramebufferWithOrientation:UIImageOrientationUp]; - [picture removeAllTargets]; - - if (completion != nil) - completion(image); - }]; - }]; - }); -} - -- (void)invalidateThumbnailImages -{ - _version = lrand48(); - - _filterThumbnailCache = [[TGMemoryImageCache alloc] initWithSoftMemoryLimit:TGFilterThumbnailCacheSoftMemoryLimit - hardMemoryLimit:TGFilterThumbnailCacheHardMemoryLimit]; -} - -- (void)haltCaching -{ - _version = lrand48(); -} - -- (void)_addCallback:(void (^)(UIImage *, bool, bool))callback forId:(NSString *)filterId createCallback:(void (^)(void))createCallback -{ - if (filterId == nil) - { - callback(nil, true, false); - return; - } - - pthread_rwlock_rdlock(&_callbackLock); - - bool isInitial = false; - if (_callbacksForId[filterId] == nil) - { - isInitial = true; - _callbacksForId[filterId] = [[NSMutableArray alloc] init]; - } - - if (callback != nil) - { - NSMutableArray *callbacksForId = _callbacksForId[filterId]; - [callbacksForId addObject:callback]; - _callbacksForId[filterId] = callbacksForId; - } - - if (isInitial && createCallback != nil) - createCallback(); - - pthread_rwlock_unlock(&_callbackLock); -} - -- (NSArray *)_callbacksForId:(NSString *)filterId -{ - if (filterId == nil) - return nil; - - __block NSArray *callbacksForId; - - pthread_rwlock_rdlock(&_callbackLock); - callbacksForId = _callbacksForId[filterId]; - pthread_rwlock_unlock(&_callbackLock); - - return [callbacksForId copy]; -} - -- (void)_removeCallbacksForId:(NSString *)filterId -{ - if (filterId == nil) - return; - - pthread_rwlock_rdlock(&_callbackLock); - [_callbacksForId removeObjectForKey:filterId]; - pthread_rwlock_unlock(&_callbackLock); -} - -@end diff --git a/submodules/LegacyComponents/Sources/STKAudioPlayer.h b/submodules/LegacyComponents/Sources/STKAudioPlayer.h deleted file mode 100755 index 0ce6d53852..0000000000 --- a/submodules/LegacyComponents/Sources/STKAudioPlayer.h +++ /dev/null @@ -1,266 +0,0 @@ -/********************************************************************************** - AudioPlayer.m - - Created by Thong Nguyen on 14/05/2012. - https://github.com/tumtumtum/StreamingKit - - Inspired by Matt Gallagher's AudioStreamer: - https://github.com/mattgallagher/AudioStreamer - - Copyright (c) 2012-2014 Thong Nguyen (tumtumtum@gmail.com). All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by Thong Nguyen (tumtumtum@gmail.com) - 4. Neither the name of Thong Nguyen nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY Thong Nguyen''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **********************************************************************************/ - -#import -#import -#import "STKDataSource.h" -#import - -#if TARGET_OS_IPHONE -#include "UIKit/UIApplication.h" -#endif - -typedef enum -{ - STKAudioPlayerStateReady, - STKAudioPlayerStateRunning = 1, - STKAudioPlayerStatePlaying = (1 << 1) | STKAudioPlayerStateRunning, - STKAudioPlayerStateBuffering = (1 << 2) | STKAudioPlayerStateRunning, - STKAudioPlayerStatePaused = (1 << 3) | STKAudioPlayerStateRunning, - STKAudioPlayerStateStopped = (1 << 4), - STKAudioPlayerStateError = (1 << 5), - STKAudioPlayerStateDisposed = (1 << 6) -} -STKAudioPlayerState; - -typedef enum -{ - STKAudioPlayerStopReasonNone = 0, - STKAudioPlayerStopReasonEof, - STKAudioPlayerStopReasonUserAction, - STKAudioPlayerStopReasonPendingNext, - STKAudioPlayerStopReasonDisposed, - STKAudioPlayerStopReasonError = 0xffff -} -STKAudioPlayerStopReason; - -typedef enum -{ - STKAudioPlayerErrorNone = 0, - STKAudioPlayerErrorDataSource, - STKAudioPlayerErrorStreamParseBytesFailed, - STKAudioPlayerErrorAudioSystemError, - STKAudioPlayerErrorCodecError, - STKAudioPlayerErrorDataNotFound, - STKAudioPlayerErrorOther = 0xffff -} -STKAudioPlayerErrorCode; - -typedef struct -{ - /// If YES then seeking a track will cause all pending items to be flushed from the queue - BOOL flushQueueOnSeek; - /// If YES then volume control will be enabled on iOS - BOOL enableVolumeMixer; - /// A pointer to a 0 terminated array of band frequencies (iOS 5.0 and later, OSX 10.9 and later) - Float32 equalizerBandFrequencies[24]; - /// The size of the internal I/O read buffer. This data in this buffer is transient and does not need to be larger. - UInt32 readBufferSize; - /// The size of the decompressed buffer (Default is 10 seconds which uses about 1.7MB of RAM) - UInt32 bufferSizeInSeconds; - /// Number of seconds of decompressed audio is required before playback first starts for each item (Default is 0.5 seconds. Must be larger than bufferSizeInSeconds) - Float32 secondsRequiredToStartPlaying; - /// Seconds after a seek is performed before data needs to come in (after which the state will change to playing/buffering) - Float32 gracePeriodAfterSeekInSeconds; - /// Number of seconds of decompressed audio required before playback resumes after a buffer underrun (Default is 5 seconds. Must be larger than bufferSizeinSeconds) - Float32 secondsRequiredToStartPlayingAfterBufferUnderun; -} -STKAudioPlayerOptions; - -typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UInt32 frameCount, void* frames); - -@interface STKFrameFilterEntry : NSObject -@property (readonly) NSString* name; -@property (readonly) STKFrameFilter filter; -@end - -@class STKAudioPlayer; - -@protocol STKAudioPlayerDelegate - -/// Raised when an item has started playing --(void) audioPlayer:(STKAudioPlayer*)audioPlayer didStartPlayingQueueItemId:(NSObject*)queueItemId; -/// Raised when an item has finished buffering (may or may not be the currently playing item) -/// This event may be raised multiple times for the same item if seek is invoked on the player --(void) audioPlayer:(STKAudioPlayer*)audioPlayer didFinishBufferingSourceWithQueueItemId:(NSObject*)queueItemId; -/// Raised when the state of the player has changed --(void) audioPlayer:(STKAudioPlayer*)audioPlayer stateChanged:(STKAudioPlayerState)state previousState:(STKAudioPlayerState)previousState; -/// Raised when an item has finished playing --(void) audioPlayer:(STKAudioPlayer*)audioPlayer didFinishPlayingQueueItemId:(NSObject*)queueItemId withReason:(STKAudioPlayerStopReason)stopReason andProgress:(double)progress andDuration:(double)duration; -/// Raised when an unexpected and possibly unrecoverable error has occured (usually best to recreate the STKAudioPlauyer) --(void) audioPlayer:(STKAudioPlayer*)audioPlayer unexpectedError:(STKAudioPlayerErrorCode)errorCode; -@optional -/// Optionally implemented to get logging information from the STKAudioPlayer (used internally for debugging) --(void) audioPlayer:(STKAudioPlayer*)audioPlayer logInfo:(NSString*)line; -/// Raised when items queued items are cleared (usually because of a call to play, setDataSource or stop) --(void) audioPlayer:(STKAudioPlayer*)audioPlayer didCancelQueuedItems:(NSArray*)queuedItems; - -@end - -@interface STKAudioPlayer : NSObject - -/// Gets or sets the volume (ranges 0 - 1.0). -/// On iOS the STKAudioPlayerOptionEnableMultichannelMixer option must be enabled for volume to work. -@property (readwrite) Float32 volume; -/// Gets or sets the player muted state -@property (readwrite) BOOL muted; -/// Gets the current item duration in seconds -@property (readonly) double duration; -/// Gets the current item progress in seconds -@property (readonly) double progress; -/// Enables or disables peak and average decibel meteting -@property (readwrite) BOOL meteringEnabled; -/// Enables or disables the EQ -@property (readwrite) BOOL equalizerEnabled; -/// Returns an array of STKFrameFilterEntry objects representing the filters currently in use -@property (readonly) NSArray* frameFilters; -/// Returns the items pending to be played (includes buffering and upcoming items but does not include the current item) -@property (readonly) NSArray* pendingQueue; -/// The number of items pending to be played (includes buffering and upcoming items but does not include the current item) -@property (readonly) NSUInteger pendingQueueCount; -/// Gets the most recently queued item that is still pending to play -@property (readonly) NSObject* mostRecentlyQueuedStillPendingItem; -/// Gets the current state of the player -@property (readwrite) STKAudioPlayerState state; -/// Gets the options provided to the player on startup -@property (readonly) STKAudioPlayerOptions options; -/// Gets the reason why the player is stopped (if any) -@property (readonly) STKAudioPlayerStopReason stopReason; -/// Gets and sets the delegate used for receiving events from the STKAudioPlayer -@property (readwrite, unsafe_unretained) id delegate; - -/// Creates a datasource from a given URL. -/// URLs with FILE schemes will return an STKLocalFileDataSource. -/// URLs with HTTP schemes will return an STKHTTPDataSource wrapped within an STKAutoRecoveringHTTPDataSource. -/// URLs with unrecognised schemes will return nil. -+(STKDataSource*) dataSourceFromURL:(NSURL*)url; - -/// Initializes a new STKAudioPlayer with the default options --(id) init; - -/// Initializes a new STKAudioPlayer with the given options --(id) initWithOptions:(STKAudioPlayerOptions)optionsIn; - -/// Plays an item from the given URL string (all pending queued items are removed). -/// The NSString is used as the queue item ID --(void) play:(NSString*)urlString; - -/// Plays an item from the given URL (all pending queued items are removed) --(void) play:(NSString*)urlString withQueueItemID:(NSObject*)queueItemId; - -/// Plays an item from the given URL (all pending queued items are removed) -/// The NSURL is used as the queue item ID --(void) playURL:(NSURL*)url; - -/// Plays an item from the given URL (all pending queued items are removed) --(void) playURL:(NSURL*)url withQueueItemID:(NSObject*)queueItemId; - -/// Plays the given item (all pending queued items are removed) -/// The STKDataSource is used as the queue item ID --(void) playDataSource:(STKDataSource*)dataSource; - -/// Plays the given item (all pending queued items are removed) --(void) playDataSource:(STKDataSource*)dataSource withQueueItemID:(NSObject*)queueItemId; - -/// Queues the URL string for playback and uses the NSString as the queueItemID --(void) queue:(NSString*)urlString; - -/// Queues the URL string for playback with the given queueItemID --(void) queue:(NSString*)urlString withQueueItemId:(NSObject*)queueItemId; - -/// Queues the URL for playback and uses the NSURL as the queueItemID --(void) queueURL:(NSURL*)url; - -/// Queues the URL for playback with the given queueItemID --(void) queueURL:(NSURL*)url withQueueItemId:(NSObject*)queueItemId; - -/// Queues a DataSource with the given queueItemId --(void) queueDataSource:(STKDataSource*)dataSource withQueueItemId:(NSObject*)queueItemId; - -/// Plays the given item (all pending queued items are removed) --(void) setDataSource:(STKDataSource*)dataSourceIn withQueueItemId:(NSObject*)queueItemId; - -/// Seeks to a specific time (in seconds) --(void) seekToTime:(double)value; - -/// Clears any upcoming items already queued for playback (does not stop the current item). -/// The didCancelItems event will be raised for the items removed from the queue. --(void) clearQueue; - -/// Pauses playback --(void) pause; - -/// Resumes playback from pause --(void) resume; - -/// Stops playback of the current file, flushes all the buffers and removes any pending queued items --(void) stop; - -/// Mutes playback --(void) mute; - -/// Unmutes playback --(void) unmute; - -/// Disposes the STKAudioPlayer and frees up all resources before returning --(void) dispose; - -/// The QueueItemId of the currently playing item --(NSObject*) currentlyPlayingQueueItemId; - -/// Removes a frame filter with the given name --(void) removeFrameFilterWithName:(NSString*)name; - -/// Appends a frame filter with the given name and filter block to the end of the filter chain --(void) appendFrameFilterWithName:(NSString*)name block:(STKFrameFilter)block; - -/// Appends a frame filter with the given name and filter block just after the filter with the given name. -/// If the given name is nil, the filter will be inserted at the beginning of the filter change --(void) addFrameFilterWithName:(NSString*)name afterFilterWithName:(NSString*)afterFilterWithName block:(STKFrameFilter)block; - -/// Reads the peak power in decibals for the given channel (0 or 1). -/// Return values are between -60 (low) and 0 (high). --(float) peakPowerInDecibelsForChannel:(NSUInteger)channelNumber; - -/// Reads the average power in decibals for the given channel (0 or 1) -/// Return values are between -60 (low) and 0 (high). --(float) averagePowerInDecibelsForChannel:(NSUInteger)channelNumber; - -/// Sets the gain value (from -96 low to +24 high) for an equalizer band (0 based index) --(void) setGain:(float)gain forEqualizerBand:(int)bandIndex; - -@end diff --git a/submodules/LegacyComponents/Sources/STKAudioPlayer.m b/submodules/LegacyComponents/Sources/STKAudioPlayer.m deleted file mode 100755 index a00a883d42..0000000000 --- a/submodules/LegacyComponents/Sources/STKAudioPlayer.m +++ /dev/null @@ -1,3157 +0,0 @@ -/********************************************************************************** - AudioPlayer.m - - Created by Thong Nguyen on 14/05/2012. - https://github.com/tumtumtum/StreamingKit - - Copyright (c) 2014 Thong Nguyen (tumtumtum@gmail.com). All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by Thong Nguyen (tumtumtum@gmail.com) - 4. Neither the name of Thong Nguyen nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY Thong Nguyen''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **********************************************************************************/ - -#import "STKAudioPlayer.h" -#import "AudioToolbox/AudioToolbox.h" -#import "STKHTTPDataSource.h" -#import "STKAutoRecoveringHTTPDataSource.h" -#import "STKLocalFileDataSource.h" -#import "STKQueueEntry.h" -#import "NSMutableArray+STKAudioPlayer.h" -#import "libkern/OSAtomic.h" -#import - -#ifndef DBL_MAX -#define DBL_MAX 1.7976931348623157e+308 -#endif - -#pragma mark Defines - -#define kOutputBus 0 -#define kInputBus 1 - -#define STK_DBMIN (-60) -#define STK_DBOFFSET (-74.0) -#define STK_LOWPASSFILTERTIMESLICE (0.0005) - -#define STK_DEFAULT_PCM_BUFFER_SIZE_IN_SECONDS (10) -#define STK_DEFAULT_SECONDS_REQUIRED_TO_START_PLAYING (1) -#define STK_DEFAULT_SECONDS_REQUIRED_TO_START_PLAYING_AFTER_BUFFER_UNDERRUN (7.5) -#define STK_MAX_COMPRESSED_PACKETS_FOR_BITRATE_CALCULATION (4096) -#define STK_DEFAULT_READ_BUFFER_SIZE (64 * 1024) -#define STK_DEFAULT_PACKET_BUFFER_SIZE (2048) -#define STK_DEFAULT_GRACE_PERIOD_AFTER_SEEK_SECONDS (0.5) - -#define LOGINFO(x) [self logInfo:[NSString stringWithFormat:@"%s %@", sel_getName(_cmd), x]]; - -static void PopulateOptionsWithDefault(STKAudioPlayerOptions* options) -{ - if (options->bufferSizeInSeconds == 0) - { - options->bufferSizeInSeconds = STK_DEFAULT_PCM_BUFFER_SIZE_IN_SECONDS; - } - - if (options->readBufferSize == 0) - { - options->readBufferSize = STK_DEFAULT_READ_BUFFER_SIZE; - } - - if (options->secondsRequiredToStartPlaying == 0) - { - options->secondsRequiredToStartPlaying = MIN(STK_DEFAULT_SECONDS_REQUIRED_TO_START_PLAYING, options->bufferSizeInSeconds); - } - - if (options->secondsRequiredToStartPlayingAfterBufferUnderun == 0) - { - options->secondsRequiredToStartPlayingAfterBufferUnderun = MIN(STK_DEFAULT_SECONDS_REQUIRED_TO_START_PLAYING_AFTER_BUFFER_UNDERRUN, options->bufferSizeInSeconds); - } - - if (options->gracePeriodAfterSeekInSeconds == 0) - { - options->gracePeriodAfterSeekInSeconds = MIN(STK_DEFAULT_GRACE_PERIOD_AFTER_SEEK_SECONDS, options->bufferSizeInSeconds); - } -} - -#define CHECK_STATUS_AND_REPORT(call) \ - if ((status = (call))) \ - { \ - [self unexpectedError:STKAudioPlayerErrorAudioSystemError]; \ - } - -#define CHECK_STATUS_AND_RETURN(call) \ - if ((status = (call))) \ - { \ - [self unexpectedError:STKAudioPlayerErrorAudioSystemError]; \ - return;\ - } - -#define CHECK_STATUS_AND_RETURN_VALUE(call, value) \ - if ((status = (call))) \ - { \ - [self unexpectedError:STKAudioPlayerErrorAudioSystemError]; \ - return value;\ - } - -typedef enum -{ - STKAudioPlayerInternalStateInitialised = 0, - STKAudioPlayerInternalStateRunning = 1, - STKAudioPlayerInternalStatePlaying = (1 << 1) | STKAudioPlayerInternalStateRunning, - STKAudioPlayerInternalStateRebuffering = (1 << 2) | STKAudioPlayerInternalStateRunning, - STKAudioPlayerInternalStateStartingThread = (1 << 3) | STKAudioPlayerInternalStateRunning, - STKAudioPlayerInternalStateWaitingForData = (1 << 4) | STKAudioPlayerInternalStateRunning, - /* Same as STKAudioPlayerInternalStateWaitingForData but isn't immediately raised as a buffering event */ - STKAudioPlayerInternalStateWaitingForDataAfterSeek = (1 << 5) | STKAudioPlayerInternalStateRunning, - STKAudioPlayerInternalStatePaused = (1 << 6) | STKAudioPlayerInternalStateRunning, - STKAudioPlayerInternalStateStopped = (1 << 9), - STKAudioPlayerInternalStatePendingNext = (1 << 10), - STKAudioPlayerInternalStateDisposed = (1 << 30), - STKAudioPlayerInternalStateError = (1 << 31) -} -STKAudioPlayerInternalState; - -#pragma mark STKFrameFilterEntry - -@interface STKFrameFilterEntry() -{ -@public - NSString* name; - STKFrameFilter filter; -} -@end - -@implementation STKFrameFilterEntry --(id) initWithFilter:(STKFrameFilter)filterIn andName:(NSString*)nameIn -{ - if (self = [super init]) - { - self->filter = [filterIn copy]; - self->name = nameIn; - } - - return self; -} - --(NSString*) name -{ - return self->name; -} - --(STKFrameFilter) filter -{ - return self->filter; -} -@end - -#pragma mark STKAudioPlayer - -static UInt32 maxFramesPerSlice = 4096; - -static AudioComponentDescription mixerDescription; -static AudioComponentDescription nbandUnitDescription; -static AudioComponentDescription outputUnitDescription; -static AudioComponentDescription convertUnitDescription; -static AudioStreamBasicDescription canonicalAudioStreamBasicDescription; - -@interface STKAudioPlayer() -{ - BOOL muted; - - UInt8* readBuffer; - int readBufferSize; - STKAudioPlayerInternalState internalState; - - Float32 volume; - Float32 peakPowerDb[2]; - Float32 averagePowerDb[2]; - - BOOL meteringEnabled; - BOOL equalizerOn; - BOOL equalizerEnabled; - STKAudioPlayerOptions options; - - NSMutableArray* converterNodes; - - AUGraph audioGraph; - AUNode eqNode; - AUNode mixerNode; - AUNode outputNode; - - AUNode eqInputNode; - AUNode eqOutputNode; - AUNode mixerInputNode; - AUNode mixerOutputNode; - - AudioComponentInstance eqUnit; - AudioComponentInstance mixerUnit; - AudioComponentInstance outputUnit; - - UInt32 eqBandCount; - int32_t waitingForDataAfterSeekFrameCount; - - UInt32 framesRequiredToStartPlaying; - UInt32 framesRequiredToPlayAfterRebuffering; - UInt32 framesRequiredBeforeWaitingForDataAfterSeekBecomesPlaying; - - STKQueueEntry* volatile currentlyPlayingEntry; - STKQueueEntry* volatile currentlyReadingEntry; - - NSMutableArray* upcomingQueue; - NSMutableArray* bufferingQueue; - - OSSpinLock pcmBufferSpinLock; - OSSpinLock internalStateLock; - volatile UInt32 pcmBufferTotalFrameCount; - volatile UInt32 pcmBufferFrameStartIndex; - volatile UInt32 pcmBufferUsedFrameCount; - volatile UInt32 pcmBufferFrameSizeInBytes; - - AudioBuffer* pcmAudioBuffer; - AudioBufferList pcmAudioBufferList; - AudioConverterRef audioConverterRef; - - AudioStreamBasicDescription audioConverterAudioStreamBasicDescription; - - BOOL deallocating; - BOOL discontinuous; - NSArray* frameFilters; - NSThread* playbackThread; - NSRunLoop* playbackThreadRunLoop; - AudioFileStreamID audioFileStream; - NSConditionLock* threadStartedLock; - NSConditionLock* threadFinishedCondLock; - - void(^stopBackBackgroundTaskBlock)(); - - int32_t seekVersion; - OSSpinLock seekLock; - OSSpinLock currentEntryReferencesLock; - - pthread_mutex_t playerMutex; - pthread_cond_t playerThreadReadyCondition; - pthread_mutex_t mainThreadSyncCallMutex; - pthread_cond_t mainThreadSyncCallReadyCondition; - - volatile BOOL waiting; - volatile double requestedSeekTime; - volatile BOOL disposeWasRequested; - volatile BOOL seekToTimeWasRequested; - volatile STKAudioPlayerStopReason stopReason; -} - -@property (readwrite) STKAudioPlayerInternalState internalState; -@property (readwrite) STKAudioPlayerInternalState stateBeforePaused; - --(void) handlePropertyChangeForFileStream:(AudioFileStreamID)audioFileStreamIn fileStreamPropertyID:(AudioFileStreamPropertyID)propertyID ioFlags:(UInt32*)ioFlags; --(void) handleAudioPackets:(const void*)inputData numberBytes:(UInt32)numberBytes numberPackets:(UInt32)numberPackets packetDescriptions:(AudioStreamPacketDescription*)packetDescriptions; -@end - -static void AudioFileStreamPropertyListenerProc(void* clientData, AudioFileStreamID audioFileStream, AudioFileStreamPropertyID propertyId, UInt32* flags) -{ - STKAudioPlayer* player = (__bridge STKAudioPlayer*)clientData; - - [player handlePropertyChangeForFileStream:audioFileStream fileStreamPropertyID:propertyId ioFlags:flags]; -} - -static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UInt32 numberPackets, const void* inputData, AudioStreamPacketDescription* packetDescriptions) -{ - STKAudioPlayer* player = (__bridge STKAudioPlayer*)clientData; - - [player handleAudioPackets:inputData numberBytes:numberBytes numberPackets:numberPackets packetDescriptions:packetDescriptions]; -} - -@implementation STKAudioPlayer - -+(void) initialize -{ - convertUnitDescription = (AudioComponentDescription) - { - .componentManufacturer = kAudioUnitManufacturer_Apple, - .componentType = kAudioUnitType_FormatConverter, - .componentSubType = kAudioUnitSubType_AUConverter, - .componentFlags = 0, - .componentFlagsMask = 0 - }; - - const int bytesPerSample = sizeof(AudioSampleType); - - canonicalAudioStreamBasicDescription = (AudioStreamBasicDescription) - { - .mSampleRate = 44100.00, - .mFormatID = kAudioFormatLinearPCM, - .mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked, - .mFramesPerPacket = 1, - .mChannelsPerFrame = 2, - .mBytesPerFrame = bytesPerSample * 2 /*channelsPerFrame*/, - .mBitsPerChannel = 8 * bytesPerSample, - .mBytesPerPacket = (bytesPerSample * 2) - }; - - outputUnitDescription = (AudioComponentDescription) - { - .componentType = kAudioUnitType_Output, -#if TARGET_OS_IPHONE - .componentSubType = kAudioUnitSubType_RemoteIO, -#else - .componentSubType = kAudioUnitSubType_DefaultOutput, -#endif - .componentFlags = 0, - .componentFlagsMask = 0, - .componentManufacturer = kAudioUnitManufacturer_Apple - }; - - mixerDescription = (AudioComponentDescription) - { - .componentType = kAudioUnitType_Mixer, - .componentSubType = kAudioUnitSubType_MultiChannelMixer, - .componentFlags = 0, - .componentFlagsMask = 0, - .componentManufacturer = kAudioUnitManufacturer_Apple - }; - - nbandUnitDescription = (AudioComponentDescription) - { - .componentType = kAudioUnitType_Effect, - .componentSubType = kAudioUnitSubType_NBandEQ, - .componentManufacturer=kAudioUnitManufacturer_Apple - }; -} --(STKAudioPlayerOptions) options -{ - return options; -} - --(STKAudioPlayerInternalState) internalState -{ - return internalState; -} - --(void) setInternalState:(STKAudioPlayerInternalState)value -{ - [self setInternalState:value ifInState:NULL]; -} - --(void) setInternalState:(STKAudioPlayerInternalState)value ifInState:(BOOL(^)(STKAudioPlayerInternalState))ifInState -{ - STKAudioPlayerState newState; - - switch (value) - { - case STKAudioPlayerInternalStateInitialised: - newState = STKAudioPlayerStateReady; - stopReason = STKAudioPlayerStopReasonNone; - break; - case STKAudioPlayerInternalStateRunning: - case STKAudioPlayerInternalStateStartingThread: - case STKAudioPlayerInternalStatePlaying: - case STKAudioPlayerInternalStateWaitingForDataAfterSeek: - newState = STKAudioPlayerStatePlaying; - stopReason = STKAudioPlayerStopReasonNone; - break; - case STKAudioPlayerInternalStatePendingNext: - case STKAudioPlayerInternalStateRebuffering: - case STKAudioPlayerInternalStateWaitingForData: - newState = STKAudioPlayerStateBuffering; - stopReason = STKAudioPlayerStopReasonNone; - break; - case STKAudioPlayerInternalStateStopped: - newState = STKAudioPlayerStateStopped; - break; - case STKAudioPlayerInternalStatePaused: - newState = STKAudioPlayerStatePaused; - stopReason = STKAudioPlayerStopReasonNone; - break; - case STKAudioPlayerInternalStateDisposed: - newState = STKAudioPlayerStateDisposed; - stopReason = STKAudioPlayerStopReasonUserAction; - break; - case STKAudioPlayerInternalStateError: - newState = STKAudioPlayerStateError; - stopReason = STKAudioPlayerStopReasonError; - break; - } - - OSSpinLockLock(&internalStateLock); - - waitingForDataAfterSeekFrameCount = 0; - - if (value == internalState) - { - OSSpinLockUnlock(&internalStateLock); - - return; - } - - if (ifInState != NULL) - { - if (!ifInState(self->internalState)) - { - OSSpinLockUnlock(&internalStateLock); - - return; - } - } - - internalState = value; - - STKAudioPlayerState previousState = self.state; - - if (newState != previousState && !deallocating) - { - self.state = newState; - - OSSpinLockUnlock(&internalStateLock); - - dispatch_async(dispatch_get_main_queue(), ^ - { - [self.delegate audioPlayer:self stateChanged:self.state previousState:previousState]; - }); - } - else - { - OSSpinLockUnlock(&internalStateLock); - } -} - --(STKAudioPlayerStopReason) stopReason -{ - return stopReason; -} - --(void) logInfo:(NSString*)line -{ - if ([NSThread currentThread].isMainThread) - { - if ([self.delegate respondsToSelector:@selector(audioPlayer:logInfo:)]) - { - [self.delegate audioPlayer:self logInfo:line]; - } - } - else - { - if ([self.delegate respondsToSelector:@selector(audioPlayer:logInfo:)]) - { - [self.delegate audioPlayer:self logInfo:line]; - } - } -} - --(id) init -{ - return [self initWithOptions:(STKAudioPlayerOptions){}]; -} - --(id) initWithOptions:(STKAudioPlayerOptions)optionsIn -{ - if (self = [super init]) - { - options = optionsIn; - - self->volume = 1.0; - self->equalizerEnabled = optionsIn.equalizerBandFrequencies[0] != 0; - - PopulateOptionsWithDefault(&options); - - framesRequiredToStartPlaying = canonicalAudioStreamBasicDescription.mSampleRate * options.secondsRequiredToStartPlaying; - framesRequiredToPlayAfterRebuffering = canonicalAudioStreamBasicDescription.mSampleRate * options.secondsRequiredToStartPlayingAfterBufferUnderun; - framesRequiredBeforeWaitingForDataAfterSeekBecomesPlaying = canonicalAudioStreamBasicDescription.mSampleRate * options.gracePeriodAfterSeekInSeconds; - - pcmAudioBuffer = &pcmAudioBufferList.mBuffers[0]; - - pcmAudioBufferList.mNumberBuffers = 1; - pcmAudioBufferList.mBuffers[0].mDataByteSize = (canonicalAudioStreamBasicDescription.mSampleRate * options.bufferSizeInSeconds) * canonicalAudioStreamBasicDescription.mBytesPerFrame; - pcmAudioBufferList.mBuffers[0].mData = (void*)calloc(pcmAudioBuffer->mDataByteSize, 1); - pcmAudioBufferList.mBuffers[0].mNumberChannels = 2; - - pcmBufferFrameSizeInBytes = canonicalAudioStreamBasicDescription.mBytesPerFrame; - pcmBufferTotalFrameCount = pcmAudioBuffer->mDataByteSize / pcmBufferFrameSizeInBytes; - - readBufferSize = options.readBufferSize; - readBuffer = calloc(sizeof(UInt8), readBufferSize); - - pthread_mutexattr_t attr; - - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - - pthread_mutex_init(&playerMutex, &attr); - pthread_mutex_init(&mainThreadSyncCallMutex, NULL); - pthread_cond_init(&playerThreadReadyCondition, NULL); - pthread_cond_init(&mainThreadSyncCallReadyCondition, NULL); - - threadStartedLock = [[NSConditionLock alloc] initWithCondition:0]; - threadFinishedCondLock = [[NSConditionLock alloc] initWithCondition:0]; - - self.internalState = STKAudioPlayerInternalStateInitialised; - - upcomingQueue = [[NSMutableArray alloc] init]; - bufferingQueue = [[NSMutableArray alloc] init]; - - [self resetPcmBuffers]; - [self createAudioGraph]; - [self createPlaybackThread]; - } - - return self; -} - --(void) destroyAudioResources -{ - if (currentlyReadingEntry) - { - currentlyReadingEntry.dataSource.delegate = nil; - [currentlyReadingEntry.dataSource unregisterForEvents]; - - currentlyReadingEntry = nil; - } - - if (currentlyPlayingEntry) - { - currentlyPlayingEntry.dataSource.delegate = nil; - [currentlyReadingEntry.dataSource unregisterForEvents]; - - OSSpinLockLock(¤tEntryReferencesLock); - - currentlyPlayingEntry = nil; - - OSSpinLockUnlock(¤tEntryReferencesLock); - } - - [self stopAudioUnitWithReason:STKAudioPlayerStopReasonDisposed]; - - [self clearQueue]; - - if (audioFileStream) - { - AudioFileStreamClose(audioFileStream); - audioFileStream = nil; - } - - if (audioConverterRef) - { - AudioConverterDispose(audioConverterRef); - audioConverterRef = nil; - } - - if (audioGraph) - { - AUGraphUninitialize(audioGraph); - AUGraphClose(audioGraph); - DisposeAUGraph(audioGraph); - - audioGraph = nil; - } -} - --(void) dealloc -{ - NSLog(@"STKAudioPlayer dealloc"); - - deallocating = YES; - - [self destroyAudioResources]; - - pthread_mutex_destroy(&playerMutex); - pthread_mutex_destroy(&mainThreadSyncCallMutex); - pthread_cond_destroy(&playerThreadReadyCondition); - pthread_cond_destroy(&mainThreadSyncCallReadyCondition); - - free(readBuffer); -} - --(void) startSystemBackgroundTask -{ -/*#if TARGET_OS_IPHONE - __block UIBackgroundTaskIdentifier backgroundTaskId = UIBackgroundTaskInvalid; - - backgroundTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^ - { - [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskId]; - backgroundTaskId = UIBackgroundTaskInvalid; - }]; - - stopBackBackgroundTaskBlock = [^ - { - if (backgroundTaskId != UIBackgroundTaskInvalid) - { - [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskId]; - backgroundTaskId = UIBackgroundTaskInvalid; - } - } copy]; -#endif*/ -} - --(void) stopSystemBackgroundTask -{ -#if TARGET_OS_IPHONE - if (stopBackBackgroundTaskBlock != NULL) - { - stopBackBackgroundTaskBlock(); - stopBackBackgroundTaskBlock = NULL; - } -#endif -} - -+(STKDataSource*) dataSourceFromURL:(NSURL*)url -{ - STKDataSource* retval = nil; - - if ([url.scheme isEqualToString:@"file"]) - { - retval = [[STKLocalFileDataSource alloc] initWithFilePath:url.path]; - } - else if ([url.scheme caseInsensitiveCompare:@"http"] == NSOrderedSame || [url.scheme caseInsensitiveCompare:@"https"] == NSOrderedSame) - { - retval = [[STKAutoRecoveringHTTPDataSource alloc] initWithHTTPDataSource:[[STKHTTPDataSource alloc] initWithURL:url]]; - } - - return retval; -} - --(void) clearQueue -{ - pthread_mutex_lock(&playerMutex); - { - if ([self.delegate respondsToSelector:@selector(audioPlayer:didCancelQueuedItems:)]) - { - NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity:bufferingQueue.count + upcomingQueue.count]; - - for (STKQueueEntry* entry in upcomingQueue) - { - [array addObject:entry.queueItemId]; - } - - for (STKQueueEntry* entry in bufferingQueue) - { - [array addObject:entry.queueItemId]; - } - - [upcomingQueue removeAllObjects]; - [bufferingQueue removeAllObjects]; - - if (array.count > 0) - { - [self playbackThreadQueueMainThreadSyncBlock:^ - { - if ([self.delegate respondsToSelector:@selector(audioPlayer:didCancelQueuedItems:)]) - { - [self.delegate audioPlayer:self didCancelQueuedItems:array]; - } - }]; - } - } - else - { - [bufferingQueue removeAllObjects]; - [upcomingQueue removeAllObjects]; - } - } - pthread_mutex_unlock(&playerMutex); -} - --(void) play:(NSString*)urlString -{ - [self play:urlString withQueueItemID:urlString]; -} - --(void) play:(NSString*)urlString withQueueItemID:(NSObject*)queueItemId -{ - NSURL* url = [NSURL URLWithString:urlString]; - - [self setDataSource:[STKAudioPlayer dataSourceFromURL:url] withQueueItemId:queueItemId]; -} - --(void) playURL:(NSURL*)url -{ - [self playURL:url withQueueItemID:url]; -} - --(void) playURL:(NSURL*)url withQueueItemID:(NSObject*)queueItemId -{ - [self setDataSource:[STKAudioPlayer dataSourceFromURL:url] withQueueItemId:queueItemId]; -} - --(void) playDataSource:(STKDataSource*)dataSource -{ - [self playDataSource:dataSource withQueueItemID:dataSource]; -} - --(void) playDataSource:(STKDataSource*)dataSource withQueueItemID:(NSObject *)queueItemId -{ - [self setDataSource:dataSource withQueueItemId:queueItemId]; -} - --(void) setDataSource:(STKDataSource*)dataSourceIn withQueueItemId:(NSObject*)queueItemId -{ - pthread_mutex_lock(&playerMutex); - { - LOGINFO(([NSString stringWithFormat:@"Playing: %@", [queueItemId description]])); - - if (![self audioGraphIsRunning]) - { - [self startSystemBackgroundTask]; - } - - [self clearQueue]; - - [upcomingQueue enqueue:[[STKQueueEntry alloc] initWithDataSource:dataSourceIn andQueueItemId:queueItemId]]; - - self.internalState = STKAudioPlayerInternalStatePendingNext; - } - pthread_mutex_unlock(&playerMutex); - - [self wakeupPlaybackThread]; -} - --(void) queue:(NSString*)urlString -{ - return [self queueURL:[NSURL URLWithString:urlString] withQueueItemId:urlString]; -} - --(void) queue:(NSString*)urlString withQueueItemId:(NSObject*)queueItemId -{ - [self queueURL:[NSURL URLWithString:urlString] withQueueItemId:queueItemId]; -} - --(void) queueURL:(NSURL*)url -{ - [self queueURL:url withQueueItemId:url]; -} - --(void) queueURL:(NSURL*)url withQueueItemId:(NSObject*)queueItemId -{ - [self queueDataSource:[STKAudioPlayer dataSourceFromURL:url] withQueueItemId:queueItemId]; -} - --(void) queueDataSource:(STKDataSource*)dataSourceIn withQueueItemId:(NSObject*)queueItemId -{ - pthread_mutex_lock(&playerMutex); - { - if (![self audioGraphIsRunning]) - { - [self startSystemBackgroundTask]; - } - - [upcomingQueue enqueue:[[STKQueueEntry alloc] initWithDataSource:dataSourceIn andQueueItemId:queueItemId]]; - } - pthread_mutex_unlock(&playerMutex); - - [self wakeupPlaybackThread]; -} - --(void) handlePropertyChangeForFileStream:(AudioFileStreamID)inAudioFileStream fileStreamPropertyID:(AudioFileStreamPropertyID)inPropertyID ioFlags:(UInt32*)ioFlags -{ - OSStatus error; - - if (!currentlyReadingEntry) - { - return; - } - - switch (inPropertyID) - { - case kAudioFileStreamProperty_DataOffset: - { - SInt64 offset; - UInt32 offsetSize = sizeof(offset); - - AudioFileStreamGetProperty(audioFileStream, kAudioFileStreamProperty_DataOffset, &offsetSize, &offset); - - currentlyReadingEntry->parsedHeader = YES; - currentlyReadingEntry->audioDataOffset = offset; - - break; - } - case kAudioFileStreamProperty_FileFormat: - { - char fileFormat[4]; - UInt32 fileFormatSize = sizeof(fileFormat); - - AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_FileFormat, &fileFormatSize, &fileFormat); - - break; - } - case kAudioFileStreamProperty_DataFormat: - { - AudioStreamBasicDescription newBasicDescription; - STKQueueEntry* entryToUpdate = currentlyReadingEntry; - - if (!currentlyReadingEntry->parsedHeader) - { - UInt32 size = sizeof(newBasicDescription); - - AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_DataFormat, &size, &newBasicDescription); - - pthread_mutex_lock(&playerMutex); - - entryToUpdate->audioStreamBasicDescription = newBasicDescription; - entryToUpdate->sampleRate = entryToUpdate->audioStreamBasicDescription.mSampleRate; - entryToUpdate->packetDuration = entryToUpdate->audioStreamBasicDescription.mFramesPerPacket / entryToUpdate->sampleRate; - - UInt32 packetBufferSize = 0; - UInt32 sizeOfPacketBufferSize = sizeof(packetBufferSize); - - error = AudioFileStreamGetProperty(audioFileStream, kAudioFileStreamProperty_PacketSizeUpperBound, &sizeOfPacketBufferSize, &packetBufferSize); - - if (error || packetBufferSize == 0) - { - error = AudioFileStreamGetProperty(audioFileStream, kAudioFileStreamProperty_MaximumPacketSize, &sizeOfPacketBufferSize, &packetBufferSize); - - if (error || packetBufferSize == 0) - { - entryToUpdate->packetBufferSize = STK_DEFAULT_PACKET_BUFFER_SIZE; - } - else - { - entryToUpdate->packetBufferSize = packetBufferSize; - } - } - else - { - entryToUpdate->packetBufferSize = packetBufferSize; - } - - [self createAudioConverter:¤tlyReadingEntry->audioStreamBasicDescription]; - - pthread_mutex_unlock(&playerMutex); - } - - break; - } - case kAudioFileStreamProperty_AudioDataByteCount: - { - UInt64 audioDataByteCount; - UInt32 byteCountSize = sizeof(audioDataByteCount); - - AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_AudioDataByteCount, &byteCountSize, &audioDataByteCount); - - currentlyReadingEntry->audioDataByteCount = audioDataByteCount; - - break; - } - case kAudioFileStreamProperty_ReadyToProducePackets: - { - if (!audioConverterAudioStreamBasicDescription.mFormatID == kAudioFormatLinearPCM) - { - discontinuous = YES; - } - - break; - } - case kAudioFileStreamProperty_FormatList: - { - Boolean outWriteable; - UInt32 formatListSize; - OSStatus err = AudioFileStreamGetPropertyInfo(inAudioFileStream, kAudioFileStreamProperty_FormatList, &formatListSize, &outWriteable); - - if (err) - { - break; - } - - AudioFormatListItem* formatList = malloc(formatListSize); - - err = AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_FormatList, &formatListSize, formatList); - - if (err) - { - free(formatList); - break; - } - - for (int i = 0; i * sizeof(AudioFormatListItem) < formatListSize; i += sizeof(AudioFormatListItem)) - { - AudioStreamBasicDescription pasbd = formatList[i].mASBD; - - if (pasbd.mFormatID == kAudioFormatMPEG4AAC_HE || pasbd.mFormatID == kAudioFormatMPEG4AAC_HE_V2) - { - // - // We've found HE-AAC, remember this to tell the audio queue - // when we construct it. - // -#if !TARGET_IPHONE_SIMULATOR - currentlyReadingEntry->audioStreamBasicDescription = pasbd; -#endif - break; - } - } - - free(formatList); - - break; - } - - } -} - --(Float64) currentTimeInFrames -{ - if (audioGraph == nil) - { - return 0; - } - - return 0; -} - --(void) unexpectedError:(STKAudioPlayerErrorCode)errorCodeIn -{ - self.internalState = STKAudioPlayerInternalStateError; - - [self playbackThreadQueueMainThreadSyncBlock:^ - { - [self.delegate audioPlayer:self unexpectedError:errorCodeIn]; - }]; -} - --(double) duration -{ - if (self.internalState == STKAudioPlayerInternalStatePendingNext) - { - return 0; - } - - OSSpinLockLock(¤tEntryReferencesLock); - STKQueueEntry* entry = currentlyPlayingEntry; - OSSpinLockUnlock(¤tEntryReferencesLock); - - if (entry == nil) - { - return 0; - } - - double retval = [entry duration]; - double progress = [self progress]; - - if (retval < progress && retval > 0) - { - return progress; - } - - return retval; -} - --(double) progress -{ - if (seekToTimeWasRequested) - { - return requestedSeekTime; - } - - if (self.internalState == STKAudioPlayerInternalStatePendingNext) - { - return 0; - } - - OSSpinLockLock(¤tEntryReferencesLock); - STKQueueEntry* entry = currentlyPlayingEntry; - OSSpinLockUnlock(¤tEntryReferencesLock); - - if (entry == nil) - { - return 0; - } - - OSSpinLockLock(&entry->spinLock); - double retval = entry->seekTime + (entry->framesPlayed / canonicalAudioStreamBasicDescription.mSampleRate); - OSSpinLockUnlock(&entry->spinLock); - - return retval; -} - --(BOOL) invokeOnPlaybackThread:(void(^)())block -{ - NSRunLoop* runLoop = playbackThreadRunLoop; - - if (runLoop) - { - CFRunLoopPerformBlock([runLoop getCFRunLoop], NSRunLoopCommonModes, block); - CFRunLoopWakeUp([runLoop getCFRunLoop]); - - return YES; - } - - return NO; -} - --(void) wakeupPlaybackThread -{ - [self invokeOnPlaybackThread:^ - { - [self processRunloop]; - }]; - - pthread_mutex_lock(&playerMutex); - - if (waiting) - { - pthread_cond_signal(&playerThreadReadyCondition); - } - - pthread_mutex_unlock(&playerMutex); -} - --(void) seekToTime:(double)value -{ - if (currentlyPlayingEntry == nil) - { - return; - } - - OSSpinLockLock(&seekLock); - - BOOL seekAlreadyRequested = seekToTimeWasRequested; - - seekToTimeWasRequested = YES; - requestedSeekTime = value; - - if (!seekAlreadyRequested) - { - OSAtomicIncrement32(&seekVersion); - - OSSpinLockUnlock(&seekLock); - - [self wakeupPlaybackThread]; - - return; - } - - OSSpinLockUnlock(&seekLock); -} - --(void) createPlaybackThread -{ - playbackThread = [[NSThread alloc] initWithTarget:self selector:@selector(startInternal) object:nil]; - - [playbackThread start]; - - [threadStartedLock lockWhenCondition:1]; - [threadStartedLock unlockWithCondition:0]; - - NSAssert(playbackThreadRunLoop != nil, @"playbackThreadRunLoop != nil"); -} - --(void) audioQueueFinishedPlaying:(STKQueueEntry*)entry -{ - STKQueueEntry* next = [bufferingQueue dequeue]; - - [self processFinishPlayingIfAnyAndPlayingNext:entry withNext:next]; - [self processRunloop]; -} - --(void) setCurrentlyReadingEntry:(STKQueueEntry*)entry andStartPlaying:(BOOL)startPlaying -{ - [self setCurrentlyReadingEntry:entry andStartPlaying:startPlaying clearQueue:YES]; -} - --(void) setCurrentlyReadingEntry:(STKQueueEntry*)entry andStartPlaying:(BOOL)startPlaying clearQueue:(BOOL)clearQueue -{ - LOGINFO(([entry description])); - - if (startPlaying) - { - memset(&pcmAudioBuffer->mData[0], 0, pcmBufferTotalFrameCount * pcmBufferFrameSizeInBytes); - } - - if (audioFileStream) - { - AudioFileStreamClose(audioFileStream); - - audioFileStream = 0; - } - - if (currentlyReadingEntry) - { - currentlyReadingEntry.dataSource.delegate = nil; - [currentlyReadingEntry.dataSource unregisterForEvents]; - [currentlyReadingEntry.dataSource close]; - } - - OSSpinLockLock(¤tEntryReferencesLock); - currentlyReadingEntry = entry; - OSSpinLockUnlock(¤tEntryReferencesLock); - - currentlyReadingEntry.dataSource.delegate = self; - [currentlyReadingEntry.dataSource registerForEvents:[NSRunLoop currentRunLoop]]; - [currentlyReadingEntry.dataSource seekToOffset:0]; - - if (startPlaying) - { - if (clearQueue) - { - [self clearQueue]; - } - - [self processFinishPlayingIfAnyAndPlayingNext:currentlyPlayingEntry withNext:entry]; - - [self startAudioGraph]; - } - else - { - [bufferingQueue enqueue:entry]; - } -} - --(void) processFinishPlayingIfAnyAndPlayingNext:(STKQueueEntry*)entry withNext:(STKQueueEntry*)next -{ - if (entry != currentlyPlayingEntry) - { - return; - } - - LOGINFO(([NSString stringWithFormat:@"Finished: %@, Next: %@, buffering.count=%d,upcoming.count=%d", entry ? [entry description] : @"nothing", [next description], (int)bufferingQueue.count, (int)upcomingQueue.count])); - - NSObject* queueItemId = entry.queueItemId; - double progress = [entry progressInFrames] / canonicalAudioStreamBasicDescription.mSampleRate; - double duration = [entry duration]; - - BOOL isPlayingSameItemProbablySeek = currentlyPlayingEntry == next; - - if (next) - { - if (!isPlayingSameItemProbablySeek) - { - OSSpinLockLock(&next->spinLock); - next->seekTime = 0; - OSSpinLockUnlock(&next->spinLock); - - OSSpinLockLock(&seekLock); - seekToTimeWasRequested = NO; - OSSpinLockUnlock(&seekLock); - } - - OSSpinLockLock(¤tEntryReferencesLock); - currentlyPlayingEntry = next; - NSObject* playingQueueItemId = playingQueueItemId = currentlyPlayingEntry.queueItemId; - OSSpinLockUnlock(¤tEntryReferencesLock); - - if (!isPlayingSameItemProbablySeek && entry) - { - [self playbackThreadQueueMainThreadSyncBlock:^ - { - [self.delegate audioPlayer:self didFinishPlayingQueueItemId:queueItemId withReason:stopReason andProgress:progress andDuration:duration]; - }]; - } - - if (!isPlayingSameItemProbablySeek) - { - [self setInternalState:STKAudioPlayerInternalStateWaitingForData]; - - [self playbackThreadQueueMainThreadSyncBlock:^ - { - [self.delegate audioPlayer:self didStartPlayingQueueItemId:playingQueueItemId]; - }]; - } - } - else - { - OSSpinLockLock(¤tEntryReferencesLock); - currentlyPlayingEntry = nil; - OSSpinLockUnlock(¤tEntryReferencesLock); - - if (!isPlayingSameItemProbablySeek && entry) - { - [self playbackThreadQueueMainThreadSyncBlock:^ - { - [self.delegate audioPlayer:self didFinishPlayingQueueItemId:queueItemId withReason:stopReason andProgress:progress andDuration:duration]; - }]; - } - } - - [self wakeupPlaybackThread]; -} - --(void) dispatchSyncOnMainThread:(void(^)())block -{ - __block BOOL finished = NO; - - if (disposeWasRequested) - { - return; - } - - dispatch_async(dispatch_get_main_queue(), ^ - { - if (!disposeWasRequested) - { - block(); - } - - pthread_mutex_lock(&mainThreadSyncCallMutex); - finished = YES; - pthread_cond_signal(&mainThreadSyncCallReadyCondition); - pthread_mutex_unlock(&mainThreadSyncCallMutex); - }); - - pthread_mutex_lock(&mainThreadSyncCallMutex); - - while (true) - { - if (disposeWasRequested) - { - break; - } - - if (finished) - { - break; - } - - pthread_cond_wait(&mainThreadSyncCallReadyCondition, &mainThreadSyncCallMutex); - } - - pthread_mutex_unlock(&mainThreadSyncCallMutex); -} - --(void) playbackThreadQueueMainThreadSyncBlock:(void(^)())block -{ - block = [block copy]; - - [self invokeOnPlaybackThread:^ - { - if (disposeWasRequested) - { - return; - } - - [self dispatchSyncOnMainThread:block]; - }]; -} - --(void) requeueBufferingEntries -{ - if (bufferingQueue.count > 0) - { - for (STKQueueEntry* queueEntry in bufferingQueue) - { - queueEntry->parsedHeader = NO; - - [queueEntry reset]; - } - - [upcomingQueue skipQueueWithQueue:bufferingQueue]; - - [bufferingQueue removeAllObjects]; - } -} - --(BOOL) processRunloop -{ - pthread_mutex_lock(&playerMutex); - { - if (disposeWasRequested) - { - pthread_mutex_unlock(&playerMutex); - - return NO; - } - else if (self.internalState == STKAudioPlayerInternalStatePaused) - { - pthread_mutex_unlock(&playerMutex); - - return YES; - } - else if (self.internalState == STKAudioPlayerInternalStatePendingNext) - { - STKQueueEntry* entry = [upcomingQueue dequeue]; - - self.internalState = STKAudioPlayerInternalStateWaitingForData; - - [self setCurrentlyReadingEntry:entry andStartPlaying:YES]; - [self resetPcmBuffers]; - } - else if (seekToTimeWasRequested && currentlyPlayingEntry && currentlyPlayingEntry != currentlyReadingEntry) - { - currentlyPlayingEntry->parsedHeader = NO; - [currentlyPlayingEntry reset]; - - if (currentlyReadingEntry != nil) - { - currentlyReadingEntry.dataSource.delegate = nil; - [currentlyReadingEntry.dataSource unregisterForEvents]; - } - - if (self->options.flushQueueOnSeek) - { - self.internalState = STKAudioPlayerInternalStateWaitingForDataAfterSeek; - [self setCurrentlyReadingEntry:currentlyPlayingEntry andStartPlaying:YES clearQueue:YES]; - } - else - { - [self requeueBufferingEntries]; - - self.internalState = STKAudioPlayerInternalStateWaitingForDataAfterSeek; - [self setCurrentlyReadingEntry:currentlyPlayingEntry andStartPlaying:YES clearQueue:NO]; - } - } - else if (currentlyReadingEntry == nil) - { - if (upcomingQueue.count > 0) - { - STKQueueEntry* entry = [upcomingQueue dequeue]; - - BOOL startPlaying = currentlyPlayingEntry == nil; - - self.internalState = STKAudioPlayerInternalStateWaitingForData; - [self setCurrentlyReadingEntry:entry andStartPlaying:startPlaying]; - } - else if (currentlyPlayingEntry == nil) - { - if (self.internalState != STKAudioPlayerInternalStateStopped) - { - [self stopAudioUnitWithReason:STKAudioPlayerStopReasonEof]; - } - } - } - - if (currentlyPlayingEntry && currentlyPlayingEntry->parsedHeader && [currentlyPlayingEntry calculatedBitRate] > 0.0) - { - int32_t originalSeekVersion; - BOOL originalSeekToTimeRequested; - - OSSpinLockLock(&seekLock); - originalSeekVersion = seekVersion; - originalSeekToTimeRequested = seekToTimeWasRequested; - OSSpinLockUnlock(&seekLock); - - if (originalSeekToTimeRequested && currentlyReadingEntry == currentlyPlayingEntry) - { - [self processSeekToTime]; - - OSSpinLockLock(&seekLock); - if (originalSeekVersion == seekVersion) - { - seekToTimeWasRequested = NO; - } - OSSpinLockUnlock(&seekLock); - } - } - else if (currentlyPlayingEntry == nil && seekToTimeWasRequested) - { - seekToTimeWasRequested = NO; - } - } - pthread_mutex_unlock(&playerMutex); - - return YES; -} - --(void) startInternal -{ - @autoreleasepool - { - playbackThreadRunLoop = [NSRunLoop currentRunLoop]; - NSThread.currentThread.threadPriority = 1; - - [threadStartedLock lockWhenCondition:0]; - [threadStartedLock unlockWithCondition:1]; - - [playbackThreadRunLoop addPort:[NSPort port] forMode:NSDefaultRunLoopMode]; - - while (true) - { - @autoreleasepool - { - if (![self processRunloop]) - { - break; - } - } - - NSDate* date = [[NSDate alloc] initWithTimeIntervalSinceNow:10]; - [playbackThreadRunLoop runMode:NSDefaultRunLoopMode beforeDate:date]; - } - - disposeWasRequested = NO; - seekToTimeWasRequested = NO; - - [currentlyReadingEntry.dataSource unregisterForEvents]; - [currentlyPlayingEntry.dataSource unregisterForEvents]; - - currentlyReadingEntry.dataSource.delegate = nil; - currentlyPlayingEntry.dataSource.delegate = nil; - - pthread_mutex_lock(&playerMutex); - OSSpinLockLock(¤tEntryReferencesLock); - currentlyPlayingEntry = nil; - currentlyReadingEntry = nil; - OSSpinLockUnlock(¤tEntryReferencesLock); - pthread_mutex_unlock(&playerMutex); - - self.internalState = STKAudioPlayerInternalStateDisposed; - - playbackThreadRunLoop = nil; - - [self destroyAudioResources]; - - [threadFinishedCondLock lock]; - [threadFinishedCondLock unlockWithCondition:1]; - } -} - --(void) processSeekToTime -{ - OSStatus error; - STKQueueEntry* currentEntry = currentlyReadingEntry; - - NSAssert(currentEntry == currentlyPlayingEntry, @"playing and reading must be the same"); - - if (!currentEntry || ([currentEntry calculatedBitRate] == 0.0 || currentlyPlayingEntry.dataSource.length <= 0)) - { - return; - } - - SInt64 seekByteOffset = currentEntry->audioDataOffset + (requestedSeekTime / self.duration) * (currentlyReadingEntry.audioDataLengthInBytes); - - if (seekByteOffset > currentEntry.dataSource.length - (2 * currentEntry->packetBufferSize)) - { - seekByteOffset = currentEntry.dataSource.length - 2 * currentEntry->packetBufferSize; - } - - OSSpinLockLock(¤tEntry->spinLock); - currentEntry->seekTime = requestedSeekTime; - OSSpinLockUnlock(¤tEntry->spinLock); - - double calculatedBitRate = [currentEntry calculatedBitRate]; - - if (currentEntry->packetDuration > 0 && calculatedBitRate > 0) - { - UInt32 ioFlags = 0; - SInt64 packetAlignedByteOffset; - SInt64 seekPacket = floor(requestedSeekTime / currentEntry->packetDuration); - - error = AudioFileStreamSeek(audioFileStream, seekPacket, &packetAlignedByteOffset, &ioFlags); - - if (!error && !(ioFlags & kAudioFileStreamSeekFlag_OffsetIsEstimated)) - { - double delta = ((seekByteOffset - (SInt64)currentEntry->audioDataOffset) - packetAlignedByteOffset) / calculatedBitRate * 8; - - OSSpinLockLock(¤tEntry->spinLock); - currentEntry->seekTime -= delta; - OSSpinLockUnlock(¤tEntry->spinLock); - - seekByteOffset = packetAlignedByteOffset + currentEntry->audioDataOffset; - } - } - - if (audioConverterRef) - { - AudioConverterReset(audioConverterRef); - } - - [currentEntry reset]; - [currentEntry.dataSource seekToOffset:seekByteOffset]; - - self->waitingForDataAfterSeekFrameCount = 0; - - self.internalState = STKAudioPlayerInternalStateWaitingForDataAfterSeek; - - if (audioGraph) - { - [self resetPcmBuffers]; - } -} - --(void) dataSourceDataAvailable:(STKDataSource*)dataSourceIn -{ - OSStatus error; - - if (currentlyReadingEntry.dataSource != dataSourceIn) - { - return; - } - - if (!currentlyReadingEntry.dataSource.hasBytesAvailable) - { - return; - } - - int read = [currentlyReadingEntry.dataSource readIntoBuffer:readBuffer withSize:readBufferSize]; - - if (read == 0) - { - return; - } - - if (audioFileStream == 0) - { - error = AudioFileStreamOpen((__bridge void*)self, AudioFileStreamPropertyListenerProc, AudioFileStreamPacketsProc, dataSourceIn.audioFileTypeHint, &audioFileStream); - - if (error) - { - [self unexpectedError:STKAudioPlayerErrorAudioSystemError]; - - return; - } - } - - if (read < 0) - { - // iOS will shutdown network connections if the app is backgrounded (i.e. device is locked when player is paused) - // We try to reopen -- should probably add a back-off protocol in the future - - SInt64 position = currentlyReadingEntry.dataSource.position; - - [currentlyReadingEntry.dataSource seekToOffset:position]; - - return; - } - - int flags = 0; - - if (discontinuous) - { - flags = kAudioFileStreamParseFlag_Discontinuity; - } - - if (audioFileStream) - { - error = AudioFileStreamParseBytes(audioFileStream, read, readBuffer, flags); - - if (error) - { - if (dataSourceIn == currentlyPlayingEntry.dataSource) - { - [self unexpectedError:STKAudioPlayerErrorStreamParseBytesFailed]; - } - - return; - } - - OSSpinLockLock(¤tEntryReferencesLock); - - if (currentlyReadingEntry == nil) - { - [dataSourceIn unregisterForEvents]; - [dataSourceIn close]; - } - - OSSpinLockUnlock(¤tEntryReferencesLock); - } -} - --(void) dataSourceErrorOccured:(STKDataSource*)dataSourceIn -{ - if (currentlyReadingEntry.dataSource != dataSourceIn) - { - return; - } - - [self unexpectedError:STKAudioPlayerErrorDataNotFound]; -} - --(void) dataSourceEof:(STKDataSource*)dataSourceIn -{ - if (currentlyReadingEntry == nil || currentlyReadingEntry.dataSource != dataSourceIn) - { - dataSourceIn.delegate = nil; - [dataSourceIn unregisterForEvents]; - [dataSourceIn close]; - - return; - } - - if (disposeWasRequested) - { - return; - } - - NSObject* queueItemId = currentlyReadingEntry.queueItemId; - - [self dispatchSyncOnMainThread:^ - { - [self.delegate audioPlayer:self didFinishBufferingSourceWithQueueItemId:queueItemId]; - }]; - - pthread_mutex_lock(&playerMutex); - - if (currentlyReadingEntry == nil) - { - dataSourceIn.delegate = nil; - [dataSourceIn unregisterForEvents]; - [dataSourceIn close]; - - return; - } - - OSSpinLockLock(¤tlyReadingEntry->spinLock); - currentlyReadingEntry->lastFrameQueued = currentlyReadingEntry->framesQueued; - OSSpinLockUnlock(¤tlyReadingEntry->spinLock); - - currentlyReadingEntry.dataSource.delegate = nil; - [currentlyReadingEntry.dataSource unregisterForEvents]; - [currentlyReadingEntry.dataSource close]; - - OSSpinLockLock(¤tEntryReferencesLock); - currentlyReadingEntry = nil; - OSSpinLockUnlock(¤tEntryReferencesLock); - - pthread_mutex_unlock(&playerMutex); - - [self processRunloop]; -} - --(void) pause -{ - pthread_mutex_lock(&playerMutex); - { - OSStatus error; - - if (self.internalState != STKAudioPlayerInternalStatePaused && (self.internalState & STKAudioPlayerInternalStateRunning)) - { - self.stateBeforePaused = self.internalState; - self.internalState = STKAudioPlayerInternalStatePaused; - - if (audioGraph) - { - error = AUGraphStop(audioGraph); - - if (error) - { - [self unexpectedError:STKAudioPlayerErrorAudioSystemError]; - - pthread_mutex_unlock(&playerMutex); - - return; - } - } - - [self wakeupPlaybackThread]; - } - } - pthread_mutex_unlock(&playerMutex); -} - --(void) resume -{ - pthread_mutex_lock(&playerMutex); - { - OSStatus error; - - if (self.internalState == STKAudioPlayerInternalStatePaused) - { - self.internalState = self.stateBeforePaused; - - if (seekToTimeWasRequested) - { - [self resetPcmBuffers]; - } - - if (audioGraph != nil) - { - error = AUGraphStart(audioGraph); - - if (error) - { - [self unexpectedError:STKAudioPlayerErrorAudioSystemError]; - - pthread_mutex_unlock(&playerMutex); - - return; - } - } - - [self wakeupPlaybackThread]; - } - } - pthread_mutex_unlock(&playerMutex); -} - --(void) resetPcmBuffers -{ - OSSpinLockLock(&pcmBufferSpinLock); - - self->pcmBufferFrameStartIndex = 0; - self->pcmBufferUsedFrameCount = 0; - self->peakPowerDb[0] = STK_DBMIN; - self->peakPowerDb[1] = STK_DBMIN; - self->averagePowerDb[0] = STK_DBMIN; - self->averagePowerDb[1] = STK_DBMIN; - - OSSpinLockUnlock(&pcmBufferSpinLock); -} - --(void) stop -{ - pthread_mutex_lock(&playerMutex); - { - if (self.internalState == STKAudioPlayerInternalStateStopped) - { - pthread_mutex_unlock(&playerMutex); - - return; - } - - [self stopAudioUnitWithReason:STKAudioPlayerStopReasonUserAction]; - - [self resetPcmBuffers]; - - [self invokeOnPlaybackThread:^ - { - pthread_mutex_lock(&playerMutex); - { - currentlyReadingEntry.dataSource.delegate = nil; - [currentlyReadingEntry.dataSource unregisterForEvents]; - [currentlyReadingEntry.dataSource close]; - - if (currentlyPlayingEntry) - { - [self processFinishPlayingIfAnyAndPlayingNext:currentlyPlayingEntry withNext:nil]; - } - - [self clearQueue]; - - OSSpinLockLock(¤tEntryReferencesLock); - currentlyPlayingEntry = nil; - currentlyReadingEntry = nil; - seekToTimeWasRequested = NO; - OSSpinLockUnlock(¤tEntryReferencesLock); - } - pthread_mutex_unlock(&playerMutex); - }]; - - [self wakeupPlaybackThread]; - } - pthread_mutex_unlock(&playerMutex); -} - --(void) stopThread -{ - BOOL wait = NO; - - NSRunLoop* runLoop = playbackThreadRunLoop; - - if (runLoop != nil) - { - wait = YES; - - [self invokeOnPlaybackThread:^ - { - disposeWasRequested = YES; - - CFRunLoopStop(CFRunLoopGetCurrent()); - }]; - - pthread_mutex_lock(&playerMutex); - disposeWasRequested = YES; - pthread_cond_signal(&playerThreadReadyCondition); - pthread_mutex_unlock(&playerMutex); - - pthread_mutex_lock(&mainThreadSyncCallMutex); - disposeWasRequested = YES; - pthread_cond_signal(&mainThreadSyncCallReadyCondition); - pthread_mutex_unlock(&mainThreadSyncCallMutex); - } - - if (wait) - { - [threadFinishedCondLock lockWhenCondition:1]; - [threadFinishedCondLock unlockWithCondition:0]; - } - - [self destroyAudioResources]; - - runLoop = nil; - playbackThread = nil; - playbackThreadRunLoop = nil; -} - --(BOOL) muted -{ - return self->muted; -} - --(void) setMuted:(BOOL)value -{ - self->muted = value; -} - --(void) mute -{ - self.muted = YES; -} - --(void) unmute -{ - self.muted = NO; -} - --(void) dispose -{ - [self stop]; - [self stopThread]; -} - --(NSObject*) currentlyPlayingQueueItemId -{ - OSSpinLockLock(¤tEntryReferencesLock); - - STKQueueEntry* entry = currentlyPlayingEntry; - - if (entry == nil) - { - OSSpinLockUnlock(¤tEntryReferencesLock); - - return nil; - } - - NSObject* retval = entry.queueItemId; - - OSSpinLockUnlock(¤tEntryReferencesLock); - - return retval; -} - -static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* classDesc) -{ -#if TARGET_OS_IPHONE - UInt32 size; - - if (AudioFormatGetPropertyInfo(kAudioFormatProperty_Decoders, sizeof(formatId), &formatId, &size) != 0) - { - return NO; - } - - UInt32 decoderCount = size / sizeof(AudioClassDescription); - AudioClassDescription encoderDescriptions[decoderCount]; - - if (AudioFormatGetProperty(kAudioFormatProperty_Decoders, sizeof(formatId), &formatId, &size, encoderDescriptions) != 0) - { - return NO; - } - - for (UInt32 i = 0; i < decoderCount; ++i) - { - if (encoderDescriptions[i].mManufacturer == kAppleHardwareAudioCodecManufacturer) - { - *classDesc = encoderDescriptions[i]; - - return YES; - } - } -#endif - - return NO; -} - --(void) destroyAudioConverter -{ - if (audioConverterRef) - { - AudioConverterDispose(audioConverterRef); - - audioConverterRef = nil; - } -} - --(void) createAudioConverter:(AudioStreamBasicDescription*)asbd -{ - OSStatus status; - Boolean writable; - UInt32 cookieSize; - - if (memcmp(asbd, &audioConverterAudioStreamBasicDescription, sizeof(AudioStreamBasicDescription)) == 0) - { - AudioConverterReset(audioConverterRef); - - return; - } - - [self destroyAudioConverter]; - - AudioClassDescription classDesc; - - if (GetHardwareCodecClassDesc(asbd->mFormatID, &classDesc)) - { - AudioConverterNewSpecific(asbd, &canonicalAudioStreamBasicDescription, 1, &classDesc, &audioConverterRef); - } - - if (!audioConverterRef) - { - status = AudioConverterNew(asbd, &canonicalAudioStreamBasicDescription, &audioConverterRef); - - if (status) - { - [self unexpectedError:STKAudioPlayerErrorAudioSystemError]; - - return; - } - } - - audioConverterAudioStreamBasicDescription = *asbd; - - status = AudioFileStreamGetPropertyInfo(audioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, &writable); - - if (!status) - { - void* cookieData = alloca(cookieSize); - - status = AudioFileStreamGetProperty(audioFileStream, kAudioFileStreamProperty_MagicCookieData, &cookieSize, cookieData); - - if (status) - { - return; - } - - status = AudioConverterSetProperty(audioConverterRef, kAudioConverterDecompressionMagicCookie, cookieSize, &cookieData); - - if (status) - { - return; - } - } -} - --(void) createOutputUnit -{ - OSStatus status; - - CHECK_STATUS_AND_RETURN(AUGraphAddNode(audioGraph, &outputUnitDescription, &outputNode)); - CHECK_STATUS_AND_RETURN(AUGraphNodeInfo(audioGraph, outputNode, &outputUnitDescription, &outputUnit)); - -#if TARGET_OS_IPHONE - UInt32 flag = 1; - - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(outputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &flag, sizeof(flag))); - - flag = 0; - - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(outputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag))); -#endif - - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription))); -} - --(void) createMixerUnit -{ - OSStatus status; - - if (!self.options.enableVolumeMixer) - { - return; - } - - CHECK_STATUS_AND_RETURN(AUGraphAddNode(audioGraph, &mixerDescription, &mixerNode)); - CHECK_STATUS_AND_RETURN(AUGraphNodeInfo(audioGraph, mixerNode, &mixerDescription, &mixerUnit)); - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFramesPerSlice, sizeof(maxFramesPerSlice))); - - UInt32 busCount = 1; - - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &busCount, sizeof(busCount))); - - Float64 graphSampleRate = 44100.0; - - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &graphSampleRate, sizeof(graphSampleRate))); - CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(mixerUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Input, 0, 1.0, 0)); -} - --(void) createEqUnit -{ -#if TARGET_OS_MAC && MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9 - return; -#else - OSStatus status; - - if (self->options.equalizerBandFrequencies[0] == 0) - { - return; - } - - CHECK_STATUS_AND_RETURN(AUGraphAddNode(audioGraph, &nbandUnitDescription, &eqNode)); - CHECK_STATUS_AND_RETURN(AUGraphNodeInfo(audioGraph, eqNode, NULL, &eqUnit)); - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(eqUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFramesPerSlice, sizeof(maxFramesPerSlice))); - - while (self->options.equalizerBandFrequencies[eqBandCount] != 0) - { - eqBandCount++; - } - - CHECK_STATUS_AND_RETURN(AudioUnitSetProperty(eqUnit, kAUNBandEQProperty_NumberOfBands, kAudioUnitScope_Global, 0, &eqBandCount, sizeof(eqBandCount))); - - for (int i = 0; i < eqBandCount; i++) - { - CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(eqUnit, kAUNBandEQParam_Frequency + i, kAudioUnitScope_Global, 0, (AudioUnitParameterValue)self->options.equalizerBandFrequencies[i], 0)); - } - - for (int i = 0; i < eqBandCount; i++) - { - CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(eqUnit, kAUNBandEQParam_BypassBand + i, kAudioUnitScope_Global, 0, (AudioUnitParameterValue)0, 0)); - } -#endif -} - --(void) setGain:(float)gain forEqualizerBand:(int)bandIndex -{ - if (!eqUnit) - { - return; - } - - OSStatus status; - - CHECK_STATUS_AND_RETURN(AudioUnitSetParameter(eqUnit, kAUNBandEQParam_Gain + bandIndex, kAudioUnitScope_Global, 0, gain, 0)); -} - --(AUNode) createConverterNode:(AudioStreamBasicDescription)srcFormat desFormat:(AudioStreamBasicDescription)desFormat -{ - OSStatus status; - AUNode convertNode; - AudioComponentInstance convertUnit; - - CHECK_STATUS_AND_RETURN_VALUE(AUGraphAddNode(audioGraph, &convertUnitDescription, &convertNode), 0); - CHECK_STATUS_AND_RETURN_VALUE(AUGraphNodeInfo(audioGraph, convertNode, &mixerDescription, &convertUnit), 0); - CHECK_STATUS_AND_RETURN_VALUE(AudioUnitSetProperty(convertUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(srcFormat)), 0); - CHECK_STATUS_AND_RETURN_VALUE(AudioUnitSetProperty(convertUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &desFormat, sizeof(desFormat)), 0); - CHECK_STATUS_AND_RETURN_VALUE(AudioUnitSetProperty(convertUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFramesPerSlice, sizeof(maxFramesPerSlice)), 0); - - [converterNodes addObject:@(convertNode)]; - - return convertNode; -} - --(void) connectNodes:(AUNode)srcNode desNode:(AUNode)desNode srcUnit:(AudioComponentInstance)srcUnit desUnit:(AudioComponentInstance)desUnit -{ - OSStatus status; - BOOL addConverter = NO; - AudioStreamBasicDescription srcFormat, desFormat; - UInt32 size = sizeof(AudioStreamBasicDescription); - - CHECK_STATUS_AND_RETURN(AudioUnitGetProperty(srcUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &srcFormat, &size)); - CHECK_STATUS_AND_RETURN(AudioUnitGetProperty(desUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &desFormat, &size)); - - addConverter = memcmp(&srcFormat, &desFormat, sizeof(srcFormat)) != 0; - - if (addConverter) - { - status = AudioUnitSetProperty(desUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(srcFormat)); - - addConverter = status != 0; - } - - if (addConverter) - { - AUNode convertNode = [self createConverterNode:srcFormat desFormat:desFormat]; - - CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, srcNode, 0, convertNode, 0)); - CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, convertNode, 0, desNode, 0)); - } - else - { - CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, srcNode, 0, desNode, 0)); - } -} - --(void) setOutputCallbackForFirstNode:(AUNode)firstNode firstUnit:(AudioComponentInstance)firstUnit -{ - OSStatus status; - AURenderCallbackStruct callbackStruct; - - callbackStruct.inputProc = OutputRenderCallback; - callbackStruct.inputProcRefCon = (__bridge void*)self; - - status = AudioUnitSetProperty(firstUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &canonicalAudioStreamBasicDescription, sizeof(canonicalAudioStreamBasicDescription)); - - if (status) - { - AudioStreamBasicDescription format; - UInt32 size = sizeof(format); - - CHECK_STATUS_AND_RETURN(AudioUnitGetProperty(firstUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &format, &size)); - - AUNode converterNode = [self createConverterNode:canonicalAudioStreamBasicDescription desFormat:format]; - - CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, converterNode, 0, &callbackStruct)); - - CHECK_STATUS_AND_RETURN(AUGraphConnectNodeInput(audioGraph, converterNode, 0, firstNode, 0)); - } - else - { - CHECK_STATUS_AND_RETURN(AUGraphSetNodeInputCallback(audioGraph, firstNode, 0, &callbackStruct)); - } -} - --(void) createAudioGraph -{ - OSStatus status; - converterNodes = [[NSMutableArray alloc] init]; - - CHECK_STATUS_AND_RETURN(NewAUGraph(&audioGraph)); - CHECK_STATUS_AND_RETURN(AUGraphOpen(audioGraph)); - - [self createEqUnit]; - [self createMixerUnit]; - [self createOutputUnit]; - - [self connectGraph]; - - CHECK_STATUS_AND_RETURN(AUGraphInitialize(audioGraph)); - - self.volume = self->volume; -} - --(void) connectGraph -{ - OSStatus status; - NSMutableArray* nodes = [[NSMutableArray alloc] init]; - NSMutableArray* units = [[NSMutableArray alloc] init]; - - AUGraphClearConnections(audioGraph); - - for (NSNumber* converterNode in converterNodes) - { - CHECK_STATUS_AND_REPORT(AUGraphRemoveNode(audioGraph, (AUNode)converterNode.intValue)); - } - - [converterNodes removeAllObjects]; - - if (eqNode) - { - if (self->equalizerEnabled) - { - [nodes addObject:@(eqNode)]; - [units addObject:[NSValue valueWithPointer:eqUnit]]; - - self->equalizerOn = YES; - } - else - { - self->equalizerOn = NO; - } - } - else - { - self->equalizerOn = NO; - } - - if (mixerNode) - { - [nodes addObject:@(mixerNode)]; - [units addObject:[NSValue valueWithPointer:mixerUnit]]; - } - - if (outputNode) - { - [nodes addObject:@(outputNode)]; - [units addObject:[NSValue valueWithPointer:outputUnit]]; - } - - [self setOutputCallbackForFirstNode:(AUNode)[[nodes objectAtIndex:0] intValue] firstUnit:(AudioComponentInstance)[[units objectAtIndex:0] pointerValue]]; - - for (int i = 0; i < nodes.count - 1; i++) - { - AUNode srcNode = [[nodes objectAtIndex:i] intValue]; - AUNode desNode = [[nodes objectAtIndex:i + 1] intValue]; - AudioComponentInstance srcUnit = (AudioComponentInstance)[[units objectAtIndex:i] pointerValue]; - AudioComponentInstance desUnit = (AudioComponentInstance)[[units objectAtIndex:i + 1] pointerValue]; - - [self connectNodes:srcNode desNode:desNode srcUnit:srcUnit desUnit:desUnit]; - } -} - --(BOOL) audioGraphIsRunning -{ - OSStatus status; - Boolean isRunning; - - status = AUGraphIsRunning(audioGraph, &isRunning); - - if (status) - { - return NO; - } - - return isRunning; -} - --(BOOL) startAudioGraph -{ - OSStatus status; - - [self resetPcmBuffers]; - - if ([self audioGraphIsRunning]) - { - return NO; - } - - status = AUGraphStart(audioGraph); - - if (status) - { - [self unexpectedError:STKAudioPlayerErrorAudioSystemError]; - - return NO; - } - - [self stopSystemBackgroundTask]; - - return YES; -} - --(void) stopAudioUnitWithReason:(STKAudioPlayerStopReason)stopReasonIn -{ - OSStatus status; - - if (!audioGraph) - { - stopReason = stopReasonIn; - self.internalState = STKAudioPlayerInternalStateStopped; - - return; - } - - Boolean isRunning; - - status = AUGraphIsRunning(audioGraph, &isRunning); - - if (status) - { - [self unexpectedError:STKAudioPlayerErrorAudioSystemError]; - } - else if (!isRunning) - { - return; - } - - status = AUGraphStop(audioGraph); - - if (status) - { - [self unexpectedError:STKAudioPlayerErrorAudioSystemError]; - } - - [self resetPcmBuffers]; - - stopReason = stopReasonIn; - self.internalState = STKAudioPlayerInternalStateStopped; -} - -typedef struct -{ - BOOL done; - UInt32 numberOfPackets; - AudioBuffer audioBuffer; - AudioStreamPacketDescription* packetDescriptions; -} -AudioConvertInfo; - -OSStatus AudioConverterCallback(AudioConverterRef inAudioConverter, UInt32* ioNumberDataPackets, AudioBufferList* ioData, AudioStreamPacketDescription **outDataPacketDescription, void* inUserData) -{ - AudioConvertInfo* convertInfo = (AudioConvertInfo*)inUserData; - - if (convertInfo->done) - { - ioNumberDataPackets = 0; - - return 100; - } - - ioData->mNumberBuffers = 1; - ioData->mBuffers[0] = convertInfo->audioBuffer; - - if (outDataPacketDescription) - { - *outDataPacketDescription = convertInfo->packetDescriptions; - } - - *ioNumberDataPackets = convertInfo->numberOfPackets; - convertInfo->done = YES; - - return 0; -} - --(void) handleAudioPackets:(const void*)inputData numberBytes:(UInt32)numberBytes numberPackets:(UInt32)numberPackets packetDescriptions:(AudioStreamPacketDescription*)packetDescriptionsIn -{ - if (currentlyReadingEntry == nil) - { - return; - } - - if (!currentlyReadingEntry->parsedHeader) - { - return; - } - - if (disposeWasRequested) - { - return; - } - - if (audioConverterRef == nil) - { - return; - } - - if ((seekToTimeWasRequested && [currentlyPlayingEntry calculatedBitRate] > 0.0)) - { - [self wakeupPlaybackThread]; - - return; - } - - discontinuous = NO; - - OSStatus status; - - AudioConvertInfo convertInfo; - - convertInfo.done = NO; - convertInfo.numberOfPackets = numberPackets; - convertInfo.packetDescriptions = packetDescriptionsIn; - convertInfo.audioBuffer.mData = (void *)inputData; - convertInfo.audioBuffer.mDataByteSize = numberBytes; - convertInfo.audioBuffer.mNumberChannels = audioConverterAudioStreamBasicDescription.mChannelsPerFrame; - - if (packetDescriptionsIn && currentlyReadingEntry->processedPacketsCount < STK_MAX_COMPRESSED_PACKETS_FOR_BITRATE_CALCULATION) - { - int count = MIN(numberPackets, STK_MAX_COMPRESSED_PACKETS_FOR_BITRATE_CALCULATION - currentlyReadingEntry->processedPacketsCount); - - for (int i = 0; i < count; i++) - { - SInt64 packetSize; - - packetSize = packetDescriptionsIn[i].mDataByteSize; - - OSAtomicAdd32((int32_t)packetSize, ¤tlyReadingEntry->processedPacketsSizeTotal); - OSAtomicIncrement32(¤tlyReadingEntry->processedPacketsCount); - } - } - - while (true) - { - OSSpinLockLock(&pcmBufferSpinLock); - UInt32 used = pcmBufferUsedFrameCount; - UInt32 start = pcmBufferFrameStartIndex; - UInt32 end = (pcmBufferFrameStartIndex + pcmBufferUsedFrameCount) % pcmBufferTotalFrameCount; - UInt32 framesLeftInsideBuffer = pcmBufferTotalFrameCount - used; - OSSpinLockUnlock(&pcmBufferSpinLock); - - if (framesLeftInsideBuffer == 0) - { - pthread_mutex_lock(&playerMutex); - - while (true) - { - OSSpinLockLock(&pcmBufferSpinLock); - used = pcmBufferUsedFrameCount; - start = pcmBufferFrameStartIndex; - end = (pcmBufferFrameStartIndex + pcmBufferUsedFrameCount) % pcmBufferTotalFrameCount; - framesLeftInsideBuffer = pcmBufferTotalFrameCount - used; - OSSpinLockUnlock(&pcmBufferSpinLock); - - if (framesLeftInsideBuffer > 0) - { - break; - } - - if (disposeWasRequested - || self.internalState == STKAudioPlayerInternalStateStopped - || self.internalState == STKAudioPlayerInternalStateDisposed - || self.internalState == STKAudioPlayerInternalStatePendingNext) - { - pthread_mutex_unlock(&playerMutex); - - return; - } - - if (seekToTimeWasRequested && [currentlyPlayingEntry calculatedBitRate] > 0.0) - { - pthread_mutex_unlock(&playerMutex); - - [self wakeupPlaybackThread]; - - return; - } - - waiting = YES; - - pthread_cond_wait(&playerThreadReadyCondition, &playerMutex); - - waiting = NO; - } - - pthread_mutex_unlock(&playerMutex); - } - - AudioBuffer* localPcmAudioBuffer; - AudioBufferList localPcmBufferList; - - localPcmBufferList.mNumberBuffers = 1; - localPcmAudioBuffer = &localPcmBufferList.mBuffers[0]; - - if (end >= start) - { - UInt32 framesAdded = 0; - UInt32 framesToDecode = pcmBufferTotalFrameCount - end; - - localPcmAudioBuffer->mData = pcmAudioBuffer->mData + (end * pcmBufferFrameSizeInBytes); - localPcmAudioBuffer->mDataByteSize = framesToDecode * pcmBufferFrameSizeInBytes; - localPcmAudioBuffer->mNumberChannels = pcmAudioBuffer->mNumberChannels; - - status = AudioConverterFillComplexBuffer(audioConverterRef, AudioConverterCallback, (void*)&convertInfo, &framesToDecode, &localPcmBufferList, NULL); - - framesAdded = framesToDecode; - - if (status == 100) - { - OSSpinLockLock(&pcmBufferSpinLock); - pcmBufferUsedFrameCount += framesAdded; - OSSpinLockUnlock(&pcmBufferSpinLock); - - OSSpinLockLock(¤tlyReadingEntry->spinLock); - currentlyReadingEntry->framesQueued += framesAdded; - OSSpinLockUnlock(¤tlyReadingEntry->spinLock); - - return; - } - else if (status != 0) - { - [self unexpectedError:STKAudioPlayerErrorCodecError]; - - return; - } - - framesToDecode = start; - - if (framesToDecode == 0) - { - OSSpinLockLock(&pcmBufferSpinLock); - pcmBufferUsedFrameCount += framesAdded; - OSSpinLockUnlock(&pcmBufferSpinLock); - - OSSpinLockLock(¤tlyReadingEntry->spinLock); - currentlyReadingEntry->framesQueued += framesAdded; - OSSpinLockUnlock(¤tlyReadingEntry->spinLock); - - continue; - } - - localPcmAudioBuffer->mData = pcmAudioBuffer->mData; - localPcmAudioBuffer->mDataByteSize = framesToDecode * pcmBufferFrameSizeInBytes; - localPcmAudioBuffer->mNumberChannels = pcmAudioBuffer->mNumberChannels; - - status = AudioConverterFillComplexBuffer(audioConverterRef, AudioConverterCallback, (void*)&convertInfo, &framesToDecode, &localPcmBufferList, NULL); - - framesAdded += framesToDecode; - - if (status == 100) - { - OSSpinLockLock(&pcmBufferSpinLock); - pcmBufferUsedFrameCount += framesAdded; - OSSpinLockUnlock(&pcmBufferSpinLock); - - OSSpinLockLock(¤tlyReadingEntry->spinLock); - currentlyReadingEntry->framesQueued += framesAdded; - OSSpinLockUnlock(¤tlyReadingEntry->spinLock); - - return; - } - else if (status == 0) - { - OSSpinLockLock(&pcmBufferSpinLock); - pcmBufferUsedFrameCount += framesAdded; - OSSpinLockUnlock(&pcmBufferSpinLock); - - OSSpinLockLock(¤tlyReadingEntry->spinLock); - currentlyReadingEntry->framesQueued += framesAdded; - OSSpinLockUnlock(¤tlyReadingEntry->spinLock); - - continue; - } - else if (status != 0) - { - [self unexpectedError:STKAudioPlayerErrorCodecError]; - - return; - } - } - else - { - UInt32 framesAdded = 0; - UInt32 framesToDecode = start - end; - - localPcmAudioBuffer->mData = pcmAudioBuffer->mData + (end * pcmBufferFrameSizeInBytes); - localPcmAudioBuffer->mDataByteSize = framesToDecode * pcmBufferFrameSizeInBytes; - localPcmAudioBuffer->mNumberChannels = pcmAudioBuffer->mNumberChannels; - - status = AudioConverterFillComplexBuffer(audioConverterRef, AudioConverterCallback, (void*)&convertInfo, &framesToDecode, &localPcmBufferList, NULL); - - framesAdded = framesToDecode; - - if (status == 100) - { - OSSpinLockLock(&pcmBufferSpinLock); - pcmBufferUsedFrameCount += framesAdded; - OSSpinLockUnlock(&pcmBufferSpinLock); - - OSSpinLockLock(¤tlyReadingEntry->spinLock); - currentlyReadingEntry->framesQueued += framesAdded; - OSSpinLockUnlock(¤tlyReadingEntry->spinLock); - - return; - } - else if (status == 0) - { - OSSpinLockLock(&pcmBufferSpinLock); - pcmBufferUsedFrameCount += framesAdded; - OSSpinLockUnlock(&pcmBufferSpinLock); - - OSSpinLockLock(¤tlyReadingEntry->spinLock); - currentlyReadingEntry->framesQueued += framesAdded; - OSSpinLockUnlock(¤tlyReadingEntry->spinLock); - - continue; - } - else if (status != 0) - { - [self unexpectedError:STKAudioPlayerErrorCodecError]; - - return; - } - } - } -} - -static OSStatus OutputRenderCallback(void* inRefCon, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData) -{ - STKAudioPlayer* audioPlayer = (__bridge STKAudioPlayer*)inRefCon; - - OSSpinLockLock(&audioPlayer->currentEntryReferencesLock); - STKQueueEntry* entry = audioPlayer->currentlyPlayingEntry; - STKQueueEntry* currentlyReadingEntry = audioPlayer->currentlyReadingEntry; - OSSpinLockUnlock(&audioPlayer->currentEntryReferencesLock); - - OSSpinLockLock(&audioPlayer->pcmBufferSpinLock); - - BOOL waitForBuffer = NO; - BOOL muted = audioPlayer->muted; - AudioBuffer* audioBuffer = audioPlayer->pcmAudioBuffer; - UInt32 frameSizeInBytes = audioPlayer->pcmBufferFrameSizeInBytes; - UInt32 used = audioPlayer->pcmBufferUsedFrameCount; - UInt32 start = audioPlayer->pcmBufferFrameStartIndex; - STKAudioPlayerInternalState state = audioPlayer->internalState; - UInt32 end = (audioPlayer->pcmBufferFrameStartIndex + audioPlayer->pcmBufferUsedFrameCount) % audioPlayer->pcmBufferTotalFrameCount; - BOOL signal = audioPlayer->waiting && used < audioPlayer->pcmBufferTotalFrameCount / 2; - NSArray* frameFilters = audioPlayer->frameFilters; - - if (entry) - { - if (state == STKAudioPlayerInternalStateWaitingForData) - { - SInt64 framesRequiredToStartPlaying = audioPlayer->framesRequiredToStartPlaying; - - if (entry->lastFrameQueued >= 0) - { - framesRequiredToStartPlaying = MIN(framesRequiredToStartPlaying, entry->lastFrameQueued); - } - - if (entry && currentlyReadingEntry == entry - && entry->framesQueued < framesRequiredToStartPlaying) - { - waitForBuffer = YES; - } - } - else if (state == STKAudioPlayerInternalStateRebuffering) - { - SInt64 framesRequiredToStartPlaying = audioPlayer->framesRequiredToPlayAfterRebuffering; - - if (entry->lastFrameQueued >= 0) - { - framesRequiredToStartPlaying = MIN(framesRequiredToStartPlaying, entry->lastFrameQueued - entry->framesQueued); - } - - if (used < framesRequiredToStartPlaying) - { - waitForBuffer = YES; - } - } - else if (state == STKAudioPlayerInternalStateWaitingForDataAfterSeek) - { - SInt64 framesRequiredToStartPlaying = 1024; - - if (entry->lastFrameQueued >= 0) - { - framesRequiredToStartPlaying = MIN(framesRequiredToStartPlaying, entry->lastFrameQueued - entry->framesQueued); - } - - if (used < framesRequiredToStartPlaying) - { - waitForBuffer = YES; - } - } - } - - OSSpinLockUnlock(&audioPlayer->pcmBufferSpinLock); - - UInt32 totalFramesCopied = 0; - - if (used > 0 && !waitForBuffer && entry != nil && ((state & STKAudioPlayerInternalStateRunning) && state != STKAudioPlayerInternalStatePaused)) - { - if (state == STKAudioPlayerInternalStateWaitingForData) - { - // Starting - } - else if (state == STKAudioPlayerInternalStateRebuffering) - { - // Resuming from buffering - } - - if (end > start) - { - UInt32 framesToCopy = MIN(inNumberFrames, used); - - ioData->mBuffers[0].mNumberChannels = 2; - ioData->mBuffers[0].mDataByteSize = frameSizeInBytes * framesToCopy; - - if (muted) - { - memset(ioData->mBuffers[0].mData, 0, ioData->mBuffers[0].mDataByteSize); - } - else - { - memcpy(ioData->mBuffers[0].mData, audioBuffer->mData + (start * frameSizeInBytes), ioData->mBuffers[0].mDataByteSize); - } - - totalFramesCopied = framesToCopy; - - OSSpinLockLock(&audioPlayer->pcmBufferSpinLock); - audioPlayer->pcmBufferFrameStartIndex = (audioPlayer->pcmBufferFrameStartIndex + totalFramesCopied) % audioPlayer->pcmBufferTotalFrameCount; - audioPlayer->pcmBufferUsedFrameCount -= totalFramesCopied; - OSSpinLockUnlock(&audioPlayer->pcmBufferSpinLock); - } - else - { - UInt32 framesToCopy = MIN(inNumberFrames, audioPlayer->pcmBufferTotalFrameCount - start); - - ioData->mBuffers[0].mNumberChannels = 2; - ioData->mBuffers[0].mDataByteSize = frameSizeInBytes * framesToCopy; - - if (muted) - { - memset(ioData->mBuffers[0].mData, 0, ioData->mBuffers[0].mDataByteSize); - } - else - { - memcpy(ioData->mBuffers[0].mData, audioBuffer->mData + (start * frameSizeInBytes), ioData->mBuffers[0].mDataByteSize); - } - - UInt32 moreFramesToCopy = 0; - UInt32 delta = inNumberFrames - framesToCopy; - - if (delta > 0) - { - moreFramesToCopy = MIN(delta, end); - - ioData->mBuffers[0].mNumberChannels = 2; - ioData->mBuffers[0].mDataByteSize += frameSizeInBytes * moreFramesToCopy; - - if (muted) - { - memset(ioData->mBuffers[0].mData + (framesToCopy * frameSizeInBytes), 0, frameSizeInBytes * moreFramesToCopy); - } - else - { - memcpy(ioData->mBuffers[0].mData + (framesToCopy * frameSizeInBytes), audioBuffer->mData, frameSizeInBytes * moreFramesToCopy); - } - } - - totalFramesCopied = framesToCopy + moreFramesToCopy; - - OSSpinLockLock(&audioPlayer->pcmBufferSpinLock); - audioPlayer->pcmBufferFrameStartIndex = (audioPlayer->pcmBufferFrameStartIndex + totalFramesCopied) % audioPlayer->pcmBufferTotalFrameCount; - audioPlayer->pcmBufferUsedFrameCount -= totalFramesCopied; - OSSpinLockUnlock(&audioPlayer->pcmBufferSpinLock); - } - - [audioPlayer setInternalState:STKAudioPlayerInternalStatePlaying ifInState:^BOOL(STKAudioPlayerInternalState state) - { - return (state & STKAudioPlayerInternalStateRunning) && state != STKAudioPlayerInternalStatePaused; - }]; - } - - if (totalFramesCopied < inNumberFrames) - { - UInt32 delta = inNumberFrames - totalFramesCopied; - - memset(ioData->mBuffers[0].mData + (totalFramesCopied * frameSizeInBytes), 0, delta * frameSizeInBytes); - - if (!(entry == nil || state == STKAudioPlayerInternalStateWaitingForDataAfterSeek || state == STKAudioPlayerInternalStateWaitingForData || state == STKAudioPlayerInternalStateRebuffering)) - { - // Buffering - - [audioPlayer setInternalState:STKAudioPlayerInternalStateRebuffering ifInState:^BOOL(STKAudioPlayerInternalState state) - { - return (state & STKAudioPlayerInternalStateRunning) && state != STKAudioPlayerInternalStatePaused; - }]; - } - else if (state == STKAudioPlayerInternalStateWaitingForDataAfterSeek) - { - if (totalFramesCopied == 0) - { - OSAtomicAdd32(inNumberFrames - totalFramesCopied, &audioPlayer->waitingForDataAfterSeekFrameCount); - - if (audioPlayer->waitingForDataAfterSeekFrameCount > audioPlayer->framesRequiredBeforeWaitingForDataAfterSeekBecomesPlaying) - { - [audioPlayer setInternalState:STKAudioPlayerInternalStatePlaying ifInState:^BOOL(STKAudioPlayerInternalState state) - { - return (state & STKAudioPlayerInternalStateRunning) && state != STKAudioPlayerInternalStatePaused; - }]; - } - } - else - { - audioPlayer->waitingForDataAfterSeekFrameCount = 0; - } - } - } - - if (frameFilters) - { - NSUInteger count = frameFilters.count; - AudioStreamBasicDescription asbd = canonicalAudioStreamBasicDescription; - - for (int i = 0; i < count; i++) - { - STKFrameFilterEntry* entry = [frameFilters objectAtIndex:i]; - - entry->filter(asbd.mChannelsPerFrame, asbd.mBytesPerFrame, inNumberFrames, ioData->mBuffers[0].mData); - } - } - - if (audioPlayer->equalizerEnabled != audioPlayer->equalizerOn) - { - Boolean isUpdated; - - [audioPlayer connectGraph]; - - AUGraphUpdate(audioPlayer->audioGraph, &isUpdated); - - isUpdated = isUpdated; - } - - if (entry == nil) - { - return 0; - } - - OSSpinLockLock(&entry->spinLock); - - SInt64 extraFramesPlayedNotAssigned = 0; - SInt64 framesPlayedForCurrent = totalFramesCopied; - - if (entry->lastFrameQueued >= 0) - { - framesPlayedForCurrent = MIN(entry->lastFrameQueued - entry->framesPlayed, framesPlayedForCurrent); - } - - entry->framesPlayed += framesPlayedForCurrent; - extraFramesPlayedNotAssigned = totalFramesCopied - framesPlayedForCurrent; - - BOOL lastFramePlayed = entry->framesPlayed == entry->lastFrameQueued; - - OSSpinLockUnlock(&entry->spinLock); - - if (signal || lastFramePlayed) - { - pthread_mutex_lock(&audioPlayer->playerMutex); - - OSSpinLockLock(&audioPlayer->currentEntryReferencesLock); - STKQueueEntry* currentlyPlayingEntry = audioPlayer->currentlyPlayingEntry; - OSSpinLockUnlock(&audioPlayer->currentEntryReferencesLock); - - if (lastFramePlayed && entry == currentlyPlayingEntry) - { - [audioPlayer audioQueueFinishedPlaying:entry]; - - while (extraFramesPlayedNotAssigned > 0) - { - OSSpinLockLock(&audioPlayer->currentEntryReferencesLock); - STKQueueEntry* newEntry = audioPlayer->currentlyPlayingEntry; - OSSpinLockUnlock(&audioPlayer->currentEntryReferencesLock); - - if (newEntry != nil) - { - SInt64 framesPlayedForCurrent = extraFramesPlayedNotAssigned; - - OSSpinLockLock(&newEntry->spinLock); - - if (newEntry->lastFrameQueued > 0) - { - framesPlayedForCurrent = MIN(newEntry->lastFrameQueued - newEntry->framesPlayed, framesPlayedForCurrent); - } - - newEntry->framesPlayed += framesPlayedForCurrent; - - if (newEntry->framesPlayed == newEntry->lastFrameQueued) - { - OSSpinLockUnlock(&newEntry->spinLock); - - [audioPlayer audioQueueFinishedPlaying:newEntry]; - } - else - { - OSSpinLockUnlock(&newEntry->spinLock); - } - - extraFramesPlayedNotAssigned -= framesPlayedForCurrent; - } - else - { - break; - } - } - } - - pthread_cond_signal(&audioPlayer->playerThreadReadyCondition); - pthread_mutex_unlock(&audioPlayer->playerMutex); - } - - return 0; -} - --(NSArray*) pendingQueue -{ - pthread_mutex_lock(&playerMutex); - - NSArray* retval; - NSMutableArray* mutableArray = [[NSMutableArray alloc] initWithCapacity:upcomingQueue.count + bufferingQueue.count]; - - for (STKQueueEntry* entry in upcomingQueue) - { - [mutableArray addObject:[entry queueItemId]]; - } - - for (STKQueueEntry* entry in bufferingQueue) - { - [mutableArray addObject:[entry queueItemId]]; - } - - retval = [NSArray arrayWithArray:mutableArray]; - - pthread_mutex_unlock(&playerMutex); - - return retval; -} - --(NSUInteger) pendingQueueCount -{ - pthread_mutex_lock(&playerMutex); - - NSUInteger retval = upcomingQueue.count + bufferingQueue.count; - - pthread_mutex_unlock(&playerMutex); - - return retval; -} - --(NSObject*) mostRecentlyQueuedStillPendingItem -{ - pthread_mutex_lock(&playerMutex); - - if (upcomingQueue.count > 0) - { - NSObject* retval = [[upcomingQueue objectAtIndex:0] queueItemId]; - - pthread_mutex_unlock(&playerMutex); - - return retval; - } - - if (bufferingQueue.count > 0) - { - NSObject* retval = [[bufferingQueue objectAtIndex:0] queueItemId]; - - pthread_mutex_unlock(&playerMutex); - - return retval; - } - - pthread_mutex_unlock(&playerMutex); - - return nil; -} - --(float) peakPowerInDecibelsForChannel:(NSUInteger)channelNumber -{ - if (channelNumber >= canonicalAudioStreamBasicDescription.mChannelsPerFrame) - { - return 0; - } - - return peakPowerDb[channelNumber]; -} - --(float) averagePowerInDecibelsForChannel:(NSUInteger)channelNumber -{ - if (channelNumber >= canonicalAudioStreamBasicDescription.mChannelsPerFrame) - { - return 0; - } - - return averagePowerDb[channelNumber]; -} - --(BOOL) meteringEnabled -{ - return self->meteringEnabled; -} - -#define CALCULATE_METER(channel) \ - Float32 currentFilteredValueOfSampleAmplitude##channel = STK_LOWPASSFILTERTIMESLICE * absoluteValueOfSampleAmplitude##channel + (1.0 - STK_LOWPASSFILTERTIMESLICE) * previousFilteredValueOfSampleAmplitude##channel; \ - previousFilteredValueOfSampleAmplitude##channel = currentFilteredValueOfSampleAmplitude##channel; \ - Float32 sampleDB##channel = 20.0 * log10(currentFilteredValueOfSampleAmplitude##channel) + STK_DBOFFSET; \ - if ((sampleDB##channel == sampleDB##channel) && (sampleDB##channel != -DBL_MAX)) \ - { \ - if(sampleDB##channel > peakValue##channel) \ - { \ - peakValue##channel = sampleDB##channel; \ - } \ - if (sampleDB##channel > -DBL_MAX) \ - { \ - count##channel++; \ - totalValue##channel += sampleDB##channel; \ - } \ - decibels##channel = peakValue##channel; \ - }; - --(void) setMeteringEnabled:(BOOL)value -{ - if (self->meteringEnabled == value) - { - return; - } - - if (!value) - { - [self removeFrameFilterWithName:@"STKMeteringFilter"]; - self->meteringEnabled = NO; - } - else - { - [self appendFrameFilterWithName:@"STKMeteringFilter" block:^(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UInt32 frameCount, void* frames) - { - SInt16* samples16 = (SInt16*)frames; - SInt32* samples32 = (SInt32*)frames; - UInt32 countLeft = 0; - UInt32 countRight = 0; - Float32 decibelsLeft = STK_DBMIN; - Float32 peakValueLeft = STK_DBMIN; - Float64 totalValueLeft = 0; - Float32 previousFilteredValueOfSampleAmplitudeLeft = 0; - Float32 decibelsRight = STK_DBMIN; - Float32 peakValueRight = STK_DBMIN; - Float64 totalValueRight = 0; - Float32 previousFilteredValueOfSampleAmplitudeRight = 0; - - if (bytesPerFrame / channelsPerFrame == 2) - { - for (int i = 0; i < frameCount * channelsPerFrame; i += channelsPerFrame) - { - Float32 absoluteValueOfSampleAmplitudeLeft = abs(samples16[i]); - Float32 absoluteValueOfSampleAmplitudeRight = abs(samples16[i + 1]); - - CALCULATE_METER(Left); - CALCULATE_METER(Right); - } - } - else if (bytesPerFrame / channelsPerFrame == 4) - { - for (int i = 0; i < frameCount * channelsPerFrame; i += channelsPerFrame) - { - Float32 absoluteValueOfSampleAmplitudeLeft = abs(samples32[i]) / 32768.0; - Float32 absoluteValueOfSampleAmplitudeRight = abs(samples32[i + 1]) / 32768.0; - - CALCULATE_METER(Left); - CALCULATE_METER(Right); - } - } - else - { - return; - } - - peakPowerDb[0] = MIN(MAX(decibelsLeft, -60), 0); - peakPowerDb[1] = MIN(MAX(decibelsRight, -60), 0); - - if (countLeft > 0) - { - averagePowerDb[0] = MIN(MAX(totalValueLeft / frameCount, -60), 0); - } - - if (countRight != 0) - { - averagePowerDb[1] = MIN(MAX(totalValueRight / frameCount, -60), 0); - } - }]; - } -} - -#pragma mark Frame Filters - --(NSArray*) frameFilters -{ - return frameFilters; -} - --(void) appendFrameFilterWithName:(NSString*)name block:(STKFrameFilter)block -{ - [self addFrameFilterWithName:name afterFilterWithName:nil block:block]; -} - --(void) removeFrameFilterWithName:(NSString*)name -{ - pthread_mutex_lock(&self->playerMutex); - - NSMutableArray* newFrameFilters = [[NSMutableArray alloc] initWithCapacity:frameFilters.count + 1]; - - for (STKFrameFilterEntry* filterEntry in frameFilters) - { - if (![filterEntry->name isEqualToString:name]) - { - [newFrameFilters addObject:filterEntry]; - } - } - - NSArray* replacement = [NSArray arrayWithArray:newFrameFilters]; - - OSSpinLockLock(&pcmBufferSpinLock); - if (newFrameFilters.count > 0) - { - frameFilters = replacement; - } - else - { - frameFilters = nil; - } - OSSpinLockUnlock(&pcmBufferSpinLock); - - pthread_mutex_unlock(&self->playerMutex); -} - --(void) addFrameFilterWithName:(NSString*)name afterFilterWithName:(NSString*)afterFilterWithName block:(STKFrameFilter)block -{ - pthread_mutex_lock(&self->playerMutex); - - NSMutableArray* newFrameFilters = [[NSMutableArray alloc] initWithCapacity:frameFilters.count + 1]; - - if (afterFilterWithName == nil) - { - [newFrameFilters addObject:[[STKFrameFilterEntry alloc] initWithFilter:block andName:name]]; - [newFrameFilters addObjectsFromArray:frameFilters]; - } - else - { - for (STKFrameFilterEntry* filterEntry in frameFilters) - { - if (afterFilterWithName != nil && [filterEntry->name isEqualToString:afterFilterWithName]) - { - [newFrameFilters addObject:[[STKFrameFilterEntry alloc] initWithFilter:block andName:name]]; - } - - [newFrameFilters addObject:filterEntry]; - } - } - - NSArray* replacement = [NSArray arrayWithArray:newFrameFilters]; - - OSSpinLockLock(&pcmBufferSpinLock); - frameFilters = replacement; - OSSpinLockUnlock(&pcmBufferSpinLock); - - pthread_mutex_unlock(&self->playerMutex); -} - --(void) addFrameFilter:(STKFrameFilter)frameFilter withName:(NSString*)name afterFilterWithName:(NSString*)afterFilterWithName -{ - pthread_mutex_lock(&self->playerMutex); - - NSMutableArray* newFrameFilters = [[NSMutableArray alloc] initWithCapacity:frameFilters.count + 1]; - - if (afterFilterWithName == nil) - { - [newFrameFilters addObjectsFromArray:frameFilters]; - [newFrameFilters addObject:[[STKFrameFilterEntry alloc] initWithFilter:frameFilter andName:name]]; - } - else - { - for (STKFrameFilterEntry* filterEntry in frameFilters) - { - [newFrameFilters addObject:filterEntry]; - - if (afterFilterWithName != nil && [filterEntry->name isEqualToString:afterFilterWithName]) - { - [newFrameFilters addObject:[[STKFrameFilterEntry alloc] initWithFilter:frameFilter andName:name]]; - } - } - } - - NSArray* replacement = [NSArray arrayWithArray:newFrameFilters]; - - OSSpinLockLock(&pcmBufferSpinLock); - frameFilters = replacement; - OSSpinLockUnlock(&pcmBufferSpinLock); - - pthread_mutex_unlock(&self->playerMutex); -} - -#pragma mark Volume - --(void) setVolume:(Float32)value -{ - self->volume = value; - -#if (TARGET_OS_IPHONE) - if (self->mixerNode) - { - AudioUnitSetParameter(self->mixerUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Output, 0, self->volume, 0); - } -#else - if (self->mixerNode) - { - AudioUnitSetParameter(self->mixerUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Output, 0, self->volume, 0); - } - else - { - AudioUnitSetParameter(outputUnit, kHALOutputParam_Volume, kAudioUnitScope_Output, kOutputBus, self->volume, 0); - } -#endif -} - --(Float32) volume -{ - return self->volume; -} - --(BOOL) equalizerEnabled -{ - return self->equalizerEnabled; -} - --(void) setEqualizerEnabled:(BOOL)value -{ - self->equalizerEnabled = value; -} - - -@end diff --git a/submodules/LegacyComponents/Sources/STKAutoRecoveringHTTPDataSource.h b/submodules/LegacyComponents/Sources/STKAutoRecoveringHTTPDataSource.h deleted file mode 100755 index c55895f3b6..0000000000 --- a/submodules/LegacyComponents/Sources/STKAutoRecoveringHTTPDataSource.h +++ /dev/null @@ -1,52 +0,0 @@ -/********************************************************************************** - AudioPlayer.m - - Created by Thong Nguyen on 16/10/2012. - https://github.com/tumtumtum/audjustable - - Copyright (c) 2012-2014 Thong Nguyen (tumtumtum@gmail.com). All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by Thong Nguyen (tumtumtum@gmail.com) - 4. Neither the name of Thong Nguyen nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY Thong Nguyen ''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THONG NGUYEN BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **********************************************************************************/ - -#import "STKDataSource.h" -#import "STKHTTPDataSource.h" -#import "STKDataSourceWrapper.h" - -typedef struct -{ - int watchdogPeriodSeconds; - int inactivePeriodBeforeReconnectSeconds; -} -STKAutoRecoveringHTTPDataSourceOptions; - -@interface STKAutoRecoveringHTTPDataSource : STKDataSourceWrapper - --(id) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSource; - -@property (readonly) STKHTTPDataSource* innerDataSource; - -@end diff --git a/submodules/LegacyComponents/Sources/STKAutoRecoveringHTTPDataSource.m b/submodules/LegacyComponents/Sources/STKAutoRecoveringHTTPDataSource.m deleted file mode 100755 index 37fa5e5a93..0000000000 --- a/submodules/LegacyComponents/Sources/STKAutoRecoveringHTTPDataSource.m +++ /dev/null @@ -1,391 +0,0 @@ -/********************************************************************************** - AudioPlayer.m - - Created by Thong Nguyen on 16/10/2012. - https://github.com/tumtumtum/audjustable - - Copyright (c) 2012-2014 Thong Nguyen (tumtumtum@gmail.com). All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by Thong Nguyen (tumtumtum@gmail.com) - 4. Neither the name of Thong Nguyen nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY Thong Nguyen''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **********************************************************************************/ - -#import -#import -#import -#import -#import -#import -#import "mach/mach_time.h" -#import -#import -#import "STKAutoRecoveringHTTPDataSource.h" - -#define DEFAULT_WATCHDOG_PERIOD_SECONDS (8) -#define DEFAULT_INACTIVE_PERIOD_BEFORE_RECONNECT_SECONDS (15) - -static uint64_t GetTickCount(void) -{ - static mach_timebase_info_data_t sTimebaseInfo; - uint64_t machTime = mach_absolute_time(); - - if (sTimebaseInfo.denom == 0 ) - { - (void) mach_timebase_info(&sTimebaseInfo); - } - - uint64_t millis = ((machTime / 1000000) * sTimebaseInfo.numer) / sTimebaseInfo.denom; - - return millis; -} - -@interface STKAutoRecoveringHTTPDataSource() -{ - int serial; - int waitSeconds; - NSTimer* timeoutTimer; - BOOL waitingForNetwork; - uint64_t ticksWhenLastDataReceived; - SCNetworkReachabilityRef reachabilityRef; - STKAutoRecoveringHTTPDataSourceOptions options; -} - --(void) reachabilityChanged; - -@end - -static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) -{ - @autoreleasepool - { - STKAutoRecoveringHTTPDataSource* dataSource = (__bridge STKAutoRecoveringHTTPDataSource*)info; - - [dataSource reachabilityChanged]; - } -} - -static void PopulateOptionsWithDefault(STKAutoRecoveringHTTPDataSourceOptions* options) -{ - if (options->watchdogPeriodSeconds == 0) - { - options->watchdogPeriodSeconds = DEFAULT_WATCHDOG_PERIOD_SECONDS; - } - - if (options->inactivePeriodBeforeReconnectSeconds == 0) - { - options->inactivePeriodBeforeReconnectSeconds = DEFAULT_INACTIVE_PERIOD_BEFORE_RECONNECT_SECONDS; - } -} - -@implementation STKAutoRecoveringHTTPDataSource - --(STKHTTPDataSource*) innerHTTPDataSource -{ - return (STKHTTPDataSource*)self.innerDataSource; -} - --(id) initWithDataSource:(STKDataSource *)innerDataSource -{ - return [self initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSource]; -} - --(id) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSourceIn -{ - return [self initWithHTTPDataSource:innerDataSourceIn andOptions:(STKAutoRecoveringHTTPDataSourceOptions){}]; -} - --(id) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSourceIn andOptions:(STKAutoRecoveringHTTPDataSourceOptions)optionsIn -{ - if (self = [super initWithDataSource:innerDataSourceIn]) - { - self.innerDataSource.delegate = self; - - struct sockaddr_in zeroAddress; - - bzero(&zeroAddress, sizeof(zeroAddress)); - zeroAddress.sin_len = sizeof(zeroAddress); - zeroAddress.sin_family = AF_INET; - - PopulateOptionsWithDefault(&optionsIn); - - self->options = optionsIn; - - reachabilityRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)&zeroAddress); - } - - return self; -} - --(BOOL) startNotifierOnRunLoop:(NSRunLoop*)runLoop -{ - BOOL retVal = NO; - SCNetworkReachabilityContext context = { 0, (__bridge void*)self, NULL, NULL, NULL }; - - if (SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context)) - { - if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, runLoop.getCFRunLoop, kCFRunLoopDefaultMode)) - { - retVal = YES; - } - } - - return retVal; -} - --(BOOL) registerForEvents:(NSRunLoop*)runLoop -{ - [super registerForEvents:runLoop]; - [self startNotifierOnRunLoop:runLoop]; - - if (timeoutTimer) - { - [timeoutTimer invalidate]; - timeoutTimer = nil; - } - - ticksWhenLastDataReceived = GetTickCount(); - - [self createTimeoutTimer]; - - return YES; -} - --(void) unregisterForEvents -{ - [super unregisterForEvents]; - [self stopNotifier]; - - [self destroyTimeoutTimer]; -} - --(void) timeoutTimerTick:(NSTimer*)timer -{ - if (![self hasBytesAvailable]) - { - if ([self hasGotNetworkConnection]) - { - uint64_t currentTicks = GetTickCount(); - - if (((currentTicks - ticksWhenLastDataReceived) / 1000) >= options.inactivePeriodBeforeReconnectSeconds) - { - serial++; - - NSLog(@"timeoutTimerTick %lld/%lld", self.position, self.length); - - [self attemptReconnectWithSerial:@(serial)]; - } - } - } -} - --(void) createTimeoutTimer -{ - [self destroyTimeoutTimer]; - - NSRunLoop* runLoop = self.innerDataSource.eventsRunLoop; - - if (runLoop == nil) - { - return; - } - - timeoutTimer = [NSTimer timerWithTimeInterval:options.watchdogPeriodSeconds target:self selector:@selector(timeoutTimerTick:) userInfo:@(serial) repeats:YES]; - - [runLoop addTimer:timeoutTimer forMode:NSRunLoopCommonModes]; -} - --(void) destroyTimeoutTimer -{ - if (timeoutTimer) - { - [timeoutTimer invalidate]; - timeoutTimer = nil; - } -} - --(void) stopNotifier -{ - if (reachabilityRef != NULL) - { - SCNetworkReachabilitySetCallback(reachabilityRef, NULL, NULL); - SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, [self.innerDataSource.eventsRunLoop getCFRunLoop], kCFRunLoopDefaultMode); - } -} - --(BOOL) hasGotNetworkConnection -{ - SCNetworkReachabilityFlags flags; - - if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) - { - return ((flags & kSCNetworkReachabilityFlagsReachable) != 0); - } - - return NO; -} - --(void) seekToOffset:(int64_t)offset -{ - ticksWhenLastDataReceived = GetTickCount(); - - [super seekToOffset:offset]; -} - --(void) close -{ - [self destroyTimeoutTimer]; - [super close]; -} - --(void) dealloc -{ - NSLog(@"STKAutoRecoveringHTTPDataSource dealloc"); - - self.innerDataSource.delegate = nil; - - [self stopNotifier]; - [self destroyTimeoutTimer]; - - [NSObject cancelPreviousPerformRequestsWithTarget:self]; - - if (reachabilityRef!= NULL) - { - CFRelease(reachabilityRef); - } -} - --(void) reachabilityChanged -{ - if (waitingForNetwork) - { - waitingForNetwork = NO; - - NSLog(@"reachabilityChanged %lld/%lld", self.position, self.length); - - serial++; - - [self attemptReconnectWithSerial:@(serial)]; - } -} - --(void) dataSourceDataAvailable:(STKDataSource*)dataSource -{ - if (![self.innerDataSource hasBytesAvailable]) - { - return; - } - - serial++; - waitSeconds = 1; - ticksWhenLastDataReceived = GetTickCount(); - - [super dataSourceDataAvailable:dataSource]; -} - --(void) attemptReconnectWithSerial:(NSNumber*)serialIn -{ - if (serialIn.intValue != self->serial) - { - return; - } - - NSLog(@"attemptReconnect %lld/%lld", self.position, self.length); - - if (self.innerDataSource.eventsRunLoop) - { - [self.innerDataSource reconnect]; - } -} - --(void) attemptReconnectWithTimer:(NSTimer*)timer -{ - [self attemptReconnectWithSerial:(NSNumber*)timer.userInfo]; -} - --(void) processRetryOnError -{ - if (![self hasGotNetworkConnection]) - { - waitingForNetwork = YES; - - return; - } - - waitingForNetwork = NO; - - NSRunLoop* runLoop = self.innerDataSource.eventsRunLoop; - - if (runLoop == nil) - { - // DataSource no longer used - - return; - } - else - { - serial++; - - NSTimer* timer = [NSTimer timerWithTimeInterval:waitSeconds target:self selector:@selector(attemptReconnectWithTimer:) userInfo:@(serial) repeats:NO]; - - [runLoop addTimer:timer forMode:NSRunLoopCommonModes]; - } - - waitSeconds = MIN(waitSeconds + 1, 5); -} - --(void) dataSourceEof:(STKDataSource*)dataSource -{ - NSLog(@"dataSourceEof"); - - if ([self position] < [self length]) - { - [self processRetryOnError]; - - return; - } - - [self.delegate dataSourceEof:self]; -} - --(void) dataSourceErrorOccured:(STKDataSource*)dataSource -{ - NSLog(@"dataSourceErrorOccured"); - - if (self.innerDataSource.httpStatusCode == 416 /* Range out of bounds */) - { - [super dataSourceEof:dataSource]; - } - else - { - [self processRetryOnError]; - } -} - --(NSString*) description -{ - return [NSString stringWithFormat:@"HTTP data source with file length: %lld and position: %lld", self.length, self.position]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/STKCoreFoundationDataSource.h b/submodules/LegacyComponents/Sources/STKCoreFoundationDataSource.h deleted file mode 100755 index 731de5d703..0000000000 --- a/submodules/LegacyComponents/Sources/STKCoreFoundationDataSource.h +++ /dev/null @@ -1,63 +0,0 @@ -/********************************************************************************** - AudioPlayer.m - - Created by Thong Nguyen on 14/05/2012. - https://github.com/tumtumtum/audjustable - - Copyright (c) 2012 Thong Nguyen (tumtumtum@gmail.com). All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by Thong Nguyen (tumtumtum@gmail.com) - 4. Neither the name of Thong Nguyen nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY Thong Nguyen ''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THONG NGUYEN BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**********************************************************************************/ - -#import "STKDataSource.h" - -@class STKCoreFoundationDataSource; - -@interface CoreFoundationDataSourceClientInfo : NSObject -@property (readwrite) CFReadStreamRef readStreamRef; -@property (readwrite, retain) STKCoreFoundationDataSource* datasource; -@end - -@interface STKCoreFoundationDataSource : STKDataSource -{ -@protected - BOOL isInErrorState; - CFReadStreamRef stream; - NSRunLoop* eventsRunLoop; -} - -@property (readonly) BOOL isInErrorState; - --(BOOL) reregisterForEvents; - --(void) open; --(void) openCompleted; --(void) dataAvailable; --(void) eof; --(void) errorOccured; --(CFStreamStatus) status; - -@end diff --git a/submodules/LegacyComponents/Sources/STKCoreFoundationDataSource.m b/submodules/LegacyComponents/Sources/STKCoreFoundationDataSource.m deleted file mode 100755 index 1763acd57a..0000000000 --- a/submodules/LegacyComponents/Sources/STKCoreFoundationDataSource.m +++ /dev/null @@ -1,201 +0,0 @@ -/********************************************************************************** - AudioPlayer.m - - Created by Thong Nguyen on 14/05/2012. - https://github.com/tumtumtum/audjustable - - Copyright (c) 2012 Thong Nguyen (tumtumtum@gmail.com). All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by Thong Nguyen (tumtumtum@gmail.com) - 4. Neither the name of Thong Nguyen nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY Thong Nguyen ''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THONG NGUYEN BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**********************************************************************************/ - -#import "STKCoreFoundationDataSource.h" - -static void ReadStreamCallbackProc(CFReadStreamRef stream, CFStreamEventType eventType, void* inClientInfo) -{ - STKCoreFoundationDataSource* datasource = (__bridge STKCoreFoundationDataSource*)inClientInfo; - - switch (eventType) - { - case kCFStreamEventErrorOccurred: - [datasource errorOccured]; - break; - case kCFStreamEventEndEncountered: - [datasource eof]; - break; - case kCFStreamEventHasBytesAvailable: - [datasource dataAvailable]; - break; - case kCFStreamEventOpenCompleted: - [datasource openCompleted]; - break; - default: - break; - } -} - -@implementation CoreFoundationDataSourceClientInfo -@synthesize readStreamRef, datasource; -@end - -@implementation STKCoreFoundationDataSource - --(BOOL) isInErrorState -{ - return self->isInErrorState; -} - --(void) dataAvailable -{ - [self.delegate dataSourceDataAvailable:self]; -} - --(void) eof -{ - [self.delegate dataSourceEof:self]; -} - --(void) errorOccured -{ - self->isInErrorState = YES; - - [self.delegate dataSourceErrorOccured:self]; -} - --(void) dealloc -{ - if (stream) - { - if (eventsRunLoop) - { - [self unregisterForEvents]; - } - - [self close]; - - stream = 0; - } -} - --(void) close -{ - if (stream) - { - if (eventsRunLoop) - { - [self unregisterForEvents]; - } - - CFReadStreamClose(stream); - CFRelease(stream); - - stream = 0; - } -} - --(void) open -{ -} - --(void) seekToOffset:(SInt64)offset -{ -} - --(int) readIntoBuffer:(UInt8*)buffer withSize:(int)size -{ - return (int)CFReadStreamRead(stream, buffer, size); -} - --(void) unregisterForEvents -{ - if (stream) - { - CFReadStreamSetClient(stream, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, NULL, NULL); - CFReadStreamUnscheduleFromRunLoop(stream, [eventsRunLoop getCFRunLoop], kCFRunLoopCommonModes); - - eventsRunLoop = nil; - } -} - --(BOOL) reregisterForEvents -{ - if (eventsRunLoop && stream) - { - CFStreamClientContext context = {0, (__bridge void*)self, NULL, NULL, NULL}; - CFReadStreamSetClient(stream, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, ReadStreamCallbackProc, &context); - CFReadStreamScheduleWithRunLoop(stream, [eventsRunLoop getCFRunLoop], kCFRunLoopCommonModes); - - return YES; - } - - return NO; -} - --(BOOL) registerForEvents:(NSRunLoop*)runLoop -{ - eventsRunLoop = runLoop; - - if (!stream) - { - // Will register when they open or seek - - return YES; - } - - CFStreamClientContext context = {0, (__bridge void*)self, NULL, NULL, NULL}; - - CFReadStreamSetClient(stream, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, ReadStreamCallbackProc, &context); - - CFReadStreamScheduleWithRunLoop(stream, [eventsRunLoop getCFRunLoop], kCFRunLoopCommonModes); - - return YES; -} - --(BOOL) hasBytesAvailable -{ - if (!stream) - { - return NO; - } - - return CFReadStreamHasBytesAvailable(stream); -} - --(CFStreamStatus) status -{ - if (stream) - { - return CFReadStreamGetStatus(stream); - } - - return 0; -} - --(void) openCompleted -{ -} - -@end diff --git a/submodules/LegacyComponents/Sources/STKDataSource.h b/submodules/LegacyComponents/Sources/STKDataSource.h deleted file mode 100755 index 69c296196f..0000000000 --- a/submodules/LegacyComponents/Sources/STKDataSource.h +++ /dev/null @@ -1,61 +0,0 @@ -/********************************************************************************** - AudioPlayer.m - - Created by Thong Nguyen on 14/05/2012. - https://github.com/tumtumtum/audjustable - - Copyright (c) 2012 Thong Nguyen (tumtumtum@gmail.com). All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by Thong Nguyen (tumtumtum@gmail.com) - 4. Neither the name of Thong Nguyen nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY Thong Nguyen ''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THONG NGUYEN BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**********************************************************************************/ - -#import -#include - -@class STKDataSource; - -@protocol STKDataSourceDelegate --(void) dataSourceDataAvailable:(STKDataSource*)dataSource; --(void) dataSourceErrorOccured:(STKDataSource*)dataSource; --(void) dataSourceEof:(STKDataSource*)dataSource; -@end - -@interface STKDataSource : NSObject - -@property (readonly) SInt64 position; -@property (readonly) SInt64 length; -@property (readonly) BOOL hasBytesAvailable; -@property (readwrite, unsafe_unretained) id delegate; - --(BOOL) registerForEvents:(NSRunLoop*)runLoop; --(void) unregisterForEvents; --(void) close; - --(void) seekToOffset:(SInt64)offset; --(int) readIntoBuffer:(UInt8*)buffer withSize:(int)size; --(AudioFileTypeID) audioFileTypeHint; - -@end diff --git a/submodules/LegacyComponents/Sources/STKDataSource.m b/submodules/LegacyComponents/Sources/STKDataSource.m deleted file mode 100755 index 9abd8215a3..0000000000 --- a/submodules/LegacyComponents/Sources/STKDataSource.m +++ /dev/null @@ -1,82 +0,0 @@ -/********************************************************************************** - AudioPlayer.m - - Created by Thong Nguyen on 14/05/2012. - https://github.com/tumtumtum/audjustable - - Copyright (c) 2012 Thong Nguyen (tumtumtum@gmail.com). All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by Thong Nguyen (tumtumtum@gmail.com) - 4. Neither the name of Thong Nguyen nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY Thong Nguyen ''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THONG NGUYEN BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**********************************************************************************/ - -#import "STKDataSource.h" - -@implementation STKDataSource -@synthesize delegate; - --(SInt64) length -{ - return 0; -} - --(void) seekToOffset:(SInt64)offset -{ -} - --(int) readIntoBuffer:(UInt8*)buffer withSize:(int)size -{ - return -1; -} - --(SInt64) position -{ - return 0; -} - --(BOOL) registerForEvents:(NSRunLoop*)runLoop -{ - return NO; -} - --(void) unregisterForEvents -{ -} - --(void) close -{ -} - --(BOOL) hasBytesAvailable -{ - return NO; -} - --(AudioFileTypeID) audioFileTypeHint -{ - return 0; -} - -@end diff --git a/submodules/LegacyComponents/Sources/STKDataSourceWrapper.h b/submodules/LegacyComponents/Sources/STKDataSourceWrapper.h deleted file mode 100755 index 4d3e035d5e..0000000000 --- a/submodules/LegacyComponents/Sources/STKDataSourceWrapper.h +++ /dev/null @@ -1,43 +0,0 @@ -/********************************************************************************** - AudioPlayer.m - - Created by Thong Nguyen on 16/10/2012. - https://github.com/tumtumtum/audjustable - - Copyright (c) 2012 Thong Nguyen (tumtumtum@gmail.com). All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by Thong Nguyen (tumtumtum@gmail.com) - 4. Neither the name of Thong Nguyen nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY Thong Nguyen''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **********************************************************************************/ - -#import "STKDataSource.h" - -@interface STKDataSourceWrapper : STKDataSource - --(id) initWithDataSource:(STKDataSource*)innerDataSource; - -@property (readonly) STKDataSource* innerDataSource; - -@end diff --git a/submodules/LegacyComponents/Sources/STKDataSourceWrapper.m b/submodules/LegacyComponents/Sources/STKDataSourceWrapper.m deleted file mode 100755 index 76e1634d91..0000000000 --- a/submodules/LegacyComponents/Sources/STKDataSourceWrapper.m +++ /dev/null @@ -1,120 +0,0 @@ -/********************************************************************************** - AudioPlayer.m - - Created by Thong Nguyen on 16/10/2012. - https://github.com/tumtumtum/audjustable - - Copyright (c) 2012 Thong Nguyen (tumtumtum@gmail.com). All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by Thong Nguyen (tumtumtum@gmail.com) - 4. Neither the name of Thong Nguyen nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY Thong Nguyen''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **********************************************************************************/ - -#import "STKDataSourceWrapper.h" - -@interface STKDataSourceWrapper() -@property (readwrite) STKDataSource* innerDataSource; -@end - -@implementation STKDataSourceWrapper - --(id) initWithDataSource:(STKDataSource*)innerDataSourceIn -{ - if (self = [super init]) - { - self.innerDataSource = innerDataSourceIn; - - self.innerDataSource.delegate = self; - } - - return self; -} - --(AudioFileTypeID) audioFileTypeHint -{ - return self.innerDataSource.audioFileTypeHint; -} - --(void) dealloc -{ - self.innerDataSource.delegate = nil; -} - --(SInt64) length -{ - return self.innerDataSource.length; -} - --(void) seekToOffset:(SInt64)offset -{ - return [self.innerDataSource seekToOffset:offset]; -} - --(int) readIntoBuffer:(UInt8*)buffer withSize:(int)size -{ - return [self.innerDataSource readIntoBuffer:buffer withSize:size]; -} - --(SInt64) position -{ - return self.innerDataSource.position; -} - --(BOOL) registerForEvents:(NSRunLoop*)runLoop -{ - return [self.innerDataSource registerForEvents:runLoop]; -} - --(void) unregisterForEvents -{ - [self.innerDataSource unregisterForEvents]; -} - --(void) close -{ - [self.innerDataSource close]; -} - --(BOOL) hasBytesAvailable -{ - return self.innerDataSource.hasBytesAvailable; -} - --(void) dataSourceDataAvailable:(STKDataSource*)dataSource -{ - [self.delegate dataSourceDataAvailable:self]; -} - --(void) dataSourceErrorOccured:(STKDataSource*)dataSource -{ - [self.delegate dataSourceErrorOccured:self]; -} - --(void) dataSourceEof:(STKDataSource*)dataSource -{ - [self.delegate dataSourceEof:self]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/STKHTTPDataSource.h b/submodules/LegacyComponents/Sources/STKHTTPDataSource.h deleted file mode 100755 index 628a62f6d6..0000000000 --- a/submodules/LegacyComponents/Sources/STKHTTPDataSource.h +++ /dev/null @@ -1,55 +0,0 @@ -/********************************************************************************** - AudioPlayer.m - - Created by Thong Nguyen on 14/05/2012. - https://github.com/tumtumtum/audjustable - - Copyright (c) 2012 Thong Nguyen (tumtumtum@gmail.com). All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by Thong Nguyen (tumtumtum@gmail.com) - 4. Neither the name of Thong Nguyen nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY Thong Nguyen ''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THONG NGUYEN BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **********************************************************************************/ - -#import "STKCoreFoundationDataSource.h" - -@class STKHTTPDataSource; - -typedef void(^STKURLBlock)(NSURL* url); -typedef NSURL*(^STKURLProvider)(); -typedef void(^STKAsyncURLProvider)(STKHTTPDataSource* dataSource, BOOL forSeek, STKURLBlock callback); - -@interface STKHTTPDataSource : STKCoreFoundationDataSource - -@property (readonly, retain) NSURL* url; -@property (readonly) UInt32 httpStatusCode; - -+(AudioFileTypeID) audioFileTypeHintFromMimeType:(NSString*)fileExtension; --(id) initWithURL:(NSURL*)url; --(id) initWithURLProvider:(STKURLProvider)urlProvider; --(id) initWithAsyncURLProvider:(STKAsyncURLProvider)asyncUrlProvider; --(NSRunLoop*) eventsRunLoop; --(void) reconnect; - -@end diff --git a/submodules/LegacyComponents/Sources/STKHTTPDataSource.m b/submodules/LegacyComponents/Sources/STKHTTPDataSource.m deleted file mode 100755 index 8a5f4d3406..0000000000 --- a/submodules/LegacyComponents/Sources/STKHTTPDataSource.m +++ /dev/null @@ -1,383 +0,0 @@ -/********************************************************************************** - AudioPlayer.m - - Created by Thong Nguyen on 14/05/2012. - https://github.com/tumtumtum/audjustable - - Copyright (c) 2012 Thong Nguyen (tumtumtum@gmail.com). All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by Thong Nguyen (tumtumtum@gmail.com) - 4. Neither the name of Thong Nguyen nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY Thong Nguyen ''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THONG NGUYEN BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - **********************************************************************************/ - -#import "STKHTTPDataSource.h" -#import "STKLocalFileDataSource.h" - -@interface STKHTTPDataSource() -{ -@private - UInt32 httpStatusCode; - SInt64 seekStart; - SInt64 relativePosition; - SInt64 fileLength; - int discontinuous; - int requestSerialNumber; - - NSURL* currentUrl; - STKAsyncURLProvider asyncUrlProvider; - NSDictionary* httpHeaders; - AudioFileTypeID audioFileTypeHint; -} --(void) open; - -@end - -@implementation STKHTTPDataSource - --(id) initWithURL:(NSURL*)urlIn -{ - return [self initWithURLProvider:^NSURL* { return urlIn; }]; -} - --(id) initWithURLProvider:(STKURLProvider)urlProviderIn -{ - urlProviderIn = [urlProviderIn copy]; - - return [self initWithAsyncURLProvider:^(STKHTTPDataSource* dataSource, BOOL forSeek, STKURLBlock block) - { - block(urlProviderIn()); - }]; -} - --(id) initWithAsyncURLProvider:(STKAsyncURLProvider)asyncUrlProviderIn -{ - if (self = [super init]) - { - seekStart = 0; - relativePosition = 0; - fileLength = -1; - - self->asyncUrlProvider = [asyncUrlProviderIn copy]; - - audioFileTypeHint = [STKLocalFileDataSource audioFileTypeHintFromFileExtension:self->currentUrl.pathExtension]; - } - - return self; -} - --(void) dealloc -{ - NSLog(@"STKHTTPDataSource dealloc"); -} - --(NSURL*) url -{ - return self->currentUrl; -} - -+(AudioFileTypeID) audioFileTypeHintFromMimeType:(NSString*)mimeType -{ - static dispatch_once_t onceToken; - static NSDictionary* fileTypesByMimeType; - - dispatch_once(&onceToken, ^ - { - fileTypesByMimeType = - @{ - @"audio/mp3": @(kAudioFileMP3Type), - @"audio/mpg": @(kAudioFileMP3Type), - @"audio/mpeg": @(kAudioFileMP3Type), - @"audio/wav": @(kAudioFileWAVEType), - @"audio/aifc": @(kAudioFileAIFCType), - @"audio/aiff": @(kAudioFileAIFFType), - @"audio/x-m4a": @(kAudioFileM4AType), - @"audio/x-mp4": @(kAudioFileMPEG4Type), - @"audio/aacp": @(kAudioFileAAC_ADTSType), - @"audio/m4a": @(kAudioFileM4AType), - @"audio/mp4": @(kAudioFileMPEG4Type), - @"audio/caf": @(kAudioFileCAFType), - @"audio/aac": @(kAudioFileAAC_ADTSType), - @"audio/ac3": @(kAudioFileAC3Type), - @"audio/3gp": @(kAudioFile3GPType) - }; - }); - - NSNumber* number = [fileTypesByMimeType objectForKey:mimeType]; - - if (!number) - { - return 0; - } - - return (AudioFileTypeID)number.intValue; -} - --(AudioFileTypeID) audioFileTypeHint -{ - return audioFileTypeHint; -} - --(void) dataAvailable -{ - if (stream == NULL) { - return; - } - - if (self.httpStatusCode == 0) - { - CFTypeRef response = CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPResponseHeader); - - if (response) - { - httpHeaders = (__bridge_transfer NSDictionary*)CFHTTPMessageCopyAllHeaderFields((CFHTTPMessageRef)response); - - self->httpStatusCode = (UInt32)CFHTTPMessageGetResponseStatusCode((CFHTTPMessageRef)response); - - CFRelease(response); - } - - if (self.httpStatusCode == 200) - { - if (seekStart == 0) - { - fileLength = (SInt64)[[httpHeaders objectForKey:@"Content-Length"] longLongValue]; - } - - NSString* contentType = [httpHeaders objectForKey:@"Content-Type"]; - AudioFileTypeID typeIdFromMimeType = [STKHTTPDataSource audioFileTypeHintFromMimeType:contentType]; - - if (typeIdFromMimeType != 0) - { - audioFileTypeHint = typeIdFromMimeType; - } - } - else if (self.httpStatusCode == 206) - { - NSString* contentRange = [httpHeaders objectForKey:@"Content-Range"]; - NSArray* components = [contentRange componentsSeparatedByString:@"/"]; - - if (components.count == 2) - { - fileLength = [[components objectAtIndex:1] integerValue]; - } - } - else if (self.httpStatusCode == 416) - { - if (self.length >= 0) - { - seekStart = self.length; - } - - [self eof]; - - return; - } - else if (self.httpStatusCode >= 300) - { - [self errorOccured]; - - return; - } - } - - [super dataAvailable]; -} - --(SInt64) position -{ - return seekStart + relativePosition; -} - --(SInt64) length -{ - return fileLength >= 0 ? fileLength : 0; -} - --(void) reconnect -{ - NSRunLoop* savedEventsRunLoop = eventsRunLoop; - - [self close]; - - eventsRunLoop = savedEventsRunLoop; - - [self seekToOffset:self.position]; -} - --(void) seekToOffset:(SInt64)offset -{ - NSRunLoop* savedEventsRunLoop = eventsRunLoop; - - [self close]; - - eventsRunLoop = savedEventsRunLoop; - - NSAssert([NSRunLoop currentRunLoop] == eventsRunLoop, @"Seek called on wrong thread"); - - stream = 0; - relativePosition = 0; - seekStart = offset; - - self->isInErrorState = NO; - - [self openForSeek:YES]; -} - --(int) readIntoBuffer:(UInt8*)buffer withSize:(int)size -{ - if (size == 0) - { - return 0; - } - - int read = (int)CFReadStreamRead(stream, buffer, size); - - if (read < 0) - { - return read; - } - - relativePosition += read; - - return read; -} - --(void) open -{ - return [self openForSeek:NO]; -} - --(void) openForSeek:(BOOL)forSeek -{ - int localRequestSerialNumber; - - requestSerialNumber++; - localRequestSerialNumber = requestSerialNumber; - - asyncUrlProvider(self, forSeek, ^(NSURL* url) - { - if (localRequestSerialNumber != self->requestSerialNumber) - { - return; - } - - self->currentUrl = url; - - if (url == nil) - { - return; - } - - CFHTTPMessageRef message = CFHTTPMessageCreateRequest(NULL, (CFStringRef)@"GET", (__bridge CFURLRef)self->currentUrl, kCFHTTPVersion1_1); - - if (seekStart > 0) - { - CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Range"), (__bridge CFStringRef)[NSString stringWithFormat:@"bytes=%lld-", seekStart]); - - discontinuous = YES; - } - - stream = CFReadStreamCreateForHTTPRequest(NULL, message); - - if (stream == nil) - { - CFRelease(message); - - [self errorOccured]; - - return; - } - - if (!CFReadStreamSetProperty(stream, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue)) - { - CFRelease(message); - - [self errorOccured]; - - return; - } - - // Proxy support - - CFDictionaryRef proxySettings = CFNetworkCopySystemProxySettings(); - CFReadStreamSetProperty(stream, kCFStreamPropertyHTTPProxy, proxySettings); - CFRelease(proxySettings); - - // SSL support - - if ([self->currentUrl.scheme caseInsensitiveCompare:@"https"] == NSOrderedSame) - { - NSDictionary* sslSettings = [NSDictionary dictionaryWithObjectsAndKeys: - (NSString*)kCFStreamSocketSecurityLevelNegotiatedSSL, kCFStreamSSLLevel, - [NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredCertificates, - [NSNumber numberWithBool:YES], kCFStreamSSLAllowsExpiredRoots, - [NSNumber numberWithBool:YES], kCFStreamSSLAllowsAnyRoot, - [NSNumber numberWithBool:NO], kCFStreamSSLValidatesCertificateChain, - [NSNull null], kCFStreamSSLPeerName, - nil]; - - CFReadStreamSetProperty(stream, kCFStreamPropertySSLSettings, (__bridge CFTypeRef)sslSettings); - } - - [self reregisterForEvents]; - - self->httpStatusCode = 0; - - // Open - - if (!CFReadStreamOpen(stream)) - { - CFRelease(stream); - CFRelease(message); - - stream = 0; - - [self errorOccured]; - - return; - } - - self->isInErrorState = NO; - - CFRelease(message); - }); -} - --(UInt32) httpStatusCode -{ - return self->httpStatusCode; -} - --(NSRunLoop*) eventsRunLoop -{ - return self->eventsRunLoop; -} - --(NSString*) description -{ - return [NSString stringWithFormat:@"HTTP data source with file length: %lld and position: %lld", self.length, self.position]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/STKLocalFileDataSource.h b/submodules/LegacyComponents/Sources/STKLocalFileDataSource.h deleted file mode 100755 index 777ee52f66..0000000000 --- a/submodules/LegacyComponents/Sources/STKLocalFileDataSource.h +++ /dev/null @@ -1,43 +0,0 @@ -/********************************************************************************** - AudioPlayer.m - - Created by Thong Nguyen on 14/05/2012. - https://github.com/tumtumtum/audjustable - - Copyright (c) 2012 Thong Nguyen (tumtumtum@gmail.com). All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by Thong Nguyen (tumtumtum@gmail.com) - 4. Neither the name of Thong Nguyen nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY Thong Nguyen ''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THONG NGUYEN BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**********************************************************************************/ - -#import "STKCoreFoundationDataSource.h" - -@interface STKLocalFileDataSource : STKCoreFoundationDataSource - -+(AudioFileTypeID) audioFileTypeHintFromFileExtension:(NSString*)fileExtension; -@property (atomic, readonly, copy) NSString* filePath; --(id) initWithFilePath:(NSString*)filePath; - -@end diff --git a/submodules/LegacyComponents/Sources/STKLocalFileDataSource.m b/submodules/LegacyComponents/Sources/STKLocalFileDataSource.m deleted file mode 100755 index 2aded28dd9..0000000000 --- a/submodules/LegacyComponents/Sources/STKLocalFileDataSource.m +++ /dev/null @@ -1,243 +0,0 @@ -/********************************************************************************** - AudioPlayer.m - - Created by Thong Nguyen on 14/05/2012. - https://github.com/tumtumtum/audjustable - - Copyright (c) 2012 Thong Nguyen (tumtumtum@gmail.com). All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by Thong Nguyen (tumtumtum@gmail.com) - 4. Neither the name of Thong Nguyen nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY Thong Nguyen ''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THONG NGUYEN BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**********************************************************************************/ - -#import "STKLocalFileDataSource.h" - -@interface STKLocalFileDataSource() -{ - SInt64 position; - SInt64 length; - AudioFileTypeID audioFileTypeHint; -} -@property (readwrite, copy) NSString* filePath; --(void) open; -@end - -@implementation STKLocalFileDataSource -@synthesize filePath; - --(id) initWithFilePath:(NSString*)filePathIn -{ - if (self = [super init]) - { - self.filePath = filePathIn; - - audioFileTypeHint = [STKLocalFileDataSource audioFileTypeHintFromFileExtension:filePathIn.pathExtension]; - } - - return self; -} - -+(AudioFileTypeID) audioFileTypeHintFromFileExtension:(NSString*)fileExtension -{ - static dispatch_once_t onceToken; - static NSDictionary* fileTypesByFileExtensions; - - dispatch_once(&onceToken, ^ - { - fileTypesByFileExtensions = - @{ - @"mp3": @(kAudioFileMP3Type), - @"wav": @(kAudioFileWAVEType), - @"aifc": @(kAudioFileAIFCType), - @"aiff": @(kAudioFileAIFFType), - @"m4a": @(kAudioFileM4AType), - @"mp4": @(kAudioFileMPEG4Type), - @"caf": @(kAudioFileCAFType), - @"aac": @(kAudioFileAAC_ADTSType), - @"ac3": @(kAudioFileAC3Type), - @"3gp": @(kAudioFile3GPType) - }; - }); - - NSNumber* number = [fileTypesByFileExtensions objectForKey:fileExtension]; - - if (!number) - { - return 0; - } - - return (AudioFileTypeID)number.intValue; -} - --(AudioFileTypeID) audioFileTypeHint -{ - return audioFileTypeHint; -} - --(void) dealloc -{ - [self close]; -} - --(void) close -{ - if (stream) - { - [self unregisterForEvents]; - - CFReadStreamClose(stream); - - stream = 0; - } -} - --(void) open -{ - if (stream) - { - [self unregisterForEvents]; - - CFReadStreamClose(stream); - CFRelease(stream); - - stream = 0; - } - - NSURL* url = [[NSURL alloc] initFileURLWithPath:self.filePath]; - - stream = CFReadStreamCreateWithFile(NULL, (__bridge CFURLRef)url); - - NSError* fileError; - NSFileManager* manager = [[NSFileManager alloc] init]; - NSDictionary* attributes = [manager attributesOfItemAtPath:filePath error:&fileError]; - - if (fileError) - { - CFReadStreamClose(stream); - CFRelease(stream); - stream = 0; - return; - } - - NSNumber* number = [attributes objectForKey:@"NSFileSize"]; - - if (number) - { - length = number.longLongValue; - } - - [self reregisterForEvents]; - - CFReadStreamOpen(stream); -} - --(SInt64) position -{ - return position; -} - --(SInt64) length -{ - return length; -} - --(int) readIntoBuffer:(UInt8*)buffer withSize:(int)size -{ - int retval = (int)CFReadStreamRead(stream, buffer, size); - - if (retval > 0) - { - position += retval; - } - else - { - NSNumber* property = (__bridge_transfer NSNumber*)CFReadStreamCopyProperty(stream, kCFStreamPropertyFileCurrentOffset); - - position = property.longLongValue; - } - - return retval; -} - --(void) seekToOffset:(SInt64)offset -{ - CFStreamStatus status = kCFStreamStatusClosed; - - if (stream != 0) - { - status = CFReadStreamGetStatus(stream); - } - - BOOL reopened = NO; - - if (status == kCFStreamStatusAtEnd || status == kCFStreamStatusClosed || status == kCFStreamStatusError) - { - reopened = YES; - - [self close]; - [self open]; - } - - if (stream == 0) - { - CFRunLoopPerformBlock(eventsRunLoop.getCFRunLoop, NSRunLoopCommonModes, ^ - { - [self errorOccured]; - }); - - CFRunLoopWakeUp(eventsRunLoop.getCFRunLoop); - - return; - } - - if (CFReadStreamSetProperty(stream, kCFStreamPropertyFileCurrentOffset, (__bridge CFTypeRef)[NSNumber numberWithLongLong:offset]) != TRUE) - { - position = 0; - } - else - { - position = offset; - } - - if (!reopened) - { - CFRunLoopPerformBlock(eventsRunLoop.getCFRunLoop, NSRunLoopCommonModes, ^ - { - if ([self hasBytesAvailable]) - { - [self dataAvailable]; - } - }); - - CFRunLoopWakeUp(eventsRunLoop.getCFRunLoop); - } -} - --(NSString*) description -{ - return self->filePath; -} - -@end diff --git a/submodules/LegacyComponents/Sources/STKQueueEntry.h b/submodules/LegacyComponents/Sources/STKQueueEntry.h deleted file mode 100755 index 78e3784276..0000000000 --- a/submodules/LegacyComponents/Sources/STKQueueEntry.h +++ /dev/null @@ -1,45 +0,0 @@ -// -// STKQueueEntry.h -// StreamingKit -// -// Created by Thong Nguyen on 30/01/2014. -// Copyright (c) 2014 Thong Nguyen. All rights reserved. -// - -#import "STKDataSource.h" -#import "libkern/OSAtomic.h" -#import "AudioToolbox/AudioToolbox.h" - -@interface STKQueueEntry : NSObject -{ -@public - OSSpinLock spinLock; - - BOOL parsedHeader; - Float64 sampleRate; - double packetDuration; - UInt64 audioDataOffset; - UInt64 audioDataByteCount; - UInt32 packetBufferSize; - volatile Float64 seekTime; - volatile SInt64 framesQueued; - volatile SInt64 framesPlayed; - volatile SInt64 lastFrameQueued; - volatile int processedPacketsCount; - volatile int processedPacketsSizeTotal; - AudioStreamBasicDescription audioStreamBasicDescription; -} - -@property (readonly) UInt64 audioDataLengthInBytes; -@property (readwrite, retain) NSObject* queueItemId; -@property (readwrite, retain) STKDataSource* dataSource; - --(id) initWithDataSource:(STKDataSource*)dataSource andQueueItemId:(NSObject*)queueItemId; - --(void) reset; --(double) duration; --(Float64) progressInFrames; --(double) calculatedBitRate; --(BOOL) isDefinitelyCompatible:(AudioStreamBasicDescription*)basicDescription; - -@end \ No newline at end of file diff --git a/submodules/LegacyComponents/Sources/STKQueueEntry.m b/submodules/LegacyComponents/Sources/STKQueueEntry.m deleted file mode 100755 index 2b6de04a3b..0000000000 --- a/submodules/LegacyComponents/Sources/STKQueueEntry.m +++ /dev/null @@ -1,121 +0,0 @@ -// -// STKQueueEntry.m -// StreamingKit -// -// Created by Thong Nguyen on 30/01/2014. -// Copyright (c) 2014 Thong Nguyen. All rights reserved. -// - -#import "STKQueueEntry.h" -#import "STKDataSource.h" - -#define STK_BIT_RATE_ESTIMATION_MIN_PACKETS_MIN (2) -#define STK_BIT_RATE_ESTIMATION_MIN_PACKETS_PREFERRED (64) - -@implementation STKQueueEntry - --(id) initWithDataSource:(STKDataSource*)dataSourceIn andQueueItemId:(NSObject*)queueItemIdIn -{ - if (self = [super init]) - { - self->spinLock = OS_SPINLOCK_INIT; - - self.dataSource = dataSourceIn; - self.queueItemId = queueItemIdIn; - self->lastFrameQueued = -1; - } - - return self; -} - --(void) reset -{ - OSSpinLockLock(&self->spinLock); - self->framesQueued = 0; - self->framesPlayed = 0; - self->lastFrameQueued = -1; - OSSpinLockUnlock(&self->spinLock); -} - --(double) calculatedBitRate -{ - double retval; - - if (packetDuration > 0) - { - if (processedPacketsCount > STK_BIT_RATE_ESTIMATION_MIN_PACKETS_PREFERRED || (audioStreamBasicDescription.mBytesPerFrame == 0 && processedPacketsCount > STK_BIT_RATE_ESTIMATION_MIN_PACKETS_MIN)) - { - double averagePacketByteSize = processedPacketsSizeTotal / processedPacketsCount; - - retval = averagePacketByteSize / packetDuration * 8; - - return retval; - } - } - - retval = (audioStreamBasicDescription.mBytesPerFrame * audioStreamBasicDescription.mSampleRate) * 8; - - return retval; -} - --(double) duration -{ - if (self->sampleRate <= 0) - { - return 0; - } - - UInt64 audioDataLengthInBytes = [self audioDataLengthInBytes]; - - double calculatedBitRate = [self calculatedBitRate]; - - if (calculatedBitRate < 1.0 || self.dataSource.length == 0) - { - return 0; - } - - return audioDataLengthInBytes / (calculatedBitRate / 8); -} - --(UInt64) audioDataLengthInBytes -{ - if (audioDataByteCount) - { - return audioDataByteCount; - } - else - { - if (!self.dataSource.length) - { - return 0; - } - - return self.dataSource.length - audioDataOffset; - } -} - --(BOOL) isDefinitelyCompatible:(AudioStreamBasicDescription*)basicDescription -{ - if (self->audioStreamBasicDescription.mSampleRate == 0) - { - return NO; - } - - return (memcmp(&(self->audioStreamBasicDescription), basicDescription, sizeof(*basicDescription)) == 0); -} - --(Float64) progressInFrames -{ - OSSpinLockLock(&self->spinLock); - Float64 retval = self->seekTime + self->framesPlayed; - OSSpinLockUnlock(&self->spinLock); - - return retval; -} - --(NSString*) description -{ - return [[self queueItemId] description]; -} - -@end \ No newline at end of file diff --git a/submodules/LegacyComponents/Sources/TGCameraController.m b/submodules/LegacyComponents/Sources/TGCameraController.m index 8482896730..faec38dcbb 100644 --- a/submodules/LegacyComponents/Sources/TGCameraController.m +++ b/submodules/LegacyComponents/Sources/TGCameraController.m @@ -4,8 +4,6 @@ #import -#import - #import #import #import @@ -2431,7 +2429,7 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus + (bool)useLegacyCamera { - return iosMajorVersion() < 7 || [UIDevice currentDevice].platformType == UIDevice4iPhone || [UIDevice currentDevice].platformType == UIDevice4GiPod; + return false; } + (NSArray *)resultSignalsForSelectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext currentItem:(id)currentItem storeAssets:(bool)storeAssets saveEditedPhotos:(bool)saveEditedPhotos descriptionGenerator:(id (^)(id, NSString *, NSArray *, NSString *))descriptionGenerator diff --git a/submodules/LegacyComponents/Sources/TGListsTableView.m b/submodules/LegacyComponents/Sources/TGListsTableView.m index 0f0f104da3..0a191029ab 100644 --- a/submodules/LegacyComponents/Sources/TGListsTableView.m +++ b/submodules/LegacyComponents/Sources/TGListsTableView.m @@ -4,8 +4,6 @@ #import "POPBasicAnimation.h" #import "Freedom.h" -#import "TGSearchBar.h" - #import @interface TGListsTableView () @@ -80,12 +78,6 @@ } } - UIView *tableHeaderView = self.tableHeaderView; - if (tableHeaderView != nil && [tableHeaderView respondsToSelector:@selector(updateClipping:)]) - { - [(TGSearchBar *)tableHeaderView updateClipping:bounds.origin.y + self.contentInset.top]; - } - UIView *indexView = self.subviews.lastObject; if ([NSStringFromClass([indexView class]) rangeOfString:@"ViewIndex"].location != NSNotFound) { diff --git a/submodules/LegacyComponents/Sources/TGLocationAnnotation.h b/submodules/LegacyComponents/Sources/TGLocationAnnotation.h deleted file mode 100644 index 1bd042c825..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationAnnotation.h +++ /dev/null @@ -1,33 +0,0 @@ -#import -#import - -@class TGLocationMediaAttachment; -@class TGUser; - -@interface TGLocationPickerAnnotation: NSObject - -@property (nonatomic, assign) CLLocationCoordinate2D coordinate; -@property (nonatomic, strong) id peer; - -- (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate; - -@end - - -@interface TGLocationAnnotation : NSObject - -@property (nonatomic, readonly) TGLocationMediaAttachment *location; -@property (nonatomic, readonly) bool isLiveLocation; -@property (nonatomic, strong) id peer; -@property (nonatomic, strong) UIColor *color; -@property (nonatomic, assign) CLLocationCoordinate2D coordinate; -@property (nonatomic, assign) int32_t messageId; -@property (nonatomic, assign) bool isOwn; -@property (nonatomic, assign) bool hasSession; -@property (nonatomic, assign) bool isExpired; -@property (nonatomic, strong) NSNumber *heading; - -- (instancetype)initWithLocation:(TGLocationMediaAttachment *)location; -- (instancetype)initWithLocation:(TGLocationMediaAttachment *)location color:(UIColor *)color; - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationAnnotation.m b/submodules/LegacyComponents/Sources/TGLocationAnnotation.m deleted file mode 100644 index 9f5a1c7e39..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationAnnotation.m +++ /dev/null @@ -1,164 +0,0 @@ -#import "TGLocationAnnotation.h" - -#import "TGLocationMediaAttachment.h" - -@interface TGLocationAnnotation () -{ - CLLocationCoordinate2D _coordinate; - NSMutableSet *_observers; -} -@end - -@implementation TGLocationAnnotation - -- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context -{ - NSString *observerId = [NSString stringWithFormat:@"%lu%@", observer.hash, keyPath]; - [_observers addObject:observerId]; - - [super addObserver:observer forKeyPath:keyPath options:options context:context]; -} - -- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath -{ - NSString *observerId = [NSString stringWithFormat:@"%lu%@", observer.hash, keyPath]; - if ([_observers containsObject:observerId]) - { - [_observers removeObject:observerId]; - [super removeObserver:observer forKeyPath:keyPath]; - } -} - -- (instancetype)initWithLocation:(TGLocationMediaAttachment *)location -{ - return [self initWithLocation:location color:nil]; -} - -- (instancetype)initWithLocation:(TGLocationMediaAttachment *)location color:(UIColor *)color -{ - self = [super init]; - if (self != nil) - { - _coordinate = CLLocationCoordinate2DMake(location.latitude, location.longitude); - _color = color; - _location = location; - _observers = [[NSMutableSet alloc] init]; - } - return self; -} - -- (NSString *)title -{ - return @""; -} - -- (NSString *)subtitle -{ - return @""; -} - -- (CLLocationCoordinate2D)coordinate -{ - return _coordinate; -} - -- (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate -{ - if (fabs(newCoordinate.latitude - _coordinate.latitude) > DBL_EPSILON || fabs(newCoordinate.longitude - _coordinate.longitude) > DBL_EPSILON) - { - [self willChangeValueForKey:@"coordinate"]; - _coordinate = newCoordinate; - [self didChangeValueForKey:@"coordinate"]; - } -} - -- (void)setIsExpired:(bool)isExpired -{ - if (isExpired != _isExpired) - { - [self willChangeValueForKey:@"isExpired"]; - _isExpired = isExpired; - [self didChangeValueForKey:@"isExpired"]; - } -} - -- (void)setHeading:(NSNumber *)heading -{ - [self willChangeValueForKey:@"heading"]; - _heading = heading; - [self didChangeValueForKey:@"heading"]; -} - -- (void)setHasSession:(bool)hasSession -{ - if (hasSession != _hasSession) - { - [self willChangeValueForKey:@"hasSession"]; - _hasSession = hasSession; - [self didChangeValueForKey:@"hasSession"]; - } -} - -- (bool)isLiveLocation -{ - return _location.period > 0; -} - -@end - - -@interface TGLocationPickerAnnotation () -{ - CLLocationCoordinate2D _coordinate; - NSMutableSet *_observers; -} -@end - -@implementation TGLocationPickerAnnotation - -- (instancetype)initWithCoordinate:(CLLocationCoordinate2D)coordinate -{ - self = [super init]; - if (self != nil) - { - _coordinate = coordinate; - _observers = [[NSMutableSet alloc] init]; - } - return self; -} - -- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context -{ - NSString *observerId = [NSString stringWithFormat:@"%lu%@", observer.hash, keyPath]; - [_observers addObject:observerId]; - - [super addObserver:observer forKeyPath:keyPath options:options context:context]; -} - -- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath -{ - NSString *observerId = [NSString stringWithFormat:@"%lu%@", observer.hash, keyPath]; - if ([_observers containsObject:observerId]) - { - [_observers removeObject:observerId]; - [super removeObserver:observer forKeyPath:keyPath]; - } -} - - -- (CLLocationCoordinate2D)coordinate -{ - return _coordinate; -} - -- (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate -{ - if (fabs(newCoordinate.latitude - _coordinate.latitude) > DBL_EPSILON || fabs(newCoordinate.longitude - _coordinate.longitude) > DBL_EPSILON) - { - [self willChangeValueForKey:@"coordinate"]; - _coordinate = newCoordinate; - [self didChangeValueForKey:@"coordinate"]; - } -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationCurrentLocationCell.h b/submodules/LegacyComponents/Sources/TGLocationCurrentLocationCell.h deleted file mode 100644 index 930f9352ac..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationCurrentLocationCell.h +++ /dev/null @@ -1,22 +0,0 @@ -#import -#import -#import - -@class TGMessage; -@class TGLocationPallete; - -@interface TGLocationCurrentLocationCell : UITableViewCell - -@property (nonatomic, strong) TGLocationPallete *pallete; -@property (nonatomic, weak) UIImageView *edgeView; - -- (void)configureForCurrentLocationWithAccuracy:(CLLocationAccuracy)accuracy; -- (void)configureForCustomLocationWithAddress:(NSString *)address; -- (void)configureForGroupLocationWithAddress:(NSString *)address; -- (void)configureForLiveLocationWithAccuracy:(CLLocationAccuracy)accuracy; -- (void)configureForStopWithMessage:(TGMessage *)message remaining:(SSignal *)remaining; - -@end - -extern NSString *const TGLocationCurrentLocationCellKind; -extern const CGFloat TGLocationCurrentLocationCellHeight; diff --git a/submodules/LegacyComponents/Sources/TGLocationCurrentLocationCell.m b/submodules/LegacyComponents/Sources/TGLocationCurrentLocationCell.m deleted file mode 100644 index 39541e7d75..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationCurrentLocationCell.m +++ /dev/null @@ -1,409 +0,0 @@ -#import "TGLocationCurrentLocationCell.h" -#import "TGLocationVenueCell.h" - -#import "TGLocationMapViewController.h" -#import "LegacyComponentsInternal.h" -#import "TGColor.h" -#import "TGImageUtils.h" -#import "TGFont.h" -#import "TGLocationUtils.h" -#import "TGDateUtils.h" - -#import "TGMessage.h" - -#import "TGLocationWavesView.h" -#import "TGLocationLiveElapsedView.h" - -NSString *const TGLocationCurrentLocationCellKind = @"TGLocationCurrentLocationCellKind"; -const CGFloat TGLocationCurrentLocationCellHeight = 68; - -@interface TGLocationCurrentLocationCell () -{ - int32_t _messageId; - bool _isCurrentLocation; - - UIView *_highlightView; - - UIImageView *_circleView; - UIImageView *_iconView; - TGLocationWavesView *_wavesView; - - UILabel *_titleLabel; - UILabel *_subtitleLabel; - TGLocationLiveElapsedView *_elapsedView; - UIView *_separatorView; - - SMetaDisposable *_remainingDisposable; -} -@end - -@implementation TGLocationCurrentLocationCell - -- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier -{ - self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; - if (self != nil) - { - self.selectedBackgroundView = [[UIView alloc] init]; - self.selectedBackgroundView.backgroundColor = [UIColor clearColor]; - - _highlightView = [[UIView alloc] initWithFrame:self.bounds]; - _highlightView.alpha = 0.0f; - _highlightView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - _highlightView.backgroundColor = TGSelectionColor(); - _highlightView.userInteractionEnabled = false; - [self.contentView addSubview:_highlightView]; - - _circleView = [[UIImageView alloc] initWithFrame:CGRectMake(12.0f, 10.0f, 48.0f, 48.0f)]; - [self.contentView addSubview:_circleView]; - - _iconView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 48.0f, 48.0f)]; - _iconView.contentMode = UIViewContentModeCenter; - [_circleView addSubview:_iconView]; - - _titleLabel = [[UILabel alloc] init]; - _titleLabel.backgroundColor = [UIColor clearColor]; - _titleLabel.font = TGBoldSystemFontOfSize(16.0); - _titleLabel.text = TGLocalized(@"Map.SendMyCurrentLocation"); - _titleLabel.textColor = TGAccentColor(); - [self.contentView addSubview:_titleLabel]; - - _subtitleLabel = [[UILabel alloc] init]; - _subtitleLabel.backgroundColor = [UIColor clearColor]; - _subtitleLabel.font = TGSystemFontOfSize(13); - _subtitleLabel.text = TGLocalized(@"Map.Locating"); - _subtitleLabel.textColor = UIColorRGB(0xa6a6a6); - [self.contentView addSubview:_subtitleLabel]; - - _elapsedView = [[TGLocationLiveElapsedView alloc] init]; - [self.contentView addSubview:_elapsedView]; - - _separatorView = [[UIView alloc] init]; - _separatorView.backgroundColor = TGSeparatorColor(); - [self addSubview:_separatorView]; - - _wavesView = [[TGLocationWavesView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 48.0f, 48.0f)]; - [_circleView addSubview:_wavesView]; - - _isCurrentLocation = true; - } - return self; -} - -- (void)dealloc -{ - [_wavesView invalidate]; -} - -- (void)setPallete:(TGLocationPallete *)pallete -{ - if (pallete == nil || _pallete == pallete) - return; - - _pallete = pallete; - - self.backgroundColor = pallete.backgroundColor; - _highlightView.backgroundColor = pallete.selectionColor; - _titleLabel.textColor = pallete.accentColor; - _subtitleLabel.textColor = pallete.secondaryTextColor; - _separatorView.backgroundColor = pallete.separatorColor; - [_elapsedView setColor:pallete.accentColor]; -} - -- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated -{ - if (animated) - { - [UIView animateWithDuration:0.2 animations:^ - { - _highlightView.alpha = highlighted ? 1.0f : 0.0f; - _edgeView.alpha = highlighted ? 1.0f : 0.0f; - }]; - } - else - { - _highlightView.alpha = highlighted ? 1.0f : 0.0f; - _edgeView.alpha = highlighted ? 1.0f : 0.0f; - } -} - -- (void)setCircleColor:(UIColor *)color -{ - UIImage *circleImage = [TGLocationVenueCell circleImage]; - _circleView.image = TGTintedImage(circleImage, color); -} - -- (void)configureForCurrentLocationWithAccuracy:(CLLocationAccuracy)accuracy -{ - _messageId = 0; - - - UIImage *icon = TGComponentsImageNamed(@"LocationMessagePinIcon"); - if (_pallete != nil) - icon = TGTintedImage(icon, _pallete.iconColor); - - _iconView.image = icon; - _titleLabel.textColor = self.pallete != nil ? self.pallete.accentColor : TGAccentColor(); - _elapsedView.hidden = true; - - if (!_isCurrentLocation) - { - [UIView transitionWithView:self duration:0.2f options:UIViewAnimationOptionTransitionCrossDissolve animations:^ - { - _titleLabel.text = TGLocalized(@"Map.SendMyCurrentLocation"); - - if (accuracy > DBL_EPSILON) - { - NSString *accuracyString = [TGLocationUtils stringFromAccuracy:(NSInteger)accuracy]; - _subtitleLabel.text = [NSString stringWithFormat:TGLocalized(@"Map.AccurateTo"), accuracyString]; - - _circleView.alpha = 1.0f; - _titleLabel.alpha = 1.0f; - _subtitleLabel.alpha = 1.0f; - } - else - { - _subtitleLabel.text = TGLocalized(@"Map.Locating"); - - _circleView.alpha = 0.5f; - _titleLabel.alpha = 0.5f; - _subtitleLabel.alpha = 0.5f; - } - } completion:nil]; - - _isCurrentLocation = true; - } - else - { - if (accuracy > DBL_EPSILON) - { - NSString *accuracyString = [TGLocationUtils stringFromAccuracy:(NSInteger)accuracy]; - _subtitleLabel.text = [NSString stringWithFormat:TGLocalized(@"Map.AccurateTo"), accuracyString]; - - [UIView animateWithDuration:0.2f animations:^ - { - _circleView.alpha = 1.0f; - _titleLabel.alpha = 1.0f; - _subtitleLabel.alpha = 1.0f; - }]; - } - else - { - _subtitleLabel.text = TGLocalized(@"Map.Locating"); - - _circleView.alpha = 0.5f; - _titleLabel.alpha = 0.5f; - _subtitleLabel.alpha = 0.5f; - } - } - - [self setCircleColor:_pallete != nil ? _pallete.locationColor : UIColorRGB(0x008df2)]; - - _separatorView.hidden = false; - [_wavesView stop]; - _wavesView.hidden = true; - - [self setNeedsLayout]; -} - -- (void)configureForLiveLocationWithAccuracy:(CLLocationAccuracy)accuracy -{ - _messageId = 0; - - UIImage *icon = TGComponentsImageNamed(@"LocationMessageLiveIcon"); - if (_pallete != nil) - icon = TGTintedImage(icon, _pallete.iconColor); - - _iconView.image = icon; - _titleLabel.textColor = self.pallete != nil ? self.pallete.accentColor : TGAccentColor(); - _elapsedView.hidden = true; - - [UIView transitionWithView:self duration:0.2f options:UIViewAnimationOptionTransitionCrossDissolve animations:^ - { - _titleLabel.text = TGLocalized(@"Map.ShareLiveLocation"); - _subtitleLabel.text = TGLocalized(@"Map.ShareLiveLocationHelp"); - - if (accuracy > DBL_EPSILON) - { - _circleView.alpha = 1.0f; - _titleLabel.alpha = 1.0f; - _subtitleLabel.alpha = 1.0f; - } - else - { - _circleView.alpha = 0.5f; - _titleLabel.alpha = 0.5f; - _subtitleLabel.alpha = 0.5f; - } - } completion:nil]; - - [self setCircleColor:_pallete != nil ? _pallete.liveLocationColor : UIColorRGB(0xff6464)]; - - _separatorView.hidden = true; - [_wavesView stop]; - _wavesView.hidden = true; - - [self setNeedsLayout]; -} - -- (void)configureForStopWithMessage:(TGMessage *)message remaining:(SSignal *)remaining -{ - bool changed = message.mid != _messageId; - _messageId = message.mid; - - UIImage *icon = TGComponentsImageNamed(@"LocationMessagePinIcon"); - if (_pallete != nil) - icon = TGTintedImage(icon, _pallete.iconColor); - - _iconView.image = icon; - - _titleLabel.textColor = self.pallete != nil ? self.pallete.destructiveColor : UIColorRGB(0xff3b2f); - _titleLabel.text = TGLocalized(@"Map.StopLiveLocation"); - _subtitleLabel.text = [TGDateUtils stringForRelativeUpdate:[message actualDate]]; - - _circleView.alpha = 1.0f; - _titleLabel.alpha = 1.0f; - _subtitleLabel.alpha = 1.0f; - - [self setCircleColor:_pallete != nil ? _pallete.liveLocationColor : UIColorRGB(0xff6464)]; - - _separatorView.hidden = true; - _wavesView.hidden = false; - _wavesView.color = self.pallete != nil ? _pallete.iconColor : [UIColor whiteColor]; - [_wavesView start]; - - if (changed) - { - _elapsedView.hidden = false; - [self setNeedsLayout]; - - TGLocationMediaAttachment *locationAttachment = message.locationAttachment; - if (_remainingDisposable == nil) - _remainingDisposable = [[SMetaDisposable alloc] init]; - - __weak TGLocationCurrentLocationCell *weakSelf = self; - [_remainingDisposable setDisposable:[remaining startWithNext:^(NSNumber *next) - { - __strong TGLocationCurrentLocationCell *strongSelf = weakSelf; - if (strongSelf != nil) - [strongSelf->_elapsedView setRemaining:next.intValue period:locationAttachment.period]; - } completed:^ - { - __strong TGLocationCurrentLocationCell *strongSelf = weakSelf; - if (strongSelf != nil) - { - strongSelf->_elapsedView.hidden = true; - [strongSelf setNeedsLayout]; - } - }]]; - } -} - -- (void)configureForCustomLocationWithAddress:(NSString *)address -{ - _messageId = 0; - - UIImage *icon = TGComponentsImageNamed(@"LocationMessagePinIcon"); - if (_pallete != nil) - icon = TGTintedImage(icon, _pallete.iconColor); - _iconView.image = icon; - _titleLabel.textColor = self.pallete != nil ? self.pallete.accentColor : TGAccentColor(); - _elapsedView.hidden = true; - - if (_isCurrentLocation) - { - [UIView transitionWithView:self duration:0.2f options:UIViewAnimationOptionTransitionCrossDissolve animations:^ - { - _titleLabel.text = TGLocalized(@"Map.SendThisLocation"); - _subtitleLabel.text = [self _subtitleForAddress:address]; - - _circleView.alpha = 1.0f; - _titleLabel.alpha = 1.0f; - _subtitleLabel.alpha = 1.0f; - } completion:nil]; - - _isCurrentLocation = false; - } - else - { - [UIView transitionWithView:self duration:0.2f options:UIViewAnimationOptionTransitionCrossDissolve animations:^ - { - _subtitleLabel.text = [self _subtitleForAddress:address]; - } completion:nil]; - } - - [self setCircleColor:_pallete != nil ? _pallete.locationColor : UIColorRGB(0x008df2)]; - - _separatorView.hidden = false; - [_wavesView stop]; - _wavesView.hidden = true; - - [self setNeedsLayout]; -} - -- (void)configureForGroupLocationWithAddress:(NSString *)address -{ - _messageId = 0; - - UIImage *icon = TGComponentsImageNamed(@"LocationMessagePinIcon"); - if (_pallete != nil) - icon = TGTintedImage(icon, _pallete.iconColor); - _iconView.image = icon; - _titleLabel.textColor = self.pallete != nil ? self.pallete.accentColor : TGAccentColor(); - _elapsedView.hidden = true; - - if (_isCurrentLocation) - { - [UIView transitionWithView:self duration:0.2f options:UIViewAnimationOptionTransitionCrossDissolve animations:^ - { - _titleLabel.text = TGLocalized(@"Map.SetThisLocation"); - _subtitleLabel.text = [self _subtitleForAddress:address]; - - _circleView.alpha = 1.0f; - _titleLabel.alpha = 1.0f; - _subtitleLabel.alpha = 1.0f; - } completion:nil]; - - _isCurrentLocation = false; - } - else - { - [UIView transitionWithView:self duration:0.2f options:UIViewAnimationOptionTransitionCrossDissolve animations:^ - { - _subtitleLabel.text = [self _subtitleForAddress:address]; - } completion:nil]; - } - - [self setCircleColor:_pallete != nil ? _pallete.locationColor : UIColorRGB(0x008df2)]; - - _separatorView.hidden = true; - [_wavesView stop]; - _wavesView.hidden = true; - - [self setNeedsLayout]; -} - -- (NSString *)_subtitleForAddress:(NSString *)address -{ - if (address != nil && address.length == 0) - return TGLocalized(@"Map.Unknown"); - else if (address == nil) - return TGLocalized(@"Map.Locating"); - - return address; -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - CGFloat padding = 76.0f; - CGFloat separatorThickness = TGScreenPixel; - - _titleLabel.frame = CGRectMake(padding, 14, self.frame.size.width - padding - 14 - (_elapsedView.hidden ? 0.0f : 38.0f), 20); - _subtitleLabel.frame = CGRectMake(padding, 36, self.frame.size.width - padding - 14 - (_elapsedView.hidden ? 0.0f : 38.0f), 20); - _separatorView.frame = CGRectMake(padding, self.frame.size.height - separatorThickness, self.frame.size.width - padding, separatorThickness); - _elapsedView.frame = CGRectMake(self.frame.size.width - 30.0f - 15.0f, floor((self.frame.size.height - 30.0f) / 2.0f), 30.0f, 30.0f); -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationInfoCell.h b/submodules/LegacyComponents/Sources/TGLocationInfoCell.h deleted file mode 100644 index 97fbe5fcce..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationInfoCell.h +++ /dev/null @@ -1,23 +0,0 @@ -#import -#import - -@class TGLocationMediaAttachment; -@class TGLocationPallete; - -@interface TGLocationInfoCell : UITableViewCell - -@property (nonatomic, strong) TGLocationPallete *pallete; -@property (nonatomic, assign) UIEdgeInsets safeInset; - -@property (nonatomic, copy) void (^locatePressed)(void); -@property (nonatomic, copy) void (^directionsPressed)(void); - -@property (nonatomic, readonly) UIButton *directionsButton; - -- (void)setLocation:(TGLocationMediaAttachment *)location color:(UIColor *)color messageId:(int32_t)messageId userLocationSignal:(SSignal *)userLocationSignal; - -@end - -extern NSString *const TGLocationInfoCellKind; -extern const CGFloat TGLocationInfoCellHeight; - diff --git a/submodules/LegacyComponents/Sources/TGLocationInfoCell.m b/submodules/LegacyComponents/Sources/TGLocationInfoCell.m deleted file mode 100644 index 46064ac1da..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationInfoCell.m +++ /dev/null @@ -1,357 +0,0 @@ -#import "TGLocationInfoCell.h" -#import "TGLocationVenueCell.h" - -#import "TGLocationMapViewController.h" -#import "TGLocationSignals.h" -#import "TGLocationUtils.h" -#import "TGLocationReverseGeocodeResult.h" - -#import "TGLocationMediaAttachment.h" - -#import "LegacyComponentsInternal.h" -#import "TGColor.h" -#import "TGFont.h" -#import "TGImageUtils.h" - -#import "TGImageView.h" -#import "TGModernButton.h" - -NSString *const TGLocationInfoCellKind = @"TGLocationInfoCell"; -const CGFloat TGLocationInfoCellHeight = 134.0f; - -@interface TGLocationInfoCell () -{ - TGModernButton *_locateButton; - UIImageView *_circleView; - TGImageView *_iconView; - - UILabel *_titleLabel; - UILabel *_addressLabel; - - TGModernButton *_directionsButton; - UILabel *_directionsButtonLabel; - UILabel *_etaLabel; - - SMetaDisposable *_addressDisposable; - int32_t _messageId; -} -@end - -@implementation TGLocationInfoCell - -- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier -{ - self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; - if (self != nil) - { - _messageId = -1; - - _locateButton = [[TGModernButton alloc] init]; - [_locateButton addTarget:self action:@selector(locateButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - [self.contentView addSubview:_locateButton]; - - _circleView = [[UIImageView alloc] init]; - [_circleView setImage:TGTintedImage([TGLocationVenueCell circleImage], UIColorRGB(0x008df2))]; - [_locateButton addSubview:_circleView]; - - _iconView = [[TGImageView alloc] init]; - _iconView.contentMode = UIViewContentModeCenter; - _iconView.image = TGComponentsImageNamed(@"LocationMessagePinIcon"); - [_circleView addSubview:_iconView]; - - _titleLabel = [[UILabel alloc] init]; - _titleLabel.font = TGBoldSystemFontOfSize(17.0f); - _titleLabel.textColor = [UIColor blackColor]; - [_locateButton addSubview:_titleLabel]; - - _addressLabel = [[UILabel alloc] init]; - _addressLabel.font = TGSystemFontOfSize(13); - _addressLabel.textColor = UIColorRGB(0x8e8e93); - [_locateButton addSubview:_addressLabel]; - - static dispatch_once_t onceToken; - static UIImage *buttonImage = nil; - dispatch_once(&onceToken, ^ - { - CGSize size = CGSizeMake(16.0f, 16.0f); - UIGraphicsBeginImageContextWithOptions(size, false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetStrokeColorWithColor(context, TGAccentColor().CGColor); - CGContextSetLineWidth(context, 1.0f); - CGContextStrokeEllipseInRect(context, CGRectMake(0.5f, 0.5f, size.width - 1.0f, size.height - 1.0f)); - buttonImage = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:(NSInteger)(size.width / 2.0f) topCapHeight:(NSInteger)(size.height / 2.0f)]; - UIGraphicsEndImageContext(); - }); - - _directionsButton = [[TGModernButton alloc] init]; - _directionsButton.adjustsImageWhenHighlighted = false; - [_directionsButton setBackgroundImage:buttonImage forState:UIControlStateNormal]; - [_directionsButton addTarget:self action:@selector(directionsButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - [self.contentView addSubview:_directionsButton]; - - _directionsButtonLabel = [[UILabel alloc] init]; - _directionsButtonLabel.backgroundColor = [UIColor clearColor]; - _directionsButtonLabel.font = TGBoldSystemFontOfSize(17.0f); - _directionsButtonLabel.text = TGLocalized(@"Map.Directions"); - _directionsButtonLabel.textAlignment = NSTextAlignmentCenter; - _directionsButtonLabel.textColor = TGAccentColor(); - _directionsButtonLabel.userInteractionEnabled = false; - [_directionsButtonLabel sizeToFit]; - [_directionsButton addSubview:_directionsButtonLabel]; - - _etaLabel = [[UILabel alloc] init]; - _etaLabel.alpha = 0.0f; - _etaLabel.font = TGSystemFontOfSize(13); - _etaLabel.textAlignment = NSTextAlignmentCenter; - _etaLabel.textColor = TGAccentColor(); - _etaLabel.userInteractionEnabled = false; - [_directionsButton addSubview:_etaLabel]; - } - return self; -} - -- (void)dealloc -{ - [_addressDisposable dispose]; -} - -- (void)setPallete:(TGLocationPallete *)pallete -{ - if (pallete == nil || _pallete == pallete) - return; - - _pallete = pallete; - - self.backgroundColor = pallete.backgroundColor; - [_circleView setImage:TGTintedImage([TGLocationVenueCell circleImage], _pallete.locationColor)]; - _titleLabel.textColor = pallete.textColor; - _addressLabel.textColor = pallete.secondaryTextColor; - _directionsButtonLabel.textColor = pallete.accentColor; - _etaLabel.textColor = pallete.accentColor; - - CGSize size = CGSizeMake(16.0f, 16.0f); - UIGraphicsBeginImageContextWithOptions(size, false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetStrokeColorWithColor(context, pallete.accentColor.CGColor); - CGContextSetLineWidth(context, 1.0f); - CGContextStrokeEllipseInRect(context, CGRectMake(0.5f, 0.5f, size.width - 1.0f, size.height - 1.0f)); - UIImage *buttonImage = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:(NSInteger)(size.width / 2.0f) topCapHeight:(NSInteger)(size.height / 2.0f)]; - UIGraphicsEndImageContext(); - - [_directionsButton setBackgroundImage:buttonImage forState:UIControlStateNormal]; -} - -- (void)locateButtonPressed -{ - if (self.locatePressed != nil) - self.locatePressed(); -} - -- (void)directionsButtonPressed -{ - if (self.directionsPressed != nil) - self.directionsPressed(); -} - -- (UIButton *)directionsButton -{ - return _directionsButton; -} - -- (void)setLocation:(TGLocationMediaAttachment *)location color:(UIColor *)color messageId:(int32_t)messageId userLocationSignal:(SSignal *)userLocationSignal -{ - if (_messageId == messageId) - return; - - _messageId = messageId; - - _titleLabel.text = location.venue.title.length > 0 ? location.venue.title : TGLocalized(@"Map.Location"); - - UIColor *pinColor = _pallete != nil ? _pallete.iconColor : [UIColor whiteColor]; - if (color != nil) { - [_circleView setImage:TGTintedImage([TGLocationVenueCell circleImage], color)]; - pinColor = [UIColor whiteColor]; - } - - if (location.venue.type.length > 0 && [location.venue.provider isEqualToString:@"foursquare"]) - [_iconView loadUri:[NSString stringWithFormat:@"location-venue-icon://type=%@&width=%d&height=%d&color=%d", location.venue.type, 48, 48, TGColorHexCode(pinColor)] withOptions:nil]; - - SSignal *addressSignal = [SSignal single:@""]; - if (location.venue.address.length > 0) - { - addressSignal = [SSignal single:location.venue.address]; - } - else - { - addressSignal = [[[TGLocationSignals reverseGeocodeCoordinate:CLLocationCoordinate2DMake(location.latitude, location.longitude)] map:^id(TGLocationReverseGeocodeResult *result) - { - return [result displayAddress]; - }] catch:^SSignal *(__unused id error) - { - return [SSignal single:[TGLocationUtils stringForCoordinate:CLLocationCoordinate2DMake(location.latitude, location.longitude)]]; - }]; - addressSignal = [[SSignal single:TGLocalized(@"Map.Locating")] then:addressSignal]; - } - - CLLocation *pointLocation = [[CLLocation alloc] initWithLatitude:location.latitude longitude:location.longitude]; - - if (_addressDisposable == nil) - _addressDisposable = [[SMetaDisposable alloc] init]; - - SSignal *updatedLocationSignal = [userLocationSignal reduceLeftWithPassthrough:nil with:^id(CLLocation *previous, CLLocation *next, void (^emit)(id)) - { - if (next == nil) - return nil; - - if (previous == nil && next != nil) - { - emit(@{@"location":next, @"update":@true}); - return next; - } - else - { - bool update = [next distanceFromLocation:previous] > 100; - emit(@{@"location":next, @"update":@(update)}); - return update ? next : previous; - } - }]; - - SSignal *signal = [[SSignal combineSignals:@[addressSignal, updatedLocationSignal] withInitialStates:@[ TGLocalized(@"Map.Locating"), [NSNull null] ]] mapToSignal:^SSignal *(NSArray *results) - { - NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; - dict[@"address"] = results.firstObject; - - if (![results.lastObject isKindOfClass:[NSNull class]]) - { - CLLocation *newLocation = ((NSDictionary *)results.lastObject)[@"location"]; - bool updateEta = [((NSDictionary *)results.lastObject)[@"update"] boolValue]; - dict[@"distance"] = @([pointLocation distanceFromLocation:newLocation]); - - if (updateEta) - { - return [[SSignal single:dict] then:[[TGLocationSignals driveEta:pointLocation.coordinate] map:^id(NSNumber *eta) - { - NSMutableDictionary *newDict = [dict mutableCopy]; - newDict[@"eta"] = eta; - return newDict; - }]]; - } - } - - return [SSignal single:dict]; - }]; - - __weak TGLocationInfoCell *weakSelf = self; - [_addressDisposable setDisposable:[[signal deliverOn:[SQueue mainQueue]] startWithNext:^(NSDictionary *next) - { - __strong TGLocationInfoCell *strongSelf = weakSelf; - if (strongSelf != nil) - { - NSString *address = next[@"address"]; - CGFloat distanceValue = [next[@"distance"] doubleValue]; - NSString *distance = next[@"distance"] ? [NSString stringWithFormat:TGLocalized(@"Map.DistanceAway"), [TGLocationUtils stringFromDistance:distanceValue]] : nil; - if (next[@"distance"] != nil && distanceValue < 10) - distance = TGLocalized(@"Map.YouAreHere"); - - if (next[@"eta"] != nil) - [strongSelf setDrivingETA:[next[@"eta"] doubleValue]]; - - NSMutableArray *components = [[NSMutableArray alloc] init]; - if (address.length > 0) - [components addObject:address]; - if (distance.length > 0) - [components addObject:distance]; - - NSString *string = [components componentsJoinedByString:@" • "]; - if ([strongSelf->_addressLabel.text isEqualToString:string]) - return; - - if (strongSelf->_addressLabel.text.length == 0) - { - strongSelf->_addressLabel.text = string; - } - else - { - [UIView transitionWithView:strongSelf->_addressLabel duration:0.2 options:UIViewAnimationOptionTransitionCrossDissolve animations:^ - { - strongSelf->_addressLabel.text = string; - } completion:nil]; - } - } - }]]; -} - -- (void)setDrivingETA:(NSTimeInterval)drivingETA -{ - if (drivingETA > 0 && drivingETA < 60 * 60 * 10) - { - drivingETA = MAX(drivingETA, 60); - - NSInteger minutes = (NSInteger)(drivingETA / 60) % 60; - NSInteger hours = (NSInteger)(drivingETA / 3600.0f); - - NSString *string = nil; - - if (hours < 1) - { - string = [NSString stringWithFormat:TGLocalized(@"Map.ETAMinutes_any"), [NSString stringWithFormat:@"%d", (int)minutes]]; - } - else - { - if (hours == 1 && minutes == 0) - { - string = [NSString stringWithFormat:TGLocalized(@"Map.ETAHours_1"), @"1"]; - } - else - { - string = [NSString stringWithFormat:TGLocalized(@"Map.ETAHours_any"), [NSString stringWithFormat:@"%d:%02d", (int)hours, (int)minutes]]; - } - } - - string = [NSString stringWithFormat:TGLocalized(@"Map.DirectionsDriveEta"), string]; - - if ([_etaLabel.text isEqualToString:string]) - return; - - if (_etaLabel.text.length == 0) - { - _etaLabel.text = string; - [UIView animateWithDuration:0.3 animations:^ - { - _etaLabel.alpha = 1.0f; - [self layoutSubviews]; - }]; - } - else - { - [UIView transitionWithView:_etaLabel duration:0.2 options:UIViewAnimationOptionTransitionCrossDissolve animations:^ - { - _etaLabel.text = string; - } completion:nil]; - } - } -} - -- (void)setSafeInset:(UIEdgeInsets)safeInset -{ - _safeInset = safeInset; - [self setNeedsLayout]; -} - -- (void)layoutSubviews -{ - _locateButton.frame = CGRectMake(0.0f, 0.0f, self.frame.size.width, 60.0f); - _circleView.frame = CGRectMake(12.0f + self.safeInset.left, 12.0f, 48.0f, 48.0f); - _iconView.frame = _circleView.bounds; - - _titleLabel.frame = CGRectMake(76.0f + self.safeInset.left, 15.0f, self.frame.size.width - 76.0f - 12.0f - self.safeInset.left - self.safeInset.right, 20.0f); - _addressLabel.frame = CGRectMake(76.0f + self.safeInset.left, 38.0f, self.frame.size.width - 76.0f - 12.0f - self.safeInset.left - self.safeInset.right, 20.0f); - - _directionsButton.frame = CGRectMake(12.0f + self.safeInset.left, 72.0f, self.frame.size.width - 12.0f * 2.0f - self.safeInset.left - self.safeInset.right, 50.0f); - - bool hasEta = _etaLabel.text.length > 0; - _directionsButtonLabel.frame = CGRectMake(0.0f, hasEta ? 6.0f : 14.0f, _directionsButton.frame.size.width, _directionsButtonLabel.frame.size.height); - _etaLabel.frame = CGRectMake(0.0f, hasEta ? 25.0f : 20.0f, _directionsButton.frame.size.width, 20.0f); -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationLiveCell.h b/submodules/LegacyComponents/Sources/TGLocationLiveCell.h deleted file mode 100644 index 362cbd6ebb..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationLiveCell.h +++ /dev/null @@ -1,24 +0,0 @@ -#import -#import - -@class TGUser; -@class TGMessage; -@class TGLocationPallete; - -@interface TGLocationLiveCell : UITableViewCell - -@property (nonatomic, strong) TGLocationPallete *pallete; -@property (nonatomic, assign) UIEdgeInsets safeInset; -@property (nonatomic, copy) void (^longPressed)(void); - -@property (nonatomic, readonly) int32_t messageId; -@property (nonatomic, weak) UIImageView *edgeView; - -- (void)configureWithPeer:(id)peer message:(TGMessage *)message remaining:(SSignal *)remaining userLocationSignal:(SSignal *)userLocationSignal; -- (void)configureForStart; -- (void)configureForStopWithMessage:(TGMessage *)message remaining:(SSignal *)remaining; - -@end - -extern NSString *const TGLocationLiveCellKind; -extern const CGFloat TGLocationLiveCellHeight; diff --git a/submodules/LegacyComponents/Sources/TGLocationLiveCell.m b/submodules/LegacyComponents/Sources/TGLocationLiveCell.m deleted file mode 100644 index 9967dff4f5..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationLiveCell.m +++ /dev/null @@ -1,361 +0,0 @@ -#import "TGLocationLiveCell.h" -#import "TGLocationVenueCell.h" - -#import "TGLocationMapViewController.h" -#import "LegacyComponentsInternal.h" -#import "TGFont.h" -#import "TGColor.h" -#import "TGImageUtils.h" -#import "TGDateUtils.h" -#import "TGLocationUtils.h" - -#import "TGUser.h" -#import "TGMessage.h" -#import "TGConversation.h" -#import "TGLocationMediaAttachment.h" - -#import "TGLetteredAvatarView.h" -#import "TGLocationWavesView.h" -#import "TGLocationLiveElapsedView.h" - -NSString *const TGLocationLiveCellKind = @"TGLocationLiveCell"; -const CGFloat TGLocationLiveCellHeight = 68; - -@interface TGLocationLiveCell () -{ - UIView *_highlightView; - - UIImageView *_circleView; - UIImageView *_iconView; - TGLocationWavesView *_wavesView; - TGLetteredAvatarView *_avatarView; - - UILabel *_titleLabel; - UILabel *_subtitleLabel; - TGLocationLiveElapsedView *_elapsedView; - - UIView *_separatorView; - - SMetaDisposable *_locationDisposable; - SMetaDisposable *_remainingDisposable; - - UILongPressGestureRecognizer *_longPressGestureRecognizer; -} -@end - -@implementation TGLocationLiveCell - -- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier -{ - self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; - if (self != nil) - { - self.selectedBackgroundView = [[UIView alloc] init]; - self.selectedBackgroundView.backgroundColor = [UIColor clearColor]; - - _highlightView = [[UIView alloc] initWithFrame:self.bounds]; - _highlightView.alpha = 0.0f; - _highlightView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - _highlightView.backgroundColor = TGSelectionColor(); - _highlightView.userInteractionEnabled = false; - [self.contentView addSubview:_highlightView]; - - _circleView = [[UIImageView alloc] init]; - [self.contentView addSubview:_circleView]; - - _iconView = [[UIImageView alloc] init]; - _iconView.contentMode = UIViewContentModeCenter; - [_circleView addSubview:_iconView]; - - _avatarView = [[TGLetteredAvatarView alloc] init]; - [_avatarView setSingleFontSize:22.0f doubleFontSize:22.0f useBoldFont:false]; - [self.contentView addSubview:_avatarView]; - - _titleLabel = [[UILabel alloc] init]; - _titleLabel = [[UILabel alloc] init]; - _titleLabel.backgroundColor = [UIColor clearColor]; - _titleLabel.font = TGBoldSystemFontOfSize(16.0); - _titleLabel.text = TGLocalized(@"Map.SendMyCurrentLocation"); - _titleLabel.textColor = TGAccentColor(); - [self.contentView addSubview:_titleLabel]; - - _subtitleLabel = [[UILabel alloc] init]; - _subtitleLabel.backgroundColor = [UIColor clearColor]; - _subtitleLabel.font = TGSystemFontOfSize(13); - _subtitleLabel.text = TGLocalized(@"Map.Locating"); - _subtitleLabel.textColor = UIColorRGB(0xa6a6a6); - [self.contentView addSubview:_subtitleLabel]; - - _elapsedView = [[TGLocationLiveElapsedView alloc] init]; - [self.contentView addSubview:_elapsedView]; - - _separatorView = [[UIView alloc] init]; - _separatorView.backgroundColor = TGSeparatorColor(); - [self addSubview:_separatorView]; - - _wavesView = [[TGLocationWavesView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 48.0f, 48.0f)]; - [_circleView addSubview:_wavesView]; - - _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlePress:)]; - [self addGestureRecognizer:_longPressGestureRecognizer]; - } - return self; -} - -- (void)dealloc -{ - [_locationDisposable dispose]; - [_wavesView invalidate]; -} - -- (void)setPallete:(TGLocationPallete *)pallete -{ - if (pallete == nil || _pallete == pallete) - return; - - _pallete = pallete; - - self.backgroundColor = pallete.backgroundColor; - _highlightView.backgroundColor = pallete.selectionColor; - _titleLabel.textColor = pallete.accentColor; - _subtitleLabel.textColor = pallete.secondaryTextColor; - _separatorView.backgroundColor = pallete.separatorColor; - _wavesView.color = pallete.iconColor; - [_elapsedView setColor:pallete.accentColor]; -} - -- (void)handlePress:(UILongPressGestureRecognizer *)gestureRecognizer -{ - if (gestureRecognizer.state == UIGestureRecognizerStateBegan) - { - if (self.longPressed != nil) - self.longPressed(); - } -} - -- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated -{ - if (animated) - { - [UIView animateWithDuration:0.2 animations:^ - { - _highlightView.alpha = highlighted ? 1.0f : 0.0f; - _edgeView.alpha = highlighted ? 1.0f : 0.0f; - }]; - } - else - { - _highlightView.alpha = highlighted ? 1.0f : 0.0f; - _edgeView.alpha = highlighted ? 1.0f : 0.0f; - } -} - -- (void)configureWithPeer:(id)peer message:(TGMessage *)message remaining:(SSignal *)remaining userLocationSignal:(SSignal *)userLocationSignal -{ - bool changed = message.mid != _messageId; - _messageId = message.mid; - - _circleView.hidden = true; - _avatarView.hidden = false; - - CGFloat diameter = 48.0f; - - static UIImage *staticPlaceholder = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^ - { - UIGraphicsBeginImageContextWithOptions(CGSizeMake(diameter, diameter), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - - //!placeholder - CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); - CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, diameter, diameter)); - CGContextSetStrokeColorWithColor(context, UIColorRGB(0xd9d9d9).CGColor); - CGContextSetLineWidth(context, 1.0f); - CGContextStrokeEllipseInRect(context, CGRectMake(0.5f, 0.5f, diameter - 1.0f, diameter - 1.0f)); - - staticPlaceholder = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - }); - - UIImage *placeholder = _pallete != nil ? _pallete.avatarPlaceholder : staticPlaceholder; - - bool isUser = [peer isKindOfClass:[TGUser class]]; - NSString *avatarUrl = isUser ? ((TGUser *)peer).photoFullUrlSmall : ((TGConversation *)peer).chatPhotoFullSmall; - if (avatarUrl.length != 0) - { - _avatarView.fadeTransitionDuration = 0.3; - if (![avatarUrl isEqualToString:_avatarView.currentUrl]) - [_avatarView loadImage:avatarUrl filter:@"circle:48x48" placeholder:placeholder]; - } - else - { - if (isUser) - { - [_avatarView loadUserPlaceholderWithSize:CGSizeMake(diameter, diameter) uid:((TGUser *)peer).uid firstName:((TGUser *)peer).firstName lastName:((TGUser *)peer).lastName placeholder:placeholder]; - } - else - { - [_avatarView loadGroupPlaceholderWithSize:CGSizeMake(diameter, diameter) conversationId:((TGConversation *)peer).conversationId title:((TGConversation *)peer).chatTitle placeholder:placeholder]; - } - } - - _titleLabel.textColor = _pallete != nil ? _pallete.textColor : [UIColor blackColor]; - _titleLabel.text = isUser ? ((TGUser *)peer).displayName : ((TGConversation *)peer).chatTitle; - - NSString *subtitle = [TGDateUtils stringForRelativeUpdate:[message actualDate]]; - _subtitleLabel.text = subtitle; - - TGLocationMediaAttachment *locationAttachment = message.locationAttachment; - CLLocation *location = [[CLLocation alloc] initWithLatitude:locationAttachment.latitude longitude:locationAttachment.longitude]; - __weak TGLocationLiveCell *weakSelf = self; - if (_locationDisposable == nil) - _locationDisposable = [[SMetaDisposable alloc] init]; - [_locationDisposable setDisposable:[userLocationSignal startWithNext:^(CLLocation *next) - { - __strong TGLocationLiveCell *strongSelf = weakSelf; - if (strongSelf != nil && next != nil) - { - CGFloat distance = [next distanceFromLocation:location]; - NSString *distanceString = [NSString stringWithFormat:TGLocalized(@"Map.DistanceAway"), [TGLocationUtils stringFromDistance:distance]]; - strongSelf->_subtitleLabel.text = [NSString stringWithFormat:@"%@ • %@", subtitle, distanceString]; - } - }]]; - - if (changed) - { - _elapsedView.hidden = false; - - _avatarView.alpha = 1.0f; - [self setNeedsLayout]; - - if (_remainingDisposable == nil) - _remainingDisposable = [[SMetaDisposable alloc] init]; - - [_remainingDisposable setDisposable:[remaining startWithNext:^(NSNumber *next) - { - __strong TGLocationLiveCell *strongSelf = weakSelf; - if (strongSelf != nil) - [strongSelf->_elapsedView setRemaining:next.intValue period:locationAttachment.period]; - } completed:^ - { - __strong TGLocationLiveCell *strongSelf = weakSelf; - if (strongSelf != nil) - { - strongSelf->_elapsedView.hidden = true; - strongSelf->_avatarView.alpha = 0.5f; - [strongSelf setNeedsLayout]; - } - }]]; - } -} - -- (void)configureForStart -{ - _messageId = 0; - - _avatarView.hidden = true; - _circleView.hidden = false; - _elapsedView.hidden = true; - - UIImage *icon = TGComponentsImageNamed(@"LocationMessageLiveIcon"); - if (_pallete != nil) - icon = TGTintedImage(icon, _pallete.iconColor); - - _iconView.image = icon; - [self setCircleColor:_pallete != nil ? _pallete.liveLocationColor : UIColorRGB(0xff6464)]; - - _titleLabel.textColor = _pallete != nil ? _pallete.accentColor : TGAccentColor(); - _titleLabel.text = TGLocalized(@"Map.ShareLiveLocation"); - _subtitleLabel.text = TGLocalized(@"Map.ShareLiveLocationHelp"); - - [_wavesView stop]; - _wavesView.hidden = true; - - [_locationDisposable setDisposable:nil]; - [_remainingDisposable setDisposable:nil]; - - [self setNeedsLayout]; -} - -- (void)configureForStopWithMessage:(TGMessage *)message remaining:(SSignal *)remaining -{ - bool changed = message.mid != _messageId; - _messageId = message.mid; - - _avatarView.hidden = true; - _circleView.hidden = false; - - UIImage *icon = TGComponentsImageNamed(@"LocationMessagePinIcon"); - if (_pallete != nil) - icon = TGTintedImage(icon, _pallete.iconColor); - _iconView.image = icon; - [self setCircleColor:_pallete != nil ? _pallete.liveLocationColor : UIColorRGB(0xff6464)]; - - _titleLabel.textColor = _pallete != nil ? _pallete.destructiveColor : UIColorRGB(0xff3b2f); - _titleLabel.text = TGLocalized(@"Map.StopLiveLocation"); - _subtitleLabel.text = [TGDateUtils stringForRelativeUpdate:[message actualDate]]; - - _wavesView.hidden = false; - _wavesView.color = _pallete != nil ? _pallete.iconColor : [UIColor whiteColor]; - [_wavesView start]; - - [_locationDisposable setDisposable:nil]; - - if (changed) - { - _elapsedView.hidden = false; - [self setNeedsLayout]; - - TGLocationMediaAttachment *locationAttachment = message.locationAttachment; - if (_remainingDisposable == nil) - _remainingDisposable = [[SMetaDisposable alloc] init]; - - __weak TGLocationLiveCell *weakSelf = self; - [_remainingDisposable setDisposable:[remaining startWithNext:^(NSNumber *next) - { - __strong TGLocationLiveCell *strongSelf = weakSelf; - if (strongSelf != nil) - [strongSelf->_elapsedView setRemaining:next.intValue period:locationAttachment.period]; - } completed:^ - { - __strong TGLocationLiveCell *strongSelf = weakSelf; - if (strongSelf != nil) - { - strongSelf->_elapsedView.hidden = true; - [strongSelf setNeedsLayout]; - } - }]]; - } -} - -- (void)setCircleColor:(UIColor *)color -{ - UIImage *circleImage = [TGLocationVenueCell circleImage]; - _circleView.image = TGTintedImage(circleImage, color); -} - -- (void)setSafeInset:(UIEdgeInsets)safeInset -{ - _safeInset = safeInset; - [self setNeedsLayout]; -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - _circleView.frame = CGRectMake(12.0f + self.safeInset.left, 12.0f, 48.0f, 48.0f); - _iconView.frame = _circleView.bounds; - _avatarView.frame = _circleView.frame; - - CGFloat padding = 76.0f + self.safeInset.left; - CGFloat separatorThickness = TGScreenPixel; - - _titleLabel.frame = CGRectMake(padding, 14, self.frame.size.width - padding - 14 - (_elapsedView.hidden ? 0.0f : 38.0f) - self.safeInset.right, 20); - _subtitleLabel.frame = CGRectMake(padding, 36, self.frame.size.width - padding - 14 - (_elapsedView.hidden ? 0.0f : 38.0f) - self.safeInset.right, 20); - _separatorView.frame = CGRectMake(padding, self.frame.size.height - separatorThickness, self.frame.size.width - padding, separatorThickness); - _elapsedView.frame = CGRectMake(self.frame.size.width - 30.0f - 15.0f - self.safeInset.right, floor((self.frame.size.height - 30.0f) / 2.0f), 30.0f, 30.0f); -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationLiveElapsedView.m b/submodules/LegacyComponents/Sources/TGLocationLiveElapsedView.m deleted file mode 100644 index ef3633a778..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationLiveElapsedView.m +++ /dev/null @@ -1,101 +0,0 @@ -#import "TGLocationLiveElapsedView.h" - -#import "LegacyComponentsInternal.h" -#import "TGColor.h" -#import "TGFont.h" - -@interface TGLocationLiveElapsedView () -{ - UIColor *_color; - CGFloat _progress; - NSString *_string; -} -@end - -@implementation TGLocationLiveElapsedView - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - _color = TGAccentColor(); - self.backgroundColor = [UIColor clearColor]; - self.contentMode = UIViewContentModeRedraw; - } - return self; -} - -- (void)setColor:(UIColor *)color -{ - _color = color; - [self setNeedsDisplay]; -} - -- (void)setRemaining:(int32_t)remaining period:(int32_t)period; -{ - NSString *string = nil; - int32_t minutes = ceil(remaining / 60.0f); - if (minutes >= 60) - { - int32_t hours = ceil(remaining / 3600.0f); - string = [[NSString alloc] initWithFormat:TGLocalized(@"Map.LiveLocationShortHour"), [[NSString alloc] initWithFormat:@"%d", hours]]; - } - else - { - string = [[NSString alloc] initWithFormat:@"%d", minutes]; - } - _progress = remaining / (CGFloat)period; - if (_progress > 1.0f - FLT_EPSILON) - _progress = 0.999f; - _string = string; - [self setNeedsDisplay]; -} - -- (void)drawRect:(CGRect)rect -{ - CGRect allRect = self.bounds; - CGContextRef context = UIGraphicsGetCurrentContext(); - - CGContextSetFillColorWithColor(context, _color.CGColor); - CGContextSetStrokeColorWithColor(context, _color.CGColor); - CGContextSetLineWidth(context, 1.5f); - CGContextSetLineCap(context, kCGLineCapRound); - CGContextSetLineJoin(context, kCGLineJoinMiter); - CGContextSetMiterLimit(context, 10); - - CGPoint center = CGPointMake(allRect.size.width / 2, allRect.size.height / 2); - CGFloat radius = 13.0f; - - CGContextSetAlpha(context, 0.2f); - CGContextStrokeEllipseInRect(context, CGRectMake(center.x - radius, center.y - radius, radius * 2, radius * 2)); - CGContextSetAlpha(context, 1.0f); - - CGFloat startAngle = -M_PI_2; - CGFloat endAngle = -M_PI_2 + 2 * M_PI * (1.0f - _progress); - - CGMutablePathRef path = CGPathCreateMutable(); - CGPathAddArc(path, NULL, center.x, center.y, radius, startAngle, endAngle, true); - CGContextAddPath(context, path); - CGPathRelease(path); - CGContextStrokePath(context); - - UIFont *font = [TGFont roundedFontOfSize:14.0f]; - if (font == nil) { - font = [UIFont systemFontOfSize:14.0]; - } - NSDictionary *attributes = @{ NSFontAttributeName: font, NSForegroundColorAttributeName: _color }; - CGSize size = iosMajorVersion() >= 7 ? [_string sizeWithAttributes:attributes] : [_string sizeWithFont:attributes[NSFontAttributeName]]; - if (iosMajorVersion() >= 7) - { - [_string drawAtPoint:CGPointMake((allRect.size.width - size.width) / 2.0f, floor((allRect.size.height - size.height) / 2.0f)) withAttributes:attributes]; - } - else - { - CGContextSetFillColorWithColor(context, _color.CGColor); - [_string drawAtPoint:CGPointMake((allRect.size.width - size.width) / 2.0f, floor((allRect.size.height - size.height) / 2.0f)) forWidth:FLT_MAX withFont:font lineBreakMode:NSLineBreakByWordWrapping]; - } -} - -@end - diff --git a/submodules/LegacyComponents/Sources/TGLocationLiveSessionItemView.m b/submodules/LegacyComponents/Sources/TGLocationLiveSessionItemView.m deleted file mode 100644 index 98d3bfc810..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationLiveSessionItemView.m +++ /dev/null @@ -1,127 +0,0 @@ -#import "TGLocationLiveSessionItemView.h" - -#import "LegacyComponentsInternal.h" - -#import "TGUser.h" -#import "TGConversation.h" - -#import "TGLetteredAvatarView.h" -#import "TGLocationLiveElapsedView.h" - -@interface TGLocationLiveSessionItemView () -{ - TGLetteredAvatarView *_avatarView; - TGLocationLiveElapsedView *_elapsedView; - UILabel *_label; - id _disposable; -} -@end - -@implementation TGLocationLiveSessionItemView - -- (instancetype)initWithMessage:(TGMessage *)message peer:(id)peer remaining:(SSignal *)remaining action:(void (^)(void))action -{ - bool isUser = [peer isKindOfClass:[TGUser class]]; - NSString *title = isUser ? ((TGUser *)peer).displayName : ((TGConversation *)peer).chatTitle; - self = [super initWithTitle:@"" type:TGMenuSheetButtonTypeDefault fontSize:20.0 action:action]; - if (self != nil) - { - _label = [[UILabel alloc] init]; - _label.backgroundColor = [UIColor clearColor]; - _label.font = _button.titleLabel.font; - _label.textColor = [UIColor blackColor]; - _label.text = title; - [_label sizeToFit]; - [_button addSubview:_label]; - - _avatarView = [[TGLetteredAvatarView alloc] init]; - [_avatarView setSingleFontSize:18.0f doubleFontSize:18.0f useBoldFont:false]; - [self addSubview:_avatarView]; - - CGFloat diameter = 36.0f; - - static UIImage *placeholder = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^ - { - UIGraphicsBeginImageContextWithOptions(CGSizeMake(diameter, diameter), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - - //!placeholder - CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); - CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, diameter, diameter)); - CGContextSetStrokeColorWithColor(context, UIColorRGB(0xd9d9d9).CGColor); - CGContextSetLineWidth(context, 1.0f); - CGContextStrokeEllipseInRect(context, CGRectMake(0.5f, 0.5f, diameter - 1.0f, diameter - 1.0f)); - - placeholder = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - }); - - NSString *avatarUrl = isUser ? ((TGUser *)peer).photoFullUrlSmall : ((TGConversation *)peer).chatPhotoFullSmall; - if (avatarUrl.length != 0) - { - _avatarView.fadeTransitionDuration = 0.3; - if (![avatarUrl isEqualToString:_avatarView.currentUrl]) - [_avatarView loadImage:avatarUrl filter:@"circle:36x36" placeholder:placeholder]; - } - else - { - if (isUser) - { - [_avatarView loadUserPlaceholderWithSize:CGSizeMake(diameter, diameter) uid:((TGUser *)peer).uid firstName:((TGUser *)peer).firstName lastName:((TGUser *)peer).lastName placeholder:placeholder]; - } - else - { - [_avatarView loadGroupPlaceholderWithSize:CGSizeMake(diameter, diameter) conversationId:((TGConversation *)peer).conversationId title:((TGConversation *)peer).chatTitle placeholder:placeholder]; - } - } - - _elapsedView = [[TGLocationLiveElapsedView alloc] init]; - [self addSubview:_elapsedView]; - - TGLocationMediaAttachment *location = nil; - for (TGMediaAttachment *attachment in message.mediaAttachments) - { - if (attachment.type == TGLocationMediaAttachmentType) - { - location = (TGLocationMediaAttachment *)attachment; - break; - } - } - - __weak TGLocationLiveSessionItemView *weakSelf = self; - _disposable = [remaining startWithNext:^(NSNumber *next) - { - __strong TGLocationLiveSessionItemView *strongSelf = weakSelf; - if (strongSelf != nil) - [strongSelf->_elapsedView setRemaining:next.intValue period:location.period]; - }]; - } - return self; -} - -- (void)dealloc -{ - [_disposable dispose]; -} - -- (void)setPallete:(TGMenuSheetPallete *)pallete -{ - [super setPallete:pallete]; - - _label.textColor = pallete.textColor; - [_elapsedView setColor:pallete.accentColor]; -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - _label.frame = CGRectMake(74.0f, (self.frame.size.height - ceil(_label.frame.size.height)) / 2.0f, self.frame.size.width - 74.0f - 52.0f - 10.0f, ceil(_label.frame.size.height)); - _avatarView.frame = CGRectMake(23.0f, 11.0f, 36.0f, 36.0f); - _elapsedView.frame = CGRectMake(self.frame.size.width - 30.0f - 22.0f, round((self.frame.size.height - 30.0f) / 2.0f), 30.0f, 30.0f); -} - -@end - diff --git a/submodules/LegacyComponents/Sources/TGLocationMapModeControl.h b/submodules/LegacyComponents/Sources/TGLocationMapModeControl.h deleted file mode 100644 index 52d228e358..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationMapModeControl.h +++ /dev/null @@ -1,5 +0,0 @@ -#import - -@interface TGLocationMapModeControl : UISegmentedControl - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationMapModeControl.m b/submodules/LegacyComponents/Sources/TGLocationMapModeControl.m deleted file mode 100644 index 24e5499617..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationMapModeControl.m +++ /dev/null @@ -1,27 +0,0 @@ -#import "TGLocationMapModeControl.h" - -#import "LegacyComponentsInternal.h" -#import "TGFont.h" -#import "TGColor.h" - -@implementation TGLocationMapModeControl - -- (instancetype)init -{ - self = [super initWithItems:@[TGLocalized(@"Map.Map"), TGLocalized(@"Map.Satellite"), TGLocalized(@"Map.Hybrid")]]; - if (self != nil) - { - [self setBackgroundImage:TGComponentsImageNamed(@"ModernSegmentedControlBackground.png") forState:UIControlStateNormal barMetrics:UIBarMetricsDefault]; - [self setBackgroundImage:TGComponentsImageNamed(@"ModernSegmentedControlSelected.png") forState:UIControlStateSelected barMetrics:UIBarMetricsDefault]; - [self setBackgroundImage:TGComponentsImageNamed(@"ModernSegmentedControlSelected.png") forState:UIControlStateSelected | UIControlStateHighlighted barMetrics:UIBarMetricsDefault]; - [self setBackgroundImage:TGComponentsImageNamed(@"ModernSegmentedControlHighlighted.png") forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault]; - UIImage *dividerImage = TGComponentsImageNamed(@"ModernSegmentedControlDivider.png"); - [self setDividerImage:dividerImage forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault]; - - [self setTitleTextAttributes:@{UITextAttributeTextColor: TGAccentColor(), UITextAttributeTextShadowColor: [UIColor clearColor], UITextAttributeFont: TGSystemFontOfSize(13)} forState:UIControlStateNormal]; - [self setTitleTextAttributes:@{UITextAttributeTextColor: [UIColor whiteColor], UITextAttributeTextShadowColor: [UIColor clearColor], UITextAttributeFont: TGSystemFontOfSize(13)} forState:UIControlStateSelected]; - } - return self; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationMapView.h b/submodules/LegacyComponents/Sources/TGLocationMapView.h deleted file mode 100644 index 46786a72e4..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationMapView.h +++ /dev/null @@ -1,17 +0,0 @@ -#import - -@interface TGLocationMapView : MKMapView - -@property (nonatomic, copy) void(^singleTap)(void); - -@property (nonatomic, copy) bool(^customAnnotationTap)(CGPoint); - -@property (nonatomic, assign) bool longPressAsTapEnabled; -@property (nonatomic, assign) bool tapEnabled; -@property (nonatomic, assign) bool manipulationEnabled; - -@property (nonatomic, assign) bool allowAnnotationSelectionChanges; - -@property (nonatomic, assign) UIEdgeInsets compassInsets; - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationMapView.m b/submodules/LegacyComponents/Sources/TGLocationMapView.m deleted file mode 100644 index 754c90e311..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationMapView.m +++ /dev/null @@ -1,114 +0,0 @@ -#import "TGLocationMapView.h" - -@interface TGLocationMapView () -{ - UITapGestureRecognizer *_tapGestureRecognizer; - UILongPressGestureRecognizer *_longPressGestureRecognizer; -} -@end - -@implementation TGLocationMapView - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - _manipulationEnabled = true; - _allowAnnotationSelectionChanges = true; - - _tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tg_handleTap:)]; - _tapGestureRecognizer.numberOfTapsRequired = 1; - _tapGestureRecognizer.numberOfTouchesRequired = 1; - [self addGestureRecognizer:_tapGestureRecognizer]; - - _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(tg_handleLongPress:)]; - _longPressGestureRecognizer.enabled = false; - _longPressGestureRecognizer.minimumPressDuration = 0.2f; - [self addGestureRecognizer:_longPressGestureRecognizer]; - } - return self; -} - -- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer -{ - NSString *viewClass = NSStringFromClass([gestureRecognizer.view class]); - if ([viewClass rangeOfString:@"Compass"].location != NSNotFound) - return true; - - if (self.customAnnotationTap && self.customAnnotationTap([gestureRecognizer locationInView:self])) - return false; - - return self.allowAnnotationSelectionChanges; -} - -- (bool)tapEnabled -{ - return _tapGestureRecognizer.enabled; -} - -- (void)setTapEnabled:(bool)enabled -{ - _tapGestureRecognizer.enabled = enabled; -} - -- (bool)longPressAsTapEnabled -{ - return _longPressGestureRecognizer.enabled; -} - -- (void)setLongPressAsTapEnabled:(bool)enabled -{ - _longPressGestureRecognizer.enabled = enabled; -} - -- (void)tg_handleTap:(UITapGestureRecognizer *)__unused gestureRecognizer -{ - if (self.singleTap != nil) - self.singleTap(); -} - -- (void)tg_handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer -{ - if (gestureRecognizer.state == UIGestureRecognizerStateBegan) - { - if (self.singleTap != nil) - self.singleTap(); - } -} - -- (void)setManipulationEnabled:(bool)enabled -{ - _manipulationEnabled = enabled; - - self.scrollEnabled = enabled; - self.zoomEnabled = enabled; - if ([self respondsToSelector:@selector(setRotateEnabled:)]) - self.rotateEnabled = enabled; - if ([self respondsToSelector:@selector(setPitchEnabled:)]) - self.pitchEnabled = enabled; -} - -- (void)setCompassInsets:(UIEdgeInsets)compassInsets -{ - _compassInsets = compassInsets; - [self setNeedsLayout]; -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - if (UIEdgeInsetsEqualToEdgeInsets(self.compassInsets, UIEdgeInsetsZero)) - return; - - for (UIView *view in self.subviews) - { - if ([NSStringFromClass([view class]) rangeOfString:@"Compass"].location != NSNotFound) - { - view.frame = CGRectMake(self.frame.size.width - self.compassInsets.right - view.frame.size.width, self.compassInsets.top, view.frame.size.width, view.frame.size.height); - } - } -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationMapViewController.m b/submodules/LegacyComponents/Sources/TGLocationMapViewController.m deleted file mode 100644 index 3a02f3c329..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationMapViewController.m +++ /dev/null @@ -1,642 +0,0 @@ -#import "TGLocationMapViewController.h" - -#import "Freedom.h" -#import "LegacyComponentsInternal.h" -#import "TGColor.h" -#import "TGImageUtils.h" -#import "TGFont.h" -#import "TGLocationUtils.h" - -#import "TGUser.h" -#import "TGLocationMapView.h" -#import "TGLocationOptionsView.h" - -#import -#import "TGSearchBar.h" - -const MKCoordinateSpan TGLocationDefaultSpan = { 0.008, 0.008 }; -const CGFloat TGLocationMapClipHeight = 1600.0f; -const CGFloat TGLocationMapInset = 100.0f; - -@interface TGLocationTableView : UITableView - -@end - -@interface TGLocationMapViewController () -{ - id _context; - - UIView *_mapClipView; - - SVariable *_userLocation; - SPipe *_userLocationPipe; - - MKPolygon *_darkPolygon; - - void (^_openLiveLocationMenuBlock)(void); -} -@end - -@implementation TGLocationMapViewController - -- (instancetype)initWithContext:(id)context -{ - self = [super initWithContext:context]; - if (self != nil) - { - _context = context; - _userLocationPipe = [[SPipe alloc] init]; - - _locationManager = [[CLLocationManager alloc] init]; - _locationManager.delegate = self; - - _userLocation = [[SVariable alloc] init]; - [_userLocation set:[[SSignal single:nil] then:_userLocationPipe.signalProducer()]]; - } - return self; -} - -- (void)dealloc -{ - _locationManager.delegate = nil; - _mapView.delegate = nil; - _tableView.dataSource = nil; - _tableView.delegate = nil; -} - -- (void)setPallete:(TGLocationPallete *)pallete { - _pallete = pallete; - if ([self isViewLoaded]) { - self.view.backgroundColor = pallete.backgroundColor; - } -} - -- (void)loadView -{ - [super loadView]; - - self.view.backgroundColor = self.pallete.backgroundColor; - self.alwaysUseTallNavigationBarHeight = true; - - _tableView = [[TGLocationTableView alloc] initWithFrame:self.view.bounds]; - if (iosMajorVersion() >= 11) - _tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; - _tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - _tableView.backgroundColor = self.view.backgroundColor; - _tableView.dataSource = self; - _tableView.delegate = self; - _tableView.separatorStyle = UITableViewCellSeparatorStyleNone; - _tableView.delaysContentTouches = false; - _tableView.canCancelContentTouches = true; - [self.view addSubview:_tableView]; - - _activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; - if (self.pallete != nil) - _activityIndicator.color = self.pallete.secondaryTextColor; - _activityIndicator.userInteractionEnabled = false; - [_tableView addSubview:_activityIndicator]; - - _messageLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 20)]; - _messageLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _messageLabel.backgroundColor = [UIColor clearColor]; - _messageLabel.font = TGSystemFontOfSize(16); - _messageLabel.hidden = true; - _messageLabel.textAlignment = NSTextAlignmentCenter; - _messageLabel.textColor = self.pallete != nil ? self.pallete.secondaryTextColor : UIColorRGB(0x8e8e93); - _messageLabel.userInteractionEnabled = false; - [_tableView addSubview:_messageLabel]; - - _tableViewTopInset = [self mapHeight]; - _mapClipView = [[UIView alloc] initWithFrame:CGRectMake(0, -TGLocationMapClipHeight, self.view.frame.size.width, TGLocationMapClipHeight + 10.0f)]; - _mapClipView.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _mapClipView.clipsToBounds = true; - [_tableView addSubview:_mapClipView]; - - _mapViewWrapper = [[UIView alloc] initWithFrame:CGRectMake(0, TGLocationMapClipHeight - _tableViewTopInset, self.view.frame.size.width, _tableViewTopInset + 10.0f)]; - _mapViewWrapper.autoresizingMask = UIViewAutoresizingFlexibleWidth; - [_mapClipView addSubview:_mapViewWrapper]; - - __weak TGLocationMapViewController *weakSelf = self; - _mapView = [[TGLocationMapView alloc] initWithFrame:CGRectMake(0, -TGLocationMapInset, self.view.frame.size.width, _tableViewTopInset + 2 * TGLocationMapInset + 10.0f)]; - _mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _mapView.delegate = self; - _mapView.showsUserLocation = true; - [_mapViewWrapper addSubview:_mapView]; - - _optionsView = [[TGLocationOptionsView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 45.0f, 90.0f)]; - if (self.pallete != nil) - _optionsView.pallete = self.pallete; - _optionsView.mapModeChanged = ^(NSInteger mapMode) { - __strong TGLocationMapViewController *strongSelf = weakSelf; - if (strongSelf != nil) - [strongSelf->_mapView setMapType:(MKMapType)mapMode]; - - }; - _optionsView.trackModePressed = ^{ - __strong TGLocationMapViewController *strongSelf = weakSelf; - if (strongSelf != nil) - [strongSelf userLocationButtonPressed]; - }; - [self.view addSubview:_optionsView]; - - UIImage *edgeImage = TGComponentsImageNamed(@"LocationPanelEdge"); - UIImage *edgeHighlightImage = TGComponentsImageNamed(@"LocationPanelEdge_Highlighted"); - if (self.pallete != nil) - { - UIGraphicsBeginImageContextWithOptions(edgeImage.size, false, 0.0f); - [edgeImage drawAtPoint:CGPointZero]; - [TGTintedImage(edgeHighlightImage, self.pallete.backgroundColor) drawAtPoint:CGPointZero]; - - edgeImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - } - - _edgeView = [[UIImageView alloc] initWithImage:[edgeImage resizableImageWithCapInsets:UIEdgeInsetsMake(0.0f, 10.0f, 0.0f, 10.0f)]]; - _edgeView.frame = CGRectMake(0.0f, _tableViewTopInset - 10.0f, _mapViewWrapper.frame.size.width, _edgeView.frame.size.height); - [_mapViewWrapper addSubview:_edgeView]; - - if (self.pallete != nil) - edgeHighlightImage = TGTintedImage(edgeHighlightImage, self.pallete.selectionColor); - - _edgeHighlightView = [[UIImageView alloc] initWithImage:[edgeHighlightImage resizableImageWithCapInsets:UIEdgeInsetsMake(0.0f, 10.0f, 0.0f, 10.0f)]]; - _edgeHighlightView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - _edgeHighlightView.frame = _edgeView.bounds; - _edgeHighlightView.alpha = 0.0f; - _edgeHighlightView.image = [edgeHighlightImage resizableImageWithCapInsets:UIEdgeInsetsMake(0.0f, 10.0f, 0.0f, 10.0f)]; - [_edgeView addSubview:_edgeHighlightView]; - - self.scrollViewsForAutomaticInsetsAdjustment = @[ _tableView ]; - - if (![self _updateControllerInset:false]) - [self controllerInsetUpdated:UIEdgeInsetsZero]; -} - -- (void)layoutControllerForSize:(CGSize)size duration:(NSTimeInterval)duration -{ - [super layoutControllerForSize:size duration:duration]; - - if (!self.isViewLoaded) - return; - - [self updateMapHeightAnimated:false]; - _optionsView.frame = CGRectMake(self.view.bounds.size.width - 45.0f - 6.0f - self.controllerSafeAreaInset.right, 56.0f + 6.0f, 45.0f, 90.0f); - _tableView.contentOffset = CGPointMake(0.0f, -_tableViewTopInset - self.controllerInset.top); -} - -- (void)setOptionsViewHidden:(bool)hidden -{ - if (_optionsView.userInteractionEnabled == !hidden) - return; - - _optionsView.userInteractionEnabled = !hidden; - [UIView animateWithDuration:0.15 animations:^ - { - _optionsView.alpha = hidden ? 0.0f : 1.0f; - }]; -} - -- (void)userLocationButtonPressed -{ - -} - -- (bool)hasUserLocation -{ - return (_mapView.userLocation != nil && _mapView.userLocation.location != nil); -} - -- (void)updateLocationAvailability -{ - bool locationAvailable = [self hasUserLocation] || _locationServicesDisabled; - [_optionsView setLocationAvailable:locationAvailable animated:true]; -} - -- (void)scrollViewDidScroll:(UIScrollView *)scrollView -{ - if (scrollView == _tableView) - { - CGFloat offset = scrollView.contentInset.top + scrollView.contentOffset.y; - CGFloat mapOffset = MIN(offset, [self mapHeight]); - _mapView.frame = CGRectMake(_mapView.frame.origin.x, -TGLocationMapInset + mapOffset / 2, _mapView.frame.size.width, _mapView.frame.size.height); - - [self setOptionsViewHidden:(scrollView.contentOffset.y > -180.0f)]; - - CGFloat additionalScrollInset = _edgeView.frame.size.height / 2.0f; - if (scrollView.contentOffset.y < -scrollView.contentInset.top) - additionalScrollInset += -scrollView.contentInset.top - scrollView.contentOffset.y; - - scrollView.scrollIndicatorInsets = UIEdgeInsetsMake(self.controllerScrollInset.top + _tableViewTopInset + additionalScrollInset, 0.0f, 0.0f, 0.0f); - } -} - -- (void)_autoAdjustInsetsForScrollView:(UIScrollView *)scrollView previousInset:(UIEdgeInsets)previousInset -{ - CGPoint contentOffset = scrollView.contentOffset; - - UIEdgeInsets controllerInset = self.controllerInset; - controllerInset.top += _tableViewTopInset; - controllerInset.bottom += _tableViewBottomInset; - - UIEdgeInsets scrollInset = self.controllerScrollInset; - scrollInset.top += _tableViewTopInset; - - scrollView.contentInset = controllerInset; - scrollView.scrollIndicatorInsets = scrollInset; - - if (!UIEdgeInsetsEqualToEdgeInsets(previousInset, UIEdgeInsetsZero)) - { - CGFloat maxOffset = scrollView.contentSize.height - (scrollView.frame.size.height - controllerInset.bottom); - - if (![self shouldAdjustScrollViewInsetsForInversedLayout]) - contentOffset.y += previousInset.top - controllerInset.top; - - contentOffset.y = MAX(-controllerInset.top, MIN(contentOffset.y, maxOffset)); - [scrollView setContentOffset:contentOffset animated:false]; - } - else if (contentOffset.y < controllerInset.top) - { - contentOffset.y = -controllerInset.top; - [scrollView setContentOffset:contentOffset animated:false]; - } - - _optionsView.frame = CGRectMake(self.view.bounds.size.width - 45.0f - 6.0f, 56.0f + 6.0f, 45.0f, 90.0f); -} - -- (NSInteger)tableView:(UITableView *)__unused tableView numberOfRowsInSection:(NSInteger)__unused section -{ - return 0; -} - -- (UITableViewCell *)tableView:(UITableView *)__unused tableView cellForRowAtIndexPath:(NSIndexPath *)__unused indexPath -{ - return nil; -} - -- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath -{ -} - -- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath -{ -} - -- (void)updateInsets -{ - UIEdgeInsets previousInset = _tableView.contentInset; - - CGPoint previousOffset = _tableView.contentOffset; - UIEdgeInsets controllerInset = self.controllerInset; - controllerInset.top += _tableViewTopInset; - controllerInset.bottom += _tableViewBottomInset; - _tableView.contentInset = controllerInset; - - if (previousInset.bottom > FLT_EPSILON) - _tableView.contentOffset = previousOffset; -} - -- (void)updateMapHeightAnimated:(bool)animated -{ - void (^changeBlock)(void) = ^ - { - _tableViewTopInset = [self mapHeight]; - - _mapViewWrapper.frame = CGRectMake(0, TGLocationMapClipHeight - _tableViewTopInset, self.view.frame.size.width, _tableViewTopInset + 10.0f); - _mapView.frame = CGRectMake(0, -TGLocationMapInset, self.view.frame.size.width, _tableViewTopInset + 2 * TGLocationMapInset + 10.0f); - _edgeView.frame = CGRectMake(0.0f, _tableViewTopInset - 10.0f, _mapViewWrapper.frame.size.width, _edgeView.frame.size.height); - - [self updateInsets]; - }; - - if (animated) - { - [UIView animateWithDuration:0.3 delay:0.0 options:7 << 16 animations:^ - { - changeBlock(); - } completion:nil]; - } - else - { - changeBlock(); - } -} - -- (CGFloat)mapHeight -{ - return self.view.frame.size.height - [self visibleContentHeight] - self.controllerInset.top; -} - -- (CGFloat)visibleContentHeight -{ - return 0.0f; -} - -- (CGFloat)safeAreaInsetBottom { - return MAX(self.context.safeAreaInset.bottom, self.controllerSafeAreaInset.bottom); -} - -#pragma mark - - -- (void)setMapCenterCoordinate:(CLLocationCoordinate2D)coordinate offset:(CGPoint)offset animated:(bool)animated -{ - [self setMapCenterCoordinate:coordinate span:TGLocationDefaultSpan offset:offset animated:animated]; -} - -- (void)setMapCenterCoordinate:(CLLocationCoordinate2D)coordinate span:(MKCoordinateSpan)span offset:(CGPoint)offset animated:(bool)animated -{ - @try - { - MKCoordinateRegion region = MKCoordinateRegionMake(coordinate, span); - if (!CGPointEqualToPoint(offset, CGPointZero)) - { - MKMapRect mapRect = [TGLocationUtils MKMapRectForCoordinateRegion:region]; - [_mapView setVisibleMapRect:mapRect edgePadding:UIEdgeInsetsMake(offset.y, offset.x, 0, 0) animated:animated]; - } - else - { - [_mapView setRegion:region animated:animated]; - } - } - @catch (NSException *exception) - { - TGLegacyLog(@"ERROR: failed to set location picker map region with exception: %@", exception); - } -} - -#pragma mark - - -- (UIView *)locationMapView -{ - return _mapView; -} - -- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id)overlay -{ - if (overlay == _darkPolygon) - { - MKPolygonRenderer *renderer = [[MKPolygonRenderer alloc] initWithPolygon:overlay]; - renderer.fillColor = [[UIColor blackColor] colorWithAlphaComponent:0.3f]; - return renderer; - } - - return nil; -} - -- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id )overlay -{ - if ([overlay isKindOfClass:[MKPolygon class]]) - { - MKPolygonView *overlayView = [[MKPolygonView alloc] initWithPolygon:overlay]; - overlayView.fillColor = [[UIColor blackColor] colorWithAlphaComponent:0.3f]; - return overlayView; - } - - return nil; -} - -- (void)mapView:(MKMapView *)__unused mapView didUpdateUserLocation:(MKUserLocation *)userLocation -{ - userLocation.title = @""; - - _locationServicesDisabled = false; - - if (userLocation.location != nil) - _userLocationPipe.sink(userLocation.location); - - [self updateLocationAvailability]; -} - -- (void)mapView:(MKMapView *)__unused mapView didFailToLocateUserWithError:(NSError *)__unused error -{ - if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied || [CLLocationManager authorizationStatus] == kCLAuthorizationStatusRestricted) - { - _userLocationPipe.sink(nil); - _locationServicesDisabled = true; - [self updateLocationAvailability]; - } -} - -- (bool)locationServicesDisabled -{ - return _locationServicesDisabled; -} - -- (SSignal *)userLocationSignal -{ - return [_userLocation signal]; -} - -- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status -{ - if (_openLiveLocationMenuBlock != nil) - { - if (status == kCLAuthorizationStatusAuthorizedAlways) - _openLiveLocationMenuBlock(); - - _openLiveLocationMenuBlock = nil; - } -} - -- (CGRect)_liveLocationMenuSourceRect -{ - return CGRectZero; -} - -- (void)_willStartOwnLiveLocation -{ - -} - -- (void)dismissLiveLocationMenu:(TGMenuSheetController *)controller doNotRemove:(bool)doNotRemove -{ - [self _willStartOwnLiveLocation]; - - if (!doNotRemove) - { - [controller dismissAnimated:true]; - } - else - { - [controller setDimViewHidden:true animated:true]; - [controller removeFromParentViewController]; - } -} - -- (void)_presentLiveLocationMenu:(CLLocationCoordinate2D)coordinate dismissOnCompletion:(bool)dismissOnCompletion -{ - void (^block)(void) = ^ - { - __weak TGLocationMapViewController *weakSelf = self; - CGRect (^sourceRect)(void) = ^CGRect - { - __strong TGLocationMapViewController *strongSelf = weakSelf; - if (strongSelf == nil) - return CGRectZero; - - return [strongSelf _liveLocationMenuSourceRect]; - }; - - TGMenuSheetController *controller = [[TGMenuSheetController alloc] initWithContext:_context dark:false]; - controller.dismissesByOutsideTap = true; - controller.hasSwipeGesture = true; - controller.narrowInLandscape = true; - controller.sourceRect = sourceRect; - - NSMutableArray *itemViews = [[NSMutableArray alloc] init]; - - NSString *title = TGLocalized(@"Map.LiveLocationGroupDescription"); - if ([self.receivingPeer isKindOfClass:[TGUser class]]) - title = [NSString stringWithFormat:TGLocalized(@"Map.LiveLocationPrivateDescription"), [(TGUser *)self.receivingPeer displayFirstName]]; - - TGMenuSheetTitleItemView *titleItem = [[TGMenuSheetTitleItemView alloc] initWithTitle:nil subtitle:title]; - [itemViews addObject:titleItem]; - - __weak TGMenuSheetController *weakController = controller; - TGMenuSheetButtonItemView *for15MinutesItem = [[TGMenuSheetButtonItemView alloc] initWithTitle:TGLocalized(@"Map.LiveLocationFor15Minutes") type:TGMenuSheetButtonTypeDefault fontSize:20.0 action:^ - { - __strong TGLocationMapViewController *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - __strong TGMenuSheetController *strongController = weakController; - if (strongController == nil) - return; - - if (strongSelf.liveLocationStarted != nil) - strongSelf.liveLocationStarted(coordinate, 15 * 60); - - [strongSelf dismissLiveLocationMenu:strongController doNotRemove:!dismissOnCompletion]; - }]; - [itemViews addObject:for15MinutesItem]; - - TGMenuSheetButtonItemView *for1HourItem = [[TGMenuSheetButtonItemView alloc] initWithTitle:TGLocalized(@"Map.LiveLocationFor1Hour") type:TGMenuSheetButtonTypeDefault fontSize:20.0 action:^ - { - __strong TGLocationMapViewController *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - __strong TGMenuSheetController *strongController = weakController; - if (strongController == nil) - return; - - if (strongSelf.liveLocationStarted != nil) - strongSelf.liveLocationStarted(coordinate, 60 * 60 - 1); - - [strongSelf dismissLiveLocationMenu:strongController doNotRemove:!dismissOnCompletion]; - }]; - [itemViews addObject:for1HourItem]; - - TGMenuSheetButtonItemView *for8HoursItem = [[TGMenuSheetButtonItemView alloc] initWithTitle:TGLocalized(@"Map.LiveLocationFor8Hours") type:TGMenuSheetButtonTypeDefault fontSize:20.0 action:^ - { - __strong TGLocationMapViewController *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - __strong TGMenuSheetController *strongController = weakController; - if (strongController == nil) - return; - - if (strongSelf.liveLocationStarted != nil) - strongSelf.liveLocationStarted(coordinate, 8 * 60 * 60); - - [strongSelf dismissLiveLocationMenu:strongController doNotRemove:!dismissOnCompletion]; - }]; - [itemViews addObject:for8HoursItem]; - - TGMenuSheetButtonItemView *cancelItem = [[TGMenuSheetButtonItemView alloc] initWithTitle:TGLocalized(@"Common.Cancel") type:TGMenuSheetButtonTypeCancel fontSize:20.0 action:^ - { - __strong TGMenuSheetController *strongController = weakController; - if (strongController == nil) - return; - - [strongController dismissAnimated:true manual:true]; - }]; - [itemViews addObject:cancelItem]; - - [controller setItemViews:itemViews]; - [controller presentInViewController:self sourceView:self.view animated:true]; - }; - - void (^errorBlock)(void) = ^ - { - [[[LegacyComponentsGlobals provider] accessChecker] checkLocationAuthorizationStatusForIntent:TGLocationAccessIntentLiveLocation alertDismissComlpetion:nil]; - }; - - if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedAlways && [CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse) - { - errorBlock(); - } - else - { - if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedAlways) - { - block(); - } - else - { - if (![TGLocationUtils requestAlwaysUserLocationAuthorizationWithLocationManager:_locationManager]) - errorBlock(); - else - _openLiveLocationMenuBlock = [block copy]; - } - } -} - -@end - - -@implementation TGLocationTableView - -- (BOOL)touchesShouldCancelInContentView:(UIView *)__unused view -{ - return true; -} - -static void TGLocationTableViewAdjustContentOffsetIfNecessary(__unused id self, __unused SEL _cmd) -{ -} - -+ (void)initialize -{ - static bool initialized = false; - if (!initialized) - { - initialized = true; - - FreedomDecoration instanceDecorations[] = - { - { .name = 0x584ab24eU, - .imp = (IMP)&TGLocationTableViewAdjustContentOffsetIfNecessary, - .newIdentifier = FreedomIdentifierEmpty, - .newEncoding = FreedomIdentifierEmpty - } - }; - - freedomClassAutoDecorate(0x5bfec194, NULL, 0, instanceDecorations, sizeof(instanceDecorations) / sizeof(instanceDecorations[0])); - } -} - -@end - -@implementation TGLocationPallete - -+ (instancetype)palleteWithBackgroundColor:(UIColor *)backgroundColor selectionColor:(UIColor *)selectionColor separatorColor:(UIColor *)separatorColor textColor:(UIColor *)textColor secondaryTextColor:(UIColor *)secondaryTextColor accentColor:(UIColor *)accentColor destructiveColor:(UIColor *)destructiveColor locationColor:(UIColor *)locationColor liveLocationColor:(UIColor *)liveLocationColor iconColor:(UIColor *)iconColor sectionHeaderBackgroundColor:(UIColor *)sectionHeaderBackgroundColor sectionHeaderTextColor:(UIColor *)sectionHeaderTextColor searchBarPallete:(TGSearchBarPallete *)searchBarPallete avatarPlaceholder:(UIImage *)avatarPlaceholder -{ - TGLocationPallete *pallete = [[TGLocationPallete alloc] init]; - pallete->_backgroundColor = backgroundColor; - pallete->_selectionColor = selectionColor; - pallete->_separatorColor = separatorColor; - pallete->_textColor = textColor; - pallete->_secondaryTextColor = secondaryTextColor; - pallete->_accentColor = accentColor; - pallete->_destructiveColor = destructiveColor; - pallete->_locationColor = locationColor; - pallete->_liveLocationColor = liveLocationColor; - pallete->_iconColor = iconColor; - pallete->_sectionHeaderBackgroundColor = sectionHeaderBackgroundColor; - pallete->_sectionHeaderTextColor = sectionHeaderTextColor; - pallete->_searchBarPallete = searchBarPallete; - pallete->_avatarPlaceholder = avatarPlaceholder; - return pallete; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationOptionsView.h b/submodules/LegacyComponents/Sources/TGLocationOptionsView.h deleted file mode 100644 index 5fc7d6a7c4..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationOptionsView.h +++ /dev/null @@ -1,15 +0,0 @@ -#import "TGLocationTrackingButton.h" - -@class TGLocationPallete; - -@interface TGLocationOptionsView : UIView - -@property (nonatomic, strong) TGLocationPallete *pallete; -@property (nonatomic, copy) void (^mapModeChanged)(NSInteger); -@property (nonatomic, copy) void (^trackModePressed)(void); - -- (void)setTrackingMode:(TGLocationTrackingMode)trackingMode animated:(bool)animated; -- (void)setLocationAvailable:(bool)available animated:(bool)animated; -- (void)setMapModeControlHidden:(bool)hidden animated:(bool)animated; - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationOptionsView.m b/submodules/LegacyComponents/Sources/TGLocationOptionsView.m deleted file mode 100644 index 3628d8c094..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationOptionsView.m +++ /dev/null @@ -1,213 +0,0 @@ -#import "TGLocationOptionsView.h" - -#import "TGFont.h" - -#import "TGModernButton.h" -#import "TGLocationMapModeControl.h" - -#import "TGLocationMapViewController.h" -#import "TGSearchBar.h" - -#import "LegacyComponentsInternal.h" -#import "TGImageUtils.h" - -@interface TGLocationOptionsView () -{ - UIImageView *_backgroundView; - TGModernButton *_mapModeButton; - UIView *_mapModeClipView; - UIView *_mapModeBackgroundView; - TGLocationMapModeControl *_mapModeControl; - TGLocationTrackingButton *_trackButton; - UIView *_separatorView; -} -@end - -@implementation TGLocationOptionsView - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - _mapModeClipView = [[UIView alloc] init]; - _mapModeClipView.clipsToBounds = true; - [self addSubview:_mapModeClipView]; - - _backgroundView = [[UIImageView alloc] init]; - _backgroundView.image = [TGComponentsImageNamed(@"LocationTopPanel") resizableImageWithCapInsets:UIEdgeInsetsMake(15.0f, 15.0f, 18.0f, 15.0f)]; - [self addSubview:_backgroundView]; - - UIView *mapModeBackgroundView = nil; - if (iosMajorVersion() >= 8) - { - _mapModeBackgroundView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]]; - mapModeBackgroundView = ((UIVisualEffectView *)_mapModeBackgroundView).contentView; - } - else - { - _mapModeBackgroundView = [[UIView alloc] init]; - _mapModeBackgroundView.backgroundColor = [UIColor whiteColor]; - mapModeBackgroundView = _mapModeBackgroundView; - } - _mapModeBackgroundView.clipsToBounds = true; - _mapModeBackgroundView.layer.cornerRadius = 4.0f; - _mapModeBackgroundView.alpha = 0.0f; - _mapModeBackgroundView.userInteractionEnabled = false; - _mapModeBackgroundView.hidden = true; - [_mapModeClipView addSubview:_mapModeBackgroundView]; - - _mapModeControl = [[TGLocationMapModeControl alloc] init]; - _mapModeControl.selectedSegmentIndex = 0; - [_mapModeControl addTarget:self action:@selector(modeChanged:) forControlEvents:UIControlEventValueChanged]; - [mapModeBackgroundView addSubview:_mapModeControl]; - - _mapModeButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 45.0f, 45.0f)]; - _mapModeButton.adjustsImageWhenHighlighted = false; - [_mapModeButton setImage:TGComponentsImageNamed(@"LocationInfo.png") forState:UIControlStateNormal]; - [_mapModeButton setImage:TGComponentsImageNamed(@"LocationInfo_Active.png") forState:UIControlStateSelected]; - [_mapModeButton setImage:TGComponentsImageNamed(@"LocationInfo_Active.png") forState:UIControlStateSelected | UIControlStateHighlighted]; - [_mapModeButton addTarget:self action:@selector(mapModeButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - [self addSubview:_mapModeButton]; - - _trackButton = [[TGLocationTrackingButton alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 45.0f, 45.0f)]; - [_trackButton addTarget:self action:@selector(trackPressed:) forControlEvents:UIControlEventTouchUpInside]; - [self addSubview:_trackButton]; - - _separatorView = [[UIView alloc] init]; - _separatorView.backgroundColor = UIColorRGB(0xcccccc); - [self addSubview:_separatorView]; - } - return self; -} - -- (void)setPallete:(TGLocationPallete *)pallete -{ - _pallete = pallete; - - if (![_mapModeBackgroundView isKindOfClass:[UIVisualEffectView class]]) - _mapModeBackgroundView.backgroundColor = pallete.backgroundColor; - else - ((UIVisualEffectView *)_mapModeBackgroundView).effect = pallete.searchBarPallete.isDark ? [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark] : [UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]; - - if (![pallete.backgroundColor isEqual:[UIColor whiteColor]]) - { - UIGraphicsBeginImageContextWithOptions(_backgroundView.image.size, false, 0.0f); - [_backgroundView.image drawAtPoint:CGPointZero]; - - CGContextRef context = UIGraphicsGetCurrentContext(); - [pallete.backgroundColor setFill]; - UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(4.0f, 4.0f, 46.5f, 46.5f) cornerRadius:10.0f]; - CGContextAddPath(context, path.CGPath); - CGContextFillPath(context); - - UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - - _backgroundView.image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(15.0f, 15.0f, 18.0f, 15.0f)]; - } - - _separatorView.backgroundColor = pallete.separatorColor; - - [_mapModeButton setImage:TGTintedImage(TGComponentsImageNamed(@"LocationInfo.png"), pallete.accentColor) forState:UIControlStateNormal]; - [_mapModeButton setImage:TGTintedImage(TGComponentsImageNamed(@"LocationInfo_Active.png"), pallete.accentColor) forState:UIControlStateSelected]; - [_mapModeButton setImage:TGTintedImage(TGComponentsImageNamed(@"LocationInfo_Active.png"), pallete.accentColor) forState:UIControlStateSelected | UIControlStateHighlighted]; - - [_trackButton setAccentColor:pallete.accentColor spinnerColor:pallete.secondaryTextColor]; - - if (pallete != nil && pallete.searchBarPallete.segmentedControlBackgroundImage == nil) - _mapModeButton.tintColor = pallete.accentColor; - - [_mapModeControl setBackgroundImage:pallete.searchBarPallete.segmentedControlBackgroundImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault]; - [_mapModeControl setBackgroundImage:pallete.searchBarPallete.segmentedControlSelectedImage forState:UIControlStateSelected barMetrics:UIBarMetricsDefault]; - [_mapModeControl setBackgroundImage:pallete.searchBarPallete.segmentedControlSelectedImage forState:UIControlStateSelected | UIControlStateHighlighted barMetrics:UIBarMetricsDefault]; - [_mapModeControl setBackgroundImage:pallete.searchBarPallete.segmentedControlHighlightedImage forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault]; - [_mapModeControl setDividerImage:pallete.searchBarPallete.segmentedControlDividerImage forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault]; - - [_mapModeControl setTitleTextAttributes:@{UITextAttributeTextColor:pallete.searchBarPallete.accentColor, UITextAttributeTextShadowColor: [UIColor clearColor], UITextAttributeFont: TGSystemFontOfSize(13)} forState:UIControlStateNormal]; - [_mapModeControl setTitleTextAttributes:@{UITextAttributeTextColor:pallete.searchBarPallete.accentColor, UITextAttributeTextShadowColor: [UIColor clearColor], UITextAttributeFont: TGSystemFontOfSize(13)} forState:UIControlStateSelected]; -} - -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event -{ - bool result = [super pointInside:point withEvent:event]; - if (!result) - result = [_mapModeControl pointInside:[self convertPoint:point toView:_mapModeControl] withEvent:event]; - - return result; -} - -- (void)mapModeButtonPressed -{ - _mapModeButton.selected = !_mapModeButton.selected; - [self setMapModeControlHidden:!_mapModeButton.selected animated:true]; -} - -- (void)modeChanged:(TGLocationMapModeControl *)sender -{ - if (self.mapModeChanged != nil) - self.mapModeChanged(sender.selectedSegmentIndex); - - _mapModeButton.selected = false; - [self setMapModeControlHidden:true animated:true]; -} - -- (void)trackPressed:(TGLocationTrackingButton *)sender -{ - if (self.trackModePressed != nil) - self.trackModePressed(); -} - -- (void)setTrackingMode:(TGLocationTrackingMode)trackingMode animated:(bool)animated -{ - [_trackButton setTrackingMode:trackingMode animated:animated]; -} - -- (void)setLocationAvailable:(bool)available animated:(bool)animated -{ - [_trackButton setLocationAvailable:available animated:animated]; -} - -- (void)layoutSubviews -{ - _backgroundView.frame = CGRectMake(-5.0f, -5.0f, 45.0f + 10.0f, 90.0f + 5.0f + 6.0f); - _mapModeButton.frame = CGRectMake(0.0f, 0.0f, 45.0f, 45.0f); - _trackButton.frame = CGRectMake(0.0f, 45.0f, 45.0f, 45.0f); - _separatorView.frame = CGRectMake(0.0f, 45.0f, 45.0f, TGScreenPixel); -} - -- (void)setMapModeControlHidden:(bool)hidden animated:(bool)animated -{ - _mapModeBackgroundView.userInteractionEnabled = !hidden; - - if (!hidden) - { - _mapModeClipView.frame = CGRectMake(-self.frame.origin.x + 12.0f, 8.0f, self.superview.frame.size.width - 45.0f - 12.0f, _mapModeControl.frame.size.height); - _mapModeControl.frame = CGRectMake(0.0f, 0.0f, _mapModeClipView.frame.size.width - 16.0f, _mapModeControl.frame.size.height); - - if (_mapModeBackgroundView.hidden) - { - _mapModeBackgroundView.hidden = false; - _mapModeBackgroundView.frame = CGRectMake(_mapModeClipView.frame.size.width, 0.0f, _mapModeClipView.frame.size.width - 16.0f, _mapModeControl.frame.size.height); - } - } - - if (animated) - { - [UIView animateWithDuration:0.3f delay:0.0f options:7 << 16 animations:^ - { - _mapModeBackgroundView.frame = CGRectMake(hidden ? _mapModeClipView.frame.size.width : 0.0f, 0.0f, _mapModeClipView.frame.size.width - 16.0f, _mapModeControl.frame.size.height); - } completion:nil]; - - [UIView animateWithDuration:0.25f animations:^ - { - _mapModeBackgroundView.alpha = hidden ? 0.0f : 1.0f; - }]; - } - else - { - _mapModeBackgroundView.alpha = hidden ? 0.0f : 1.0f; - } -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationPickerController.m b/submodules/LegacyComponents/Sources/TGLocationPickerController.m deleted file mode 100644 index c622a67afa..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationPickerController.m +++ /dev/null @@ -1,1324 +0,0 @@ -#import "TGLocationPickerController.h" - -#import "LegacyComponentsInternal.h" -#import "TGColor.h" -#import "TGImageUtils.h" -#import "TGFont.h" - -#import - -#import "TGLocationUtils.h" - -#import "TGLocationSignals.h" - -#import "TGListsTableView.h" -#import "TGSearchBar.h" -#import "TGSearchDisplayMixin.h" -#import -#import -#import -#import "TGLocationViewController.h" - -#import "TGLocationAnnotation.h" -#import "TGLocationReverseGeocodeResult.h" - -#import "TGLocationMapView.h" - -#import "TGLocationVenue.h" -#import "TGLocationAnnotation.h" - -#import "TGLocationVenueCell.h" -#import "TGLocationCurrentLocationCell.h" -#import "TGLocationSectionHeaderCell.h" -#import "TGLocationOptionsView.h" -#import "TGLocationPinAnnotationView.h" - -const CGPoint TGLocationPickerPinOffset = { 0.0f, 33.0f }; - -@interface TGLocationPair : NSObject - -@property (nonatomic, readonly) CLLocation *location; -@property (nonatomic, readonly, getter=isCurrent) bool current; -@property (nonatomic, assign) bool onlyLocationUpdate; - -@end - -@implementation TGLocationPair - -+ (TGLocationPair *)pairWithLocation:(CLLocation *)location isCurrent:(bool)isCurrent onlyLocationUpdate:(bool)onlyLocationUpdate -{ - TGLocationPair *pair = [[TGLocationPair alloc] init]; - pair->_location = location; - pair->_current = isCurrent; - pair->_onlyLocationUpdate = onlyLocationUpdate; - return pair; -} - -@end - -@interface TGLocationPickerController () -{ - TGLocationPickerControllerIntent _intent; - - bool _nearbyVenuesLoadFailed; - NSArray *_nearbyVenues; - NSArray *_searchResults; - NSString *_searchResultsQuery; - - TGLocationPinAnnotationView *_ownLocationView; - __weak MKAnnotationView *_userLocationView; - - CLLocation *_currentUserLocation; - CLLocation *_startLocation; - CLLocation *_venuesFetchLocation; - SMetaDisposable *_locationUpdateDisposable; - void (^_userLocationObserver)(CLLocation *location); - - SMetaDisposable *_nearbyVenuesDisposable; - SMetaDisposable *_searchDisposable; - SMetaDisposable *_reverseGeocodeDisposable; - - UIView *_pickerPinWrapper; - TGLocationPinAnnotationView *_pickerPinView; - - NSValue *_fullScreenMapSpan; - - bool _mapInFullScreenMode; - bool _pinMovedFromUserLocation; - bool _updatePinAnnotation; - NSString *_customAddress; - - UIView *_searchBarOverlay; - UIBarButtonItem *_searchButtonItem; - UIView *_searchReferenceView; - UIView *_searchBarWrapper; - TGSearchBar *_searchBar; - TGSearchDisplayMixin *_searchMixin; - - UIView *_safeAreaCurtainView; - CGRect _initialCurtainFrame; - - UIImageView *_attributionView; - - bool _placesListVisible; - - id _liveLocationsDisposable; - TGLiveLocation *_liveLocation; -} -@end - -@implementation TGLocationPickerController - -- (instancetype)initWithContext:(id)context intent:(TGLocationPickerControllerIntent)intent -{ - self = [super initWithContext:context]; - if (self != nil) - { - _intent = intent; - - _locationUpdateDisposable = [[SMetaDisposable alloc] init]; - _nearbyVenuesDisposable = [[SMetaDisposable alloc] init]; - - self.title = TGLocalized(@"Map.ChooseLocationTitle"); - [self setLeftBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Cancel") style:UIBarButtonItemStylePlain target:self action:@selector(cancelButtonPressed)]]; - - _searchButtonItem = [self controllerRightBarButtonItem]; - _searchButtonItem.enabled = false; - [self setRightBarButtonItem:_searchButtonItem]; - - [TGLocationUtils requestWhenInUserLocationAuthorizationWithLocationManager:_locationManager]; - } - return self; -} - -- (void)dealloc -{ - [_locationUpdateDisposable dispose]; - [_nearbyVenuesDisposable dispose]; - [_searchDisposable dispose]; - [_reverseGeocodeDisposable dispose]; - [_liveLocationsDisposable dispose]; - - _searchBar.delegate = nil; - _searchMixin.delegate = nil; -} - -- (void)loadView -{ - _tableViewBottomInset = 400.0f; - - [super loadView]; - - _attributionView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, _tableView.frame.size.width, 55)]; - _attributionView.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _attributionView.contentMode = UIViewContentModeCenter; - _attributionView.hidden = true; - _attributionView.image = self.pallete != nil ? TGTintedImage(TGComponentsImageNamed(@"FoursquareAttribution.png"), self.pallete.secondaryTextColor) : TGComponentsImageNamed(@"FoursquareAttribution.png"); - _tableView.tableFooterView = _attributionView; - - _mapView.tapEnabled = true; - _mapView.longPressAsTapEnabled = true; - if (iosMajorVersion() >= 7) - _mapView.rotateEnabled = false; - - __weak TGLocationPickerController *weakSelf = self; - _mapView.singleTap = ^ - { - __strong TGLocationPickerController *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - [strongSelf switchToFullscreen]; - }; - - _searchBarOverlay = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.navigationController.view.frame.size.width, 44.0f)]; - _searchBarOverlay.alpha = 0.0f; - _searchBarOverlay.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _searchBarOverlay.backgroundColor = self.pallete != nil ? self.pallete.sectionHeaderBackgroundColor : UIColorRGB(0xf7f7f7); - _searchBarOverlay.userInteractionEnabled = false; - [self.navigationController.view addSubview:_searchBarOverlay]; - - CGFloat safeAreaInset = self.controllerSafeAreaInset.top > FLT_EPSILON ? self.controllerSafeAreaInset.top : 0.0f; - _searchBarWrapper = [[UIView alloc] initWithFrame:CGRectMake(0, -44.0f, self.navigationController.view.frame.size.width, 44.0f)]; - _searchBarWrapper.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _searchBarWrapper.backgroundColor = self.pallete != nil ? self.pallete.backgroundColor : [UIColor whiteColor]; - _searchBarWrapper.hidden = true; - [self.navigationController.view addSubview:_searchBarWrapper]; - - _searchBar = [[TGSearchBar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, _searchBarWrapper.frame.size.width, [TGSearchBar searchBarBaseHeight]) style:TGSearchBarStyleHeader]; - if (self.pallete != nil) - [_searchBar setPallete:self.pallete.searchBarPallete]; - _searchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _searchBar.customBackgroundView.image = nil; - _searchBar.customActiveBackgroundView.image = nil; - _searchBar.delegate = self; - [_searchBar setShowsCancelButton:true animated:false]; - [_searchBar setAlwaysExtended:true]; - _searchBar.placeholder = TGLocalized(@"Map.Search"); - [_searchBar sizeToFit]; - _searchBar.delayActivity = false; - [_searchBarWrapper addSubview:_searchBar]; - - _searchMixin = [[TGSearchDisplayMixin alloc] init]; - _searchMixin.searchBar = _searchBar; - _searchMixin.alwaysShowsCancelButton = true; - _searchMixin.delegate = self; - - _searchReferenceView = [[UIView alloc] initWithFrame:self.view.bounds]; - _searchReferenceView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - _searchReferenceView.userInteractionEnabled = false; - [self.view addSubview:_searchReferenceView]; - - _activityIndicator.alpha = 0.0f; - [self setIsLoading:true]; - - if (self.safeAreaInsetBottom > FLT_EPSILON) - { - _safeAreaCurtainView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, _tableView.frame.size.width, self.safeAreaInsetBottom)]; - _safeAreaCurtainView.backgroundColor = self.pallete != nil ? self.pallete.sectionHeaderBackgroundColor : UIColorRGB(0xf7f7f7); - } - - if (![self _updateControllerInset:false]) - [self controllerInsetUpdated:UIEdgeInsetsZero]; - - TGLocationPickerAnnotation *annotation = [[TGLocationPickerAnnotation alloc] initWithCoordinate:kCLLocationCoordinate2DInvalid]; - annotation.peer = self.peer; - - _ownLocationView = [[TGLocationPinAnnotationView alloc] initWithAnnotation:annotation]; - _ownLocationView.pallete = self.pallete; - _ownLocationView.frame = CGRectOffset(_ownLocationView.frame, 21.0f, 22.0f); - - CGFloat pinWrapperWidth = self.view.frame.size.width; - _pickerPinWrapper = [[TGLocationPinWrapperView alloc] initWithFrame:CGRectMake((_mapViewWrapper.frame.size.width - pinWrapperWidth) / 2, (_mapViewWrapper.frame.size.height - pinWrapperWidth) / 2, pinWrapperWidth, pinWrapperWidth)]; - _pickerPinWrapper.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin; - _pickerPinWrapper.hidden = true; - [_mapViewWrapper addSubview:_pickerPinWrapper]; - - _pickerPinView = [[TGLocationPinAnnotationView alloc] initWithAnnotation:annotation]; - _pickerPinView.pallete = self.pallete; - _pickerPinView.center = CGPointMake(_pickerPinWrapper.frame.size.width / 2.0f, _pickerPinWrapper.frame.size.width / 2.0f + 16.0f); - [_pickerPinWrapper addSubview:_pickerPinView]; -} - -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; - - if (_intent == TGLocationPickerControllerCustomLocationIntent) - [self switchToFullscreen]; - - __weak TGLocationPickerController *weakSelf = self; - [_locationUpdateDisposable setDisposable:[[self pickerUserLocationSignal] startWithNext:^(TGLocationPair *locationPair) - { - __strong TGLocationPickerController *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - [strongSelf setCurrentUserLocation:locationPair.location storeLocation:locationPair.isCurrent updateMapView:!locationPair.onlyLocationUpdate]; - - if (strongSelf->_placesListVisible && strongSelf->_intent != TGLocationPickerControllerCustomLocationIntent && locationPair.isCurrent && !locationPair.onlyLocationUpdate) - { - [strongSelf fetchNearbyVenuesWithLocation:locationPair.location]; - } - }]]; - - [self _layoutTableProgressViews]; -} - -- (void)setLiveLocationsSignal:(SSignal *)signal -{ - __weak TGLocationPickerController *weakSelf = self; - _liveLocationsDisposable = [[signal deliverOn:[SQueue mainQueue]] startWithNext:^(TGLiveLocation *liveLocation) - { - __strong TGLocationPickerController *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - strongSelf->_liveLocation = liveLocation; - [strongSelf updateCurrentLocationCell]; - }]; -} - -- (void)fetchNearbyVenuesWithLocation:(CLLocation *)location -{ - _venuesFetchLocation = location; - _messageLabel.hidden = true; - - [self setIsLoading:true]; - - __weak TGLocationPickerController *weakSelf = self; - [_nearbyVenuesDisposable setDisposable:[[self.nearbyPlacesSignal(@"", location) deliverOn:[SQueue mainQueue]] startWithNext:^(NSArray *venues) - { - __strong TGLocationPickerController *strongSelf = weakSelf; - if (strongSelf != nil && venues != nil) - [strongSelf setNearbyVenues:venues]; - } error:^(__unused id error) - { - __strong TGLocationPickerController *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - strongSelf->_nearbyVenuesLoadFailed = true; - - [strongSelf setIsLoading:false]; - - [strongSelf _layoutTableProgressViews]; - strongSelf->_messageLabel.hidden = false; - strongSelf->_messageLabel.text = TGLocalized(@"Map.LoadError"); - } completed:nil]]; -} - -- (void)viewDidAppear:(BOOL)animated -{ - [super viewDidAppear:animated]; - - _searchBarWrapper.hidden = false; - - if (_intent != TGLocationPickerControllerCustomLocationIntent) - { - [[[LegacyComponentsGlobals provider] accessChecker] checkLocationAuthorizationStatusForIntent:TGLocationAccessIntentSend alertDismissComlpetion:^ - { - if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse) - [self switchToFullscreen]; - }]; - } -} - -- (void)viewWillDisappear:(BOOL)animated -{ - [super viewWillDisappear:animated]; - - _searchBarWrapper.hidden = true; -} - -#pragma mark - Actions - -- (void)cancelButtonPressed -{ - [self.presentingViewController dismissViewControllerAnimated:true completion:nil]; -} - -- (void)_sendLocation -{ - _tableView.userInteractionEnabled = false; - - CLLocationCoordinate2D coordinate = _currentUserLocation.coordinate; - if (_mapInFullScreenMode) - coordinate = [self mapCenterCoordinateForPickerPin]; - - if (self.locationPicked != nil) - self.locationPicked(coordinate, nil, _customAddress); -} - -- (void)searchButtonPressed -{ - [self setSearchHidden:false animated:true]; - [_searchBar becomeFirstResponder]; -} - -- (void)_presentVenuesList -{ - if (fabs(_tableView.contentOffset.y + _tableView.contentInset.top) < 1.0f) - { - [_tableView setContentOffset:CGPointMake(0.0f, -_tableView.contentInset.top + (self.view.frame.size.height - [self visibleContentHeight] - self.controllerInset.top * 2.0f) / 2.0f - 16.0f) animated:true]; - } -} - -- (void)userLocationButtonPressed -{ - if (!_pinMovedFromUserLocation || _currentUserLocation == nil) - return; - - [self switchToUserLocation]; - - _mapInFullScreenMode = false; - _pinMovedFromUserLocation = false; - - [self hidePickerAnnotationAnimated:true]; - [_pickerPinView setPinRaised:true avatar:_intent == TGLocationPickerControllerCustomLocationIntent animated:true completion:nil]; - - MKCoordinateSpan span = _fullScreenMapSpan != nil ? _fullScreenMapSpan.MKCoordinateSpanValue : TGLocationDefaultSpan; - [self setMapCenterCoordinate:_mapView.userLocation.location.coordinate span:span offset:TGLocationPickerPinOffset animated:true]; -} - -#pragma mark - Map View Delegate - -- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)__unused animated -{ - UIView *view = mapView.subviews.firstObject; - - for (UIGestureRecognizer *recognizer in view.gestureRecognizers) - { - if(recognizer.state == UIGestureRecognizerStateBegan || recognizer.state == UIGestureRecognizerStateEnded) - { - if (_mapInFullScreenMode) - { - [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(pinPinView) object:nil]; - [self hidePickerAnnotationAnimated:true]; - } - else - { - [self switchToFullscreen]; - } - - [_pickerPinView setPinRaised:true avatar:_intent == TGLocationPickerControllerCustomLocationIntent animated:true completion:nil]; - - _pinMovedFromUserLocation = true; - _updatePinAnnotation = false; - - break; - } - } -} - -- (void)mapView:(MKMapView *)__unused mapView regionDidChangeAnimated:(BOOL)__unused animated -{ - if (_pickerPinView.isPinRaised) - { - NSTimeInterval delay = _pinMovedFromUserLocation ? 0.38 : 0.05; - [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(pinPinView) object:nil]; - [self performSelector:@selector(pinPinView) withObject:nil afterDelay:delay]; - } - else if (_updatePinAnnotation) - { - [self pinPinView]; - } - - for (id annotation in [mapView annotations]) - { - if (![annotation isKindOfClass:[MKUserLocation class]]) - { - MKAnnotationView *view = [mapView viewForAnnotation:annotation]; - [view.superview bringSubviewToFront:view]; - } - } -} - -- (void)pinPinView -{ - __weak TGLocationPickerController *weakSelf = self; - [_pickerPinView setPinRaised:false avatar:_intent == TGLocationPickerControllerCustomLocationIntent animated:true completion:^ - { - __strong TGLocationPickerController *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - if (strongSelf->_mapInFullScreenMode) - { - [strongSelf showPickerAnnotationAnimated:true]; - } - else - { - strongSelf->_ownLocationView.hidden = false; - strongSelf->_pickerPinWrapper.hidden = true; - } - }]; - - if (!_mapInFullScreenMode) - [_pickerPinView setCustomPin:false animated:true]; -} - -- (void)updateLocationAvailability -{ - [super updateLocationAvailability]; - - if (_locationServicesDisabled) - [self switchToFullscreen]; -} - -- (void)mapView:(MKMapView *)__unused mapView didUpdateUserLocation:(MKUserLocation *)userLocation -{ - userLocation.title = @""; - - _locationServicesDisabled = false; - - if (_userLocationObserver != nil) - _userLocationObserver(userLocation.location); - else if (userLocation.location != nil) - _startLocation = userLocation.location; -} - -- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation -{ - if (annotation == mapView.userLocation) - return nil; - - TGLocationPinAnnotationView *view = (TGLocationPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:TGLocationPinAnnotationKind]; - if (view == nil) - { - view = [[TGLocationPinAnnotationView alloc] initWithAnnotation:annotation]; - view.pallete = self.pallete; - } - else - { - view.annotation = annotation; - } - return view; -} - -- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views -{ - for (MKAnnotationView *view in views) - { - if ([view.annotation isKindOfClass:[MKUserLocation class]]) - { - _userLocationView = view; - if (_ownLocationView != nil) - [_userLocationView addSubview:_ownLocationView]; - } - } -} - -- (void)updatePickerAnnotation -{ - __weak TGLocationPickerController *weakSelf = self; - - CLLocationCoordinate2D coordinate = [self mapCenterCoordinateForPickerPin]; - [_reverseGeocodeDisposable setDisposable:[[[TGLocationSignals reverseGeocodeCoordinate:coordinate] deliverOn:[SQueue mainQueue]] startWithNext:^(TGLocationReverseGeocodeResult *result) - { - __strong TGLocationPickerController *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - NSString *address = @""; - if (result != nil) - address = result.fullAddress; - - strongSelf->_customAddress = address; - [strongSelf updateCurrentLocationCell]; - } error:^(__unused id error) - { - __strong TGLocationPickerController *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - strongSelf->_customAddress = @""; - [strongSelf updateCurrentLocationCell]; - } completed:nil]]; -} - -- (void)showPickerAnnotationAnimated:(bool)__unused animated -{ - [self updatePickerAnnotation]; - [self updateCurrentLocationCell]; -} - -- (void)hidePickerAnnotationAnimated:(bool)__unused animated -{ - [self updateCurrentLocationCell]; -} - -- (CLLocationCoordinate2D)mapCenterCoordinateForPickerPin -{ - return [_mapView convertPoint:CGPointMake((_mapView.frame.size.width + TGLocationPickerPinOffset.x) / 2, (_mapView.frame.size.height + TGLocationPickerPinOffset.y) / 2) toCoordinateFromView:_mapView]; -} - -#pragma mark - Signals - -- (SSignal *)pickerUserLocationSignal -{ - __weak TGLocationPickerController *weakSelf = self; - return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) - { - SMetaDisposable *disposable = [[SMetaDisposable alloc] init]; - - [disposable setDisposable:[[[[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) - { - __strong TGLocationPickerController *strongSelf = weakSelf; - if (strongSelf == nil) - return nil; - - if (strongSelf->_startLocation != nil) - { - [subscriber putNext:[TGLocationPair pairWithLocation:strongSelf->_startLocation isCurrent:true onlyLocationUpdate:false]]; - strongSelf->_startLocation = nil; - } - else - { - CLLocation *knownUserLocation = [TGLocationSignals lastKnownUserLocation]; - [subscriber putNext:[TGLocationPair pairWithLocation:knownUserLocation isCurrent:false onlyLocationUpdate:false]]; - } - - strongSelf->_userLocationObserver = ^(CLLocation *location) - { - [subscriber putNext:[TGLocationPair pairWithLocation:location isCurrent:true onlyLocationUpdate:false]]; - }; - - return nil; - }] map:^TGLocationPair *(TGLocationPair *locationPair) - { - if (!locationPair.isCurrent) - return locationPair; - - __strong TGLocationPickerController *strongSelf = weakSelf; - CLLocation *location = locationPair.location; - - if (strongSelf != nil && strongSelf->_venuesFetchLocation != nil) - { - CLLocation *currentLocation = strongSelf->_venuesFetchLocation; - if ([location distanceFromLocation:currentLocation] < 250) - { - if ((location.horizontalAccuracy < currentLocation.horizontalAccuracy || fabs(location.horizontalAccuracy - currentLocation.horizontalAccuracy) < 50)) - { - locationPair.onlyLocationUpdate = true; - } - } - } - - return locationPair; - }] startWithNext:^(TGLocationPair *locationPair) - { - [subscriber putNext:locationPair]; - }]]; - - return disposable; - }]; -} - -- (void)setCurrentUserLocation:(CLLocation *)userLocation storeLocation:(bool)storeLocation updateMapView:(bool)updateMapView -{ - if (userLocation == nil) - return; - - bool hadNoLocation = (_currentUserLocation == nil); - - if (_mapInFullScreenMode && hadNoLocation) - _pinMovedFromUserLocation = true; - - if (storeLocation) - { - [TGLocationSignals storeLastKnownUserLocation:userLocation]; - _currentUserLocation = userLocation; - _searchButtonItem.enabled = true; - [_optionsView setLocationAvailable:true animated:true]; - } - - [self updateCurrentLocationCell]; - - if (updateMapView) - { - if (!_mapInFullScreenMode) - { - [self setMapCenterCoordinate:userLocation.coordinate offset:TGLocationPickerPinOffset animated:true]; - } - else if (_intent == TGLocationPickerControllerCustomLocationIntent && hadNoLocation) - { - _pinMovedFromUserLocation = false; - _updatePinAnnotation = true; - [self setMapCenterCoordinate:userLocation.coordinate offset:TGLocationPickerPinOffset animated:true]; - } - } -} - -#pragma mark - Appearance - -- (void)switchToFullscreen -{ - if (_mapInFullScreenMode) - return; - - _mapInFullScreenMode = true; - _pinMovedFromUserLocation = true; - - _searchButtonItem.enabled = true; - - _ownLocationView.hidden = true; - _pickerPinWrapper.hidden = false; - //if (_intent != TGLocationPickerControllerCustomLocationIntent) { - [_pickerPinView setCustomPin:true animated:true]; - //} - - _mapView.tapEnabled = false; - _mapView.longPressAsTapEnabled = false; - - _tableView.clipsToBounds = false; - _tableView.scrollEnabled = false; - [_mapViewWrapper.superview bringSubviewToFront:_mapViewWrapper]; - - [_safeAreaCurtainView.superview bringSubviewToFront:_safeAreaCurtainView]; - [UIView animateWithDuration:0.25 animations:^ - { - _safeAreaCurtainView.alpha = 1.0f; - }]; - - void (^changeBlock)(void) = ^ - { - _tableView.contentOffset = CGPointMake(0, -_tableView.contentInset.top); - _tableView.frame = CGRectMake(_tableView.frame.origin.x, self.view.frame.size.height - [self mapHeight] - TGLocationCurrentLocationCellHeight - self.controllerInset.top - self.safeAreaInsetBottom, _tableView.frame.size.width, _tableView.frame.size.height); - - _mapViewWrapper.frame = CGRectMake(0, TGLocationMapClipHeight - self.view.frame.size.height + self.controllerInset.top + 20, _mapViewWrapper.frame.size.width, self.view.frame.size.height - self.controllerInset.top - 10.0f); - _mapView.center = CGPointMake(_mapView.center.x, _mapViewWrapper.frame.size.height / 2); - _edgeView.frame = CGRectMake(0.0f, _mapViewWrapper.frame.size.height - _edgeView.frame.size.height, _edgeView.frame.size.width, _edgeView.frame.size.height); - - if (_safeAreaCurtainView != nil) - { - UITableViewCell *firstCell = [_tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]; - _safeAreaCurtainView.frame = CGRectMake(0.0f, CGRectGetMaxY(firstCell.frame), _safeAreaCurtainView.frame.size.width,_safeAreaCurtainView.frame.size.height); - } - }; - - void (^completionBlock)(BOOL) = ^(BOOL finished) - { - if (finished) - { - _mapView.manipulationEnabled = true; - - _mapViewWrapper.clipsToBounds = true; - _fullScreenMapSpan = [NSValue valueWithMKCoordinateSpan:_mapView.region.span]; - } - }; - - if (iosMajorVersion() >= 7) - { - [UIView animateWithDuration:0.5f delay:0.0f usingSpringWithDamping:0.75f initialSpringVelocity:0.5f options:UIViewAnimationOptionCurveLinear animations:changeBlock completion:completionBlock]; - } - else - { - [UIView animateWithDuration:0.4f delay:0.0f options:UIViewAnimationOptionCurveEaseInOut animations:changeBlock completion:completionBlock]; - } - - [self updateCurrentLocationCell]; -} - -- (void)switchToUserLocation -{ - if (!_mapInFullScreenMode) - return; - - _mapInFullScreenMode = false; - _mapViewWrapper.clipsToBounds = false; - _searchButtonItem.enabled = !_locationServicesDisabled; - - void (^changeBlock)(void) = ^ - { - _tableView.contentOffset = CGPointMake(0, -_tableView.contentInset.top); - _tableView.frame = self.view.bounds; - - _mapViewWrapper.frame = CGRectMake(0, TGLocationMapClipHeight - _tableViewTopInset, self.view.frame.size.width, _tableViewTopInset + 10.0f); - _mapView.frame = CGRectMake(0, -TGLocationMapInset, self.view.frame.size.width, _tableViewTopInset + 2 * TGLocationMapInset + 10.0f); - _edgeView.frame = CGRectMake(0.0f, _tableViewTopInset - 10.0f, _mapViewWrapper.frame.size.width, _edgeView.frame.size.height); - - _safeAreaCurtainView.frame = CGRectMake(0.0f, _initialCurtainFrame.origin.y, _safeAreaCurtainView.frame.size.width,_safeAreaCurtainView.frame.size.height); - }; - - [_safeAreaCurtainView.superview bringSubviewToFront:_safeAreaCurtainView]; - [UIView animateWithDuration:0.25 animations:^ - { - _safeAreaCurtainView.alpha = 1.0f; - }]; - - void (^completionBlock)(BOOL) = ^(BOOL finished) - { - if (finished) - { - _tableView.clipsToBounds = true; - _tableView.scrollEnabled = true; - - _mapView.tapEnabled = true; - _mapView.longPressAsTapEnabled = true; - } - }; - - if (iosMajorVersion() >= 7) - { - [UIView animateWithDuration:0.5f delay:0.0f usingSpringWithDamping:0.75f initialSpringVelocity:0.5f options:UIViewAnimationOptionCurveLinear animations:changeBlock completion:completionBlock]; - } - else - { - [UIView animateWithDuration:0.4f delay:0.0f options:UIViewAnimationOptionCurveEaseInOut animations:changeBlock completion:completionBlock]; - } -} - -- (UIBarButtonItem *)controllerRightBarButtonItem -{ - if (_intent == TGLocationPickerControllerCustomLocationIntent) { - return nil; - } - if (iosMajorVersion() < 7) - { - TGModernBarButton *searchButton = [[TGModernBarButton alloc] initWithImage:TGComponentsImageNamed(@"NavigationSearchIcon.png")]; - searchButton.portraitAdjustment = CGPointMake(-7, -5); - [searchButton addTarget:self action:@selector(searchButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - return [[UIBarButtonItem alloc] initWithCustomView:searchButton]; - } - - return [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSearch target:self action:@selector(searchButtonPressed)]; -} - -- (CGRect)_liveLocationMenuSourceRect -{ - TGLocationCurrentLocationCell *cell = [_tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]]; - if ([cell isKindOfClass:[TGLocationCurrentLocationCell class]]) - return [cell convertRect:cell.bounds toView:self.view]; - - return CGRectZero; -} - -#pragma mark - Search - -- (void)setSearchHidden:(bool)hidden animated:(bool)animated -{ - void (^changeBlock)(void) = ^ - { - CGRect frame = _searchBarWrapper.frame; - if (hidden) - { - frame.origin.y = -frame.size.height; - _searchBarOverlay.alpha = 0.0f; - } - else - { - frame.origin.y = 0; - _searchBarOverlay.alpha = 1.0f; - } - _searchBarWrapper.frame = frame; - }; - - if (animated) - [UIView animateWithDuration:0.2f animations:changeBlock]; - else - changeBlock(); -} - -- (void)searchBar:(TGSearchBar *)__unused searchBar willChangeHeight:(CGFloat)__unused newHeight -{ - -} - -- (void)searchMixin:(TGSearchDisplayMixin *)__unused searchMixin hasChangedSearchQuery:(NSString *)searchQuery withScope:(int)__unused scope -{ - if (searchQuery.length == 0) - { - [_searchDisposable setDisposable:nil]; - [_searchMixin reloadSearchResults]; - [_searchMixin setSearchResultsTableViewHidden:true]; - _searchBar.showActivity = false; - } - else - { - __weak TGLocationPickerController *weakSelf = self; - void (^changeActivityIndicatorState)(bool) = ^(bool active) - { - __strong TGLocationPickerController *strongSelf = weakSelf; - if (strongSelf != nil) - strongSelf->_searchBar.showActivity = active; - }; - - SSignal *searchSignal = [[SSignal complete] delay:0.65f onQueue:[SQueue mainQueue]]; - searchSignal = [searchSignal onCompletion:^ - { - changeActivityIndicatorState(true); - }]; - - CLLocationCoordinate2D coordinate = _currentUserLocation.coordinate; - searchSignal = [searchSignal then:[self.nearbyPlacesSignal(searchQuery, _currentUserLocation) deliverOn:[SQueue mainQueue]]]; - - if (_searchDisposable == nil) - _searchDisposable = [[SMetaDisposable alloc] init]; - - [_searchDisposable setDisposable:[[searchSignal onDispose:^ - { - changeActivityIndicatorState(false); - }] startWithNext:^(NSArray *results) - { - __strong TGLocationPickerController *strongSelf = weakSelf; - if (strongSelf != nil) - [strongSelf setSearchResults:results withSearchQuery:searchQuery]; - } error:^(__unused id error) - { - changeActivityIndicatorState(false); - } completed:^ - { - changeActivityIndicatorState(false); - }]]; - } -} - -- (void)searchMixinWillActivate:(bool)__unused animated -{ - if (_mapInFullScreenMode) - return; - - _tableView.scrollEnabled = false; - - [UIView animateWithDuration:0.2f animations:^ - { - _tableView.contentOffset = CGPointMake(0, -_tableView.contentInset.top); - [self _layoutTableProgressViews]; - }]; -} - -- (void)searchMixinWillDeactivate:(bool)animated -{ - [_searchDisposable setDisposable:nil]; - - [self setSearchHidden:true animated:animated]; - - if (_mapInFullScreenMode) - return; - - _tableView.scrollEnabled = true; - - [UIView animateWithDuration:0.2f animations:^ - { - _tableView.contentOffset = CGPointMake(0, -_tableView.contentInset.top); - [self _layoutTableProgressViews]; - }]; -} - -- (UITableView *)createTableViewForSearchMixin:(TGSearchDisplayMixin *)__unused searchMixin -{ - UITableView *tableView = [[UITableView alloc] init]; - tableView.delegate = self; - tableView.dataSource = self; - tableView.separatorStyle = UITableViewCellSeparatorStyleNone; - tableView.tableFooterView = [[UIView alloc] init]; - tableView.backgroundColor = self.pallete != nil ? self.pallete.backgroundColor : [UIColor whiteColor]; - - return tableView; -} - -- (UIView *)referenceViewForSearchResults -{ - return _searchReferenceView; -} - -#pragma mark - Scroll View Delegate - -- (void)scrollViewDidScroll:(UIScrollView *)scrollView -{ - if (_searchMixin.isActive && scrollView == _searchMixin.searchResultsTableView) - { - [_searchBar resignFirstResponder]; - } - else - { - [super scrollViewDidScroll:scrollView]; - [self _layoutTableProgressViews]; - - TGLocationSectionHeaderCell *cell = [_tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:_allowLiveLocationSharing ? 2 : 1 inSection:0]]; - if (cell == nil || ![cell isKindOfClass:[TGLocationSectionHeaderCell class]]) - return; - - if (scrollView.contentOffset.y > -scrollView.contentInset.top) - { - if (!_placesListVisible) - { - _placesListVisible = true; - if (_currentUserLocation != nil) - [self fetchNearbyVenuesWithLocation:_currentUserLocation]; - } - if (_intent != TGLocationPickerControllerCustomLocationIntent) { - [cell configureWithTitle:TGLocalized(@"Map.ChooseAPlace")]; - } - - if (scrollView.contentOffset.y > -scrollView.contentInset.top + TGLocationSectionHeaderHeight) - { - if (_activityIndicator.alpha < FLT_EPSILON) - { - [UIView animateWithDuration:0.25 animations:^ - { - _activityIndicator.alpha = 1.0f; - }]; - } - } - else - { - [UIView animateWithDuration:0.0 animations:^ - { - _activityIndicator.alpha = 0.0f; - }]; - } - - if (_safeAreaCurtainView != nil) - { - [UIView animateWithDuration:0.25 animations:^ - { - _safeAreaCurtainView.alpha = 0.0f; - }]; - } - } - else - { - _activityIndicator.alpha = 0.0f; - if (_intent != TGLocationPickerControllerCustomLocationIntent) { - [cell configureWithTitle:TGLocalized(@"Map.PullUpForPlaces")]; - } - - if (_safeAreaCurtainView != nil) - { - [_safeAreaCurtainView.superview bringSubviewToFront:_safeAreaCurtainView]; - [UIView animateWithDuration:0.25 animations:^ - { - _safeAreaCurtainView.alpha = 1.0f; - }]; - } - } - } -} - -- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView -{ - if (_searchMixin.isActive && scrollView == _searchMixin.searchResultsTableView) - [_searchBar resignFirstResponder]; -} - -#pragma mark - Data - -- (void)updateCurrentLocationCell -{ - UITableViewCell *cell = [_tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]; - if ([cell isKindOfClass:[TGLocationCurrentLocationCell class]]) - { - TGLocationCurrentLocationCell *locationCell = (TGLocationCurrentLocationCell *)cell; - - if (_intent == TGLocationPickerControllerCustomLocationIntent) { - [locationCell configureForGroupLocationWithAddress:_customAddress]; - } else { - if (_mapInFullScreenMode) - [locationCell configureForCustomLocationWithAddress:_customAddress]; - else - [locationCell configureForCurrentLocationWithAccuracy:_currentUserLocation.horizontalAccuracy]; - } - } - - cell = [_tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]]; - if ([cell isKindOfClass:[TGLocationCurrentLocationCell class]]) - { - TGLocationCurrentLocationCell *locationCell = (TGLocationCurrentLocationCell *)cell; - if (_liveLocation != nil) - [locationCell configureForStopWithMessage:_liveLocation.message remaining:self.remainingTimeForMessage(_liveLocation.message)]; - else - [locationCell configureForLiveLocationWithAccuracy:_currentUserLocation.horizontalAccuracy]; - } -} - -- (void)setNearbyVenues:(NSArray *)nearbyVenues -{ - bool shouldFadeIn = (_nearbyVenues.count == 0); - - if (shouldFadeIn) - { - _tableViewBottomInset = 0.0f; - [self updateInsets]; - } - - _nearbyVenues = nearbyVenues; - [_tableView reloadData]; - - [self setIsLoading:false]; - - _attributionView.hidden = (_nearbyVenues.count == 0); - - if (shouldFadeIn) - { - NSMutableArray *animatedCells = [[NSMutableArray alloc] init]; - - for (UIView *cell in _tableView.visibleCells) - { - if ([cell isKindOfClass:[TGLocationVenueCell class]]) - { - cell.alpha = 0.0f; - [animatedCells addObject:cell]; - } - } - - [UIView animateWithDuration:0.14f animations:^ - { - for (UIView *cell in animatedCells) - cell.alpha = 1.0f; - }]; - } -} - -- (void)setSearchResults:(NSArray *)results withSearchQuery:(NSString *)query -{ - _searchResults = results; - _searchResultsQuery = query; - - [_searchMixin reloadSearchResults]; - [_searchMixin setSearchResultsTableViewHidden:query.length == 0]; -} - -#pragma mark - Table View Data Source & Delegate - -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath -{ - if (tableView == _tableView && indexPath.row < [self venueEntriesOffset]) - { - if (indexPath.row == 0) - { - [self _sendLocation]; - } - else if (_allowLiveLocationSharing && indexPath.row == 1) - { - if (_liveLocation != nil) - { - if (self.liveLocationStopped != nil) - self.liveLocationStopped(); - - return; - } - else - { - [self _presentLiveLocationMenu:_currentUserLocation.coordinate dismissOnCompletion:false]; - } - - [tableView deselectRowAtIndexPath:tableView.indexPathForSelectedRow animated:true]; - } - else if ((_allowLiveLocationSharing && indexPath.row == 2) || (!_allowLiveLocationSharing && indexPath.row == 1)) - { - if (_intent != TGLocationPickerControllerCustomLocationIntent) { - [self _presentVenuesList]; - } - } - } - else - { - TGLocationVenue *venue = nil; - if (tableView == _tableView) - { - venue = _nearbyVenues[indexPath.row - [self venueEntriesOffset]]; - } - else if (tableView == _searchMixin.searchResultsTableView) - { - venue = _searchResults[indexPath.row]; - [_searchBar resignFirstResponder]; - } - - if (self.locationPicked != nil) - self.locationPicked(venue.coordinate, [venue venueAttachment], _customAddress); - } -} - -- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath -{ - if (tableView == _tableView) - { - if (indexPath.row == 0 || (_allowLiveLocationSharing && indexPath.row == 1)) - return (_mapInFullScreenMode || _currentUserLocation != nil); - } - - return true; -} - -- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath -{ - if ([cell isKindOfClass:[TGLocationSectionHeaderCell class]]) - { - if (_safeAreaCurtainView.superview == nil) - [_tableView addSubview:_safeAreaCurtainView]; - _safeAreaCurtainView.frame = CGRectMake(0.0f, CGRectGetMaxY(cell.frame), _safeAreaCurtainView.frame.size.width, _safeAreaCurtainView.frame.size.height); - _initialCurtainFrame = _safeAreaCurtainView.frame; - } -} - -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath -{ - UITableViewCell *cell = nil; - - if (tableView == _tableView && indexPath.row == 0) - { - TGLocationCurrentLocationCell *locationCell = [tableView dequeueReusableCellWithIdentifier:TGLocationCurrentLocationCellKind]; - if (locationCell == nil) - locationCell = [[TGLocationCurrentLocationCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TGLocationCurrentLocationCellKind]; - locationCell.pallete = self.pallete; - locationCell.edgeView = _edgeHighlightView; - - if (_intent == TGLocationPickerControllerCustomLocationIntent) { - [locationCell configureForGroupLocationWithAddress:_customAddress]; - } else { - if (_mapInFullScreenMode) - [locationCell configureForCustomLocationWithAddress:_customAddress]; - else - [locationCell configureForCurrentLocationWithAccuracy:_currentUserLocation.horizontalAccuracy]; - } - - cell = locationCell; - } - else if (tableView == _tableView && _allowLiveLocationSharing && indexPath.row == 1) - { - TGLocationCurrentLocationCell *locationCell = [tableView dequeueReusableCellWithIdentifier:TGLocationCurrentLocationCellKind]; - if (locationCell == nil) - locationCell = [[TGLocationCurrentLocationCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TGLocationCurrentLocationCellKind]; - locationCell.pallete = self.pallete; - locationCell.edgeView = nil; - - if (_liveLocation != nil) - [locationCell configureForStopWithMessage:_liveLocation.message remaining:self.remainingTimeForMessage(_liveLocation.message)]; - else - [locationCell configureForLiveLocationWithAccuracy:_currentUserLocation.horizontalAccuracy]; - - cell = locationCell; - } - else if (tableView == _tableView && ((_allowLiveLocationSharing && indexPath.row == 2) || (!_allowLiveLocationSharing && indexPath.row == 1))) - { - TGLocationSectionHeaderCell *sectionCell = [tableView dequeueReusableCellWithIdentifier:TGLocationSectionHeaderKind]; - if (sectionCell == nil) - sectionCell = [[TGLocationSectionHeaderCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TGLocationSectionHeaderKind]; - sectionCell.pallete = self.pallete; - - if (_intent != TGLocationPickerControllerCustomLocationIntent) { - if (tableView.contentOffset.y > -tableView.contentInset.top) - [sectionCell configureWithTitle:TGLocalized(@"Map.ChooseAPlace")]; - else - [sectionCell configureWithTitle:TGLocalized(@"Map.PullUpForPlaces")]; - } - - cell = sectionCell; - } - else - { - TGLocationVenueCell *venueCell = [tableView dequeueReusableCellWithIdentifier:TGLocationVenueCellKind]; - if (venueCell == nil) - venueCell = [[TGLocationVenueCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TGLocationVenueCellKind]; - venueCell.pallete = self.pallete; - TGLocationVenue *venue = nil; - if (tableView == _tableView) - venue = _nearbyVenues[indexPath.row - [self venueEntriesOffset]]; - else if (tableView == _searchMixin.searchResultsTableView) - venue = _searchResults[indexPath.row]; - - [venueCell configureWithVenue:venue]; - - cell = venueCell; - } - - return cell; -} - -- (NSInteger)venueEntriesOffset -{ - return _allowLiveLocationSharing ? 3 : 2; -} - -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)__unused section -{ - if (tableView == _tableView) - return _nearbyVenues.count + 2 + (_allowLiveLocationSharing ? 1 : 0); - else if (tableView == _searchMixin.searchResultsTableView) - return _searchResults.count; - - return 0; -} - -- (CGFloat)tableView:(UITableView *)__unused tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath -{ - if (tableView == _tableView) - { - if (indexPath.row == 0 || (_allowLiveLocationSharing && indexPath.row == 1)) - return TGLocationCurrentLocationCellHeight; - else if ((_allowLiveLocationSharing && indexPath.row == 2) || (!_allowLiveLocationSharing && indexPath.row == 1)) - return TGLocationSectionHeaderHeight; - } - - return TGLocationVenueCellHeight; -} - -- (CGFloat)tableView:(UITableView *)__unused tableView heightForFooterInSection:(NSInteger)__unused section -{ - return 0.001f; -} - -- (UIView *)tableView:(UITableView *)__unused tableView viewForFooterInSection:(NSInteger)__unused section -{ - return [[UIView alloc] init]; -} - -#pragma mark - - -- (void)setIsLoading:(bool)isLoading -{ - if (isLoading) - { - if (_nearbyVenues.count == 0) - [_activityIndicator startAnimating]; - } - else - { - [_activityIndicator stopAnimating]; - } -} - -#pragma mark - Layout - -- (BOOL)shouldAutorotate -{ - return false; -} - -- (void)controllerInsetUpdated:(UIEdgeInsets)previousInset -{ - if (_searchMixin != nil) - { - UIEdgeInsets inset = self.controllerInset; - inset.top -= 44; - [_searchMixin controllerInsetUpdated:inset]; - } - - [super controllerInsetUpdated:previousInset]; -} - -- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration -{ - [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; - - if (_searchMixin != nil) - [_searchMixin controllerLayoutUpdated:[TGViewController screenSizeForInterfaceOrientation:toInterfaceOrientation]]; -} - -- (void)_layoutTableProgressViews -{ - _activityIndicator.center = CGPointMake(_tableView.frame.size.width / 2, TGLocationCurrentLocationCellHeight * (_allowLiveLocationSharing ? 2 : 1) + TGLocationSectionHeaderHeight + (_tableView.contentInset.top + _tableView.contentOffset.y) / 2); - - _messageLabel.frame = CGRectMake(0, _activityIndicator.center.y - _messageLabel.frame.size.height / 2.0f, _messageLabel.frame.size.width, _messageLabel.frame.size.height); -} - -#pragma mark - - -- (CGFloat)visibleContentHeight -{ - return (_allowLiveLocationSharing ? 165.0f : 97.0f) + self.safeAreaInsetBottom; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationPinAnnotationView.h b/submodules/LegacyComponents/Sources/TGLocationPinAnnotationView.h deleted file mode 100644 index 9332f8d00e..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationPinAnnotationView.h +++ /dev/null @@ -1,23 +0,0 @@ -#import - -@class TGLocationPallete; - -@interface TGLocationPinAnnotationView : MKAnnotationView - -- (instancetype)initWithAnnotation:(id)annotation; - -@property (nonatomic, assign, getter=isPinRaised) bool pinRaised; -- (void)setPinRaised:(bool)raised avatar:(bool)avatar animated:(bool)animated completion:(void (^)(void))completion; - -- (void)setCustomPin:(bool)customPin animated:(bool)animated; - -@property (nonatomic, strong) TGLocationPallete *pallete; - -@end - -extern NSString * const TGLocationPinAnnotationKind; - - -@interface TGLocationPinWrapperView : UIView - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationPinAnnotationView.m b/submodules/LegacyComponents/Sources/TGLocationPinAnnotationView.m deleted file mode 100644 index d1f0464105..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationPinAnnotationView.m +++ /dev/null @@ -1,679 +0,0 @@ -#import "TGLocationPinAnnotationView.h" - -#import "LegacyComponentsInternal.h" -#import "TGImageUtils.h" - -#import "TGLocationMapViewController.h" - -#import "TGUser.h" -#import "TGConversation.h" -#import "TGLocationAnnotation.h" -#import "TGLocationMediaAttachment.h" - -#import "TGImageView.h" -#import "TGLetteredAvatarView.h" -#import "TGLocationPulseView.h" - -NSString *const TGLocationPinAnnotationKind = @"TGLocationPinAnnotation"; - -@interface TGLocationPinAnnotationView () -{ - TGLocationPulseView *_pulseView; - UIImageView *_smallView; - UIImageView *_shadowView; - UIImageView *_backgroundView; - TGImageView *_iconView; - UIImageView *_dotView; - TGLetteredAvatarView *_avatarView; - UIImageView *_smallArrowView; - UIImageView *_arrowView; - - bool _liveLocation; - SMetaDisposable *_userDisposable; - - bool _animating; - - bool _observingExpiration; -} -@end - -@implementation TGLocationPinAnnotationView - -- (instancetype)initWithAnnotation:(id)annotation -{ - self = [super initWithAnnotation:annotation reuseIdentifier:TGLocationPinAnnotationKind]; - if (self != nil) - { - _pulseView = [[TGLocationPulseView alloc] init]; - [self addSubview:_pulseView]; - - _shadowView = [[UIImageView alloc] initWithImage:TGComponentsImageNamed(@"LocationPinShadow")]; - [self addSubview:_shadowView]; - - _backgroundView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 83.0f, 83.0f)]; - [_shadowView addSubview:_backgroundView]; - - _iconView = [[TGImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 64.0f, 64.0f)]; - _iconView.contentMode = UIViewContentModeCenter; - [_backgroundView addSubview:_iconView]; - - static dispatch_once_t onceToken; - static UIImage *smallDotImage; - static UIImage *largeDotImage; - static UIImage *smallHeadingArrowImage; - static UIImage *largeHeadingArrowImage; - dispatch_once(&onceToken, ^ - { - UIGraphicsBeginImageContextWithOptions(CGSizeMake(6.0f, 6.0f), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, UIColorRGB(0x008df2).CGColor); - CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, 6.0f, 6.0f)); - - smallDotImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - - - UIGraphicsBeginImageContextWithOptions(CGSizeMake(16.0f, 16.0f), false, 0.0f); - context = UIGraphicsGetCurrentContext(); - - CGContextSaveGState(context); - CGContextSetShadowWithColor(context, CGSizeMake(0, 1), 1.0f, [UIColor colorWithWhite:0.0f alpha:0.22f].CGColor); - CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); - CGContextFillEllipseInRect(context, CGRectMake(2, 2, 12.0, 12.0)); - - CGContextRestoreGState(context); - - CGContextSetFillColorWithColor(context, UIColorRGB(0x008df2).CGColor); - CGContextFillEllipseInRect(context, CGRectMake(4.0f, 4.0f, 8.0f, 8.0f)); - - largeDotImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - - - UIGraphicsBeginImageContextWithOptions(CGSizeMake(16.0f, 16.0f), false, 0.0f); - context = UIGraphicsGetCurrentContext(); - - CGContextClearRect(context, CGRectMake(0, 0, 18.0f, 18.0f)); - - CGContextSetFillColorWithColor(context, UIColorRGB(0x3393fe).CGColor); - - CGContextMoveToPoint(context, 9, 0); - CGContextAddLineToPoint(context, 13, 7); - CGContextAddLineToPoint(context, 5, 7); - CGContextClosePath(context); - CGContextFillPath(context); - - CGContextSetBlendMode(context, kCGBlendModeClear); - CGContextFillEllipseInRect(context, CGRectMake(3.0, 3.0, 12.0, 12.0)); - - smallHeadingArrowImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - - - UIGraphicsBeginImageContextWithOptions(CGSizeMake(33.0f, 33.0f), false, 0.0f); - context = UIGraphicsGetCurrentContext(); - - CGContextClearRect(context, CGRectMake(0, 0, 16.0f, 16.0f)); - - CGContextSetFillColorWithColor(context, UIColorRGB(0x3393fe).CGColor); - - CGContextMoveToPoint(context, 16.5, 0); - CGContextAddLineToPoint(context, 21.5, 6); - CGContextAddLineToPoint(context, 11.5, 6); - CGContextClosePath(context); - CGContextFillPath(context); - - CGContextSetBlendMode(context, kCGBlendModeClear); - CGContextFillEllipseInRect(context, CGRectMake(3.0, 3.0, 27.0, 27.0)); - - largeHeadingArrowImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - }); - - _smallView = [[UIImageView alloc] initWithImage:TGComponentsImageNamed(@"LocationSmallCircle")]; - _smallView.hidden = true; - [self addSubview:_smallView]; - - UIImage *dotImage = smallDotImage; - if ([annotation isKindOfClass:[TGLocationAnnotation class]]) - { - TGLocationAnnotation *locationAnnotation = (TGLocationAnnotation *)annotation; - if (locationAnnotation.location.period > 0) { - dotImage = largeDotImage; - } - } - - _dotView = [[UIImageView alloc] initWithImage:dotImage]; - [self addSubview:_dotView]; - - _smallArrowView = [[UIImageView alloc] initWithImage:smallHeadingArrowImage]; - _smallArrowView.hidden = true; - [self addSubview:_smallArrowView]; - - _arrowView = [[UIImageView alloc] initWithImage:largeHeadingArrowImage]; - _arrowView.hidden = true; - [self addSubview:_arrowView]; - - [self setAnnotation:annotation]; - } - return self; -} - -- (void)dealloc -{ - [self unsubscribeFromExpiration]; -} - -- (void)prepareForReuse -{ - [_pulseView stop]; - [_iconView reset]; - _smallView.hidden = true; - _backgroundView.hidden = false; -} - -- (void)subscribeForExpiration -{ - if (_observingExpiration) - return; - _observingExpiration = true; - [self addObserver:self forKeyPath:@"annotation.isExpired" options:NSKeyValueObservingOptionNew context:NULL]; - [self addObserver:self forKeyPath:@"annotation.heading" options:NSKeyValueObservingOptionNew context:NULL]; -} - -- (void)unsubscribeFromExpiration -{ - if (!_observingExpiration) - return; - _observingExpiration = false; - [self removeObserver:self forKeyPath:@"annotation.isExpired"]; - [self removeObserver:self forKeyPath:@"annotation.heading"]; -} - -- (void)setSelected:(BOOL)selected animated:(BOOL)animated -{ - if (iosMajorVersion() < 7) - animated = false; - - [super setSelected:selected animated:animated]; - - if (!_liveLocation) - return; - - if (animated) - { - [self layoutSubviews]; - _animating = true; - if (selected) - { - //dispatch_async(dispatch_get_main_queue(), ^ - //{ - UIView *avatarSnapshot = [_avatarView snapshotViewAfterScreenUpdates:false]; - [_smallView addSubview:avatarSnapshot]; - avatarSnapshot.transform = _avatarView.transform; - avatarSnapshot.center = CGPointMake(_smallView.frame.size.width / 2.0f, _smallView.frame.size.height / 2.0f); - - _avatarView.transform = CGAffineTransformIdentity; - [_backgroundView addSubview:_avatarView]; - _avatarView.center = CGPointMake(_backgroundView.frame.size.width / 2.0f, _backgroundView.frame.size.height / 2.0f - 5.0f); - - _dotView.alpha = 0.0f; - - _shadowView.center = CGPointMake(_shadowView.center.x, _shadowView.center.y + _shadowView.frame.size.height / 2.0f); - _shadowView.layer.anchorPoint = CGPointMake(0.5f, 1.0f); - _shadowView.hidden = false; - _shadowView.transform = CGAffineTransformMakeScale(0.1f, 0.1f); - [UIView animateWithDuration:0.35 delay:0.0 usingSpringWithDamping:0.6f initialSpringVelocity:0.5f options:kNilOptions animations:^ - { - _smallView.transform = CGAffineTransformMakeScale(0.001f, 0.001f); - _shadowView.transform = CGAffineTransformIdentity; - if (_dotView.hidden) - _smallView.alpha = 0.0f; - } completion:^(BOOL finished) - { - _animating = false; - _shadowView.layer.anchorPoint = CGPointMake(0.5f, 0.5f); - - _smallView.hidden = true; - _smallView.transform = CGAffineTransformIdentity; - [avatarSnapshot removeFromSuperview]; - - [self addSubview:_avatarView]; - }]; - - [UIView animateWithDuration:0.2 animations:^ - { - _dotView.alpha = 1.0f; - }]; - //}); - } - else - { - UIView *avatarSnapshot = [_avatarView snapshotViewAfterScreenUpdates:false]; - [_backgroundView addSubview:avatarSnapshot]; - avatarSnapshot.transform = _avatarView.transform; - avatarSnapshot.center = CGPointMake(_backgroundView.frame.size.width / 2.0f, _backgroundView.frame.size.height / 2.0f - 5.0f); - - _avatarView.transform = CGAffineTransformMakeScale(0.64f, 0.64f); - [_smallView addSubview:_avatarView]; - _avatarView.center = CGPointMake(_smallView.frame.size.width / 2.0f, _smallView.frame.size.height / 2.0f); - - _smallView.hidden = false; - _smallView.transform = CGAffineTransformMakeScale(0.01f, 0.01f); - - _shadowView.center = CGPointMake(_shadowView.center.x, _shadowView.center.y + _shadowView.frame.size.height / 2.0f); - _shadowView.layer.anchorPoint = CGPointMake(0.5f, 1.0f); - [UIView animateWithDuration:0.35 delay:0.0 usingSpringWithDamping:0.6f initialSpringVelocity:0.5f options:kNilOptions animations:^ - { - _smallView.transform = CGAffineTransformIdentity; - _shadowView.transform = CGAffineTransformMakeScale(0.1f, 0.1f); - if (_dotView.hidden) - _smallView.alpha = 1.0f; - } completion:^(BOOL finished) - { - _animating = false; - _shadowView.layer.anchorPoint = CGPointMake(0.5f, 0.5f); - - _shadowView.hidden = true; - _shadowView.transform = CGAffineTransformIdentity; - [avatarSnapshot removeFromSuperview]; - - [self addSubview:_avatarView]; - }]; - - [UIView animateWithDuration:0.1 animations:^ - { - _dotView.alpha = 0.0f; - } completion:nil]; - } - } - else - { - _smallView.hidden = selected; - _shadowView.hidden = !selected; - _dotView.alpha = selected ? 1.0f : 0.0f; - _smallView.alpha = 1.0f; - [self layoutSubviews]; - } - - [self updateHeading]; -} - -- (void)setPallete:(TGLocationPallete *)pallete -{ - if (pallete == nil || _pallete == pallete) - return; - - _pallete = pallete; - - UIImage *dotImage; - if ([self.annotation isKindOfClass:[TGLocationAnnotation class]]) - { - TGLocationAnnotation *locationAnnotation = (TGLocationAnnotation *)self.annotation; - if (locationAnnotation.location.period > 0) { - UIGraphicsBeginImageContextWithOptions(CGSizeMake(16.0f, 16.0f), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - - CGContextSaveGState(context); - CGContextSetShadowWithColor(context, CGSizeMake(0, 1), 1.0f, [UIColor colorWithWhite:0.0f alpha:0.22f].CGColor); - CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); - CGContextFillEllipseInRect(context, CGRectMake(2, 2, 12.0, 12.0)); - - CGContextRestoreGState(context); - - CGContextSetFillColorWithColor(context, pallete.locationColor.CGColor); - CGContextFillEllipseInRect(context, CGRectMake(4.0f, 4.0f, 8.0f, 8.0f)); - - dotImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - } - } - - if (dotImage == nil) { - UIGraphicsBeginImageContextWithOptions(CGSizeMake(6.0f, 6.0f), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, pallete.locationColor.CGColor); - CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, 6.0f, 6.0f)); - - dotImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - } - - _dotView.image = dotImage; - - [self setAnnotation:self.annotation]; -} - -- (void)setAnnotation:(id)annotation -{ - [super setAnnotation:annotation]; - - if ([annotation isKindOfClass:[TGLocationPickerAnnotation class]]) - { - _avatarView.hidden = false; - _avatarView.alpha = 1.0f; - _iconView.hidden = true; - _dotView.hidden = true; - - _backgroundView.image = TGComponentsImageNamed(@"LocationPinBackground"); - - _liveLocation = false; - [self setPeer:((TGLocationPickerAnnotation *)annotation).peer]; - - [self unsubscribeFromExpiration]; - } - else if ([annotation isKindOfClass:[TGLocationAnnotation class]]) - { - TGLocationAnnotation *locationAnnotation = ((TGLocationAnnotation *)annotation); - TGLocationMediaAttachment *location = locationAnnotation.location; - if (location.period == 0) - { - _dotView.hidden = false; - _avatarView.hidden = true; - _avatarView.alpha = 1.0f; - _iconView.hidden = false; - - UIColor *color = _pallete != nil ? _pallete.locationColor : UIColorRGB(0x008df2); - UIColor *pinColor = _pallete != nil ? _pallete.iconColor : [UIColor whiteColor]; - if (locationAnnotation.color != nil) { - color = locationAnnotation.color; - pinColor = [UIColor whiteColor]; - } - - _backgroundView.image = TGTintedImage(TGComponentsImageNamed(@"LocationPinBackground"), color); - if (location.venue.type.length > 0) - { - [_iconView loadUri:[NSString stringWithFormat:@"location-venue-icon://type=%@&width=%d&height=%d&color=%d", location.venue.type, 64, 64, TGColorHexCode(pinColor)] withOptions:nil]; - } - else - { - [_iconView reset]; - UIImage *image = TGComponentsImageNamed(@"LocationPinIcon"); - if (_pallete != nil) - image = TGTintedImage(image, _pallete.iconColor); - - _iconView.image = image; - } - - _liveLocation = false; - - [self unsubscribeFromExpiration]; - } - else - { - _avatarView.hidden = false; - _avatarView.alpha = locationAnnotation.isExpired ? 0.5f : 1.0f; - _iconView.hidden = true; - - _backgroundView.image = TGComponentsImageNamed(@"LocationPinBackground"); - - [self setPeer:locationAnnotation.peer]; - if (!locationAnnotation.isOwn) - { - if (!locationAnnotation.isExpired) - [_pulseView start]; - _dotView.hidden = false; - } - else - { - _dotView.hidden = true; - } - - [self subscribeForExpiration]; - - _liveLocation = true; - - if (!self.selected) - { - _shadowView.hidden = true; - _smallView.hidden = false; - } - } - } -} - -- (void)updateHeading -{ - if ([self.annotation isKindOfClass:[TGLocationAnnotation class]]) { - NSNumber *heading = ((TGLocationAnnotation *)self.annotation).heading; - - if (heading != nil) { - _arrowView.hidden = self.isSelected; - _smallArrowView.hidden = !self.isSelected; - _arrowView.transform = CGAffineTransformMakeRotation(heading.floatValue); - _smallArrowView.transform = CGAffineTransformMakeRotation(heading.floatValue); - } else { - _arrowView.hidden = true; - _smallArrowView.hidden = true; - } - } else { - _arrowView.hidden = true; - _smallArrowView.hidden = true; - } -} - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context -{ - if ([keyPath isEqualToString:@"annotation.isExpired"]) - { - if (((TGLocationAnnotation *)self.annotation).isExpired) - { - [_pulseView stop]; - _avatarView.alpha = 0.5f; - } - else - { - [_pulseView start]; - _avatarView.alpha = 1.0f; - } - } - else if ([keyPath isEqual:@"annotation.heading"]) - { - [self updateHeading]; - } - else - { - [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; - } -} - -- (void)setPeer:(id)peer -{ - CGFloat diameter = 55.0f; - - static UIImage *placeholder = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^ - { - UIGraphicsBeginImageContextWithOptions(CGSizeMake(diameter, diameter), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - - //!placeholder - CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); - CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, diameter, diameter)); - CGContextSetStrokeColorWithColor(context, UIColorRGB(0xd9d9d9).CGColor); - CGContextSetLineWidth(context, 1.0f); - CGContextStrokeEllipseInRect(context, CGRectMake(0.5f, 0.5f, diameter - 1.0f, diameter - 1.0f)); - - placeholder = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - }); - - if (_avatarView == nil) - { - _avatarView = [[TGLetteredAvatarView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 55.0f, 55.0f)]; - [_avatarView setSingleFontSize:24.0f doubleFontSize:24.0f useBoldFont:false]; - [self addSubview:_avatarView]; - } - else - { - [_avatarView.superview bringSubviewToFront:_avatarView]; - } - - bool isUser = [peer isKindOfClass:[TGUser class]]; - NSString *avatarUrl = isUser ? ((TGUser *)peer).photoFullUrlSmall : ((TGConversation *)peer).chatPhotoFullSmall; - if (avatarUrl.length != 0) - { - _avatarView.fadeTransitionDuration = 0.3; - if (![avatarUrl isEqualToString:_avatarView.currentUrl]) - [_avatarView loadImage:avatarUrl filter:@"circle:55x55" placeholder:placeholder]; - } - else - { - if (isUser) - { - [_avatarView loadUserPlaceholderWithSize:CGSizeMake(diameter, diameter) uid:((TGUser *)peer).uid firstName:((TGUser *)peer).firstName lastName:((TGUser *)peer).lastName placeholder:placeholder]; - } - else - { - [_avatarView loadGroupPlaceholderWithSize:CGSizeMake(diameter, diameter) conversationId:((TGConversation *)peer).conversationId title:((TGConversation *)peer).chatTitle placeholder:placeholder]; - } - } -} - -#pragma mark - Layout - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - if (_animating) - return; - - _dotView.center = CGPointZero; - _smallView.center = CGPointZero; - _arrowView.center = CGPointZero; - _smallArrowView.center = CGPointZero; - _shadowView.center = CGPointMake(TGScreenPixel, -36.0f); - _backgroundView.center = CGPointMake(_shadowView.frame.size.width / 2.0f, _shadowView.frame.size.height / 2.0f); - _iconView.center = CGPointMake(_shadowView.frame.size.width / 2.0f, _shadowView.frame.size.height / 2.0f - 5.0f); - - if (_liveLocation) - { - if (self.selected) - { - _avatarView.center = CGPointMake(TGScreenPixel, -41.0f); - _avatarView.transform = CGAffineTransformIdentity; - } - else - { - _avatarView.center = CGPointZero; - _avatarView.transform = CGAffineTransformMakeScale(0.64f, 0.64f); - } - } - else - { - _avatarView.center = CGPointMake(TGScreenPixel, -41.0f); - _avatarView.transform = CGAffineTransformIdentity; - } -} - -- (void)setPinRaised:(bool)raised -{ - [self setPinRaised:raised avatar:false animated:false completion:nil]; -} - -- (void)setPinRaised:(bool)raised avatar:(bool)avatar animated:(bool)animated completion:(void (^)(void))completion -{ - _pinRaised = raised; - avatar = false; - - [_shadowView.layer removeAllAnimations]; - if (iosMajorVersion() < 7) - animated = false; - - if (animated) - { - if (raised) - { - [UIView animateWithDuration:0.2 delay:0.0 options:7 << 16 | UIViewAnimationOptionAllowAnimatedContent animations:^ - { - _shadowView.center = CGPointMake(TGScreenPixel, -66.0f); - if (avatar) - _avatarView.center = CGPointMake(TGScreenPixel, -71.0f); - } completion:^(BOOL finished) { - if (finished && completion != nil) - completion(); - }]; - } - else - { - [UIView animateWithDuration:0.2 delay:0.0 usingSpringWithDamping:0.6 initialSpringVelocity:0.0 options:UIViewAnimationOptionAllowAnimatedContent animations:^ - { - _shadowView.center = CGPointMake(TGScreenPixel, -36.0f); - if (avatar) - _avatarView.center = CGPointMake(TGScreenPixel, -41.0f); - } completion:^(BOOL finished) - { - if (finished && completion != nil) - completion(); - }]; - } - } - else - { - _shadowView.center = CGPointMake(TGScreenPixel, raised ? -66.0f : -36.0f); - if (avatar) - _avatarView.center = CGPointMake(TGScreenPixel, raised ? -71.0 : -41.0f); - - if (completion != nil) - completion(); - } -} - -- (void)setCustomPin:(bool)customPin animated:(bool)animated -{ - if (animated) - { - _animating = true; - UIImage *image = TGComponentsImageNamed(@"LocationPinIcon"); - if (_pallete != nil) - image = TGTintedImage(image, _pallete.iconColor); - - _iconView.image = image; - [_backgroundView addSubview:_avatarView]; - _avatarView.center = CGPointMake(_backgroundView.frame.size.width / 2.0f, _backgroundView.frame.size.height / 2.0f - 5.0f); - _shadowView.center = CGPointMake(TGScreenPixel, -36.0f); - _backgroundView.center = CGPointMake(_shadowView.frame.size.width / 2.0f, _shadowView.frame.size.height / 2.0f); - _iconView.center = CGPointMake(_shadowView.frame.size.width / 2.0f, _shadowView.frame.size.height / 2.0f - 5.0f); - - TGDispatchAfter(0.01, dispatch_get_main_queue(), ^ - { - [UIView transitionWithView:_backgroundView duration:0.2 options:UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionAllowAnimatedContent animations:^ - { - _backgroundView.image = customPin ? TGTintedImage(TGComponentsImageNamed(@"LocationPinBackground"), _pallete != nil ? _pallete.locationColor : UIColorRGB(0x008df2)) : TGComponentsImageNamed(@"LocationPinBackground"); - _avatarView.hidden = customPin; - _iconView.hidden = !customPin; - } completion:^(BOOL finished) - { - if (!customPin) - [self addSubview:_avatarView]; - _animating = false; - [self setNeedsLayout]; - }]; - }); - - [self setNeedsLayout]; - } - else - { - - } - - _dotView.hidden = !customPin; -} - -@end - -@implementation TGLocationPinWrapperView - -- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event -{ - UIView *view = [super hitTest:point withEvent:event]; - if (view == self) - return nil; - - return view; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationPinView.h b/submodules/LegacyComponents/Sources/TGLocationPinView.h deleted file mode 100644 index 3561f28de9..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationPinView.h +++ /dev/null @@ -1,11 +0,0 @@ -#import - -@class TGLocationPallete; - -@interface TGLocationPinView : UIView - -@property (nonatomic, strong) TGLocationPallete *pallete; -@property (nonatomic, assign, getter=isPinRaised) bool pinRaised; -- (void)setPinRaised:(bool)raised animated:(bool)animated completion:(void (^)(void))completion; - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationPinView.m b/submodules/LegacyComponents/Sources/TGLocationPinView.m deleted file mode 100644 index 099d43ef2d..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationPinView.m +++ /dev/null @@ -1,125 +0,0 @@ -#import "TGLocationPinView.h" - -#import "TGImageUtils.h" -#import "LegacyComponentsInternal.h" - -#import "TGLocationMapViewController.h" - -const CGSize TGLocationPinSize = { 13.5f, 36 }; -const CGFloat TGLocationPinDamping = 2.0f; -const CGFloat TGLocationPinPinnedOrigin = 47; -const CGFloat TGLocationPinRaisedOrigin = 7; -const CGPoint TGLocationPinShadowPinnedOrigin = { 43, 47 }; -const CGPoint TGLocationPinShadowRaisedOrigin = { 87, -33 }; - -@interface TGLocationPinView () -{ - UIImageView *_pinView; - UIImageView *_pinPointView; - UIImageView *_shadowView; -} -@end - -@implementation TGLocationPinView - -- (instancetype)init -{ - self = [super initWithFrame:CGRectMake(0, 0, 100, 100)]; - if (self != nil) - { - self.userInteractionEnabled = false; - - _shadowView = [[UIImageView alloc] initWithFrame:CGRectMake(43, 47, 32, 39)]; - _shadowView.alpha = 0.9f; - _shadowView.image = TGComponentsImageNamed(@"LocationPinShadow.png"); - [self addSubview:_shadowView]; - - _pinPointView = [[UIImageView alloc] initWithFrame:CGRectMake(CGFloor(self.frame.size.width / 2 - 2), self.frame.size.height - 18.5f, 3.5f, 1.5f)]; - _pinPointView.image = TGComponentsImageNamed(@"LocationPinPoint.png"); - [self addSubview:_pinPointView]; - - _pinView = [[UIImageView alloc] initWithFrame:CGRectMake(CGFloor(self.frame.size.width / 2 - 7), 47, 13.5f, 36)]; - _pinView.image = TGComponentsImageNamed(@"LocationPin.png"); - [self addSubview:_pinView]; - } - return self; -} - -- (void)setPallete:(TGLocationPallete *)pallete -{ - _pallete = pallete; - - _pinView.image = TGTintedImage(_pinView.image, pallete.locationColor); - _pinPointView.image = TGTintedImage(_pinPointView.image, pallete.locationColor); -} - -- (void)setPinRaised:(bool)pinRaised -{ - [self setPinRaised:pinRaised animated:false completion:nil]; -} - -- (void)setPinRaised:(bool)raised animated:(bool)animated completion:(void (^)(void))completion -{ - _pinRaised = raised; - - [_pinView.layer removeAllAnimations]; - [_shadowView.layer removeAllAnimations]; - - if (animated) - { - if (raised) - { - [UIView animateWithDuration:0.2f delay:0.0f options:UIViewAnimationOptionBeginFromCurrentState animations:^ - { - _pinView.frame = CGRectMake(_pinView.frame.origin.x, TGLocationPinRaisedOrigin, TGLocationPinSize.width, TGLocationPinSize.height); - _shadowView.frame = CGRectMake(TGLocationPinShadowRaisedOrigin.x, TGLocationPinShadowRaisedOrigin.y, _shadowView.frame.size.width, _shadowView.frame.size.height); - } completion:^(BOOL finished) - { - if (finished && completion != nil) - completion(); - }]; - } - else - { - [UIView animateWithDuration:0.2f delay:0.0f options:UIViewAnimationOptionBeginFromCurrentState animations:^ - { - _pinView.frame = CGRectMake(_pinView.frame.origin.x, TGLocationPinPinnedOrigin, TGLocationPinSize.width, TGLocationPinSize.height); - _shadowView.frame = CGRectMake(TGLocationPinShadowPinnedOrigin.x, TGLocationPinShadowPinnedOrigin.y, _shadowView.frame.size.width, _shadowView.frame.size.height); - } completion:^(BOOL finished) - { - if (finished) - { - [UIView animateWithDuration:0.1f delay:0.0f options:UIViewAnimationOptionBeginFromCurrentState animations:^ - { - _pinView.frame = CGRectMake(_pinView.frame.origin.x, TGLocationPinPinnedOrigin + TGLocationPinDamping, TGLocationPinSize.width, TGLocationPinSize.height - TGLocationPinDamping); - } completion:^(BOOL finished) - { - if (finished) - { - [UIView animateWithDuration:0.1f delay:0.0f options:UIViewAnimationOptionBeginFromCurrentState animations:^ - { - _pinView.frame = CGRectMake(_pinView.frame.origin.x, TGLocationPinPinnedOrigin, TGLocationPinSize.width, TGLocationPinSize.height); - } completion:^(BOOL finished) - { - if (finished && completion != nil) - completion(); - }]; - } - }]; - } - }]; - } - } - else - { - _pinView.frame = CGRectMake(_pinView.frame.origin.x, raised ? TGLocationPinRaisedOrigin : TGLocationPinPinnedOrigin, TGLocationPinSize.width, TGLocationPinSize.height); - - CGPoint shadowOrigin = raised ? TGLocationPinShadowRaisedOrigin : TGLocationPinShadowPinnedOrigin; - _shadowView.frame = CGRectMake(shadowOrigin.x, shadowOrigin.y, _shadowView.frame.size.width, _shadowView.frame.size.height); - - if (completion != nil) - completion(); - } -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationPulseView.m b/submodules/LegacyComponents/Sources/TGLocationPulseView.m deleted file mode 100644 index 050f8d8fd0..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationPulseView.m +++ /dev/null @@ -1,59 +0,0 @@ -#import "TGLocationPulseView.h" - -#import "LegacyComponentsInternal.h" - -@interface TGLocationPulseView () -{ - CAShapeLayer *_circleLayer; -} -@end - -@implementation TGLocationPulseView - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - self.userInteractionEnabled = false; - - _circleLayer = [CAShapeLayer layer]; - _circleLayer.hidden = true; - _circleLayer.opacity = 0.0f; - _circleLayer.path = CGPathCreateWithEllipseInRect(CGRectMake(-60.0f, -60.0f, 120.0f, 120.0f), NULL); - _circleLayer.fillColor = UIColorRGBA(0x007aff, 0.27f).CGColor; - [self.layer addSublayer:_circleLayer]; - } - return self; -} - -- (void)start -{ - _circleLayer.hidden = false; - - if (_circleLayer.animationKeys.count > 0) - return; - - CAKeyframeAnimation *scaleAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"]; - scaleAnimation.values = @[@0.0f, @0.72f, @1.0f, @1.0f]; - scaleAnimation.keyTimes = @[@0.0, @0.49f, @0.88f, @1.0f]; - scaleAnimation.duration = 3.0; - scaleAnimation.repeatCount = INFINITY; - scaleAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; - [_circleLayer addAnimation:scaleAnimation forKey:@"circle-scale"]; - - CAKeyframeAnimation *opacityAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"]; - opacityAnimation.values = @[@1.0f, @0.2f, @0.0, @0.0f]; - opacityAnimation.keyTimes = @[@0.0, @0.4f, @0.62f, @1.0f]; - opacityAnimation.duration = 3.0; - opacityAnimation.repeatCount = INFINITY; - [_circleLayer addAnimation:opacityAnimation forKey:@"circle-opacity"]; -} - -- (void)stop -{ - _circleLayer.hidden = true; - [_circleLayer removeAllAnimations]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationReverseGeocodeResult.h b/submodules/LegacyComponents/Sources/TGLocationReverseGeocodeResult.h deleted file mode 100644 index 02dd86e16f..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationReverseGeocodeResult.h +++ /dev/null @@ -1,23 +0,0 @@ -#import - -@interface TGLocationReverseGeocodeResult : NSObject - -@property (nonatomic, readonly) NSString *identifier; -@property (nonatomic, readonly) CLLocationCoordinate2D coordinate; - -@property (nonatomic, readonly) NSString *displayAddress; - -@property (nonatomic, readonly) NSString *country; -@property (nonatomic, readonly) NSString *countryAbbr; -@property (nonatomic, readonly) NSString *state; -@property (nonatomic, readonly) NSString *stateAbbr; -@property (nonatomic, readonly) NSString *city; -@property (nonatomic, readonly) NSString *district; -@property (nonatomic, readonly) NSString *street; - -@property (nonatomic, readonly) NSString *fullAddress; - -+ (TGLocationReverseGeocodeResult *)reverseGeocodeResultWithDictionary:(NSDictionary *)dictionary; -+ (TGLocationReverseGeocodeResult *)reverseGeocodeResultWithPlacemark:(CLPlacemark *)placemark; - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationReverseGeocodeResult.m b/submodules/LegacyComponents/Sources/TGLocationReverseGeocodeResult.m deleted file mode 100644 index 0274544642..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationReverseGeocodeResult.m +++ /dev/null @@ -1,85 +0,0 @@ -#import "TGLocationReverseGeocodeResult.h" - -@implementation TGLocationReverseGeocodeResult - -+ (TGLocationReverseGeocodeResult *)reverseGeocodeResultWithDictionary:(NSDictionary *)dictionary -{ - TGLocationReverseGeocodeResult *result = [[TGLocationReverseGeocodeResult alloc] init]; - - for (NSDictionary *component in dictionary[@"address_components"]) - { - NSArray *types = component[@"types"]; - __unused NSString *shortName = component[@"short_name"]; - NSString *longName = component[@"long_name"]; - - if ([types containsObject:@"country"]) - { - result->_country = longName; - result->_countryAbbr = shortName; - } - else if ([types containsObject:@"administrative_area_level_1"]) - { - result->_state = longName; - result->_stateAbbr = shortName; - } - else if ([types containsObject:@"locality"]) - { - result->_city = longName; - } - else if ([types containsObject:@"sublocality"]) - { - result->_district = longName; - } - else if ([types containsObject:@"neighborhood"]) - { - if (result->_district.length == 0) - result->_district = longName; - } - else if ([types containsObject:@"route"]) - { - result->_street = longName; - } - } - - return result; -} - -+ (TGLocationReverseGeocodeResult *)reverseGeocodeResultWithPlacemark:(CLPlacemark *)placemark -{ - TGLocationReverseGeocodeResult *result = [[TGLocationReverseGeocodeResult alloc] init]; - result->_country = placemark.country; - result->_countryAbbr = placemark.ISOcountryCode; - result->_city = placemark.locality; - result->_district = placemark.subLocality; - result->_street = placemark.thoroughfare; - if (placemark.name.length > 0 && result->_street.length == 0) { - result->_street = placemark.name; - } - return result; -} - -- (NSString *)displayAddress -{ - if (self.street.length > 0) - return self.street; - else if (self.city.length > 0) - return self.city; - else if (self.country.length > 0) - return self.country; - - return nil; -} - -- (NSString *)fullAddress -{ - NSMutableArray *components = [[NSMutableArray alloc] init]; - if (self.street.length > 0) - [components addObject:self.street]; - if (self.city.length > 0) - [components addObject:self.city]; - if (self.country.length > 0) - [components addObject:self.country]; - return [components componentsJoinedByString:@", "]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationSectionHeaderCell.h b/submodules/LegacyComponents/Sources/TGLocationSectionHeaderCell.h deleted file mode 100644 index d6d2169451..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationSectionHeaderCell.h +++ /dev/null @@ -1,14 +0,0 @@ -#import - -@class TGLocationPallete; - -@interface TGLocationSectionHeaderCell : UITableViewCell - -@property (nonatomic, strong) TGLocationPallete *pallete; - -- (void)configureWithTitle:(NSString *)title; - -@end - -extern NSString *const TGLocationSectionHeaderKind; -extern const CGFloat TGLocationSectionHeaderHeight; diff --git a/submodules/LegacyComponents/Sources/TGLocationSectionHeaderCell.m b/submodules/LegacyComponents/Sources/TGLocationSectionHeaderCell.m deleted file mode 100644 index 1ba6be10da..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationSectionHeaderCell.m +++ /dev/null @@ -1,73 +0,0 @@ -#import "TGLocationSectionHeaderCell.h" - -#import "TGLocationMapViewController.h" -#import "LegacyComponentsInternal.h" -#import "TGFont.h" - -NSString *const TGLocationSectionHeaderKind = @"TGLocationSectionHeaderKind"; -const CGFloat TGLocationSectionHeaderHeight = 29.0f; - -@interface TGLocationSectionHeaderCell () -{ - UILabel *_titleLabel; -} -@end - -@implementation TGLocationSectionHeaderCell - -- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier -{ - self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; - if (self != nil) - { - self.backgroundColor = UIColorRGB(0xf7f7f7); - self.selectedBackgroundView = [[UIView alloc] init]; - - _titleLabel = [[UILabel alloc] init]; - _titleLabel.backgroundColor = self.backgroundColor; - _titleLabel.font = TGMediumSystemFontOfSize(12); - _titleLabel.textColor = UIColorRGB(0x8e8e93); - [self addSubview:_titleLabel]; - } - return self; -} - -- (void)setPallete:(TGLocationPallete *)pallete -{ - if (pallete == nil || _pallete == pallete) - return; - - _pallete = pallete; - - self.backgroundColor = pallete.sectionHeaderBackgroundColor; - _titleLabel.backgroundColor = self.backgroundColor; - _titleLabel.textColor = pallete.sectionHeaderTextColor; -} - -- (void)configureWithTitle:(NSString *)title -{ - title = [title uppercaseString]; - - void (^changeBlock)(void) = ^ - { - _titleLabel.text = title; - }; - - if ([_titleLabel.text isEqualToString:title]) - return; - - if (_titleLabel.text.length == 0) - changeBlock(); - else - [UIView transitionWithView:_titleLabel duration:0.2 options:UIViewAnimationOptionTransitionCrossDissolve animations:changeBlock completion:nil]; -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - CGFloat padding = 14.0f; - _titleLabel.frame = CGRectMake(padding, 1.0f, self.frame.size.width - padding, self.frame.size.height - 2.0f); -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationSignals.h b/submodules/LegacyComponents/Sources/TGLocationSignals.h deleted file mode 100644 index 5d534a4814..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationSignals.h +++ /dev/null @@ -1,18 +0,0 @@ -#import -#import - -@interface TGLocationSignals : NSObject - -+ (SSignal *)geocodeAddress:(NSString *)address; -+ (SSignal *)geocodeAddressDictionary:(NSDictionary *)dictionary; - -+ (SSignal *)reverseGeocodeCoordinate:(CLLocationCoordinate2D)coordinate; -+ (SSignal *)cityForCoordinate:(CLLocationCoordinate2D)coordinate; -+ (SSignal *)driveEta:(CLLocationCoordinate2D)coordinate; - -+ (void)storeLastKnownUserLocation:(CLLocation *)location; -+ (CLLocation *)lastKnownUserLocation; - -+ (SSignal *)userLocation:(SVariable *)locationRequired; - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationSignals.m b/submodules/LegacyComponents/Sources/TGLocationSignals.m deleted file mode 100644 index 46b631dba4..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationSignals.m +++ /dev/null @@ -1,257 +0,0 @@ -#import "TGLocationSignals.h" - -#import "LegacyComponentsInternal.h" -#import "TGStringUtils.h" - -#import - -#import -#import - -#import "TGLocationVenue.h" -#import "TGLocationReverseGeocodeResult.h" - -NSString *const TGLocationGoogleGeocodeLocale = @"en"; - -@interface TGLocationHelper : NSObject { - CLLocationManager *_locationManager; - void (^_locationDetermined)(CLLocation *); - bool _startedUpdating; -} - -@end - -@implementation TGLocationHelper - -- (instancetype)initWithLocationDetermined:(void (^)(CLLocation *))locationDetermined { - self = [super init]; - if (self != nil) { - _locationDetermined = [locationDetermined copy]; - - _locationManager = [[CLLocationManager alloc] init]; - _locationManager.delegate = self; - _locationManager.distanceFilter = kCLDistanceFilterNone; - _locationManager.desiredAccuracy = kCLLocationAccuracyBest; - - bool startUpdating = false; - if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) { - switch ([CLLocationManager authorizationStatus]) - { - case kCLAuthorizationStatusAuthorizedAlways: - case kCLAuthorizationStatusAuthorizedWhenInUse: - startUpdating = true; - default: - break; - } - } - - if (startUpdating) { - [self startUpdating]; - } - } - return self; -} - -- (void)dealloc { - [_locationManager stopUpdatingLocation]; -} - -- (void)startUpdating { - if (!_startedUpdating) { - _startedUpdating = true; - if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) { - [_locationManager requestWhenInUseAuthorization]; - } - [_locationManager startUpdatingLocation]; - } -} - -- (void)locationManager:(CLLocationManager *)__unused manager didUpdateLocations:(NSArray *)locations { - if (locations.count != 0) { - if (_locationDetermined) { - _locationDetermined([locations lastObject]); - } - } -} - -@end - -@implementation TGLocationSignals - -+ (SSignal *)geocodeAddress:(NSString *)address -{ - return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) - { - CLGeocoder *geocoder = [[CLGeocoder alloc] init]; - [geocoder geocodeAddressString:address completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) - { - if (error != nil) - { - [subscriber putError:error]; - return; - } - else - { - [subscriber putNext:placemarks.firstObject]; - [subscriber putCompletion]; - } - }]; - - return [[SBlockDisposable alloc] initWithBlock:^ - { - [geocoder cancelGeocode]; - }]; - }]; -} - -+ (SSignal *)geocodeAddressDictionary:(NSDictionary *)dictionary -{ - return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) - { - CLGeocoder *geocoder = [[CLGeocoder alloc] init]; - [geocoder geocodeAddressDictionary:dictionary completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) - { - if (error != nil) - { - [subscriber putError:error]; - return; - } - else - { - [subscriber putNext:placemarks.firstObject]; - [subscriber putCompletion]; - } - }]; - - return [[SBlockDisposable alloc] initWithBlock:^ - { - [geocoder cancelGeocode]; - }]; - }]; -} - -+ (SSignal *)reverseGeocodeCoordinate:(CLLocationCoordinate2D)coordinate -{ - return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) - { - CLGeocoder *geocoder = [[CLGeocoder alloc] init]; - [geocoder reverseGeocodeLocation:[[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude] completionHandler:^(NSArray *placemarks, NSError *error) - { - if (error != nil) - { - [subscriber putError:error]; - return; - } - else - { - [subscriber putNext:[TGLocationReverseGeocodeResult reverseGeocodeResultWithPlacemark:placemarks.firstObject]]; - [subscriber putCompletion]; - } - }]; - - return [[SBlockDisposable alloc] initWithBlock:^ - { - [geocoder cancelGeocode]; - }]; - }]; -} - -+ (SSignal *)cityForCoordinate:(CLLocationCoordinate2D)coordinate -{ - return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) - { - CLGeocoder *geocoder = [[CLGeocoder alloc] init]; - [geocoder reverseGeocodeLocation:[[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude] completionHandler:^(NSArray *placemarks, NSError *error) - { - if (error != nil) - { - [subscriber putError:error]; - return; - } - else - { - [subscriber putNext:[placemarks.firstObject locality]]; - [subscriber putCompletion]; - } - }]; - - return [[SBlockDisposable alloc] initWithBlock:^ - { - [geocoder cancelGeocode]; - }]; - }]; -} - -+ (SSignal *)driveEta:(CLLocationCoordinate2D)destinationCoordinate -{ - if (iosMajorVersion() < 7) - return [SSignal single:@0]; - - return [[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) - { - MKPlacemark *destinationPlacemark = [[MKPlacemark alloc] initWithCoordinate:destinationCoordinate addressDictionary:nil]; - MKMapItem *destinationMapItem = [[MKMapItem alloc] initWithPlacemark:destinationPlacemark]; - - MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init]; - request.source = [MKMapItem mapItemForCurrentLocation]; - request.destination = destinationMapItem; - request.transportType = MKDirectionsTransportTypeAutomobile; - request.requestsAlternateRoutes = false; - - MKDirections *directions = [[MKDirections alloc] initWithRequest:request]; - [directions calculateETAWithCompletionHandler:^(MKETAResponse *response, NSError *error) - { - if (error != nil) - { - [subscriber putError:error]; - return; - } - - [subscriber putNext:@(response.expectedTravelTime)]; - [subscriber putCompletion]; - }]; - - - return [[SBlockDisposable alloc] initWithBlock:^ - { - [directions cancel]; - }]; - }]; -} - -#pragma mark - - -static CLLocation *lastKnownUserLocation; - -+ (void)storeLastKnownUserLocation:(CLLocation *)location -{ - lastKnownUserLocation = location; -} - -+ (CLLocation *)lastKnownUserLocation -{ - NSTimeInterval locationAge = -[lastKnownUserLocation.timestamp timeIntervalSinceNow]; - if (locationAge > 600) - lastKnownUserLocation = nil; - - return lastKnownUserLocation; -} - -+ (SSignal *)userLocation:(SVariable *)locationRequired { - return [[[SSignal alloc] initWithGenerator:^id(SSubscriber *subscriber) { - TGLocationHelper *helper = [[TGLocationHelper alloc] initWithLocationDetermined:^(CLLocation *location) { - [subscriber putNext:location]; - }]; - - id requiredDisposable = [[[[locationRequired signal] take:1] deliverOn:[SQueue mainQueue]] startWithNext:^(__unused id next) { - [helper startUpdating]; - }]; - - return [[SBlockDisposable alloc] initWithBlock:^{ - [helper description]; // keep reference - [requiredDisposable dispose]; - }]; - }] startOn:[SQueue mainQueue]]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationTitleView.h b/submodules/LegacyComponents/Sources/TGLocationTitleView.h deleted file mode 100644 index aa96ebd5fe..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationTitleView.h +++ /dev/null @@ -1,12 +0,0 @@ -#import - -@interface TGLocationTitleView : UIView - -@property (nonatomic, strong) NSString *title; -@property (nonatomic, strong) NSString *address; - -@property (nonatomic, assign) UIInterfaceOrientation interfaceOrientation; -@property (nonatomic, assign) CGFloat backButtonWidth; -@property (nonatomic, assign) CGFloat actionsButtonWidth; - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationTitleView.m b/submodules/LegacyComponents/Sources/TGLocationTitleView.m deleted file mode 100644 index d8198d51e8..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationTitleView.m +++ /dev/null @@ -1,135 +0,0 @@ -#import "TGLocationTitleView.h" - -#import "LegacyComponentsInternal.h" -#import "TGFont.h" - -@interface TGLocationTitleView () -{ - UILabel *_titleLabel; - UILabel *_addressLabel; -} -@end - -@implementation TGLocationTitleView - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - _titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 5, frame.size.width, 20)]; - _titleLabel.backgroundColor = [UIColor clearColor]; - _titleLabel.font = TGBoldSystemFontOfSize(17); - _titleLabel.textColor = [UIColor blackColor]; - _titleLabel.textAlignment = NSTextAlignmentCenter; - [self addSubview:_titleLabel]; - - _addressLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 21, frame.size.width, 21)]; - _addressLabel.backgroundColor = [UIColor clearColor]; - _addressLabel.font = TGSystemFontOfSize(13.0f); - _addressLabel.textColor = UIColorRGB(0x787878); - _addressLabel.textAlignment = NSTextAlignmentCenter; - [self addSubview:_addressLabel]; - } - return self; -} - -- (NSString *)title -{ - return _titleLabel.text; -} - -- (void)setTitle:(NSString *)title -{ - _titleLabel.text = title; - [self setNeedsLayout]; -} - -- (NSString *)address -{ - return _addressLabel.text; -} - -- (void)setAddress:(NSString *)address -{ - _addressLabel.text = address; - [self setNeedsLayout]; -} - -- (UIView *)_findNavigationBar:(UIView *)view -{ - if (view.superview == nil) - return nil; - else if ([view.superview isKindOfClass:[UINavigationBar class]]) - return view.superview; - else - return [self _findNavigationBar:view.superview]; -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - [_titleLabel sizeToFit]; - [_addressLabel sizeToFit]; - - CGRect titleFrame = _titleLabel.frame; - titleFrame.size.width = CGCeil(titleFrame.size.width); - - CGRect addressFrame = _addressLabel.frame; - addressFrame.size.width = CGCeil(addressFrame.size.width); - - UIView *navigationBar = [self _findNavigationBar:self]; - CGRect offsetRect = [self.superview convertRect:self.frame toView:navigationBar]; - - UIEdgeInsets edges = UIEdgeInsetsMake(0, self.backButtonWidth, 0, navigationBar.frame.size.width - self.actionsButtonWidth); - - if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) - { - if (_addressLabel.text.length > 0) - titleFrame.origin.y = 5; - else - titleFrame.origin.y = 12; - - addressFrame.origin.y = 23.5f; - - titleFrame.origin.x = (navigationBar.frame.size.width - titleFrame.size.width) / 2; - if (titleFrame.origin.x < edges.left || CGRectGetMaxX(titleFrame) > edges.right) - { - titleFrame.origin.x = edges.left; - titleFrame.size.width = edges.right - edges.left; - } - - CGFloat titleCenter = CGRectGetMidX(titleFrame); - addressFrame.origin.x = titleCenter - addressFrame.size.width / 2; - if (addressFrame.origin.x < edges.left || CGRectGetMaxX(addressFrame) > edges.right) - { - addressFrame.origin.x = edges.left; - addressFrame.size.width = edges.right - edges.left; - } - } - else - { - titleFrame.origin.y = 10; - addressFrame.origin.y = 13; - - CGFloat jointWidth = titleFrame.size.width + addressFrame.size.width + 6; - CGFloat jointOrigin = (navigationBar.frame.size.width - jointWidth) / 2; - if (jointOrigin < edges.left || jointOrigin + jointWidth > edges.right) - { - jointOrigin = edges.left; - - CGFloat newJointWidth = edges.right - edges.left; - addressFrame.size.width -= (jointWidth - newJointWidth); - jointWidth = newJointWidth; - } - - titleFrame.origin.x = jointOrigin; - addressFrame.origin.x = jointOrigin + jointWidth - addressFrame.size.width; - } - - _titleLabel.frame = CGRectOffset(titleFrame, -offsetRect.origin.x, 0); - _addressLabel.frame = CGRectOffset(addressFrame, -offsetRect.origin.x, 0); -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationTrackingButton.h b/submodules/LegacyComponents/Sources/TGLocationTrackingButton.h deleted file mode 100644 index 351babf281..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationTrackingButton.h +++ /dev/null @@ -1,23 +0,0 @@ -#import -#import "TGModernButton.h" - -typedef enum { - TGLocationTrackingModeNone, - TGLocationTrackingModeFollow, - TGLocationTrackingModeFollowWithHeading -} TGLocationTrackingMode; - -@interface TGLocationTrackingButton : TGModernButton - -@property (nonatomic, assign) TGLocationTrackingMode trackingMode; -- (void)setTrackingMode:(TGLocationTrackingMode)trackingMode animated:(bool)animated; - -@property (nonatomic, assign, getter=isLocationAvailable) bool locationAvailable; -- (void)setLocationAvailable:(bool)available animated:(bool)animated; - -- (void)setAccentColor:(UIColor *)accentColor spinnerColor:(UIColor *)spinnerColor; - -+ (TGLocationTrackingMode)locationTrackingModeWithUserTrackingMode:(MKUserTrackingMode)mode; -+ (MKUserTrackingMode)userTrackingModeWithLocationTrackingMode:(TGLocationTrackingMode)mode; - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationTrackingButton.m b/submodules/LegacyComponents/Sources/TGLocationTrackingButton.m deleted file mode 100644 index 0735912848..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationTrackingButton.m +++ /dev/null @@ -1,151 +0,0 @@ -#import "TGLocationTrackingButton.h" - -#import "TGImageUtils.h" -#import "LegacyComponentsInternal.h" - -@interface TGLocationTrackingButton () -{ - UIImageView *_noneModeIconView; - UIImageView *_followModeIconView; - UIImageView *_followWithHeadingModeIconView; - UIActivityIndicatorView *_activityIndicator; -} -@end - -@implementation TGLocationTrackingButton - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - self.exclusiveTouch = true; - - _noneModeIconView = [[UIImageView alloc] initWithFrame:self.bounds]; - _noneModeIconView.contentMode = UIViewContentModeCenter; - _noneModeIconView.image = TGComponentsImageNamed(@"TrackingLocationOff.png"); - [self addSubview:_noneModeIconView]; - - _followModeIconView = [[UIImageView alloc] initWithFrame:self.bounds]; - _followModeIconView.contentMode = UIViewContentModeCenter; - _followModeIconView.image = TGComponentsImageNamed(@"TrackingLocation.png"); - [self addSubview:_followModeIconView]; - - _followWithHeadingModeIconView = [[UIImageView alloc] initWithFrame:CGRectOffset(self.bounds, 1, 0.5f)]; - _followWithHeadingModeIconView.contentMode = UIViewContentModeCenter; - _followWithHeadingModeIconView.image = TGComponentsImageNamed(@"TrackingHeading.png"); - [self addSubview:_followWithHeadingModeIconView]; - - _activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; - _activityIndicator.userInteractionEnabled = false; - _activityIndicator.frame = CGRectOffset(_activityIndicator.frame, 0, 0); - _activityIndicator.alpha = 0.0f; - _activityIndicator.transform = CGAffineTransformMakeScale(0.1f, 0.1f); - [self addSubview:_activityIndicator]; - - _locationAvailable = true; - [self setTrackingMode:TGLocationTrackingModeNone]; - } - return self; -} - -- (void)setAccentColor:(UIColor *)accentColor spinnerColor:(UIColor *)spinnerColor -{ - _noneModeIconView.image = TGTintedImage(TGComponentsImageNamed(@"TrackingLocationOff.png"), accentColor); - _followModeIconView.image = TGTintedImage(TGComponentsImageNamed(@"TrackingLocation.png"), accentColor); - _followWithHeadingModeIconView.image = TGTintedImage(TGComponentsImageNamed(@"TrackingHeading.png"), accentColor); - _activityIndicator.color = spinnerColor; -} - -- (void)setTrackingMode:(TGLocationTrackingMode)trackingMode -{ - [self setTrackingMode:trackingMode animated:false]; -} - -- (void)setTrackingMode:(TGLocationTrackingMode)trackingMode animated:(bool)animated -{ - _trackingMode = trackingMode; - - CGFloat noneModeAlpha = (trackingMode == TGLocationTrackingModeNone) ? 1.0f : 0.0f; - CGFloat followModeAlpha = (trackingMode == TGLocationTrackingModeFollow) ? 1.0f : 0.0f; - CGFloat followWithHeadingModeAlpha = (trackingMode == TGLocationTrackingModeFollowWithHeading) ? 1.0f : 0.0f; - - void (^changeBlock)(void) = ^ - { - _noneModeIconView.alpha = noneModeAlpha; - _followModeIconView.alpha = followModeAlpha; - _followWithHeadingModeIconView.alpha = followWithHeadingModeAlpha; - - if (followWithHeadingModeAlpha < FLT_EPSILON) - { - _noneModeIconView.transform = CGAffineTransformIdentity; - _followModeIconView.transform = CGAffineTransformIdentity; - _followWithHeadingModeIconView.transform = CGAffineTransformMakeScale(0.1f, 0.1f); - } - else - { - _noneModeIconView.transform = CGAffineTransformMakeScale(0.1f, 0.1f); - _followModeIconView.transform = CGAffineTransformMakeScale(0.1f, 0.1f); - _followWithHeadingModeIconView.transform = CGAffineTransformIdentity; - } - }; - - if (animated) - [UIView animateWithDuration:0.2f delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:changeBlock completion:nil]; - else - changeBlock(); -} - -- (void)setIsLocationAvailable:(bool)available -{ - [self setLocationAvailable:available animated:false]; -} - -- (void)setLocationAvailable:(bool)available animated:(bool)animated -{ - if (available == _locationAvailable) - return; - - _locationAvailable = available; - - if (animated) - { - - } - else - { - - } -} - -+ (TGLocationTrackingMode)locationTrackingModeWithUserTrackingMode:(MKUserTrackingMode)mode -{ - switch (mode) - { - case MKUserTrackingModeFollow: - return TGLocationTrackingModeFollow; - - case MKUserTrackingModeFollowWithHeading: - return TGLocationTrackingModeFollowWithHeading; - - default: - return TGLocationTrackingModeNone; - } -} - -+ (MKUserTrackingMode)userTrackingModeWithLocationTrackingMode:(TGLocationTrackingMode)mode -{ - switch (mode) - { - case TGLocationTrackingModeFollow: - return MKUserTrackingModeFollow; - - case TGLocationTrackingModeFollowWithHeading: - return MKUserTrackingModeFollowWithHeading; - - default: - return MKUserTrackingModeNone; - } -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationUtils.h b/submodules/LegacyComponents/Sources/TGLocationUtils.h deleted file mode 100644 index 56bd839f3c..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationUtils.h +++ /dev/null @@ -1,50 +0,0 @@ -#import -#import - -@interface TGLocationUtils : NSObject - -+ (MKMapRect)MKMapRectForCoordinateRegion:(MKCoordinateRegion)region; - -+ (bool)requestWhenInUserLocationAuthorizationWithLocationManager:(CLLocationManager *)locationManager; -+ (bool)requestAlwaysUserLocationAuthorizationWithLocationManager:(CLLocationManager *)locationManager; - -+ (NSString *)stringFromDistance:(CLLocationDistance)distance; -+ (NSString *)stringFromAccuracy:(CLLocationAccuracy)accuracy; - -+ (NSString *)stringForCoordinate:(CLLocationCoordinate2D)coordinate; - -@end - -@interface TGLocationUtils (GoogleMaps) - -+ (CLLocationDegrees)adjustGMapLatitude:(CLLocationDegrees)latitude withPixelOffset:(NSInteger)offset zoom:(NSInteger)zoom; -+ (CLLocationDegrees)adjustGMapLongitude:(CLLocationDegrees)longitude withPixelOffset:(NSInteger)offset zoom:(NSInteger)zoom; -+ (CLLocationCoordinate2D)adjustGMapCoordinate:(CLLocationCoordinate2D)coordinate withPixelOffset:(CGPoint)offset zoom:(NSInteger)zoom; - -@end - -@interface TGLocationUtils (ThirdPartyAppLauncher) - -+ (void)openMapsWithCoordinate:(CLLocationCoordinate2D)coordinate withDirections:(bool)withDirections locationName:(NSString *)locationName; - -+ (void)openGoogleMapsWithCoordinate:(CLLocationCoordinate2D)coordinate withDirections:(bool)withDirections; -+ (bool)isGoogleMapsInstalled; - -+ (void)openGoogleWithPlaceId:(NSString *)placeId; - -+ (void)openFoursquareWithVenueId:(NSString *)venueId; -+ (bool)isFoursquareInstalled; - -+ (void)openHereMapsWithCoordinate:(CLLocationCoordinate2D)coordinate; -+ (bool)isHereMapsInstalled; - -+ (void)openYandexMapsWithCoordinate:(CLLocationCoordinate2D)coordinate withDirections:(bool)withDirections; -+ (bool)isYandexMapsInstalled; - -+ (void)openDirectionsInYandexNavigatorWithCoordinate:(CLLocationCoordinate2D)coordinate; -+ (bool)isYandexNavigatorInstalled; - -+ (void)openWazeWithCoordinate:(CLLocationCoordinate2D)coordinate withDirections:(bool)withDirections; -+ (bool)isWazeInstalled; - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationUtils.m b/submodules/LegacyComponents/Sources/TGLocationUtils.m deleted file mode 100644 index 30d4a1fbea..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationUtils.m +++ /dev/null @@ -1,381 +0,0 @@ -#import "TGLocationUtils.h" - -#import "LegacyComponentsInternal.h" -#import "TGLocalization.h" - -#import - -@implementation TGLocationUtils - -+ (MKMapRect)MKMapRectForCoordinateRegion:(MKCoordinateRegion)region -{ - MKMapPoint a = MKMapPointForCoordinate(CLLocationCoordinate2DMake(region.center.latitude + region.span.latitudeDelta / 2, - region.center.longitude - region.span.longitudeDelta / 2)); - MKMapPoint b = MKMapPointForCoordinate(CLLocationCoordinate2DMake(region.center.latitude - region.span.latitudeDelta / 2, - region.center.longitude + region.span.longitudeDelta / 2)); - return MKMapRectMake(MIN(a.x,b.x), MIN(a.y,b.y), ABS(a.x-b.x), ABS(a.y-b.y)); -} - -+ (bool)requestWhenInUserLocationAuthorizationWithLocationManager:(CLLocationManager *)locationManager -{ - CLAuthorizationStatus authorizationStatus = [CLLocationManager authorizationStatus]; - - if (authorizationStatus == kCLAuthorizationStatusDenied || authorizationStatus == kCLAuthorizationStatusRestricted) - return false; - - if ([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) - { - if (authorizationStatus == kCLAuthorizationStatusNotDetermined) - [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"TG_askedForAlwaysAuthorization_v0"]; - - [locationManager requestWhenInUseAuthorization]; - return true; - } - - return false; -} - -+ (bool)requestAlwaysUserLocationAuthorizationWithLocationManager:(CLLocationManager *)locationManager -{ - CLAuthorizationStatus authorizationStatus = [CLLocationManager authorizationStatus]; - if (authorizationStatus == kCLAuthorizationStatusDenied || authorizationStatus == kCLAuthorizationStatusRestricted) - return false; - - if ([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) - { - NSString *key = @"TG_askedForAlwaysAuthorization_v0"; - bool askedForAlwaysAuthorization = [[[NSUserDefaults standardUserDefaults] objectForKey:key] boolValue]; - if (authorizationStatus == kCLAuthorizationStatusAuthorizedWhenInUse && askedForAlwaysAuthorization) - return false; - - [locationManager requestAlwaysAuthorization]; - [[NSUserDefaults standardUserDefaults] setObject:@true forKey:key]; - - return true; - } - - return false; -} - -+ (NSString *)stringFromDistance:(CLLocationDistance)distance -{ - if (iosMajorVersion() >= 7) - { - MKDistanceFormatter *formatter = [self sharedDistanceFormatter]; - NSString *systemLocale = [NSLocale currentLocale].localeIdentifier; - NSString *finalLocale = legacyEffectiveLocalization().code; - NSRange range = [systemLocale rangeOfString:@"_"]; - if (range.location != NSNotFound) { - finalLocale = [finalLocale stringByAppendingString:[systemLocale substringFromIndex:range.location]]; - } - formatter.locale = [NSLocale localeWithLocaleIdentifier:finalLocale]; - if ([[formatter.locale objectForKey:NSLocaleUsesMetricSystem] boolValue]) - formatter.unitStyle = MKDistanceFormatterUnitStyleAbbreviated; - else - formatter.unitStyle = MKDistanceFormatterUnitStyleDefault; - - return [[self sharedDistanceFormatter] stringFromDistance:distance]; - } - else - { - return [self _customStringFromDistance:distance]; - } -} - -+ (NSString *)stringFromAccuracy:(CLLocationAccuracy)accuracy -{ - if (iosMajorVersion() >= 7) - { - MKDistanceFormatter *formatter = [self sharedAccuracyFormatter]; - //formatter.locale = [NSLocale localeWithLocaleIdentifier:legacyEffectiveLocalization().code]; - return [[self sharedAccuracyFormatter] stringFromDistance:accuracy]; - } - else - { - return [self _customStringFromDistance:accuracy]; - } -} - -+ (NSString *)stringForCoordinate:(CLLocationCoordinate2D)coordinate -{ - NSInteger latSeconds = (NSInteger)(coordinate.latitude * 3600); - NSInteger latDegrees = latSeconds / 3600; - latSeconds = labs(latSeconds % 3600); - NSInteger latMinutes = latSeconds / 60; - latSeconds %= 60; - - NSInteger longSeconds = (NSInteger)(coordinate.longitude * 3600); - NSInteger longDegrees = longSeconds / 3600; - longSeconds = labs(longSeconds % 3600); - NSInteger longMinutes = longSeconds / 60; - longSeconds %= 60; - - NSString *result = [NSString stringWithFormat:@"%@%02ld° %02ld' %02ld\" %@%02ld° %02ld' %02ld\"", latDegrees >= 0 ? @"N" : @"S", labs(latDegrees), (long)latMinutes, (long)latSeconds, longDegrees >= 0 ? @"E" : @"W", labs(longDegrees), (long)longMinutes, (long)longSeconds]; - - return result; -} - -+ (NSString *)_customStringFromDistance:(CLLocationDistance)distance -{ - NSLocale *locale = [NSLocale localeWithLocaleIdentifier:legacyEffectiveLocalization().code]; - bool metricUnits = [[locale objectForKey:NSLocaleUsesMetricSystem] boolValue]; - - NSString *distanceString = nil; - - if (metricUnits) - { - if (distance >= 1000 * 1000) - distanceString = [[NSString alloc] initWithFormat:@"%.1fK km", distance / (1000.0 * 1000.0)]; - else if (distance > 1000) - distanceString = [[NSString alloc] initWithFormat:@"%.1f km", distance / 1000.0]; - else - distanceString = [[NSString alloc] initWithFormat:@"%d m", (int)distance]; - } - else - { - double feetDistance = distance / 0.3048; - - if (feetDistance >= 5280) - { - char buf[32]; - snprintf(buf, 32, "%.1f", feetDistance / 5280.0); - bool dot = false; - for (int i = 0; i < 32; i++) - { - char c = buf[i]; - if (c == '\0') - break; - else if (c < '0' || c > '9') - { - dot = true; - break; - } - } - distanceString = [[NSString alloc] initWithFormat:@"%s mile%s", buf, dot || feetDistance / 5280.0 > 1.0 ? "s" : ""]; - } - else - { - distanceString = [[NSString alloc] initWithFormat:@"%d %s", (int)feetDistance, (int)feetDistance != 1 ? "feet" : "foot"]; - } - } - - return distanceString; -} - -+ (MKDistanceFormatter *)sharedDistanceFormatter -{ - static dispatch_once_t once; - static MKDistanceFormatter *distanceFormatter; - dispatch_once(&once, ^ - { - distanceFormatter = [[MKDistanceFormatter alloc] init]; - }); - - return distanceFormatter; -} - -+ (MKDistanceFormatter *)sharedAccuracyFormatter -{ - static dispatch_once_t once; - static MKDistanceFormatter *accuracyFormatter; - dispatch_once(&once, ^ - { - accuracyFormatter = [[MKDistanceFormatter alloc] init]; - accuracyFormatter.unitStyle = MKDistanceFormatterUnitStyleFull; - }); - - return accuracyFormatter; -} - -@end - -const NSInteger TGGoogleMapsOffset = 268435456; -const CGFloat TGGoogleMapsRadius = TGGoogleMapsOffset / (CGFloat)M_PI; - -@implementation TGLocationUtils (GoogleMaps) - -+ (CLLocationCoordinate2D)adjustGMapCoordinate:(CLLocationCoordinate2D)coordinate withPixelOffset:(CGPoint)offset zoom:(NSInteger)zoom -{ - return CLLocationCoordinate2DMake([self adjustGMapLatitude:coordinate.latitude withPixelOffset:(NSInteger)offset.y zoom:zoom], [self adjustGMapLongitude:coordinate.longitude withPixelOffset:(NSInteger)offset.x zoom:zoom]); -} - -+ (CLLocationDegrees)adjustGMapLatitude:(CLLocationDegrees)latitude withPixelOffset:(NSInteger)offset zoom:(NSInteger)zoom -{ - return [self _yToLatitude:([self _latitudeToY:latitude] + (offset << (21 - zoom)))]; -} - -+ (CLLocationDegrees)adjustGMapLongitude:(CLLocationDegrees)longitude withPixelOffset:(NSInteger)offset zoom:(NSInteger)zoom -{ - return [self _xToLongitude:([self _longitudeToX:longitude] + (offset << (21 - zoom)))]; -} - -+ (NSInteger)_latitudeToY:(CLLocationDegrees)latitude -{ - return (NSInteger)round(TGGoogleMapsOffset - TGGoogleMapsRadius * log((1 + sin(latitude * M_PI / 180.0)) / (1 - sin(latitude * M_PI / 180.0))) / 2); -} - -+ (CLLocationDegrees)_yToLatitude:(NSInteger)y -{ - return (M_PI_2 - 2 * atan(exp((y - TGGoogleMapsOffset) / TGGoogleMapsRadius))) * 180.0 / M_PI; -} - -+ (NSInteger)_longitudeToX:(CLLocationDegrees)longitude -{ - return (NSInteger)round(TGGoogleMapsOffset + TGGoogleMapsRadius * longitude * M_PI / 180); -} - -+ (CLLocationDegrees)_xToLongitude:(NSInteger)x -{ - return (x - TGGoogleMapsOffset) / TGGoogleMapsRadius * 180.0 / M_PI; -} - -@end - -@implementation TGLocationUtils (ThirdPartyAppLauncher) - -#pragma mark Apple Maps - -+ (void)openMapsWithCoordinate:(CLLocationCoordinate2D)coordinate withDirections:(bool)withDirections locationName:(NSString *)locationName -{ - MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:coordinate - addressDictionary:nil]; - MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark]; - [mapItem setName:locationName]; - - if (withDirections) - { - NSDictionary *options = @{ MKLaunchOptionsDirectionsModeKey : MKLaunchOptionsDirectionsModeDriving }; - MKMapItem *currentLocationMapItem = [MKMapItem mapItemForCurrentLocation]; - [MKMapItem openMapsWithItems:@[ currentLocationMapItem, mapItem ] - launchOptions:options]; - } - else - { - [mapItem openInMapsWithLaunchOptions:nil]; - } -} - -#pragma mark Google Maps - -+ (void)openGoogleMapsWithCoordinate:(CLLocationCoordinate2D)coordinate withDirections:(bool)withDirections -{ - NSURL *url = nil; - NSString *coordinatePair = [NSString stringWithFormat:@"%f,%f", coordinate.latitude, coordinate.longitude]; - - if (withDirections) - { - url = [NSURL URLWithString:[[NSString alloc] initWithFormat:@"comgooglemaps-x-callback://?daddr=%@&directionsmode=driving&x-success=telegram://?resume=true&&x-source=Telegram", coordinatePair]]; - } - else - { - url = [NSURL URLWithString:[[NSString alloc] initWithFormat:@"comgooglemaps-x-callback://?center=%@&q=%@&x-success=telegram://?resume=true&&x-source=Telegram", coordinatePair, coordinatePair]]; - } - - [[LegacyComponentsGlobals provider] openURL:url]; -} - -+ (bool)isGoogleMapsInstalled -{ - return [[LegacyComponentsGlobals provider] canOpenURL:[NSURL URLWithString:@"comgooglemaps-x-callback://"]]; -} - - -+ (void)openGoogleWithPlaceId:(NSString *)placeId -{ - NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://maps.google.com/maps/place?cid=%@", placeId]]; - [[LegacyComponentsGlobals provider] openURL:url]; -} -#pragma mark Foursquare - -+ (void)openFoursquareWithVenueId:(NSString *)venueId -{ - NSURL *url = nil; - - if ([self isFoursquareInstalled]) - url = [NSURL URLWithString:[NSString stringWithFormat:@"foursquare://venues/%@", venueId]]; - else - url = [NSURL URLWithString:[NSString stringWithFormat:@"https://foursquare.com/venue/%@", venueId]]; - - [[LegacyComponentsGlobals provider] openURL:url]; -} - -+ (bool)isFoursquareInstalled -{ - return [[LegacyComponentsGlobals provider] canOpenURL:[NSURL URLWithString:@"foursquare://"]]; -} - -#pragma mark Here Maps - -+ (void)openHereMapsWithCoordinate:(CLLocationCoordinate2D)coordinate -{ - NSURL *url = [NSURL URLWithString:[[NSString alloc] initWithFormat:@"here-location://%f,%f", coordinate.latitude, coordinate.longitude]]; - - [[LegacyComponentsGlobals provider] openURL:url]; -} - -+ (bool)isHereMapsInstalled -{ - return [[LegacyComponentsGlobals provider] canOpenURL:[NSURL URLWithString:@"here-location://"]]; -} - -#pragma mark Yandex Maps - -+ (void)openYandexMapsWithCoordinate:(CLLocationCoordinate2D)coordinate withDirections:(bool)withDirections -{ - NSURL *url = nil; - - if (withDirections) - { - url = [NSURL URLWithString:[[NSString alloc] initWithFormat:@"yandexmaps://build_route_on_map?lat_to=%f&lon_to=%f", coordinate.latitude, coordinate.longitude]]; - } - else - { - url = [NSURL URLWithString:[[NSString alloc] initWithFormat:@"yandexmaps://maps.yandex.ru/?pt=%f,%f&z=16", coordinate.longitude, coordinate.latitude]]; - } - - [[LegacyComponentsGlobals provider] openURL:url]; -} - -+ (bool)isYandexMapsInstalled -{ - return [[LegacyComponentsGlobals provider] canOpenURL:[NSURL URLWithString:@"yandexmaps://"]]; -} - -#pragma mark Yandex Navigator - -+ (void)openDirectionsInYandexNavigatorWithCoordinate:(CLLocationCoordinate2D)coordinate -{ - NSURL *url = [NSURL URLWithString:[[NSString alloc] initWithFormat:@"yandexnavi://build_route_on_map?lat_to=%f&lon_to=%f", coordinate.latitude, coordinate.longitude]]; - - [[LegacyComponentsGlobals provider] openURL:url]; -} - -+ (bool)isYandexNavigatorInstalled -{ - return [[LegacyComponentsGlobals provider] canOpenURL:[NSURL URLWithString:@"yandexnavi://"]]; -} - -#pragma mark - Waze - -+ (void)openWazeWithCoordinate:(CLLocationCoordinate2D)coordinate withDirections:(bool)withDirections -{ - NSURL *url = nil; - - if (withDirections) - { - url = [NSURL URLWithString:[[NSString alloc] initWithFormat:@"waze://?ll=%f,%f&navigate=yes", coordinate.latitude, coordinate.longitude]]; - } - else - { - url = [NSURL URLWithString:[[NSString alloc] initWithFormat:@"waze://?ll=%f,%f", coordinate.latitude, coordinate.longitude]]; - } - - [[LegacyComponentsGlobals provider] openURL:url]; -} - -+ (bool)isWazeInstalled -{ - return [[LegacyComponentsGlobals provider] canOpenURL:[NSURL URLWithString:@"waze://"]]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationVenue.m b/submodules/LegacyComponents/Sources/TGLocationVenue.m deleted file mode 100644 index b981c95cd2..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationVenue.m +++ /dev/null @@ -1,118 +0,0 @@ -#import "TGLocationVenue.h" - -#import - -NSString *const TGLocationGooglePlacesVenueProvider = @"google"; -NSString *const TGLocationFoursquareVenueProvider = @"foursquare"; - -@interface TGLocationVenue () -{ - NSString *_displayAddress; -} -@end - -@implementation TGLocationVenue - -+ (TGLocationVenue *)venueWithFoursquareDictionary:(NSDictionary *)dictionary -{ - TGLocationVenue *venue = [[TGLocationVenue alloc] init]; - venue->_identifier = dictionary[@"id"]; - venue->_name = dictionary[@"name"]; - - NSDictionary *location = dictionary[@"location"]; - venue->_coordinate = CLLocationCoordinate2DMake([location[@"lat"] doubleValue], [location[@"lng"] doubleValue]); - - NSArray *categories = dictionary[@"categories"]; - if (categories.count > 0) - { - NSDictionary *category = categories.firstObject; - NSDictionary *icon = category[@"icon"]; - if (icon != nil) - venue->_categoryIconUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@64%@", icon[@"prefix"], icon[@"suffix"]]]; - - NSURL *url = [NSURL URLWithString:icon[@"prefix"]]; - NSArray *components = url.pathComponents; - NSString *categoryName = [[NSString stringWithFormat:@"%@/%@", [components objectAtIndex:components.count - 2], components.lastObject] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"_"]]; - venue->_categoryName = categoryName; - } - - venue->_country = location[@"country"]; - venue->_state = location[@"state"]; - venue->_city = location[@"city"]; - venue->_address = location[@"address"]; - venue->_crossStreet = location[@"crossStreet"]; - - venue->_provider = TGLocationFoursquareVenueProvider; - - return venue; -} - -+ (TGLocationVenue *)venueWithGooglePlacesDictionary:(NSDictionary *)dictionary -{ - TGLocationVenue *venue = [[TGLocationVenue alloc] init]; - venue->_identifier = dictionary[@"place_id"]; - venue->_name = dictionary[@"name"]; - - NSDictionary *location = dictionary[@"geometry"][@"location"]; - venue->_coordinate = CLLocationCoordinate2DMake([location[@"lat"] doubleValue], [location[@"lng"] doubleValue]); - - NSArray *types = dictionary[@"types"]; - if (types.count > 0) - { - if ([types containsObject:@"political"]) - return nil; - - venue->_categoryName = types.firstObject; - } - - venue->_displayAddress = dictionary[@"vicinity"]; - - venue->_provider = TGLocationGooglePlacesVenueProvider; - - return venue; -} - -+ (TGLocationVenue *)venueWithLocationAttachment:(TGLocationMediaAttachment *)attachment -{ - TGLocationVenue *venue = [[TGLocationVenue alloc] init]; - venue->_identifier = attachment.venue.venueId; - venue->_name = attachment.venue.title; - - venue->_coordinate = CLLocationCoordinate2DMake(attachment.latitude, attachment.longitude); - venue->_categoryName = attachment.venue.type; - - venue->_displayAddress = attachment.venue.address; - - venue->_provider = attachment.venue.provider; - - return venue; -} - -- (NSString *)displayAddress -{ - if (_displayAddress.length > 0) - return _displayAddress; - if (self.street.length > 0) - return self.street; - else if (self.city.length > 0) - return self.city; - else if (self.country.length > 0) - return self.country; - - return nil; -} - -- (NSString *)street -{ - if (self.address.length > 0) - return self.address; - else - return self.crossStreet; -} - -- (TGVenueAttachment *)venueAttachment -{ - return [[TGVenueAttachment alloc] initWithTitle:self.name address:self.displayAddress provider:self.provider venueId:self.identifier type:self.categoryName]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationVenueCell.h b/submodules/LegacyComponents/Sources/TGLocationVenueCell.h deleted file mode 100644 index 0019c192b6..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationVenueCell.h +++ /dev/null @@ -1,17 +0,0 @@ -#import - -@class TGLocationVenue; -@class TGLocationPallete; - -@interface TGLocationVenueCell : UITableViewCell - -@property (nonatomic, strong) TGLocationPallete *pallete; - -- (void)configureWithVenue:(TGLocationVenue *)venue; - -+ (UIImage *)circleImage; - -@end - -extern NSString *const TGLocationVenueCellKind; -extern const CGFloat TGLocationVenueCellHeight; diff --git a/submodules/LegacyComponents/Sources/TGLocationVenueCell.m b/submodules/LegacyComponents/Sources/TGLocationVenueCell.m deleted file mode 100644 index 90a2bd7446..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationVenueCell.m +++ /dev/null @@ -1,140 +0,0 @@ -#import "TGLocationVenueCell.h" - -#import "TGLocationMapViewController.h" -#import "LegacyComponentsInternal.h" -#import "TGColor.h" -#import "TGFont.h" -#import "TGStringUtils.h" -#import "TGImageUtils.h" - -#import "TGLocationVenue.h" - -#import - -NSString *const TGLocationVenueCellKind = @"TGLocationVenueCell"; -const CGFloat TGLocationVenueCellHeight = 56.0f; - -@interface TGLocationVenueCell () -{ - UIImageView *_circleView; - TGImageView *_iconView; - UILabel *_titleLabel; - UILabel *_addressLabel; - UIView *_separatorView; -} -@end - -@implementation TGLocationVenueCell - -- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier -{ - self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; - if (self != nil) - { - self.selectedBackgroundView = [[UIView alloc] init]; - self.selectedBackgroundView.backgroundColor = TGSelectionColor(); - - _circleView = [[UIImageView alloc] initWithFrame:CGRectMake(12.0f, 12.0f, 48.0f, 48.0f)]; - [self setCircleColor:UIColorRGB(0xf2f2f2)]; - [self.contentView addSubview:_circleView]; - - _iconView = [[TGImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 48.0f, 48.0f)]; - _iconView.contentMode = UIViewContentModeCenter; - [_circleView addSubview:_iconView]; - - _titleLabel = [[UILabel alloc] init]; - _titleLabel.backgroundColor = [UIColor clearColor]; - _titleLabel.font = TGSystemFontOfSize(16.0f); - _titleLabel.textColor = [UIColor blackColor]; - [self.contentView addSubview:_titleLabel]; - - _addressLabel = [[UILabel alloc] init]; - _addressLabel.backgroundColor = [UIColor clearColor]; - _addressLabel.font = TGSystemFontOfSize(13); - _addressLabel.textColor = UIColorRGB(0x8e8e93); - [self.contentView addSubview:_addressLabel]; - - _separatorView = [[UIView alloc] init]; - _separatorView.backgroundColor = TGSeparatorColor(); - [self addSubview:_separatorView]; - } - return self; -} - -- (void)setPallete:(TGLocationPallete *)pallete -{ - if (pallete == nil || _pallete == pallete) - return; - - _pallete = pallete; - - self.backgroundColor = pallete.backgroundColor; - self.selectedBackgroundView.backgroundColor = pallete.selectionColor; - [self setCircleColor:pallete.sectionHeaderBackgroundColor]; - _titleLabel.textColor = pallete.textColor; - _addressLabel.textColor = pallete.secondaryTextColor; - _separatorView.backgroundColor = pallete.separatorColor; -} - -- (void)setCircleColor:(UIColor *)color -{ - UIImage *circleImage = [TGLocationVenueCell circleImage]; - _circleView.image = TGTintedImage(circleImage, color); -} - -- (void)prepareForReuse -{ - [super prepareForReuse]; - [_iconView reset]; -} - -- (void)configureWithVenue:(TGLocationVenue *)venue -{ - _titleLabel.text = venue.name; - _addressLabel.text = venue.displayAddress; - if (venue.categoryName.length > 0) - { - [_iconView loadUri:[NSString stringWithFormat:@"location-venue-icon://type=%@&width=%d&height=%d&color=%d", venue.categoryName, 48, 48, TGColorHexCode(_pallete != nil ? _pallete.sectionHeaderTextColor : UIColorRGB(0xa0a0a0))] withOptions:nil]; - } - else - { - UIImage *pinImage = TGComponentsImageNamed(@"LocationMessagePinIcon"); - if (self.pallete != nil) - pinImage = TGTintedImage(pinImage, self.pallete.sectionHeaderTextColor); - else - pinImage = TGTintedImage(pinImage, UIColorRGB(0xa0a0a0)); - [_iconView loadUri:@"embedded://" withOptions:@{ TGImageViewOptionEmbeddedImage:pinImage }]; - } -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - CGFloat padding = 76.0f; - CGFloat separatorThickness = TGScreenPixel; - - _circleView.frame = CGRectMake(12.0f, 4.0f, 48.0f, 48.0f); - _iconView.frame = CGRectMake(0.0f, 0.0f, 48.0f, 48.0f); - _titleLabel.frame = CGRectMake(padding, 8, self.frame.size.width - padding - 14, 20); - _addressLabel.frame = CGRectMake(padding, 29, self.frame.size.width - padding - 14, 20); - _separatorView.frame = CGRectMake(padding, self.frame.size.height - separatorThickness, self.frame.size.width - padding, separatorThickness); -} - -+ (UIImage *)circleImage -{ - static dispatch_once_t onceToken; - static UIImage *circleImage; - dispatch_once(&onceToken, ^ - { - UIGraphicsBeginImageContextWithOptions(CGSizeMake(48.0f, 48.0f), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); - CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, 48.0f, 48.0f)); - circleImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - }); - return circleImage; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationViewController.m b/submodules/LegacyComponents/Sources/TGLocationViewController.m deleted file mode 100644 index a2d540b4e8..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationViewController.m +++ /dev/null @@ -1,1410 +0,0 @@ -#import "TGLocationViewController.h" - -#import "LegacyComponentsInternal.h" - -#import "TGNavigationBar.h" -#import "TGUser.h" -#import "TGConversation.h" -#import "TGMessage.h" -#import "TGImageUtils.h" -#import "TGFont.h" - -#import - -#import "TGLocationUtils.h" -#import "TGLocationSignals.h" - -#import "TGLocationVenue.h" -#import "TGLocationAnnotation.h" - -#import "TGLocationTitleView.h" -#import "TGLocationMapView.h" -#import "TGLocationTrackingButton.h" -#import "TGLocationMapModeControl.h" -#import "TGLocationPinAnnotationView.h" - -#import "TGLocationOptionsView.h" -#import "TGLocationInfoCell.h" -#import "TGLocationLiveCell.h" - -#import - -@interface TGLiveLocation () - -- (CLLocation *)location; - -@end - -@interface TGLocationViewController () -{ - id _context; - bool _dismissing; - - id _peer; - TGMessage *_message; - TGLocationMediaAttachment *_locationAttachment; - UIColor *_venueColor; - - TGLocationAnnotation *_annotation; - - UIBarButtonItem *_actionsBarItem; - bool _didSetRightBarButton; - - SVariable *_reloadReady; - SMetaDisposable *_reloadDisposable; - - id _frequentUpdatesDisposable; - - SSignal *_signal; - TGLiveLocation *_currentLiveLocation; - SMetaDisposable *_liveLocationsDisposable; - NSArray *_initialLiveLocations; - NSArray *_liveLocations; - bool _hasOwnLiveLocation; - bool _ownLocationExpired; - - bool _presentedLiveLocations; - bool _selectedCurrentLiveLocation; - - bool _ignoreNextUpdates; - bool _focusOnOwnLocation; - bool _throttle; - TGLocationPinAnnotationView *_ownLiveLocationView; - __weak MKAnnotationView *_userLocationView; - - UIImageView *_headingArrowView; -} -@end - -@implementation TGLocationViewController - -- (instancetype)initWithContext:(id)context locationAttachment:(TGLocationMediaAttachment *)locationAttachment peer:(id)peer color:(UIColor *)color -{ - self = [self initWithContext:context]; - if (self != nil) - { - _locationAttachment = locationAttachment; - _venueColor = color; - - _reloadDisposable = [[SMetaDisposable alloc] init]; - _reloadReady = [[SVariable alloc] init]; - [self setReloadReady:true]; - - _context = context; - _peer = peer; - - if (locationAttachment.period == 0) - _annotation = [[TGLocationAnnotation alloc] initWithLocation:locationAttachment color:color]; - - _liveLocationsDisposable = [[SMetaDisposable alloc] init]; - - self.titleText = locationAttachment.period > 0 ? TGLocalized(@"Map.LiveLocationTitle") : TGLocalized(@"Map.LocationTitle"); - } - return self; -} - -- (instancetype)initWithContext:(id)context liveLocation:(TGLiveLocation *)liveLocation -{ - self = [self initWithContext:context]; - if (self != nil) - { - _message = liveLocation.message; - _locationAttachment = liveLocation.message.locationAttachment; - _currentLiveLocation = liveLocation; - if (liveLocation) - { - _liveLocations = @[liveLocation]; - _hasOwnLiveLocation = liveLocation.hasOwnSession; - if (_hasOwnLiveLocation) - _ownLocationExpired = liveLocation.isExpired; - } - _reloadDisposable = [[SMetaDisposable alloc] init]; - _reloadReady = [[SVariable alloc] init]; - [self setReloadReady:true]; - - _context = context; - _peer = liveLocation.peer; - - _liveLocationsDisposable = [[SMetaDisposable alloc] init]; - - self.titleText = _locationAttachment.period > 0 ? TGLocalized(@"Map.LiveLocationTitle") : TGLocalized(@"Map.LocationTitle"); - } - return self; -} - -- (instancetype)initWithContext:(id)context message:(TGMessage *)message peer:(id)peer color:(UIColor *)color -{ - self = [self initWithContext:context]; - if (self != nil) - { - _message = message; - _locationAttachment = message.locationAttachment; - - _reloadDisposable = [[SMetaDisposable alloc] init]; - _reloadReady = [[SVariable alloc] init]; - [self setReloadReady:true]; - - _context = context; - _peer = peer; - _venueColor = color; - - if (_locationAttachment.period == 0) - _annotation = [[TGLocationAnnotation alloc] initWithLocation:_locationAttachment color:color]; - - _liveLocationsDisposable = [[SMetaDisposable alloc] init]; - - self.titleText = _locationAttachment.period > 0 ? TGLocalized(@"Map.LiveLocationTitle") : TGLocalized(@"Map.LocationTitle"); - } - return self; -} - -- (void)dealloc -{ - _mapView.delegate = nil; - [_liveLocationsDisposable dispose]; - [_reloadDisposable dispose]; - [_frequentUpdatesDisposable dispose]; - - [_locationManager stopUpdatingHeading]; -} - -- (void)tg_setRightBarButtonItem:(UIBarButtonItem *)barButtonItem action:(bool)action animated:(bool)animated { - if (self.updateRightBarItem != nil) { - self.updateRightBarItem(barButtonItem, action, animated); - } else { - [self setRightBarButtonItem:barButtonItem animated:animated]; - } -} - -- (void)setFrequentUpdatesHandle:(id)disposable -{ - _frequentUpdatesDisposable = disposable; -} - -- (void)setLiveLocationsSignal:(SSignal *)signal -{ - if (_currentLiveLocation.isOwnLocation) - { - _signal = [[signal reduceLeftWithPassthrough:nil with:^id(id current, id value, void (^emit)(id)) - { - if (current == nil) - { - emit([SSignal single:value]); - return @true; - } - else - { - emit([[SSignal single:value] delay:0.25 onQueue:[SQueue concurrentDefaultQueue]]); - return current; - } - }] switchToLatest]; - } - else - { - __weak TGLocationViewController *weakSelf = self; - _signal = [signal mapToSignal:^SSignal *(id value) - { - __strong TGLocationViewController *strongSelf = weakSelf; - if (strongSelf == nil) - return nil; - - if (strongSelf->_throttle) - return [[SSignal single:value] delay:0.25 onQueue:[SQueue concurrentDefaultQueue]]; - else - return [SSignal single:value]; - }]; - } - - [self setupSignals]; -} - -- (void)setLiveLocations:(NSArray *)liveLocations actual:(bool)actual -{ - if (liveLocations.count == 0 && _currentLiveLocation != nil) - liveLocations = @[ _currentLiveLocation ]; - - TGLiveLocation *ownLiveLocation = nil; - for (TGLiveLocation *liveLocation in liveLocations) - { - if (liveLocation.hasOwnSession) - { - ownLiveLocation = liveLocation; - break; - } - } - - _hasOwnLiveLocation = ownLiveLocation != nil; - _ownLocationExpired = ownLiveLocation.isExpired; - - if (_hasOwnLiveLocation && !_ownLocationExpired) - { - TGLocationAnnotation *annotation = [[TGLocationAnnotation alloc] initWithLocation:ownLiveLocation.message.locationAttachment]; - annotation.peer = ownLiveLocation.peer; - annotation.isOwn = true; - - if (_ownLiveLocationView == nil) - { - _ownLiveLocationView = [[TGLocationPinAnnotationView alloc] initWithAnnotation:annotation]; - _ownLiveLocationView.pallete = self.pallete; - _ownLiveLocationView.frame = CGRectOffset(_ownLiveLocationView.frame, 21.0f, 22.0f); - [_userLocationView addSubview:_ownLiveLocationView]; - - if (_currentLiveLocation.hasOwnSession) - [self selectOwnAnnotationAnimated:false]; - } - else - { - _ownLiveLocationView.annotation = annotation; - } - } - else - { - [_ownLiveLocationView removeFromSuperview]; - _ownLiveLocationView = nil; - } - - CGFloat previousLocationsCount = _liveLocations.count; - _liveLocations = liveLocations; - [self reloadData]; - - if (!_presentedLiveLocations && actual) - { - _presentedLiveLocations = true; - if (previousLocationsCount < liveLocations.count > 0) - { - CGFloat updatedHeight = [self possibleContentHeight] - [self visibleContentHeight]; - if (fabs(-_tableView.contentInset.top + updatedHeight - _tableView.contentOffset.y) > FLT_EPSILON) - { - TGDispatchAfter(0.3, dispatch_get_main_queue(), ^ - { - [self setReloadReady:false]; - [_tableView setContentOffset:CGPointMake(0.0f, -_tableView.contentInset.top + updatedHeight) animated:true]; - }); - } - } - - if (_currentLiveLocation.hasOwnSession && !_ownLocationExpired && !self.zoomToFitAllLocationsOnScreen) - { - [_mapView setUserTrackingMode:[TGLocationTrackingButton userTrackingModeWithLocationTrackingMode:TGLocationTrackingModeFollow] animated:false]; - [_optionsView setTrackingMode:TGLocationTrackingModeFollow animated:true]; - } - } - [self updateAnnotations]; - - if ([self isLiveLocation]) - { - if ([self hasMoreThanOneLocation]) - { - if (!_didSetRightBarButton) - { - _didSetRightBarButton = true; - [self tg_setRightBarButtonItem:_actionsBarItem action:false animated:true]; - } - - if (actual && self.zoomToFitAllLocationsOnScreen) - { - _zoomToFitAllLocationsOnScreen = false; - dispatch_async(dispatch_get_main_queue(), ^ - { - MKMapRect visibleMapRect = _mapView.visibleMapRect; - NSSet *visibleAnnotations = [_mapView annotationsInMapRect:visibleMapRect]; - if (visibleAnnotations.count == _mapView.annotations.count) - return; - - [self showAllPressed]; - }); - } - } - else - { - if (_didSetRightBarButton) - { - _didSetRightBarButton = false; - [self tg_setRightBarButtonItem:nil action:false animated:true]; - } - } - } - - if (_focusOnOwnLocation) - { - if (_ownLiveLocationView != nil && !_ownLiveLocationView.isSelected) - { - [self selectOwnAnnotationAnimated:false]; - _focusOnOwnLocation = false; - _throttle = false; - - dispatch_async(dispatch_get_main_queue(), ^ - { - MKMapRect visibleMapRect = _mapView.visibleMapRect; - NSSet *visibleAnnotations = [_mapView annotationsInMapRect:visibleMapRect]; - if (visibleAnnotations.count == _mapView.annotations.count) - return; - - [self showAllPressed]; - }); - } - } -} - -- (bool)handleOwnAnnotationTap:(CGPoint)location -{ - if (_ownLiveLocationView == nil) - return false; - - if (CGRectContainsPoint([_ownLiveLocationView.superview convertRect:CGRectInset(_ownLiveLocationView.frame, -16.0f, - 16.0f) toView:_mapView], location)) - { - [self selectOwnAnnotation]; - [self setMapCenterCoordinate:_ownLiveLocationView.annotation.coordinate offset:CGPointZero animated:true]; - return true; - } - - return false; -} - -- (void)reloadData -{ - [_reloadDisposable setDisposable:[[self reloadReadySignal] startWithNext:nil completed:^ - { - [_tableView reloadData]; - _edgeView.highlighted = false; - }]]; -} - -double DegreesToRadians(double degrees) {return degrees * M_PI / 180.0;}; -double RadiansToDegrees(double radians) {return radians * 180.0/M_PI;}; - -- (double)bearingFromLocation:(CLLocationCoordinate2D)fromLocation toLocation:(CLLocationCoordinate2D)toLocation -{ - double lat1 = DegreesToRadians(fromLocation.latitude); - double lon1 = DegreesToRadians(fromLocation.longitude); - - double lat2 = DegreesToRadians(toLocation.latitude); - double lon2 = DegreesToRadians(toLocation.longitude); - - double dLon = lon2 - lon1; - - double y = sin(dLon) * cos(lat2); - double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon); - double radiansBearing = atan2(y, x); - - return radiansBearing; -} - -- (void)updateAnnotations -{ - NSMutableDictionary *liveLocations = [[NSMutableDictionary alloc] init]; - for (TGLiveLocation *liveLocation in _liveLocations) - { - if (!liveLocation.hasOwnSession || liveLocation.isExpired) - liveLocations[@(liveLocation.message.mid)] = liveLocation; - } - - TGLocationAnnotation *currentAnnotation = nil; - NSMutableSet *annotationsToRemove = [[NSMutableSet alloc] init]; - for (TGLocationAnnotation *annotation in _mapView.annotations) - { - if (![annotation isKindOfClass:[TGLocationAnnotation class]] || annotation == _annotation) - continue; - - if (liveLocations[@(annotation.messageId)] != nil) - { - [UIView animateWithDuration:0.3 animations:^{ - CLLocationCoordinate2D previousCoordinate = annotation.coordinate; - annotation.coordinate = [(TGLiveLocation *)liveLocations[@(annotation.messageId)] location].coordinate; - - - CLLocation *previous = [[CLLocation alloc] initWithLatitude:previousCoordinate.latitude longitude:previousCoordinate.longitude]; - CLLocation *new = [[CLLocation alloc] initWithLatitude:annotation.coordinate.latitude longitude:annotation.coordinate.longitude]; -// if ([new distanceFromLocation:previous] > 20) { - CGFloat hdg = [self bearingFromLocation:previousCoordinate toLocation:annotation.coordinate]; - if (hdg != 0.0) { - annotation.heading = @(hdg); - } -// } - }]; - annotation.isExpired = [(TGLiveLocation *)liveLocations[@(annotation.messageId)] isExpired]; - [liveLocations removeObjectForKey:@(annotation.messageId)]; - - if (annotation.messageId == _currentLiveLocation.message.mid) - currentAnnotation = annotation; - } - else - { - [annotationsToRemove addObject:annotation]; - } - } - - [_mapView removeAnnotations:annotationsToRemove.allObjects]; - - NSMutableArray *newAnnotations = [[NSMutableArray alloc] init]; - for (TGLiveLocation *liveLocation in liveLocations.allValues) - { - TGLocationAnnotation *annotation = [[TGLocationAnnotation alloc] initWithLocation:liveLocation.message.locationAttachment]; - annotation.peer = liveLocation.peer; - annotation.messageId = liveLocation.message.mid; - annotation.isExpired = liveLocation.isExpired; - - [newAnnotations addObject:annotation]; - - if (annotation.messageId == _currentLiveLocation.message.mid) - currentAnnotation = annotation; - } - - [_mapView addAnnotations:newAnnotations]; - - NSInteger annotationsCount = _ownLiveLocationView != nil ? 1 : 0; - for (TGLocationAnnotation *annotation in _mapView.annotations) - { - if ([annotation isKindOfClass:[TGLocationAnnotation class]] && ((TGLocationAnnotation *)annotation).isLiveLocation) - annotationsCount += 1; - } - - _mapView.allowAnnotationSelectionChanges = annotationsCount; - - if (!_selectedCurrentLiveLocation && currentAnnotation != nil) - { - _selectedCurrentLiveLocation = true; - dispatch_async(dispatch_get_main_queue(), ^ - { - [_mapView setSelectedAnnotations:@[currentAnnotation]]; - }); - } -} - -- (void)loadView -{ - [super loadView]; - - static UIImage *headingArrowImage = nil; - static dispatch_once_t onceToken; - - dispatch_once(&onceToken, ^ - { - UIGraphicsBeginImageContextWithOptions(CGSizeMake(28.0f, 28.0f), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - - CGContextClearRect(context, CGRectMake(0, 0, 28, 28)); - - CGContextSetFillColorWithColor(context, UIColorRGB(0x3393fe).CGColor); - - CGContextMoveToPoint(context, 14, 0); - CGContextAddLineToPoint(context, 19, 7); - CGContextAddLineToPoint(context, 9, 7); - CGContextClosePath(context); - CGContextFillPath(context); - - CGContextSetBlendMode(context, kCGBlendModeClear); - CGContextFillEllipseInRect(context, CGRectMake(5.0, 5.0, 18.0, 18.0)); - - headingArrowImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - }); - - _headingArrowView = [[UIImageView alloc] init]; - _headingArrowView.hidden = true; - _headingArrowView.frame = CGRectMake(0.0, 0.0, 28.0, 28.0); - _headingArrowView.image = headingArrowImage; - - _tableView.scrollsToTop = false; - _mapView.tapEnabled = false; - - __weak TGLocationViewController *weakSelf = self; - _mapView.customAnnotationTap = ^bool(CGPoint location) - { - __strong TGLocationViewController *strongSelf = weakSelf; - if (strongSelf == nil) - return false; - return [strongSelf handleOwnAnnotationTap:location]; - }; - - if (TGIsPad() || _modalMode) - { - [self setLeftBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Done") style:UIBarButtonItemStyleDone target:self action:@selector(dismissButtonPressed)]]; - } - - if ([self isLiveLocation]) - { - NSString *actionsButtonTitle = TGLocalized(@"Map.LiveLocationShowAll"); - _actionsBarItem = [[UIBarButtonItem alloc] initWithTitle:actionsButtonTitle style:UIBarButtonItemStylePlain target:self action:@selector(showAllPressed)]; - } - else - { - if (iosMajorVersion() >= 7) - { - _actionsBarItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(actionsButtonPressed)]; - [self tg_setRightBarButtonItem:_actionsBarItem action:true animated:false]; - } - else - { - NSString *actionsButtonTitle = TGLocalized(@"Common.More"); - _actionsBarItem = [[UIBarButtonItem alloc] initWithTitle:actionsButtonTitle style:UIBarButtonItemStylePlain target:self action:@selector(actionsButtonPressed)]; - [self tg_setRightBarButtonItem:_actionsBarItem action:true animated:false]; - } - } - - if (_previewMode) - _optionsView.hidden = true; -} - -- (void)viewDidLoad -{ - [super viewDidLoad]; - - [_mapView addAnnotation:_annotation]; - [_mapView selectAnnotation:_annotation animated:false]; - - _mapView.region = MKCoordinateRegionMake([self locationCoordinate], MKCoordinateSpanMake(0.008, 0.008)); - - [TGLocationUtils requestWhenInUserLocationAuthorizationWithLocationManager:_locationManager]; -} - -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; - - [_locationManager startUpdatingHeading]; - - if (self.previewMode && !animated) - { - UIView *contentView = [[_mapView subviews] firstObject]; - UIView *annotationContainer = nil; - for (NSUInteger i = 1; i < contentView.subviews.count; i++) - { - UIView *view = contentView.subviews[i]; - if ([NSStringFromClass(view.class) rangeOfString:@"AnnotationContainer"].location != NSNotFound) - { - annotationContainer = view; - break; - } - } - - for (UIView *view in annotationContainer.subviews) - view.frame = CGRectOffset(view.frame, 0, 48.5f); - } - - if ([_tableView numberOfRowsInSection:0] > 0) - [_tableView layoutSubviews]; - - CGFloat updatedHeight = [self possibleContentHeight] - [self visibleContentHeight]; - [_tableView setContentOffset:CGPointMake(0.0f, -_tableView.contentInset.top + updatedHeight) animated:false]; - - if (_initialLiveLocations.count > 0) - { - [self setLiveLocations:_initialLiveLocations actual:false]; - _initialLiveLocations = nil; - } -} - -- (void)viewDidAppear:(BOOL)animated -{ - [super viewDidAppear:animated]; - if (self.onViewDidAppear != nil) - self.onViewDidAppear(); -} - -- (void)setupSignals -{ - SSignal *combinedSignal = [SSignal combineSignals:@[ [[[self userLocationSignal] deliverOn:[SQueue concurrentBackgroundQueue]] map:^id(id location) { - if (location != nil) - return location; - else - return [NSNull null]; - }], _signal ]]; - - __weak TGLocationViewController *weakSelf = self; - [_liveLocationsDisposable setDisposable:[combinedSignal startWithNext:^(NSArray *next) - { - __strong TGLocationViewController *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - if (strongSelf->_dismissing) - return; - - CLLocation *currentLocation = [next.firstObject isKindOfClass:[CLLocation class]] ? next.firstObject : nil; - NSArray *liveLocations = next.lastObject; - bool actual = liveLocations.count > 0; - - NSMutableArray *filteredLiveLocations = [[NSMutableArray alloc] init]; - bool hasCurrentLocation = false; - bool currentExpiredLocationIsOwn = false; - for (TGLiveLocation *liveLocation in liveLocations) - { - if (!liveLocation.isExpired) - [filteredLiveLocations addObject:liveLocation]; - if (liveLocation.message.mid == strongSelf->_currentLiveLocation.message.mid) - hasCurrentLocation = true; - } - if (!hasCurrentLocation && strongSelf->_currentLiveLocation != nil) - { - bool isChannel = [strongSelf->_currentLiveLocation.peer isKindOfClass:[TGConversation class]] && !((TGConversation *)strongSelf->_currentLiveLocation.peer).isChannelGroup; - - TGLiveLocation *currentExpiredLiveLocation = [[TGLiveLocation alloc] initWithMessage:strongSelf->_currentLiveLocation.message peer:strongSelf->_currentLiveLocation.peer hasOwnSession:strongSelf->_currentLiveLocation.hasOwnSession isOwnLocation:strongSelf->_currentLiveLocation.isOwnLocation isExpired:isChannel ? strongSelf->_currentLiveLocation.isExpired : true]; - [filteredLiveLocations addObject:currentExpiredLiveLocation]; - - if (currentExpiredLiveLocation.isOwnLocation && currentExpiredLiveLocation.isExpired) - currentExpiredLocationIsOwn = true; - } - liveLocations = filteredLiveLocations; - - for (TGLiveLocation *location in filteredLiveLocations) - { - if (strongSelf->_ignoreNextUpdates && location.hasOwnSession && !location.isExpired && (currentExpiredLocationIsOwn || (strongSelf->_currentLiveLocation.isOwnLocation && strongSelf->_currentLiveLocation.isExpired))) - { - strongSelf->_dismissing = true; - TGDispatchOnMainThread(^ - { - if (strongSelf.openLocation != nil) - strongSelf.openLocation(location.message); - }); - return; - } - } - - if (strongSelf->_ignoreNextUpdates) - return; - - NSMutableArray *sortedLiveLocations = [liveLocations mutableCopy]; - if (currentLocation != nil) - { - [sortedLiveLocations sortUsingComparator:^NSComparisonResult(TGLiveLocation *obj1, TGLiveLocation *obj2) - { - if (obj1.hasOwnSession) - return NSOrderedAscending; - else if (obj2.hasOwnSession) - return NSOrderedDescending; - - if (obj1.message.mid == strongSelf->_currentLiveLocation.message.mid) - return NSOrderedAscending; - else if (obj2.message.mid == strongSelf->_currentLiveLocation.message.mid) - return NSOrderedDescending; - - CGFloat distance1 = [obj1.location distanceFromLocation:currentLocation]; - CGFloat distance2 = [obj2.location distanceFromLocation:currentLocation]; - - if (distance1 > distance2) - return NSOrderedDescending; - else if (distance1 < distance2) - return NSOrderedAscending; - - return NSOrderedSame; - }]; - } - else - { - [sortedLiveLocations sortUsingComparator:^NSComparisonResult(TGLiveLocation *obj1, TGLiveLocation *obj2) - { - if (obj1.hasOwnSession) - return NSOrderedAscending; - else if (obj2.hasOwnSession) - return NSOrderedDescending; - - if (obj1.message.mid == strongSelf->_currentLiveLocation.message.mid) - return NSOrderedAscending; - else if (obj2.message.mid == strongSelf->_currentLiveLocation.message.mid) - return NSOrderedDescending; - - int32_t date1 = [obj1.message actualDate]; - int32_t date2 = [obj2.message actualDate]; - - if (date1 > date2) - return NSOrderedAscending; - else if (date1 < date2) - return NSOrderedDescending; - - return NSOrderedSame; - }]; - } - - TGDispatchOnMainThread(^ - { - if ([strongSelf isViewLoaded]) - [strongSelf setLiveLocations:sortedLiveLocations actual:actual]; - else - strongSelf->_initialLiveLocations = sortedLiveLocations; - }); - }]]; -} - -#pragma mark - - -- (void)setPreviewMode:(bool)previewMode -{ - _previewMode = previewMode; - - if (!previewMode) - { - [self setRightBarButtonItem:_actionsBarItem]; - _optionsView.hidden = false; - } -} - -#pragma mark - Actions - -- (void)fitAllLocations:(NSArray *)locations -{ - MKMapRect zoomRect = MKMapRectNull; - for (CLLocation *location in locations) - { - MKMapPoint annotationPoint = MKMapPointForCoordinate(location.coordinate); - MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1); - zoomRect = MKMapRectUnion(zoomRect, pointRect); - } - UIEdgeInsets insets = UIEdgeInsetsMake(TGLocationMapInset + 110.0f, 80.0f, TGLocationMapInset + 110.0f, 80.0f); - zoomRect = [_mapView mapRectThatFits:zoomRect edgePadding:insets]; - [_mapView setVisibleMapRect:zoomRect animated:true]; -} - -- (void)showAllPressed -{ - NSMutableArray *locations = [[NSMutableArray alloc] init]; - for (id annotation in _mapView.annotations) - { - CLLocation *location = [[CLLocation alloc] initWithLatitude:annotation.coordinate.latitude longitude:annotation.coordinate.longitude]; - [locations addObject:location]; - } - - [self fitAllLocations:locations]; -} - -- (void)dismissButtonPressed -{ - [self.presentingViewController dismissViewControllerAnimated:true completion:nil]; -} - -- (void)actionsButtonPressed -{ - TGLocationMediaAttachment *locationAttachment = _locationAttachment; - if (locationAttachment == nil) - return; - - if (self.presentActionsMenu != nil) - { - self.presentActionsMenu(locationAttachment, false); - return; - } - - CGRect (^sourceRect)(void) = ^CGRect - { - return CGRectZero; - }; - - __weak TGLocationViewController *weakSelf = self; - if (_presentOpenInMenu && _presentOpenInMenu(self, locationAttachment, false, ^(TGMenuSheetController *menuController) - { - __strong TGLocationViewController *strongSelf = weakSelf; - if (strongSelf != nil && strongSelf->_presentShareMenu) { - strongSelf->_presentShareMenu(menuController, [strongSelf locationCoordinate]); - } - })) - { - } - else - { - TGMenuSheetController *controller = [[TGMenuSheetController alloc] initWithContext:_context dark:false]; - controller.dismissesByOutsideTap = true; - controller.hasSwipeGesture = true; - controller.narrowInLandscape = true; - controller.sourceRect = sourceRect; - controller.barButtonItem = self.navigationItem.rightBarButtonItem; - - NSMutableArray *itemViews = [[NSMutableArray alloc] init]; - - __weak TGMenuSheetController *weakController = controller; - TGMenuSheetButtonItemView *openItem = [[TGMenuSheetButtonItemView alloc] initWithTitle:TGLocalized(@"Map.OpenInMaps") type:TGMenuSheetButtonTypeDefault fontSize:20.0 action:^ - { - __strong TGLocationViewController *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - __strong TGMenuSheetController *strongController = weakController; - if (strongController == nil) - return; - - [strongController dismissAnimated:true]; - [TGLocationUtils openMapsWithCoordinate:[strongSelf locationCoordinate] withDirections:false locationName:strongSelf->_annotation.title]; - }]; - [itemViews addObject:openItem]; - - TGMenuSheetButtonItemView *shareItem = [[TGMenuSheetButtonItemView alloc] initWithTitle:TGLocalized(@"Conversation.ContextMenuShare") type:TGMenuSheetButtonTypeDefault fontSize:20.0 action:^ - { - __strong TGMenuSheetController *strongController = weakController; - if (strongController == nil) - return; - - __strong TGLocationViewController *strongSelf = weakSelf; - if (strongSelf != nil && strongSelf->_presentShareMenu) { - strongSelf->_presentShareMenu(strongController, [strongSelf locationCoordinate]); - } - }]; - [itemViews addObject:shareItem]; - - TGMenuSheetButtonItemView *cancelItem = [[TGMenuSheetButtonItemView alloc] initWithTitle:TGLocalized(@"Common.Cancel") type:TGMenuSheetButtonTypeCancel fontSize:20.0 action:^ - { - __strong TGMenuSheetController *strongController = weakController; - if (strongController == nil) - return; - - [strongController dismissAnimated:true manual:true]; - }]; - [itemViews addObject:cancelItem]; - - [controller setItemViews:itemViews]; - [controller presentInViewController:self sourceView:self.view animated:true]; - } -} - -- (void)userLocationButtonPressed -{ - if (![self hasUserLocation]) - { - if (![TGLocationUtils requestWhenInUserLocationAuthorizationWithLocationManager:_locationManager]) - { - if (_locationServicesDisabled) - [[[LegacyComponentsGlobals provider] accessChecker] checkLocationAuthorizationStatusForIntent:TGLocationAccessIntentTracking alertDismissComlpetion:nil]; - } - - [self updateLocationAvailability]; - return; - } - - TGLocationTrackingMode newMode = TGLocationTrackingModeNone; - switch ([TGLocationTrackingButton locationTrackingModeWithUserTrackingMode:_mapView.userTrackingMode]) - { - case TGLocationTrackingModeFollow: - newMode = TGLocationTrackingModeFollowWithHeading; - break; - - case TGLocationTrackingModeFollowWithHeading: - newMode = TGLocationTrackingModeNone; - break; - - default: - newMode = TGLocationTrackingModeFollow; - break; - } - - [_mapView setUserTrackingMode:[TGLocationTrackingButton userTrackingModeWithLocationTrackingMode:newMode] animated:true]; - [_optionsView setTrackingMode:newMode animated:true]; - - if (newMode != TGLocationTrackingModeNone && _ownLiveLocationView != nil) - [self selectOwnAnnotation]; -} - -- (void)selectOwnAnnotation -{ - [self selectOwnAnnotationAnimated:true]; -} - -- (void)selectOwnAnnotationAnimated:(bool)animated -{ - if (!_ownLiveLocationView.isSelected) - [_ownLiveLocationView setSelected:true animated:animated]; - [_mapView deselectAnnotation:_mapView.selectedAnnotations.firstObject animated:true]; - [_ownLiveLocationView.superview.superview bringSubviewToFront:_ownLiveLocationView.superview]; -} - -- (void)getDirectionsPressed:(TGLocationMediaAttachment *)locationAttachment prompt:(bool)prompt -{ - if (self.presentActionsMenu != nil) - { - self.presentActionsMenu(locationAttachment, true); - return; - } - - if (_presentOpenInMenu && _presentOpenInMenu(self, locationAttachment, true, nil)) - { - } - else - { - void (^block)(void) = ^ - { - NSString *title = @""; - if (locationAttachment.venue != nil) - title = locationAttachment.venue.title; - else if ([_peer isKindOfClass:[TGUser class]]) - title = ((TGUser *)_peer).displayName; - else if ([_peer isKindOfClass:[TGConversation class]]) - title = ((TGConversation *)_peer).chatTitle; - - [TGLocationUtils openMapsWithCoordinate:[self locationCoordinate] withDirections:true locationName:title]; - }; - - if (prompt) - { - TGMenuSheetController *controller = [[TGMenuSheetController alloc] initWithContext:_context dark:false]; - controller.dismissesByOutsideTap = true; - controller.narrowInLandscape = true; - - __weak TGMenuSheetController *weakController = controller; - NSArray *items = @ - [ - [[TGMenuSheetButtonItemView alloc] initWithTitle:TGLocalized(@"Map.GetDirections") type:TGMenuSheetButtonTypeDefault fontSize:20.0 action:^ - { - __strong TGMenuSheetController *strongController = weakController; - if (strongController == nil) - return; - - [strongController dismissAnimated:true]; - block(); - }], - [[TGMenuSheetButtonItemView alloc] initWithTitle:TGLocalized(@"Common.Cancel") type:TGMenuSheetButtonTypeCancel fontSize:20.0 action:^ - { - __strong TGMenuSheetController *strongController = weakController; - if (strongController != nil) - [strongController dismissAnimated:true]; - }] - ]; - - [controller setItemViews:items]; - controller.sourceRect = ^ - { - return CGRectZero; - }; - controller.permittedArrowDirections = UIPopoverArrowDirectionUp; - [controller presentInViewController:self sourceView:self.view animated:true]; - } - else - { - block(); - } - } -} - -- (UIButton *)directionsButton -{ - TGLocationInfoCell *infoCell = [_tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]; - if ([infoCell isKindOfClass:[TGLocationInfoCell class]]) - return infoCell.directionsButton; - - return nil; -} - -- (CGRect)_liveLocationMenuSourceRect -{ - TGLocationLiveCell *cell = [_tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]; - if ([cell isKindOfClass:[TGLocationLiveCell class]]) - return [cell convertRect:cell.bounds toView:self.view]; - - return CGRectZero; -} - -#pragma mark - Map View Delegate - -- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation -{ - if (annotation == mapView.userLocation) - return nil; - - TGLocationPinAnnotationView *view = (TGLocationPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:TGLocationPinAnnotationKind]; - if (view == nil) - { - view = [[TGLocationPinAnnotationView alloc] initWithAnnotation:annotation]; - view.pallete = self.pallete; - } - else - { - view.annotation = annotation; - } - view.layer.zPosition = -1; - - return view; -} - -- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views -{ - for (MKAnnotationView *view in views) - { - if ([view.annotation isKindOfClass:[MKUserLocation class]]) - { - _userLocationView = view; - - [_userLocationView addSubview:_headingArrowView]; - _headingArrowView.center = CGPointMake(view.frame.size.width / 2.0, view.frame.size.height / 2.0); - - if (_ownLiveLocationView != nil) - { - [_userLocationView addSubview:_ownLiveLocationView]; - - if (_currentLiveLocation.hasOwnSession && _mapView.selectedAnnotations.count == 0) - [_ownLiveLocationView setSelected:true animated:false]; - } - } - } -} - -- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view -{ - if (_ownLiveLocationView.isSelected) - [_ownLiveLocationView setSelected:false animated:true]; - - [self setMapCenterCoordinate:view.annotation.coordinate offset:CGPointZero animated:true]; - - [_optionsView setTrackingMode:TGLocationTrackingModeNone animated:true]; -} - -- (void)mapView:(MKMapView *)mapView didChangeUserTrackingMode:(MKUserTrackingMode)mode animated:(BOOL)animated -{ - if (mode == MKUserTrackingModeNone) - [_optionsView setTrackingMode:TGLocationTrackingModeNone animated:true]; -} - -- (CLLocationCoordinate2D)locationCoordinate -{ - return CLLocationCoordinate2DMake(_locationAttachment.latitude, _locationAttachment.longitude); -} - -- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading -{ - if (newHeading != nil) { - _headingArrowView.hidden = false; - _headingArrowView.transform = CGAffineTransformMakeRotation(newHeading.magneticHeading / 180.0 * M_PI); - } -} - -#pragma mark - - -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section -{ - NSInteger count = 0; - if (![self isLiveLocation]) - count += 1; - - if (_liveLocations.count > 0) - { - count += _liveLocations.count; - if (self.allowLiveLocationSharing && !_hasOwnLiveLocation) - count += 1; - } - return count; -} - -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath -{ - __weak TGLocationViewController *weakSelf = self; - if (indexPath.row == 0 && ![self isLiveLocation]) - { - TGLocationInfoCell *cell = [tableView dequeueReusableCellWithIdentifier:TGLocationInfoCellKind]; - if (cell == nil) - cell = [[TGLocationInfoCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TGLocationInfoCellKind]; - cell.pallete = self.pallete; - [cell setLocation:_locationAttachment color: _venueColor messageId:_message.mid userLocationSignal:[self userLocationSignal]]; - cell.locatePressed = ^ - { - __strong TGLocationViewController *strongSelf = weakSelf; - if (strongSelf != nil) - { - [strongSelf->_mapView deselectAnnotation:strongSelf->_mapView.selectedAnnotations.firstObject animated:true]; - [strongSelf setMapCenterCoordinate:[strongSelf locationCoordinate] offset:CGPointZero animated:true]; - } - }; - cell.directionsPressed = ^ - { - __strong TGLocationViewController *strongSelf = weakSelf; - if (strongSelf != nil) - [strongSelf getDirectionsPressed:strongSelf->_locationAttachment prompt:false]; - }; - cell.safeInset = self.controllerSafeAreaInset; - return cell; - } - else - { - TGLocationLiveCell *cell = [tableView dequeueReusableCellWithIdentifier:TGLocationLiveCellKind]; - if (cell == nil) - cell = [[TGLocationLiveCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TGLocationLiveCellKind]; - cell.pallete = self.pallete; - cell.edgeView = indexPath.row == 0 ? _edgeHighlightView : nil; - cell.safeInset = self.controllerSafeAreaInset; - - if (self.allowLiveLocationSharing && (indexPath.row == 0 || (![self isLiveLocation] && indexPath.row == 1))) - { - if (_hasOwnLiveLocation) - { - TGLiveLocation *liveLocation = _liveLocations.firstObject; - if (liveLocation.isExpired) - [cell configureForStart]; - else - [cell configureForStopWithMessage:liveLocation.message remaining:self.remainingTimeForMessage(liveLocation.message)]; - } - else - { - [cell configureForStart]; - } - - cell.longPressed = nil; - } - else - { - NSInteger index = indexPath.row; - if (![self isLiveLocation]) - index -= 1; - if (self.allowLiveLocationSharing && !_hasOwnLiveLocation) - index -= 1; - - TGLiveLocation *liveLocation = index >= 0 && index < _liveLocations.count ? _liveLocations[index] : nil; - [cell configureWithPeer:liveLocation.peer message:liveLocation.message remaining:self.remainingTimeForMessage(liveLocation.message) userLocationSignal:[self userLocationSignal]]; - - cell.longPressed = ^ - { - __strong TGLocationViewController *strongSelf = weakSelf; - if (strongSelf != nil) - [strongSelf getDirectionsPressed:liveLocation.message.locationAttachment prompt:true]; - }; - } - return cell; - } - - return nil; -} - -- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath -{ - if (indexPath.row == 0 && ![self isLiveLocation]) - return false; - - return true; -} - -- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath -{ - [super tableView:tableView didHighlightRowAtIndexPath:indexPath]; - [self setReloadReady:false]; -} - -- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath -{ - [super tableView:tableView didUnhighlightRowAtIndexPath:indexPath]; - if (!_tableView.isTracking) - [self setReloadReady:true]; -} - -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath -{ - bool animated = true; - if (indexPath.row == 0 && ![self isLiveLocation]) - { - - } - else - { - TGLocationLiveCell *cell = [tableView dequeueReusableCellWithIdentifier:TGLocationLiveCellKind]; - if (cell == nil) - cell = [[TGLocationLiveCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:TGLocationInfoCellKind]; - - if (self.allowLiveLocationSharing && (indexPath.row == 0 || (![self isLiveLocation] && indexPath.row == 1))) - { - if (_hasOwnLiveLocation && !_ownLocationExpired) - { - if (self.liveLocationStopped != nil) - self.liveLocationStopped(); - } - else - { - [[[self userLocationSignal] take:1] startWithNext:^(CLLocation *location) - { - [self _presentLiveLocationMenu:location.coordinate dismissOnCompletion:true]; - }]; - } - } - else - { - NSInteger index = indexPath.row; - if (![self isLiveLocation]) - index -= 1; - if (self.allowLiveLocationSharing && !_hasOwnLiveLocation) - index -= 1; - - TGLiveLocation *liveLocation = _liveLocations[index]; - for (TGLocationAnnotation *annotation in _mapView.annotations) - { - if (![annotation isKindOfClass:[TGLocationAnnotation class]]) - continue; - - if (annotation.messageId == liveLocation.message.mid) - { - if ([_mapView.selectedAnnotations containsObject:annotation]) - [self setMapCenterCoordinate:annotation.coordinate offset:CGPointZero animated:true]; - else - [_mapView selectAnnotation:annotation animated:true]; - break; - } - } - } - } - [tableView deselectRowAtIndexPath:indexPath animated:animated]; -} - -- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath -{ - if (indexPath.row == 0 && ![self isLiveLocation]) - return TGLocationInfoCellHeight; - else - return TGLocationLiveCellHeight; - - return 0; -} - -- (CGFloat)visibleContentHeight -{ - if (![self isLiveLocation]) - return TGLocationInfoCellHeight + self.safeAreaInsetBottom; - else - return TGLocationLiveCellHeight + self.safeAreaInsetBottom; -} - -- (CGFloat)possibleContentHeight -{ - if (![self isLiveLocation]) - { - CGFloat height = TGLocationInfoCellHeight; - if (_liveLocations.count > 0) - { - CGFloat count = _liveLocations.count; - if (self.allowLiveLocationSharing && !_hasOwnLiveLocation) - count += 1; - count = MIN(1.5f, count); - height += count * TGLocationLiveCellHeight; - } - return height + self.safeAreaInsetBottom; - } - else - { - CGFloat count = _liveLocations.count; - if (self.allowLiveLocationSharing && !_hasOwnLiveLocation) - count += 1; - count = MIN(2.5f, count); - CGFloat height = count * TGLocationLiveCellHeight; - return height + self.safeAreaInsetBottom; - } -} - -- (bool)isLiveLocation -{ - return _locationAttachment.period > 0; -} - -- (bool)hasMoreThanOneLocation -{ - return ((_hasOwnLiveLocation && _liveLocations.count > 1) || (!_hasOwnLiveLocation && _liveLocations.count > 0)); -} - -- (void)setReloadReady:(bool)ready -{ - [_reloadReady set:[SSignal single:@(ready)]]; -} - -- (SSignal *)reloadReadySignal -{ - return [[_reloadReady.signal filter:^bool(NSNumber *value) { - return value.boolValue; - }] take:1]; -} - -- (void)scrollViewDidScroll:(UIScrollView *)scrollView -{ - [super scrollViewDidScroll:scrollView]; - - _mapView.compassInsets = UIEdgeInsetsMake(TGLocationMapInset + 120.0f + (scrollView.contentOffset.y + scrollView.contentInset.top) / 2.0f, 0.0f, 0.0f, 10.0f + TGScreenPixel); -} - -- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView -{ - [self setReloadReady:false]; -} - -- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView -{ - if (!scrollView.isTracking) - [self setReloadReady:true]; -} - -- (void)scrollViewDidEndDragging:(UIScrollView *)__unused scrollView willDecelerate:(BOOL)decelerate -{ - if (!decelerate) - [self setReloadReady:true]; -} - -- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)__unused scrollView -{ - if (!scrollView.isTracking) - [self setReloadReady:true]; -} - -- (void)_willStartOwnLiveLocation -{ - _focusOnOwnLocation = true; - - if (_currentLiveLocation.isOwnLocation) - _ignoreNextUpdates = true; - else - _throttle = true; -} - -- (void)layoutControllerForSize:(CGSize)size duration:(NSTimeInterval)duration -{ - [super layoutControllerForSize:size duration:duration]; - - if (!self.isViewLoaded) - return; - - for (UITableViewCell *cell in _tableView.visibleCells) - { - if ([cell isKindOfClass:[TGLocationInfoCell class]]) - { - ((TGLocationInfoCell *)cell).safeInset = self.controllerSafeAreaInset; - } else if ([cell isKindOfClass:[TGLocationLiveCell class]]) - { - ((TGLocationLiveCell *)cell).safeInset = self.controllerSafeAreaInset; - } - } -} - -@end - - -@implementation TGLiveLocation - -- (instancetype)initWithMessage:(TGMessage *)message peer:(id)peer hasOwnSession:(bool)hasOwnSession isOwnLocation:(bool)isOwnLocation isExpired:(bool)isExpired -{ - self = [super init]; - if (self != nil) - { - _message = message; - _peer = peer; - _hasOwnSession = hasOwnSession; - _isOwnLocation = isOwnLocation; - _isExpired = isExpired; - } - return self; -} - - -- (instancetype)initWithMessage:(TGMessage *)message peer:(id)peer -{ - self = [super init]; - if (self != nil) - { - _message = message; - _peer = peer; - _hasOwnSession = true; - _isOwnLocation = true; - _isExpired = false; - } - return self; -} - -- (int64_t)peerId -{ - return [_peer isKindOfClass:[TGUser class]] ? ((TGUser *)_peer).uid : ((TGConversation *)_peer).conversationId; -} - -- (CLLocation *)location -{ - TGLocationMediaAttachment *location = _message.locationAttachment; - if (location == nil) - return nil; - - return [[CLLocation alloc] initWithLatitude:location.latitude longitude:location.longitude]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGLocationWavesView.m b/submodules/LegacyComponents/Sources/TGLocationWavesView.m deleted file mode 100644 index e9580806f5..0000000000 --- a/submodules/LegacyComponents/Sources/TGLocationWavesView.m +++ /dev/null @@ -1,126 +0,0 @@ -#import "TGLocationWavesView.h" - -#import "LegacyComponentsInternal.h" -#import "TGImageUtils.h" -#import "TGPhotoEditorUtils.h" - -@interface TGLocationWavesView () -{ - CADisplayLink *_displayLink; - NSTimeInterval _previousTime; - - CGFloat _progress; - UIImage *_image; -} -@end - -@implementation TGLocationWavesView - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - self.backgroundColor = [UIColor clearColor]; - _image = TGComponentsImageNamed(@"LocationWave"); - self.userInteractionEnabled = false; - _color = [UIColor whiteColor]; - } - return self; -} - -- (void)invalidate -{ - [_displayLink invalidate]; - _displayLink = nil; -} - -- (CADisplayLink *)displayLink { - if (_displayLink == nil) { - _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkUpdate)]; - _displayLink.paused = true; - [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; - } - return _displayLink; -} - -- (void)setColor:(UIColor *)color -{ - _color = color; - _image = TGTintedImage(TGComponentsImageNamed(@"LocationWave"), color); -} - -- (void)start -{ - [self displayLink].paused = false; -} - -- (void)stop -{ - _displayLink.paused = true; -} - -- (void)drawRect:(CGRect)rect -{ - CGPoint center = CGPointMake(rect.size.width / 2.0f, rect.size.height / 2.0f); - CGFloat length = 9.0f; - - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, _color.CGColor); - - void (^draw)(CGFloat, bool) = ^(CGFloat pos, bool right) - { - CGMutablePathRef path = CGPathCreateMutable(); - CGPathAddArc(path, NULL, center.x, center.y, length * pos + 7.0f, right ? TGDegreesToRadians(-26) : TGDegreesToRadians(154), right ? TGDegreesToRadians(26) : TGDegreesToRadians(206), false); - - CGPathRef strokedArc = CGPathCreateCopyByStrokingPath(path, NULL, 1.65f, kCGLineCapRound, kCGLineJoinMiter, 10); - - CGContextAddPath(context, strokedArc); - - CGPathRelease(strokedArc); - CGPathRelease(path); - - CGContextFillPath(context); - }; - - CGFloat position = _progress; - CGFloat alpha = position / 0.5f; - if (alpha > 1.0f) - alpha = 2.0f - alpha; - CGContextSetAlpha(context, alpha * 0.7f); - - draw(position, false); - draw(position, true); - - CGFloat progress = _progress + 0.5f; - if (progress > 1.0f) - progress = progress - 1.0f; - - CGFloat largerPos = progress; - CGFloat largerAlpha = largerPos / 0.5f; - if (largerAlpha > 1.0f) - largerAlpha = 2.0f - largerAlpha; - CGContextSetAlpha(context, largerAlpha * 0.7f); - - draw(largerPos, false); - draw(largerPos, true); -} - -- (void)displayLinkUpdate -{ - NSTimeInterval previousTime = _previousTime; - NSTimeInterval currentTime = CACurrentMediaTime(); - _previousTime = currentTime; - - NSTimeInterval delta = previousTime > DBL_EPSILON ? currentTime - previousTime : 0.0; - if (delta < DBL_EPSILON) - return; - - _progress += delta * 0.52; - if (_progress > 1.0f) - _progress = 1.0f - _progress; - - [self setNeedsDisplay]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGMediaAssetsController.m b/submodules/LegacyComponents/Sources/TGMediaAssetsController.m index 2f0f9b13af..df17228fe4 100644 --- a/submodules/LegacyComponents/Sources/TGMediaAssetsController.m +++ b/submodules/LegacyComponents/Sources/TGMediaAssetsController.m @@ -17,7 +17,6 @@ #import "TGModernBarButton.h" #import -#import "TGMediaAssetsTipView.h" #import #import @@ -586,23 +585,6 @@ } } -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; - - if (_intent == TGMediaAssetsControllerSendFileIntent && self.shouldShowFileTipIfNeeded && iosMajorVersion() >= 7) - { - if (![[[NSUserDefaults standardUserDefaults] objectForKey:@"didShowDocumentPickerTip_v2"] boolValue]) - { - [[NSUserDefaults standardUserDefaults] setObject:@true forKey:@"didShowDocumentPickerTip_v2"]; - - TGMediaAssetsTipView *tipView = [[TGMediaAssetsTipView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.view.bounds.size.width, self.view.bounds.size.height)]; - tipView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - [self.navigationController.view addSubview:tipView]; - } - } -} - - (NSArray *)resultSignalsWithCurrentItem:(TGMediaAsset *)currentItem descriptionGenerator:(id (^)(id, NSString *, NSArray *, NSString *))descriptionGenerator { bool storeAssets = (_editingContext != nil) && self.shouldStoreAssets; diff --git a/submodules/LegacyComponents/Sources/TGMediaAssetsGifCell.m b/submodules/LegacyComponents/Sources/TGMediaAssetsGifCell.m index 819953cfe1..ca3015a6e4 100644 --- a/submodules/LegacyComponents/Sources/TGMediaAssetsGifCell.m +++ b/submodules/LegacyComponents/Sources/TGMediaAssetsGifCell.m @@ -59,7 +59,7 @@ NSString *const TGMediaAssetsGifCellKind = @"TGMediaAssetsGifCellKind"; _typeLabel.textColor = [UIColor whiteColor]; _typeLabel.backgroundColor = [UIColor clearColor]; _typeLabel.textAlignment = NSTextAlignmentLeft; - _typeLabel.font = TGSystemFontOfSize(12.0f); + _typeLabel.font = TGBoldSystemFontOfSize(13); _typeLabel.text = @"GIF"; [_typeLabel sizeToFit]; [self addSubview:_typeLabel]; @@ -78,7 +78,9 @@ NSString *const TGMediaAssetsGifCellKind = @"TGMediaAssetsGifCellKind"; [super layoutSubviews]; _shadowView.frame = (CGRect){ { 0, self.frame.size.height - _shadowView.frame.size.height }, {self.frame.size.width, _shadowView.frame.size.height } }; - _typeLabel.frame = (CGRect){ { 5, _shadowView.frame.origin.y }, {self.frame.size.width - 5 - 4, _shadowView.frame.size.height } }; + + CGSize typeSize = _typeLabel.frame.size; + _typeLabel.frame = CGRectMake(self.frame.size.width - floor(typeSize.width) - 5.0, self.frame.size.height - floor(typeSize.height) - 4.0, typeSize.width, typeSize.height); } @end diff --git a/submodules/LegacyComponents/Sources/TGMediaAssetsTipView.h b/submodules/LegacyComponents/Sources/TGMediaAssetsTipView.h deleted file mode 100644 index ab5b611419..0000000000 --- a/submodules/LegacyComponents/Sources/TGMediaAssetsTipView.h +++ /dev/null @@ -1,5 +0,0 @@ -#import - -@interface TGMediaAssetsTipView : UIView - -@end diff --git a/submodules/LegacyComponents/Sources/TGMediaAssetsTipView.m b/submodules/LegacyComponents/Sources/TGMediaAssetsTipView.m deleted file mode 100644 index fa1ed784a7..0000000000 --- a/submodules/LegacyComponents/Sources/TGMediaAssetsTipView.m +++ /dev/null @@ -1,97 +0,0 @@ -#import "TGMediaAssetsTipView.h" - -#import "LegacyComponentsInternal.h" -#import "TGColor.h" -#import "TGImageUtils.h" -#import "TGFont.h" -#import "TGStringUtils.h" - -#import - -@interface TGMediaAssetsTipView () -{ - UIView *_wrapperView; - UIImageView *_imageView; - UILabel *_titleLabel; - UILabel *_textLabel; - TGModernButton *_doneButton; -} -@end - -@implementation TGMediaAssetsTipView - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - self.backgroundColor = [UIColor whiteColor]; - - _wrapperView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)]; - [self addSubview:_wrapperView]; - - _imageView = [[UIImageView alloc] initWithImage:TGComponentsImageNamed(@"AttachmentTipIcons")]; - [self addSubview:_imageView]; - - _titleLabel = [[UILabel alloc] init]; - _titleLabel.backgroundColor = [UIColor clearColor]; - _titleLabel.textColor = UIColorRGB(0x222222); - _titleLabel.font = TGSystemFontOfSize(19.0f + TGRetinaPixel); - _titleLabel.text = TGLocalized(@"ShareFileTip.Title"); - [_wrapperView addSubview:_titleLabel]; - - _textLabel = [[UILabel alloc] init]; - _textLabel.backgroundColor = [UIColor clearColor]; - _textLabel.textColor = UIColorRGB(0x808080); - _textLabel.font = TGSystemFontOfSize(15.0f + TGRetinaPixel); - - NSString *shareTipText = [[NSString alloc] initWithFormat:TGLocalized(@"ShareFileTip.Text"), [TGStringUtils stringForDeviceType]]; - _textLabel.attributedText = [shareTipText attributedFormattedStringWithRegularFont:TGSystemFontOfSize(15.0f + TGRetinaPixel) boldFont:TGBoldSystemFontOfSize(15.0f + TGRetinaPixel) lineSpacing:3.0f paragraphSpacing:-1.0f alignment:NSTextAlignmentCenter]; - _textLabel.numberOfLines = 0; - _textLabel.lineBreakMode = NSLineBreakByWordWrapping; - [_wrapperView addSubview:_textLabel]; - - _doneButton = [[TGModernButton alloc] init]; - [_doneButton setTitle:TGLocalized(@"ShareFileTip.CloseTip") forState:UIControlStateNormal]; - _doneButton.titleLabel.font = TGSystemFontOfSize(18.0f); - [_doneButton setTitleColor:TGAccentColor()]; - _doneButton.contentEdgeInsets = UIEdgeInsetsMake(8.0f, 20.0f, 8.0f, 20.0f); - [_doneButton sizeToFit]; - [_doneButton addTarget:self action:@selector(doneButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - [self addSubview:_doneButton]; - } - return self; -} - -- (void)doneButtonPressed -{ - [UIView animateWithDuration:0.4 animations:^ - { - self.frame = CGRectMake(0.0f, self.superview.frame.size.height, self.frame.size.width, self.frame.size.height); - } completion:^(__unused BOOL finished) - { - [self removeFromSuperview]; - }]; -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - _imageView.frame = CGRectMake((self.frame.size.width - _imageView.frame.size.width) / 2, 0, _imageView.frame.size.width, _imageView.frame.size.height); - - CGFloat padding = 22.0f; - - CGSize titleSize = [_titleLabel sizeThatFits:CGSizeMake(self.bounds.size.width - padding * 2.0f, CGFLOAT_MAX)]; - _titleLabel.frame = CGRectMake(padding, CGRectGetMaxY(_imageView.frame) + 22.0f + TGRetinaPixel, titleSize.width, titleSize.height); - - CGSize textSize = [_textLabel sizeThatFits:CGSizeMake(self.bounds.size.width - padding * 2.0f, CGFLOAT_MAX)]; - _textLabel.frame = CGRectMake(padding, CGRectGetMaxY(_titleLabel.frame) + 15.0f + TGRetinaPixel, textSize.width, textSize.height); - - CGFloat wrapperHeight = CGRectGetMaxY(_textLabel.frame); - _wrapperView.frame = CGRectMake(0, floor((self.frame.size.height - wrapperHeight) / 2.0f) - 30.0f, self.frame.size.width, wrapperHeight); - - _doneButton.frame = CGRectMake(CGFloor((self.bounds.size.width - _doneButton.frame.size.width) / 2.0f), self.frame.size.height - _doneButton.frame.size.height - 16.0f + TGRetinaPixel, _doneButton.frame.size.width, _doneButton.frame.size.height); -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGMediaAssetsVideoCell.m b/submodules/LegacyComponents/Sources/TGMediaAssetsVideoCell.m index e88099df21..69a26f9b7b 100644 --- a/submodules/LegacyComponents/Sources/TGMediaAssetsVideoCell.m +++ b/submodules/LegacyComponents/Sources/TGMediaAssetsVideoCell.m @@ -67,13 +67,12 @@ NSString *const TGMediaAssetsVideoCellKind = @"TGMediaAssetsVideoCellKind"; _iconView = [[UIImageView alloc] init]; _iconView.contentMode = UIViewContentModeCenter; - [self addSubview:_iconView]; _durationLabel = [[UILabel alloc] init]; _durationLabel.textColor = [UIColor whiteColor]; _durationLabel.backgroundColor = [UIColor clearColor]; _durationLabel.textAlignment = NSTextAlignmentRight; - _durationLabel.font = TGSystemFontOfSize(12.0f); + _durationLabel.font = TGBoldSystemFontOfSize(13); [_durationLabel sizeToFit]; [self addSubview:_durationLabel]; @@ -113,6 +112,7 @@ NSString *const TGMediaAssetsVideoCellKind = @"TGMediaAssetsVideoCellKind"; durationString = [NSString stringWithFormat:@"%d:%02d", duration / 60, duration % 60]; _durationLabel.text = durationString; + [_durationLabel sizeToFit]; if (asset.subtypes & TGMediaAssetSubtypeVideoTimelapse) _iconView.image = TGComponentsImageNamed(@"ModernMediaItemTimelapseIcon"); @@ -235,7 +235,9 @@ NSString *const TGMediaAssetsVideoCellKind = @"TGMediaAssetsVideoCellKind"; self.checkButton.frame = (CGRect){ { self.frame.size.width - self.checkButton.frame.size.width - 2, 2 }, self.checkButton.frame.size }; _shadowView.frame = (CGRect){ { 0, self.frame.size.height - _shadowView.frame.size.height }, {self.frame.size.width, _shadowView.frame.size.height } }; _iconView.frame = CGRectMake(0, self.frame.size.height - 19, 19, 19); - _durationLabel.frame = (CGRect){ { 5, _shadowView.frame.origin.y }, {self.frame.size.width - 5 - 4, _shadowView.frame.size.height } }; + + CGSize durationSize = _durationLabel.frame.size; + _durationLabel.frame = CGRectMake(self.frame.size.width - floor(durationSize.width) - 5.0, self.frame.size.height - floor(durationSize.height) - 4.0, durationSize.width, durationSize.height); } @end diff --git a/submodules/LegacyComponents/Sources/TGMediaPickerLayoutMetrics.m b/submodules/LegacyComponents/Sources/TGMediaPickerLayoutMetrics.m index a180be82f1..14eef45878 100644 --- a/submodules/LegacyComponents/Sources/TGMediaPickerLayoutMetrics.m +++ b/submodules/LegacyComponents/Sources/TGMediaPickerLayoutMetrics.m @@ -51,40 +51,49 @@ CGSize itemSize = TGPhotoThumbnailSizeForCurrentScreen(); if ([UIScreen mainScreen].scale >= 2.0f - FLT_EPSILON) { - if (widescreenWidth >= 736.0f - FLT_EPSILON) + if (widescreenWidth >= 844.0f - FLT_EPSILON) { metrics->_normalItemSize = itemSize; metrics->_wideItemSize = itemSize; - metrics->_normalEdgeInsets = UIEdgeInsetsMake(4.0f, 0.0f, 2.0f, 0.0f); - metrics->_wideEdgeInsets = UIEdgeInsetsMake(4.0f, 2.0f, 1.0f, 2.0f); - metrics->_normalLineSpacing = 1.0f; + metrics->_normalEdgeInsets = UIEdgeInsetsMake(2.0f, 0.0f, 2.0f, 0.0f); + metrics->_wideEdgeInsets = UIEdgeInsetsMake(2.0f, 2.0f, 1.0f, 2.0f); + metrics->_normalLineSpacing = 2.0f; + metrics->_wideLineSpacing = 2.0f; + } + else if (widescreenWidth >= 736.0f - FLT_EPSILON) + { + metrics->_normalItemSize = itemSize; + metrics->_wideItemSize = itemSize; + metrics->_normalEdgeInsets = UIEdgeInsetsMake(2.0f, 0.0f, 2.0f, 0.0f); + metrics->_wideEdgeInsets = UIEdgeInsetsMake(2.0f, 2.0f, 1.0f, 2.0f); + metrics->_normalLineSpacing = 2.0f; metrics->_wideLineSpacing = 2.0f; } else if (widescreenWidth >= 667.0f - FLT_EPSILON) { metrics->_normalItemSize = itemSize; metrics->_wideItemSize = CGSizeMake(floor(itemSize.width), floor(itemSize.height)); - metrics->_normalEdgeInsets = UIEdgeInsetsMake(4.0f, 0.0f, 2.0f, 0.0f); - metrics->_wideEdgeInsets = UIEdgeInsetsMake(4.0f, 2.0f, 1.0f, 2.0f); - metrics->_normalLineSpacing = 1.0f; + metrics->_normalEdgeInsets = UIEdgeInsetsMake(2.0f, 0.0f, 2.0f, 0.0f); + metrics->_wideEdgeInsets = UIEdgeInsetsMake(2.0f, 2.0f, 1.0f, 2.0f); + metrics->_normalLineSpacing = 2.0f; metrics->_wideLineSpacing = 2.0f; } else { metrics->_normalItemSize = itemSize; metrics->_wideItemSize = CGSizeMake(floor(itemSize.width), floor(itemSize.height)); - metrics->_normalEdgeInsets = UIEdgeInsetsMake(4.0f, 0.0f, 2.0f, 0.0f); - metrics->_wideEdgeInsets = UIEdgeInsetsMake(4.0f, 1.0f, 1.0f, 1.0f); + metrics->_normalEdgeInsets = UIEdgeInsetsMake(2.0f, 0.0f, 2.0f, 0.0f); + metrics->_wideEdgeInsets = UIEdgeInsetsMake(2.0f, 1.0f, 1.0f, 1.0f); metrics->_normalLineSpacing = 2.0f; - metrics->_wideLineSpacing = 3.0f; + metrics->_wideLineSpacing = 2.0f; } } else { metrics->_normalItemSize = itemSize; metrics->_wideItemSize = CGSizeMake(floor(itemSize.width), floor(itemSize.height)); - metrics->_normalEdgeInsets = UIEdgeInsetsMake(4.0f, 0.0f, 2.0f, 0.0f); - metrics->_wideEdgeInsets = UIEdgeInsetsMake(4.0f, 1.0f, 1.0f, 1.0f); + metrics->_normalEdgeInsets = UIEdgeInsetsMake(2.0f, 0.0f, 2.0f, 0.0f); + metrics->_wideEdgeInsets = UIEdgeInsetsMake(2.0f, 1.0f, 1.0f, 1.0f); metrics->_normalLineSpacing = 2.0f; metrics->_wideLineSpacing = 2.0f; } diff --git a/submodules/LegacyComponents/Sources/TGMentionPanelCell.m b/submodules/LegacyComponents/Sources/TGMentionPanelCell.m index b9affa9f34..c316003e8a 100644 --- a/submodules/LegacyComponents/Sources/TGMentionPanelCell.m +++ b/submodules/LegacyComponents/Sources/TGMentionPanelCell.m @@ -59,7 +59,7 @@ NSString *const TGMentionPanelCellKind = @"TGMentionPanelCell"; self.selectedBackgroundView.backgroundColor = selectionColor; _avatarView = [[TGLetteredAvatarView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 32.0f, 32.0f)]; - [_avatarView setSingleFontSize:18.0f doubleFontSize:18.0f useBoldFont:false]; + [_avatarView setSingleFontSize:16.0f doubleFontSize:16.0f useBoldFont:false]; _avatarView.fadeTransition = true; [self.contentView addSubview:_avatarView]; diff --git a/submodules/LegacyComponents/Sources/TGNavigationBar.m b/submodules/LegacyComponents/Sources/TGNavigationBar.m index 9db9f3ba8f..57a2ba7d6c 100644 --- a/submodules/LegacyComponents/Sources/TGNavigationBar.m +++ b/submodules/LegacyComponents/Sources/TGNavigationBar.m @@ -204,9 +204,23 @@ static id _musicPlayerProvider; - (void)layoutSubviews { - [self updateLayout]; - [super layoutSubviews]; + + for (UIView *view in self.subviews) { + if (iosMajorVersion() >= 11) { + view.frame = CGRectOffset(view.frame, 0.0, 6.0); + } + } + + [self updateLayout]; +} + +- (CGSize)sizeThatFits:(CGSize)size { + if (iosMajorVersion() < 11) { + return CGSizeMake(MAX(self.frame.size.width, size.width), 36.0 - 6.0); + } else { + return [super sizeThatFits:size]; + } } - (void)updateLayout @@ -217,7 +231,13 @@ static id _musicPlayerProvider; if (iosMajorVersion() >= 11 && self.superview.safeAreaInsets.top > FLT_EPSILON) backgroundOverflow = self.superview.safeAreaInsets.top; - _backgroundContainerView.frame = CGRectMake(0, -backgroundOverflow, self.bounds.size.width, backgroundOverflow + self.bounds.size.height); + CGFloat heightAddition = 0.0; + if (iosMajorVersion() < 11) { + backgroundOverflow = 20.0; + heightAddition = 6.0 + TGScreenPixel; + } + + _backgroundContainerView.frame = CGRectMake(0, -backgroundOverflow, self.bounds.size.width, backgroundOverflow + self.bounds.size.height + heightAddition); if (_barBackgroundView != nil) _barBackgroundView.frame = _backgroundContainerView.bounds; @@ -298,6 +318,10 @@ static id _musicPlayerProvider; - (void)setFrame:(CGRect)frame { + if (frame.size.height < 56.0) { + frame.size.height = 56.0; + } + [super setFrame:frame]; if (_statusBarBackgroundView != nil && _statusBarBackgroundView.superview != nil) diff --git a/submodules/LegacyComponents/Sources/TGPhotoBrushSettingsView.m b/submodules/LegacyComponents/Sources/TGPhotoBrushSettingsView.m index 6547a3c5ca..144cf5b68a 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoBrushSettingsView.m +++ b/submodules/LegacyComponents/Sources/TGPhotoBrushSettingsView.m @@ -24,10 +24,6 @@ const CGFloat TGPhotoBrushSettingsItemHeight = 44.0f; NSArray *_brushViews; NSArray *_brushIconViews; NSArray *_brushSeparatorViews; - - UIImage *_landscapeLeftBackgroundImage; - UIImage *_landscapeRightBackgroundImage; - UIImage *_portraitBackgroundImage; } @end diff --git a/submodules/LegacyComponents/Sources/TGPhotoEditorBlurToolView.m b/submodules/LegacyComponents/Sources/TGPhotoEditorBlurToolView.m index c7eeaefa5b..331e050725 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoEditorBlurToolView.m +++ b/submodules/LegacyComponents/Sources/TGPhotoEditorBlurToolView.m @@ -280,17 +280,22 @@ _sliderView.frame = CGRectMake((self.frame.size.width - 32) / 2, TGPhotoEditorSliderViewMargin, 32, self.frame.size.height - 2 * TGPhotoEditorSliderViewMargin); + CGFloat titleOffset = 10; + if (MAX(_offButton.title.length, MAX(_radialButton.title.length, _linearButton.title.length)) > 7) { + titleOffset = -2; + } + [UIView performWithoutAnimation:^ { if (orientation == UIInterfaceOrientationLandscapeLeft) { _titleLabel.transform = CGAffineTransformMakeRotation(M_PI_2); - _titleLabel.frame = CGRectMake(self.frame.size.width - _titleLabel.frame.size.width - 10, (self.frame.size.height - _titleLabel.frame.size.height) / 2, _titleLabel.frame.size.width, _titleLabel.frame.size.height); + _titleLabel.frame = CGRectMake(self.frame.size.width - _titleLabel.frame.size.width - titleOffset, (self.frame.size.height - _titleLabel.frame.size.height) / 2, _titleLabel.frame.size.width, _titleLabel.frame.size.height); } else if (orientation == UIInterfaceOrientationLandscapeRight) { _titleLabel.transform = CGAffineTransformMakeRotation(-M_PI_2); - _titleLabel.frame = CGRectMake(10, (self.frame.size.height - _titleLabel.frame.size.height) / 2, _titleLabel.frame.size.width, _titleLabel.frame.size.height); + _titleLabel.frame = CGRectMake(titleOffset, (self.frame.size.height - _titleLabel.frame.size.height) / 2, _titleLabel.frame.size.width, _titleLabel.frame.size.height); } }]; } diff --git a/submodules/LegacyComponents/Sources/TGPhotoEditorBlurTypeButton.m b/submodules/LegacyComponents/Sources/TGPhotoEditorBlurTypeButton.m index 8c9da4e3e2..cb74b72a2a 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoEditorBlurTypeButton.m +++ b/submodules/LegacyComponents/Sources/TGPhotoEditorBlurTypeButton.m @@ -121,7 +121,7 @@ - (void)layoutSubviews { _imageView.frame = CGRectMake((self.frame.size.width - 50) / 2, (self.frame.size.height - 68) / 2, 50, 50); - _titleLabel.frame = CGRectMake(0, _imageView.frame.origin.y +_imageView.frame.size.height - 1, self.frame.size.width, 16); + _titleLabel.frame = CGRectMake(0, _imageView.frame.origin.y + _imageView.frame.size.height - 1, self.frame.size.width, 16); } @end diff --git a/submodules/LegacyComponents/Sources/TGPhotoEditorCollectionView.h b/submodules/LegacyComponents/Sources/TGPhotoEditorCollectionView.h index a15141fc27..df00dfb4aa 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoEditorCollectionView.h +++ b/submodules/LegacyComponents/Sources/TGPhotoEditorCollectionView.h @@ -1,9 +1,7 @@ #import -@class PGPhotoFilter; @class PGPhotoTool; -@protocol TGPhotoEditorCollectionViewFiltersDataSource; @protocol TGPhotoEditorCollectionViewToolsDataSource; @interface TGPhotoEditorCollectionView : UICollectionView @@ -11,9 +9,7 @@ @property (nonatomic, copy) void(^interactionBegan)(void); @property (nonatomic, copy) void(^interactionEnded)(void); -@property (nonatomic, weak) id filtersDataSource; @property (nonatomic, weak) id toolsDataSource; -@property (nonatomic, strong) UIImage *filterThumbnailImage; @property (nonatomic, readonly) bool hasAnyTracking; @@ -24,15 +20,6 @@ @end -@protocol TGPhotoEditorCollectionViewFiltersDataSource - -- (NSInteger)numberOfFiltersInCollectionView:(TGPhotoEditorCollectionView *)collectionView; -- (PGPhotoFilter *)collectionView:(TGPhotoEditorCollectionView *)collectionView filterAtIndex:(NSInteger)index; -- (void)collectionView:(TGPhotoEditorCollectionView *)collectionView didSelectFilterWithIndex:(NSInteger)index; -- (void)collectionView:(TGPhotoEditorCollectionView *)collectionView requestThumbnailImageForFilterAtIndex:(NSInteger)index completion:(void (^)(UIImage *thumbnailImage, bool cached, bool finished))completion; - -@end - @protocol TGPhotoEditorCollectionViewToolsDataSource - (NSInteger)numberOfToolsInCollectionView:(TGPhotoEditorCollectionView *)collectionView; diff --git a/submodules/LegacyComponents/Sources/TGPhotoEditorCollectionView.m b/submodules/LegacyComponents/Sources/TGPhotoEditorCollectionView.m index 71ad38a911..bcd4c64165 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoEditorCollectionView.m +++ b/submodules/LegacyComponents/Sources/TGPhotoEditorCollectionView.m @@ -2,9 +2,6 @@ #import "LegacyComponentsInternal.h" -#import "PGPhotoFilter.h" - -#import "TGPhotoFilterCell.h" #import "TGPhotoToolCell.h" #import "TGPhotoEditorSliderView.h" @@ -43,7 +40,6 @@ const CGPoint TGPhotoEditorEdgeScrollTriggerOffset = { 100, 150 }; self.showsHorizontalScrollIndicator = false; self.showsVerticalScrollIndicator = false; - [self registerClass:[TGPhotoFilterCell class] forCellWithReuseIdentifier:TGPhotoFilterCellKind]; [self registerClass:[TGPhotoToolCell class] forCellWithReuseIdentifier:TGPhotoToolCellKind]; } return self; @@ -106,13 +102,6 @@ const CGPoint TGPhotoEditorEdgeScrollTriggerOffset = { 100, 150 }; - (void)setSelectedItemIndexPath:(NSIndexPath *)indexPath { - NSArray *visibleItemsIndexPathes = self.indexPathsForVisibleItems; - for (NSIndexPath *i in visibleItemsIndexPathes) - { - UICollectionViewCell *cell = [self cellForItemAtIndexPath:i]; - if ([cell isKindOfClass:[TGPhotoFilterCell class]]) - [(TGPhotoFilterCell *)cell setFilterSelected:[i isEqual:indexPath]]; - } } - (void)selectItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UICollectionViewScrollPosition)scrollPosition @@ -140,12 +129,9 @@ const CGPoint TGPhotoEditorEdgeScrollTriggerOffset = { 100, 150 }; - (NSInteger)collectionView:(UICollectionView *)__unused collectionView numberOfItemsInSection:(NSInteger)__unused section { - id filtersDataSource = self.filtersDataSource; id toolsDataSource = self.toolsDataSource; - if ([filtersDataSource respondsToSelector:@selector(numberOfFiltersInCollectionView:)]) - return [filtersDataSource numberOfFiltersInCollectionView:self]; - else if ([toolsDataSource respondsToSelector:@selector(numberOfToolsInCollectionView:)]) + if ([toolsDataSource respondsToSelector:@selector(numberOfToolsInCollectionView:)]) return [toolsDataSource numberOfToolsInCollectionView:self]; return 0; @@ -153,29 +139,11 @@ const CGPoint TGPhotoEditorEdgeScrollTriggerOffset = { 100, 150 }; - (UICollectionViewCell *)collectionView:(UICollectionView *)__unused collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { - id filtersDataSource = self.filtersDataSource; id toolsDataSource = self.toolsDataSource; UICollectionViewCell *cell = nil; - if ([filtersDataSource respondsToSelector:@selector(collectionView:filterAtIndex:)]) - { - PGPhotoFilter *filter = [filtersDataSource collectionView:self filterAtIndex:indexPath.row]; - - cell = [self dequeueReusableCellWithReuseIdentifier:TGPhotoFilterCellKind forIndexPath:indexPath]; - [(TGPhotoFilterCell *)cell setPhotoFilter:filter]; - [(TGPhotoFilterCell *)cell setFilterSelected:[_selectedItemIndexPath isEqual:indexPath]]; - - [filtersDataSource collectionView:self requestThumbnailImageForFilterAtIndex:indexPath.row completion:^(UIImage *thumbnailImage, bool cached, __unused bool finished) - { - TGDispatchOnMainThread(^ - { - if ([[(TGPhotoFilterCell *)cell filterIdentifier] isEqualToString:filter.identifier]) - [(TGPhotoFilterCell *)cell setImage:thumbnailImage animated:!cached]; - }); - }]; - } - else if ([toolsDataSource respondsToSelector:@selector(collectionView:toolAtIndex:)]) + if ([toolsDataSource respondsToSelector:@selector(collectionView:toolAtIndex:)]) { cell = [self dequeueReusableCellWithReuseIdentifier:TGPhotoToolCellKind forIndexPath:indexPath]; cell.alpha = 1.0f; @@ -231,97 +199,6 @@ const CGPoint TGPhotoEditorEdgeScrollTriggerOffset = { 100, 150 }; block(); } -- (void)collectionView:(UICollectionView *)__unused collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath -{ - id filtersDataSource = self.filtersDataSource; - - if ([filtersDataSource respondsToSelector:@selector(collectionView:didSelectFilterWithIndex:)]) - { - bool vertical = false; - if (self.frame.size.height > self.frame.size.width) - vertical = true; - - CGFloat screenSize = 0; - CGFloat contentSize = 0; - CGFloat contentOffset = 0; - CGFloat itemPosition = 0; - CGFloat itemSize = 0; - CGFloat targetOverlap = 0; - CGFloat startInset = 0; - CGFloat endInset = 0; - - CGFloat triggerOffset = 0; - - if (!vertical) - { - screenSize = self.frame.size.width; - contentSize = self.contentSize.width; - contentOffset = self.contentOffset.x; - itemPosition = [self.collectionViewLayout layoutAttributesForItemAtIndexPath:indexPath].frame.origin.x; - itemSize = ((UICollectionViewFlowLayout *)self.collectionViewLayout).itemSize.width; - startInset = self.contentInset.left; - endInset = self.contentInset.right; - triggerOffset = TGPhotoEditorEdgeScrollTriggerOffset.x; - targetOverlap = itemSize / 2 + ((UICollectionViewFlowLayout *)self.collectionViewLayout).minimumLineSpacing; - } - else - { - screenSize = self.frame.size.height; - contentSize = self.contentSize.height; - contentOffset = self.contentOffset.y; - itemPosition = [self.collectionViewLayout layoutAttributesForItemAtIndexPath:indexPath].frame.origin.y; - itemSize = ((UICollectionViewFlowLayout *)self.collectionViewLayout).itemSize.height; - startInset = self.contentInset.top; - endInset = self.contentInset.bottom; - triggerOffset = TGPhotoEditorEdgeScrollTriggerOffset.y; - targetOverlap = itemSize + 2 * ((UICollectionViewFlowLayout *)self.collectionViewLayout).minimumLineSpacing; - } - - CGFloat itemsScreenPosition = itemPosition - contentOffset; - - if (itemsScreenPosition < triggerOffset) - { - CGFloat targetContentOffset = MAX(-startInset, itemPosition - targetOverlap); - - if (!vertical && targetContentOffset < startInset + itemSize) - targetContentOffset = -startInset; - - if (contentOffset > targetContentOffset) - { - if (!vertical) - [self setContentOffset:CGPointMake(targetContentOffset, -self.contentInset.top) animated:YES]; - else - [self setContentOffset:CGPointMake(-self.contentInset.left, targetContentOffset) animated:YES]; - - self.scrollEnabled = false; - } - } - else if (itemsScreenPosition > screenSize - triggerOffset) - { - CGFloat targetContentOffset = MIN(contentSize - screenSize + endInset, - itemPosition - screenSize + itemSize + targetOverlap); - - if (!vertical && targetContentOffset > contentSize - screenSize - endInset - itemSize) - targetContentOffset = contentSize - screenSize + endInset; - - if (contentOffset < targetContentOffset) - { - if (!vertical) - [self setContentOffset:CGPointMake(targetContentOffset, -self.contentInset.top) animated:YES]; - else - [self setContentOffset:CGPointMake(-self.contentInset.left, targetContentOffset) animated:YES]; - - self.scrollEnabled = false; - } - } - - [filtersDataSource collectionView:self didSelectFilterWithIndex:indexPath.row]; - - _selectedItemIndexPath = indexPath; - [self setSelectedItemIndexPath:indexPath]; - } -} - - (BOOL)collectionView:(UICollectionView *)__unused collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)__unused indexPath { return false; diff --git a/submodules/LegacyComponents/Sources/TGPhotoEditorInterfaceAssets.m b/submodules/LegacyComponents/Sources/TGPhotoEditorInterfaceAssets.m index 67f1ec0008..0f24694816 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoEditorInterfaceAssets.m +++ b/submodules/LegacyComponents/Sources/TGPhotoEditorInterfaceAssets.m @@ -69,7 +69,7 @@ + (UIImage *)paintIcon { - return TGTintedImage([UIImage imageNamed:@"Editor/Drawing"], [self toolbarIconColor]); + return TGTintedImage([UIImage imageNamed:@"Editor/BrushSelectedPen"], [self toolbarIconColor]); } + (UIImage *)stickerIcon diff --git a/submodules/LegacyComponents/Sources/TGPhotoEditorUtils.m b/submodules/LegacyComponents/Sources/TGPhotoEditorUtils.m index c2a2882fe3..43490ea095 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoEditorUtils.m +++ b/submodules/LegacyComponents/Sources/TGPhotoEditorUtils.m @@ -26,27 +26,31 @@ CGSize TGPhotoThumbnailSizeForCurrentScreen() { if (widescreenWidth >= 896.0f - FLT_EPSILON) { - return CGSizeMake(103.0f, 103.0f); + return CGSizeMake(137.0f - TGScreenPixel, 137.0f - TGScreenPixel); + } + else if (widescreenWidth >= 844.0f - FLT_EPSILON) + { + return CGSizeMake(129.0f - TGScreenPixel, 129.0f - TGScreenPixel); } else if (widescreenWidth >= 812.0f - FLT_EPSILON) { - return CGSizeMake(93.0f, 93.0f); + return CGSizeMake(124.0f - TGScreenPixel, 124.0f - TGScreenPixel); } else if (widescreenWidth >= 736.0f - FLT_EPSILON) { - return CGSizeMake(103.0f, 103.0f); + return CGSizeMake(137.0f - TGScreenPixel, 137.0f - TGScreenPixel); } else if (widescreenWidth >= 667.0f - FLT_EPSILON) { - return CGSizeMake(93.0f, 93.5f); + return CGSizeMake(124.0f - TGScreenPixel, 124.0f - TGScreenPixel); } else { - return CGSizeMake(78.5f, 78.5f); + return CGSizeMake(106.0f - TGScreenPixel, 106.0f - TGScreenPixel); } } - return CGSizeMake(78.5f, 78.5f); + return CGSizeMake(106.0f, 106.0f); } CGSize TGScaleToSize(CGSize size, CGSize maxSize) diff --git a/submodules/LegacyComponents/Sources/TGPhotoFilterCell.h b/submodules/LegacyComponents/Sources/TGPhotoFilterCell.h deleted file mode 100644 index 5a2cca3956..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoFilterCell.h +++ /dev/null @@ -1,19 +0,0 @@ -#import - -@class PGPhotoFilter; - -@interface TGPhotoFilterCell : UICollectionViewCell - -@property (nonatomic, readonly) NSString *filterIdentifier; - -- (void)setPhotoFilter:(PGPhotoFilter *)photoFilter; -- (void)setFilterSelected:(BOOL)selected; - -- (void)setImage:(UIImage *)image; -- (void)setImage:(UIImage *)image animated:(bool)animated; - -+ (CGFloat)filterCellWidth; - -@end - -extern NSString * const TGPhotoFilterCellKind; diff --git a/submodules/LegacyComponents/Sources/TGPhotoFilterCell.m b/submodules/LegacyComponents/Sources/TGPhotoFilterCell.m deleted file mode 100644 index d558038669..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoFilterCell.m +++ /dev/null @@ -1,126 +0,0 @@ -#import "TGPhotoFilterCell.h" - -#import "PGPhotoFilter.h" -#import "PGPhotoFilterDefinition.h" - -#import "TGPhotoEditorInterfaceAssets.h" - -NSString * const TGPhotoFilterCellKind = @"TGPhotoFilterCellKind"; - -@interface TGPhotoFilterCell () -{ - UIImageView *_imageView; - UIImageView *_selectionView; - UILabel *_titleLabel; -} -@end - -@implementation TGPhotoFilterCell - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.width)]; - _imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - [self addSubview:_imageView]; - - _titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, _imageView.frame.origin.y + _imageView.frame.size.height + 5, frame.size.width, 17)]; - _titleLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _titleLabel.backgroundColor = [UIColor clearColor]; - _titleLabel.font = [TGPhotoEditorInterfaceAssets editorItemTitleFont]; - _titleLabel.textAlignment = NSTextAlignmentCenter; - _titleLabel.textColor = [TGPhotoEditorInterfaceAssets editorItemTitleColor]; - _titleLabel.highlightedTextColor = [TGPhotoEditorInterfaceAssets editorActiveItemTitleColor]; - [self addSubview:_titleLabel]; - - static UIImage *selectionImage = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^ - { - CGFloat width = [TGPhotoFilterCell filterCellWidth]; - UIGraphicsBeginImageContextWithOptions(CGSizeMake(width, width), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, [TGPhotoEditorInterfaceAssets filterSelectionColor].CGColor); - - UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(3, 3, width - 2 * 3, width - 2 * 3)]; - [path appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(0, 0, width, width)]]; - path.usesEvenOddFillRule = true; - [path fill]; - - selectionImage = [UIGraphicsGetImageFromCurrentImageContext() resizableImageWithCapInsets:UIEdgeInsetsMake(3, 3, 3, 3)]; - UIGraphicsEndImageContext(); - }); - - _selectionView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.width)]; - _selectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - _selectionView.image = selectionImage; - _selectionView.hidden = true; - [self addSubview:_selectionView]; - } - return self; -} - -- (void)setPhotoFilter:(PGPhotoFilter *)photoFilter -{ - _filterIdentifier = photoFilter.identifier; - _titleLabel.text = photoFilter.definition.title; -} - -- (void)setFilterSelected:(BOOL)selected -{ - [super setSelected:selected]; - - _titleLabel.highlighted = selected; - _selectionView.hidden = !selected; -} - -- (void)setImage:(UIImage *)image -{ - [self setImage:image animated:false]; -} - -- (void)setImage:(UIImage *)image animated:(bool)animated -{ - if (_imageView.image == nil) - animated = false; - - if (animated) - { - UIImageView *transitionView = [[UIImageView alloc] initWithImage:_imageView.image]; - transitionView.frame = _imageView.frame; - [self insertSubview:transitionView aboveSubview:_imageView]; - - _imageView.image = image; - - [UIView animateWithDuration:0.3f animations:^ - { - transitionView.alpha = 0.0f; - } completion:^(__unused BOOL finished) - { - [transitionView removeFromSuperview]; - }]; - } - else - { - _imageView.image = image; - } -} - -- (void)setSelected:(BOOL)__unused selected -{ - -} - -- (void)setHighlighted:(BOOL)__unused highlighted -{ - -} - -+ (CGFloat)filterCellWidth -{ - return 64; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintController.m b/submodules/LegacyComponents/Sources/TGPhotoPaintController.m index 06583aa272..f90dad60c1 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintController.m +++ b/submodules/LegacyComponents/Sources/TGPhotoPaintController.m @@ -347,7 +347,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f; [_doneButton setTitle:TGLocalized(@"Common.Done") forState:UIControlStateNormal]; _doneButton.titleLabel.font = TGSystemFontOfSize(17.0); [_doneButton sizeToFit]; - [_wrapperView addSubview:_doneButton]; +// [_wrapperView addSubview:_doneButton]; void (^settingsPressed)(void) = ^ { diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsView.h b/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsView.h index bc962f881f..035895cab6 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsView.h +++ b/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsView.h @@ -35,10 +35,6 @@ typedef enum - (void)setIcon:(TGPhotoPaintSettingsViewIcon)icon animated:(bool)animated; - (void)setHighlighted:(bool)highlighted; -+ (UIImage *)landscapeLeftBackgroundImage; -+ (UIImage *)landscapeRightBackgroundImage; -+ (UIImage *)portraitBackgroundImage; - @end @protocol TGPhotoPaintPanelView diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsView.m b/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsView.m index 6a9489a2ed..9a48e7c7c5 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsView.m +++ b/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsView.m @@ -236,37 +236,4 @@ const CGFloat TGPhotoPaintSettingsPadPickerWidth = 360.0f; } } -+ (UIImage *)landscapeLeftBackgroundImage -{ - static dispatch_once_t onceToken; - static UIImage *image; - dispatch_once(&onceToken, ^ - { - image = [TGTintedImage(TGComponentsImageNamed(@"PaintPopupLandscapeLeftBackground"), UIColorRGB(0xf7f7f7)) resizableImageWithCapInsets:UIEdgeInsetsMake(32.0f, 32.0f, 32.0f, 32.0f)]; - }); - return image; -} - -+ (UIImage *)landscapeRightBackgroundImage -{ - static dispatch_once_t onceToken; - static UIImage *image; - dispatch_once(&onceToken, ^ - { - image = [TGTintedImage(TGComponentsImageNamed(@"PaintPopupLandscapeRightBackground"), UIColorRGB(0xf7f7f7)) resizableImageWithCapInsets:UIEdgeInsetsMake(32.0f, 32.0f, 32.0f, 32.0f)]; - }); - return image; -} - -+ (UIImage *)portraitBackgroundImage -{ - static dispatch_once_t onceToken; - static UIImage *image; - dispatch_once(&onceToken, ^ - { - image = [TGTintedImage(TGComponentsImageNamed(@"PaintPopupPortraitBackground"), UIColorRGB(0xf7f7f7)) resizableImageWithCapInsets:UIEdgeInsetsMake(32.0f, 32.0f, 32.0f, 32.0f)]; - }); - return image; -} - @end diff --git a/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m b/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m index 8d9a75c1d4..e45d5b3673 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m +++ b/submodules/LegacyComponents/Sources/TGPhotoVideoEditor.m @@ -102,7 +102,7 @@ } } -+ (void)presentWithContext:(id)context controller:(TGViewController *)controller caption:(NSString *)caption entities:(NSArray *)entities withItem:(id)item recipientName:(NSString *)recipientName stickersContext:(id)stickersContext completion:(void (^)(id, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed ++ (void)presentWithContext:(id)context controller:(TGViewController *)controller caption:(NSString *)caption entities:(NSArray *)entities withItem:(id)item paint:(bool)paint recipientName:(NSString *)recipientName stickersContext:(id)stickersContext completion:(void (^)(id, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed { id windowManager = [context makeOverlayWindowManager]; id windowContext = [windowManager context]; @@ -173,14 +173,6 @@ completion(item.asset, editingContext); [strongController dismissWhenReadyAnimated:true]; - - /*[UIView animateWithDuration:0.3f delay:0.0f options:(7 << 16) animations:^ - { - strongController.view.frame = CGRectOffset(strongController.view.frame, 0, strongController.view.frame.size.height); - } completion:^(__unused BOOL finished) - { - [strongController dismiss]; - }];*/ }; galleryController.beginTransitionIn = ^UIView *(__unused TGMediaPickerGalleryItem *item, __unused TGModernGalleryItemView *itemView) @@ -207,10 +199,14 @@ dismissed(); } }; - + TGOverlayControllerWindow *controllerWindow = [[TGOverlayControllerWindow alloc] initWithManager:windowManager parentController:controller contentController:galleryController]; controllerWindow.hidden = false; galleryController.view.clipsToBounds = true; + +// if (paint) { +// [model presentPhotoEditorForItem:galleryItem tab:TGPhotoEditorPaintTab]; +// } } @end diff --git a/submodules/LegacyComponents/Sources/TGSearchBar.m b/submodules/LegacyComponents/Sources/TGSearchBar.m deleted file mode 100644 index 150b84d8b9..0000000000 --- a/submodules/LegacyComponents/Sources/TGSearchBar.m +++ /dev/null @@ -1,1197 +0,0 @@ -#import "TGSearchBar.h" - -#import "LegacyComponentsInternal.h" -#import "TGColor.h" - -#import -#import - -#import - -#import - -#import - -#import - -@interface TGSearchBar () -{ - CGFloat _cancelButtonWidth; - - TGSearchBarPallete *_pallete; -} - -@property (nonatomic, strong) UIView *wrappingClip; -@property (nonatomic, strong) UIView *wrappingView; - -@property (nonatomic, strong) UIImageView *textFieldBackground; - -@property (nonatomic, strong) UIImage *normalTextFieldBackgroundImage; -@property (nonatomic, strong) UIImage *activeTextFieldBackgroundImage; - -@property (nonatomic) bool showsCustomCancelButton; -@property (nonatomic, strong) UILabel *placeholderLabel; -@property (nonatomic, strong) UILabel *prefixLabel; -@property (nonatomic, strong) UIImageView *customSearchIcon; -@property (nonatomic, strong) UIActivityIndicatorView *customSearchActivityIndicator; -@property (nonatomic, strong) NSTimer *searchActivityTimer; -@property (nonatomic, strong) UIButton *customClearButton; - -@property (nonatomic, strong) UIView *customScopeButtonContainer; -@property (nonatomic, strong) UISegmentedControl *customSegmentedControl; -@property (nonatomic) int customCurrentScope; - -@end - -@implementation TGSearchBar - -+ (CGFloat)searchBarBaseHeight -{ - return 44.0f; -} - -- (CGFloat)baseHeight { - if (self.showsScopeBar) - return 44.0f; - if (_style == TGSearchBarStyleKeyboard) { - return [self inputHeight] + 17.0f; - } - return [self inputHeight] + 12.0f; -} - -- (CGFloat)inputContentOffset { - if (_style == TGSearchBarStyleKeyboard) { - return 3.0f; - } - return _style == TGSearchBarStyleLightAlwaysPlain ? 3.0f : 0.0f; -} - -- (CGFloat)searchIconOffset { - return _style == TGSearchBarStyleLightAlwaysPlain ? TGScreenPixel : 0.0f; -} - -- (CGFloat)inputHeight { - if (_style == TGSearchBarStyleKeyboard) { - return 33.0f; - } else { - return _style == TGSearchBarStyleLightAlwaysPlain ? 36.0f : 28.0f; - } -} - -+ (CGFloat)searchBarScopeHeight -{ - return 44.0f; -} - -- (CGFloat)topPadding -{ - if (_style == TGSearchBarStyleKeyboard) - return 4.0f; - - return -1.0f; -} - -- (CGFloat)cancelButtonPadding -{ - if (_style == TGSearchBarStyleKeyboard) - return -2.0f; - - return 0.0f; -} - -- (id)initWithFrame:(CGRect)frame -{ - return [self initWithFrame:frame style:TGSearchBarStyleLightPlain]; -} - -- (instancetype)initWithFrame:(CGRect)frame style:(TGSearchBarStyle)style -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - _delayActivity = true; - - _wrappingClip = [[UIView alloc] initWithFrame:CGRectMake(0.0f, -20.0f, frame.size.width, frame.size.height + 20.0f)]; - _wrappingClip.clipsToBounds = true; - [self addSubview:_wrappingClip]; - - _wrappingView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 20.0f, frame.size.width, frame.size.height)]; - [_wrappingClip addSubview:_wrappingView]; - - _style = style; - - NSString *backgroundFileName = nil; - NSString *backgroundActiveFileName = nil; - - UIImage *backgroundManualImage = nil; - UIImage *backgroundManualActiveImage = nil; - - if (_style == TGSearchBarStyleDefault) - { - backgroundFileName = @"SearchBarBackground.png"; - backgroundActiveFileName = @"SearchBarBackground_Active.png"; - } - else if (_style == TGSearchBarStyleDark) - { - backgroundFileName = @"SearchBarBackgroundDark.png"; - backgroundActiveFileName = @"SearchBarBackgroundDark.png"; - } - else if (_style == TGSearchBarStyleLight || _style == TGSearchBarStyleLightPlain || _style == TGSearchBarStyleLightAlwaysPlain || _style == TGSearchBarStyleHeader) - { - static UIImage *image = nil; - static UIImage *imagePlain = nil; - static UIImage *imagePlainForced = nil; - static UIImage *imageHeader = nil; - - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^ - { - UIGraphicsBeginImageContextWithOptions(CGSizeMake(1.0f, 3.0f), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor); - CGContextFillRect(context, CGRectMake(0.0f, 0.0f, 1.0f, 3.0f)); - imagePlain = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:0 topCapHeight:1]; - CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); - CGContextFillRect(context, CGRectMake(0.0f, 0.0f, 1.0f, 3.0f)); - imagePlainForced = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:0 topCapHeight:1]; - - CGContextSetFillColorWithColor(context, UIColorRGB(0xc8c7cc).CGColor); - CGFloat separatorHeight = TGScreenPixel; - CGContextFillRect(context, CGRectMake(0.0f, 3.0f - separatorHeight, 1.0f, separatorHeight)); - - image = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:0 topCapHeight:1]; - UIGraphicsEndImageContext(); - - - UIGraphicsBeginImageContextWithOptions(CGSizeMake(1.0f, 3.0f), true, 0.0f); - context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, UIColorRGB(0xf7f7f7).CGColor); - CGContextFillRect(context, CGRectMake(0.0f, 0.0f, 1.0f, 3.0f)); - - CGContextSetFillColorWithColor(context, UIColorRGB(0xc8c7cc).CGColor); - CGContextFillRect(context, CGRectMake(0.0f, 3.0f - separatorHeight, 1.0f, separatorHeight)); - - imageHeader = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:0 topCapHeight:1]; - - UIGraphicsEndImageContext(); - }); - - if (_style == TGSearchBarStyleHeader) - { - backgroundManualImage = imageHeader; - backgroundManualActiveImage = imageHeader; - } - else - { - backgroundManualImage = _style == TGSearchBarStyleLight ? image : imagePlain; - backgroundManualActiveImage = _style == TGSearchBarStyleLightAlwaysPlain ? imagePlainForced : image; - } - } - - UIImage *backgroundImage = nil; - if (backgroundManualImage != nil) - backgroundImage = backgroundManualImage; - else - backgroundImage = [TGImageNamed(backgroundFileName) stretchableImageWithLeftCapWidth:1 topCapHeight:1]; - _customBackgroundView = [[UIImageView alloc] initWithFrame:self.bounds]; - _customBackgroundView.image = backgroundImage; - _customBackgroundView.userInteractionEnabled = true; - [_customBackgroundView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(backgroundTapGesture:)]]; - [_wrappingView addSubview:_customBackgroundView]; - - UIImage *activeBackgroundImage = nil; - if (backgroundManualActiveImage != nil) - activeBackgroundImage = backgroundManualActiveImage; - else - activeBackgroundImage = [TGImageNamed(backgroundActiveFileName) stretchableImageWithLeftCapWidth:1 topCapHeight:1]; - _customActiveBackgroundView = [[UIImageView alloc] initWithFrame:self.bounds]; - _customActiveBackgroundView.image = activeBackgroundImage; - _customActiveBackgroundView.alpha = 0.0f; - [_wrappingView addSubview:_customActiveBackgroundView]; - - _textFieldBackground = [[UIImageView alloc] initWithImage:self.normalTextFieldBackgroundImage]; - _textFieldBackground.userInteractionEnabled = false; - [_wrappingView addSubview:_textFieldBackground]; - - UIColor *placeholderColor = nil; - if (_style == TGSearchBarStyleDefault) - placeholderColor = UIColorRGB(0x8e8e93); - else if (_style == TGSearchBarStyleDark) - placeholderColor = [UIColor whiteColor]; - else if (_style == TGSearchBarStyleLight || _style == TGSearchBarStyleLightPlain || _style == TGSearchBarStyleLightAlwaysPlain || _style == TGSearchBarStyleHeader) - placeholderColor = UIColorRGB(0x8e8e93); - - _placeholderLabel = [[UILabel alloc] init]; - _placeholderLabel.textAlignment = NSTextAlignmentLeft; - _placeholderLabel.userInteractionEnabled = false; - _placeholderLabel.textColor = placeholderColor; - _placeholderLabel.backgroundColor = [UIColor clearColor]; - _placeholderLabel.font = TGSystemFontOfSize(style == TGSearchBarStyleLightAlwaysPlain ? 16.0f : 14.0f); - _placeholderLabel.text = TGLocalized(@"Common.Search"); - [_wrappingView addSubview:_placeholderLabel]; - - _prefixLabel = [[UILabel alloc] init]; - _prefixLabel.textAlignment = NSTextAlignmentLeft; - _prefixLabel.userInteractionEnabled = false; - _prefixLabel.textColor = placeholderColor; - _prefixLabel.backgroundColor = [UIColor clearColor]; - _prefixLabel.font = TGSystemFontOfSize(style == TGSearchBarStyleLightAlwaysPlain ? 16.0f : 14.0f); - [_wrappingView addSubview:_prefixLabel]; - - UIImage *iconImage = nil; - if (_style == TGSearchBarStyleDefault) - { - iconImage = TGImageNamed(@"SearchBarIcon.png"); - } - else if (_style == TGSearchBarStyleDark) - { - iconImage = TGImageNamed(@"SearchBarIconDark.png"); - } - else if (_style == TGSearchBarStyleLight || _style == TGSearchBarStyleLightPlain || _style == TGSearchBarStyleHeader) - { - iconImage = [TGSearchBar searchBarIcon:UIColorRGB(0x8e8e93)]; - } - else if (_style == TGSearchBarStyleLightAlwaysPlain || _style == TGSearchBarStyleKeyboard) - { - iconImage = TGImageNamed(@"SearchBarIconLightLarge.png"); - } - - _customSearchIcon = [[UIImageView alloc] initWithImage:iconImage]; - _customSearchIcon.userInteractionEnabled = false; - [_wrappingView addSubview:_customSearchIcon]; - } - return self; -} - -- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event -{ - return [super hitTest:point withEvent:event]; -} - -+ (UIImage *)searchBarIcon:(UIColor *)color -{ - UIGraphicsBeginImageContextWithOptions(CGSizeMake(13, 13), false, 0.0f); - - CGContextRef context = UIGraphicsGetCurrentContext(); - - CGContextSetStrokeColorWithColor(context, color.CGColor); - CGContextSetLineWidth(context, 1.0f); - CGContextSetLineCap(context, kCGLineCapRound); - CGContextStrokeEllipseInRect(context, CGRectMake(0.5f, 0.5f, 9.0f, 9.0f)); - - CGContextSetLineWidth(context, 1.5f); - CGContextMoveToPoint(context, 8.5f, 8.5f); - CGContextAddLineToPoint(context, 8.5f + 3.5f, 8.5f + 3.5f); - CGContextStrokePath(context); - - UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - - return image; -} - -- (void)setHighContrast:(bool)highContrast { - if (_highContrast != highContrast) { - _highContrast = highContrast; - _textFieldBackground.image = _showsCustomCancelButton ? self.activeTextFieldBackgroundImage : self.normalTextFieldBackgroundImage; - } -} - -- (void)setAlwaysExtended:(bool)alwaysExtended -{ - if (_alwaysExtended != alwaysExtended) - { - _alwaysExtended = alwaysExtended; - - [self layoutSubviews]; - } -} - -- (void)setFrame:(CGRect)frame -{ - [super setFrame:frame]; -} - -- (void)sizeToFit -{ - CGFloat requiredHeight = 0; - - if (_searchBarShouldShowScopeControl && ![self landscapeMode] && !_scopeBarCollapsed) - { - requiredHeight = [self baseHeight] + [TGSearchBar searchBarScopeHeight]; - } - else - { - requiredHeight = [self baseHeight]; - } - - if (_style == TGSearchBarStyleLight) - requiredHeight += 4.0f; - - CGRect frame = self.frame; - frame.size.height = requiredHeight; - self.frame = frame; -} - -- (BOOL)showsCancelButton -{ - return _showsCustomCancelButton; -} - -- (void)setPallete:(TGSearchBarPallete *)pallete -{ - _pallete = pallete; - - _customSearchActivityIndicator.color = _pallete.placeholderColor; - - _customTextField.textColor = pallete.textColor; - _prefixLabel.textColor = pallete.placeholderColor; - _placeholderLabel.textColor = pallete.placeholderColor; - - [UIView performWithoutAnimation:^ - { - bool shouldFlip = _customTextField.isFirstResponder; - if (shouldFlip) - [_customTextField resignFirstResponder]; - _customTextField.keyboardAppearance = _style == TGSearchBarStyleDark || _pallete.isDark ? UIKeyboardAppearanceAlert : UIKeyboardAppearanceDefault; - if (shouldFlip) - [_customTextField becomeFirstResponder]; - }]; - _customSearchIcon.image = [TGSearchBar searchBarIcon:pallete.placeholderColor]; - [_customClearButton setBackgroundImage:_pallete.clearIcon forState:UIControlStateNormal]; - - _normalTextFieldBackgroundImage = nil; - _activeTextFieldBackgroundImage = nil; - _textFieldBackground.image = _showsCustomCancelButton ? self.activeTextFieldBackgroundImage : self.normalTextFieldBackgroundImage; - - UIImage *backgroundManualImage = nil; - UIImage *backgroundManualActiveImage = nil; - - if (_style == TGSearchBarStyleLight || _style == TGSearchBarStyleLightPlain || _style == TGSearchBarStyleLightAlwaysPlain || _style == TGSearchBarStyleHeader || _style == TGSearchBarStyleKeyboard) - { - [(TGModernButton *)_customCancelButton setTitleColor:_pallete.accentColor]; - - UIGraphicsBeginImageContextWithOptions(CGSizeMake(1.0f, 3.0f), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor); - CGContextFillRect(context, CGRectMake(0.0f, 0.0f, 1.0f, 3.0f)); - UIImage *imagePlain = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:0 topCapHeight:1]; - CGContextSetFillColorWithColor(context, _style == TGSearchBarStyleLightAlwaysPlain ? pallete.menuBackgroundColor.CGColor : pallete.plainBackgroundColor.CGColor); - CGContextFillRect(context, CGRectMake(0.0f, 0.0f, 1.0f, 3.0f)); - UIImage *imagePlainForced = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:0 topCapHeight:1]; - - CGContextSetFillColorWithColor(context, pallete.barSeparatorColor.CGColor); - CGFloat separatorHeight = TGScreenPixel; - CGContextFillRect(context, CGRectMake(0.0f, 3.0f - separatorHeight, 1.0f, separatorHeight)); - - UIImage *image = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:0 topCapHeight:1]; - UIGraphicsEndImageContext(); - - - UIGraphicsBeginImageContextWithOptions(CGSizeMake(1.0f, 3.0f), true, 0.0f); - context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, pallete.barBackgroundColor.CGColor); - CGContextFillRect(context, CGRectMake(0.0f, 0.0f, 1.0f, 3.0f)); - - CGContextSetFillColorWithColor(context, pallete.barSeparatorColor.CGColor); - CGContextFillRect(context, CGRectMake(0.0f, 3.0f - separatorHeight, 1.0f, separatorHeight)); - - UIImage *imageHeader = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:0 topCapHeight:1]; - - UIGraphicsEndImageContext(); - - if (_style == TGSearchBarStyleHeader) - { - backgroundManualImage = imageHeader; - backgroundManualActiveImage = imageHeader; - } - else - { - backgroundManualImage = _style == TGSearchBarStyleLight ? image : imagePlain; - backgroundManualActiveImage = _style == TGSearchBarStyleLightAlwaysPlain ? imagePlainForced : image; - } - - if (backgroundManualImage != nil) - _customBackgroundView.image = backgroundManualImage; - - if (backgroundManualActiveImage != nil) - _customActiveBackgroundView.image = backgroundManualActiveImage; - } -} - -- (UIImage *)normalTextFieldBackgroundImage -{ - if (_highContrast) { - UIColor *highContrastColor = _pallete != nil ? _pallete.highContrastBackgroundColor : UIColorRGB(0xe5e5e5); - CGFloat diameter = 14.0f; - UIGraphicsBeginImageContextWithOptions(CGSizeMake(diameter, diameter), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, highContrastColor.CGColor); - CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, diameter, diameter)); - UIImage *image = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:(NSInteger)(diameter / 2.0f) topCapHeight:(NSInteger)(diameter / 2.0f)]; - UIGraphicsEndImageContext(); - - return image; - } else if (_normalTextFieldBackgroundImage == nil) { - NSString *fileName = nil; - - if (_style == TGSearchBarStyleDefault) - fileName = @"SearchInputField.png"; - else if (_style == TGSearchBarStyleDark) - fileName = @"SearchInputFieldDark.png"; - else if (_style == TGSearchBarStyleLight || _style == TGSearchBarStyleLightPlain) - { - UIColor *color = _pallete != nil ? _pallete.backgroundColor : UIColorRGB(0xf1f1f1); - UIGraphicsBeginImageContextWithOptions(CGSizeMake(14.0f, 14.0f), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, color.CGColor); - CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, 14.0f, 14.0f)); - UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); - image = [image stretchableImageWithLeftCapWidth:(int)(image.size.width / 2) topCapHeight:(int)(image.size.height / 2)]; - UIGraphicsEndImageContext(); - - _normalTextFieldBackgroundImage = image; - return _normalTextFieldBackgroundImage; - } - else if (_style == TGSearchBarStyleLightAlwaysPlain) - { - CGFloat diameter = 16.0f; - UIGraphicsBeginImageContextWithOptions(CGSizeMake(diameter, diameter), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, (_pallete != nil ? _pallete.highContrastBackgroundColor : UIColorRGB(0xe4e4e4)).CGColor); - CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, diameter, diameter)); - UIImage *image = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:(NSInteger)(diameter / 2.0f) topCapHeight:(NSInteger)(diameter / 2.0f)]; - UIGraphicsEndImageContext(); - - _normalTextFieldBackgroundImage = image; - return _normalTextFieldBackgroundImage; - } - else if (_style == TGSearchBarStyleKeyboard) - { - CGFloat diameter = 33.0; - UIGraphicsBeginImageContextWithOptions(CGSizeMake(diameter, diameter), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, (_pallete != nil ? _pallete.highContrastBackgroundColor : UIColorRGB(0xe4e4e4)).CGColor); - CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, diameter, diameter)); - UIImage *image = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:(NSInteger)(diameter / 2.0f) topCapHeight:(NSInteger)(diameter / 2.0f)]; - UIGraphicsEndImageContext(); - - _normalTextFieldBackgroundImage = image; - return _normalTextFieldBackgroundImage; - } - else if (_style == TGSearchBarStyleHeader) - { - CGFloat diameter = 10.0f; - UIGraphicsBeginImageContextWithOptions(CGSizeMake(diameter, diameter), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, (_pallete != nil ? _pallete.highContrastBackgroundColor : UIColorRGB(0xe4e4e4)).CGColor); - CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, diameter, diameter)); - UIImage *headerImage = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:(NSInteger)(diameter / 2.0f) topCapHeight:(NSInteger)(diameter / 2.0f)]; - UIGraphicsEndImageContext(); - - _normalTextFieldBackgroundImage = headerImage; - return _normalTextFieldBackgroundImage; - } - - UIImage *rawImage = TGImageNamed(fileName); - _normalTextFieldBackgroundImage = [rawImage stretchableImageWithLeftCapWidth:(int)(rawImage.size.width / 2) topCapHeight:(int)(rawImage.size.height / 2)]; - } - - return _normalTextFieldBackgroundImage; -} - -- (UIImage *)activeTextFieldBackgroundImage -{ - if (_activeTextFieldBackgroundImage == nil) - { - NSString *fileName = nil; - - if (_style == TGSearchBarStyleDefault) - fileName = @"SearchInputField_Active.png"; - else if (_style == TGSearchBarStyleDark) - fileName = @"SearchInputFieldDark.png"; - else if (_style == TGSearchBarStyleLight || _style == TGSearchBarStyleLightPlain) - { - UIColor *color = _pallete != nil ? _pallete.backgroundColor : UIColorRGB(0xf1f1f1); - UIGraphicsBeginImageContextWithOptions(CGSizeMake(14.0f, 14.0f), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, color.CGColor); - CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, 14.0f, 14.0f)); - UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); - image = [image stretchableImageWithLeftCapWidth:(int)(image.size.width / 2) topCapHeight:(int)(image.size.height / 2)]; - UIGraphicsEndImageContext(); - - _activeTextFieldBackgroundImage = image; - return _activeTextFieldBackgroundImage; - } - else if (_style == TGSearchBarStyleLightAlwaysPlain || _style == TGSearchBarStyleHeader || _style == TGSearchBarStyleKeyboard) { - _activeTextFieldBackgroundImage = [self normalTextFieldBackgroundImage]; - return _activeTextFieldBackgroundImage; - } - - UIImage *rawImage = TGImageNamed(fileName); - _activeTextFieldBackgroundImage = [rawImage stretchableImageWithLeftCapWidth:(int)(rawImage.size.width / 2) topCapHeight:(int)(rawImage.size.height / 2)]; - } - - return _activeTextFieldBackgroundImage; -} - -- (UITextField *)maybeCustomTextField -{ - return _customTextField; -} - -- (UITextField *)customTextField -{ - if (_customTextField == nil) - { - CGRect frame = _textFieldBackground.frame; - frame.origin.y -= TGIsRetina() ? 0.0f : 0.0f; - frame.origin.x += 27; - frame.size.width -= 27 + 8 + 14; - _customTextField = [[TGTextField alloc] initWithFrame:frame]; - __weak TGSearchBar *weakSelf = self; - ((TGTextField *)_customTextField).deleteBackwardEmpty = ^{ - __strong TGSearchBar *strongSelf = weakSelf; - if (strongSelf != nil && strongSelf->_clearPrefix) { - strongSelf->_clearPrefix(false); - } - }; - _customTextField.font = _placeholderLabel.font; - if (iosMajorVersion() >= 7) - _customTextField.textAlignment = NSTextAlignmentNatural; - _customTextField.autocapitalizationType = UITextAutocapitalizationTypeNone; - _customTextField.autocorrectionType = UITextAutocorrectionTypeNo; - - UIColor *textColor = nil; - UIImage *clearImage = nil; - - if (_style == TGSearchBarStyleDefault || _style == TGSearchBarStyleLight || _style == TGSearchBarStyleLightPlain || _style == TGSearchBarStyleLightAlwaysPlain || _style == TGSearchBarStyleHeader || _style == TGSearchBarStyleKeyboard) - { - textColor = _pallete != nil ? _pallete.textColor : [UIColor blackColor]; - clearImage = TGImageNamed(@"SearchBarClearIcon.png"); - } - else if (_style == TGSearchBarStyleDark) - { - textColor = [UIColor whiteColor]; - clearImage = TGImageNamed(@"SearchBarClearIconDark.png"); - } - - _customTextField.textColor = textColor; - - _customTextField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter; - _customTextField.returnKeyType = UIReturnKeySearch; - _customTextField.keyboardAppearance = _style == TGSearchBarStyleDark || _pallete.isDark ? UIKeyboardAppearanceAlert : UIKeyboardAppearanceDefault; - _customTextField.delegate = self; - [_customTextField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged]; - - _customClearButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, clearImage.size.width, clearImage.size.height)]; - [_customClearButton setBackgroundImage:_pallete != nil ? _pallete.clearIcon : clearImage forState:UIControlStateNormal]; - [_customClearButton addTarget:self action:@selector(customClearButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - _customClearButton.hidden = true; - - [_wrappingView addSubview:_customTextField]; - [_wrappingView addSubview:_customClearButton]; - - [self setNeedsLayout]; - } - - return _customTextField; -} - -- (UIButton *)customCancelButton -{ - if (_customCancelButton == nil) - { - _cancelButtonWidth = [TGLocalized(@"Common.Cancel") sizeWithFont:TGSystemFontOfSize(17.0f)].width + 11.0f; - - CGRect textFieldBackgroundFrame = _textFieldBackground.frame; - _customCancelButton = [[TGModernButton alloc] initWithFrame:CGRectMake(textFieldBackgroundFrame.origin.x + textFieldBackgroundFrame.size.width + 10, 0, _cancelButtonWidth, [self baseHeight])]; - [_customCancelButton setTitle:TGLocalized(@"Common.Cancel") forState:UIControlStateNormal]; - - UIColor *buttonColor = nil; - - if (_style == TGSearchBarStyleDefault || _style == TGSearchBarStyleLight || _style == TGSearchBarStyleLightPlain || _style == TGSearchBarStyleLightAlwaysPlain || _style == TGSearchBarStyleHeader || _style == TGSearchBarStyleKeyboard) - buttonColor = _pallete != nil ? _pallete.accentColor : TGAccentColor(); - else if (_style == TGSearchBarStyleDark) - buttonColor = [UIColor whiteColor]; - - [(TGModernButton *)_customCancelButton setTitleColor:buttonColor]; - _customCancelButton.titleLabel.font = TGSystemFontOfSize(17.0f); - _customCancelButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight; - _customCancelButton.hidden = true; - [_customCancelButton addTarget:self action:@selector(searchCancelButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - [_wrappingView addSubview:_customCancelButton]; - } - - return _customCancelButton; -} - -- (void)setShowsCancelButton:(BOOL)showsCancelButton -{ - [self setShowsCancelButton:showsCancelButton animated:false]; -} - -- (void)setShowsCancelButton:(bool)showsCancelButton animated:(bool)animated -{ - if (_showsCustomCancelButton != showsCancelButton) - { - if (showsCancelButton) - { - [self customCancelButton]; - _customCancelButton.hidden = _hidesCancelButton; - - if (_customScopeButtonTitles.count > 1) - { - self.customScopeButtonContainer.hidden = false; - [_customSegmentedControl setSelectedSegmentIndex:0]; - } - } - else - { - [_customTextField setText:@""]; - [self updatePlaceholder:@""]; - } - - _textFieldBackground.image = showsCancelButton ? self.activeTextFieldBackgroundImage : self.normalTextFieldBackgroundImage; - - _showsCustomCancelButton = showsCancelButton; - - if (animated) - { - if (showsCancelButton) - _wrappingClip.clipsToBounds = false; - - [UIView animateWithDuration:0.2 animations:^ - { - if (!showsCancelButton) - { - _customTextField.alpha = 0.0f; - _customClearButton.alpha = 0.0f; - } - - if (_customScopeButtonTitles.count > 1) - { - [self setSearchBarShouldShowScopeControl:showsCancelButton]; - _customScopeButtonContainer.alpha = showsCancelButton ? 1.0f : 0.0f; - } - - [self layoutSubviews]; - - _customActiveBackgroundView.alpha = showsCancelButton ? 1.0f : 0.0f; - } completion:^(__unused BOOL finished) - { - //if (finished) - { - if (showsCancelButton) - { - _customTextField.alpha = 1.0f; - _customClearButton.alpha = 1.0f; - } - else - { - _customCancelButton.hidden = true; - _customScopeButtonContainer.hidden = true; - - _wrappingClip.clipsToBounds = true; - } - } - }]; - } - else - { - _wrappingClip.clipsToBounds = !showsCancelButton; - - if (_customScopeButtonTitles.count > 1) - { - [self setSearchBarShouldShowScopeControl:showsCancelButton]; - _customScopeButtonContainer.alpha = showsCancelButton ? 1.0f : 0.0f; - } - - _customTextField.alpha = showsCancelButton ? 1.0f : 0.0f; - _customClearButton.alpha = _customTextField.alpha; - _customActiveBackgroundView.alpha = showsCancelButton ? 1.0f : 0.0f; - _customCancelButton.hidden = !showsCancelButton; - _customScopeButtonContainer.hidden = !showsCancelButton; - - [self layoutSubviews]; - } - } -} - -- (void)setSafeAreaInset:(UIEdgeInsets)safeAreaInset -{ - _safeAreaInset = safeAreaInset; - [self setNeedsLayout]; -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - CGRect bounds = self.bounds; - - bool landscapeMode = [self landscapeMode]; - - CGRect clippingFrame = _wrappingClip.frame; - clippingFrame.size = CGSizeMake(bounds.size.width, bounds.size.height + 20.0f); - _wrappingClip.frame = clippingFrame; - - CGRect wrappingFrame = _wrappingView.frame; - wrappingFrame.size = bounds.size; - _wrappingView.frame = wrappingFrame; - - float retinaPixel = TGIsRetina() ? TGScreenPixel : 0.0f; - const float scopeBarHorizontalWidth = 220; - - CGFloat rightPadding = _showsCustomCancelButton && !_hidesCancelButton ? ((_customScopeButtonContainer != nil && landscapeMode ? scopeBarHorizontalWidth : 0) + _cancelButtonWidth) : 0.0f; - - CGFloat safeInsetHeight = self.safeAreaInset.top > FLT_EPSILON ? self.safeAreaInset.top : 20.0f; - _customBackgroundView.frame = CGRectMake(0, ((_showsCustomCancelButton || _alwaysExtended) ? -safeInsetHeight : 0.0f), self.frame.size.width, self.frame.size.height + (_showsCustomCancelButton || _alwaysExtended ? safeInsetHeight : 0.0f)); - _customActiveBackgroundView.frame = _customBackgroundView.frame; - - _textFieldBackground.frame = CGRectMake(8 + _safeAreaInset.left, 9 + [self topPadding], self.frame.size.width - 16 - rightPadding - _safeAreaInset.left - _safeAreaInset.right, [self inputHeight]); - - CGFloat prefixOffset = 0.0f; - { - [_prefixLabel sizeToFit]; - - CGRect frame = _textFieldBackground.frame; - frame.origin.y += 5.0f; - frame.origin.x += 27; - frame.size = _prefixLabel.bounds.size; - - frame.size.width = MIN(frame.size.width, CGFloor((bounds.size.width - rightPadding - 20.0f) / 2.0f)); - - _prefixLabel.frame = frame; - - prefixOffset = frame.size.width; - } - - CGSize placeholderSize = [_placeholderLabel.text sizeWithFont:_placeholderLabel.font]; - placeholderSize.width = MIN(placeholderSize.width, self.frame.size.width - rightPadding - 50.0f - prefixOffset); - - _customSearchIcon.frame = CGRectMake(_showsCustomCancelButton ? (_textFieldBackground.frame.origin.x + 8.0f) : ((CGFloor((self.frame.size.width - placeholderSize.width) / 2) + 10 + TGScreenPixel) - 20), [self searchIconOffset] + [self inputContentOffset] + 16 + retinaPixel + [self topPadding], _customSearchIcon.frame.size.width, _customSearchIcon.frame.size.height); - - _customSearchActivityIndicator.frame = (CGRect){{CGFloor(_customSearchIcon.frame.origin.x + (_customSearchIcon.frame.size.width - _customSearchActivityIndicator.frame.size.width) / 2.0f), CGFloor(_customSearchIcon.frame.origin.y + (_customSearchIcon.frame.size.height - _customSearchActivityIndicator.frame.size.height) / 2.0f) + 1.0f + TGScreenPixel}, _customSearchActivityIndicator.frame.size}; - - _placeholderLabel.frame = CGRectMake(_showsCustomCancelButton ? ((TGIsRTL() ? (CGRectGetMaxX(_textFieldBackground.frame) - placeholderSize.width - 32.0f) : 36 + _safeAreaInset.left) + prefixOffset) : (CGFloor((self.frame.size.width - placeholderSize.width) / 2) + 10 + TGScreenPixel), [self inputContentOffset] + 14 + [self topPadding], placeholderSize.width, placeholderSize.height); - - if (_customTextField != nil) - { - CGRect frame = _textFieldBackground.frame; - frame.origin.y -= retinaPixel; - frame.origin.x += 27; - frame.size.width -= 27 + 8 + 24; - - frame.origin.x += prefixOffset; - frame.size.width -= prefixOffset; - - _customTextField.frame = frame; - - _customClearButton.frame = CGRectMake(CGRectGetMaxX(_textFieldBackground.frame) - 22, [self inputContentOffset] + 16 + [self topPadding] + (_style == TGSearchBarStyleLightAlwaysPlain ? 1.0f : 0.0f), _customClearButton.frame.size.width, _customClearButton.frame.size.height); - } - - if (_customCancelButton != nil) - { - _customCancelButton.frame = CGRectMake(self.frame.size.width + (_showsCustomCancelButton ? (-_customCancelButton.frame.size.width - 9 - self.safeAreaInset.right) : 9), [self topPadding] + 2.0f + [self cancelButtonPadding], _cancelButtonWidth, [self baseHeight]); - } - - if (_customScopeButtonContainer != nil) - { - if (_showsCustomCancelButton) - { - if (!landscapeMode) - _customScopeButtonContainer.frame = CGRectMake(7.0f, self.frame.size.height - 29.0f - 9.0f + [self topPadding], self.frame.size.width - 14.0f, 29.0f); - else - _customScopeButtonContainer.frame = CGRectMake(self.frame.size.width - scopeBarHorizontalWidth - _customCancelButton.frame.size.width - self.safeAreaInset.right, 5.0f + [self topPadding], scopeBarHorizontalWidth - 14.0f, 32.0f); - } - else - { - if (!landscapeMode) - _customScopeButtonContainer.frame = CGRectMake(7.0f, self.frame.size.height - 29.0f - 9.0f + [self topPadding], self.frame.size.width - 14.0f, 29.0f); - else - _customScopeButtonContainer.frame = CGRectMake(self.frame.size.width + 71.0f, 5.0f + [self topPadding], scopeBarHorizontalWidth - 14.0f, 29.0f); - } - } -} - -- (bool)landscapeMode -{ - static CGFloat landscapeScreenWidth = 0.0f; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^ - { - CGSize screenSize = TGScreenSize(); - landscapeScreenWidth = MAX(screenSize.width, screenSize.height); - }); - - return self.frame.size.width >= landscapeScreenWidth - FLT_EPSILON; -} - -- (void)setSearchBarShouldShowScopeControl:(bool)searchBarShouldShowScopeControl -{ - _searchBarShouldShowScopeControl = searchBarShouldShowScopeControl; - - if (_searchBarShouldShowScopeControl) - self.customScopeButtonContainer.hidden = false; - - CGFloat requiredHeight = 0; - - if (_searchBarShouldShowScopeControl && ![self landscapeMode]) - requiredHeight = [self baseHeight] + [TGSearchBar searchBarScopeHeight]; - else - requiredHeight = [self baseHeight]; - - if (ABS(requiredHeight - self.frame.size.height) > FLT_EPSILON) - { - id delegate = (id)self.delegate; - if ([delegate respondsToSelector:@selector(searchBar:willChangeHeight:)]) - [delegate searchBar:self willChangeHeight:requiredHeight]; - } -} - -- (void)setCustomScopeBarHidden:(bool)hidden -{ - self.customScopeButtonContainer.alpha = hidden ? 0.0f : 1.0f; - self.customScopeButtonContainer.userInteractionEnabled = !hidden; -} - -#pragma mark - - -- (void)tappedSearchBar:(id)__unused arg -{ -} - -- (BOOL)becomeFirstResponder -{ - if (![_customTextField isFirstResponder]) - { - bool shouldBeginEditing = true; - id delegate = self.delegate; - if ([delegate respondsToSelector:@selector(searchBarShouldBeginEditing:)]) - shouldBeginEditing = [delegate searchBarShouldBeginEditing:(UISearchBar *)self]; - - if (shouldBeginEditing) - { - [self.customTextField becomeFirstResponder]; - - if ([delegate respondsToSelector:@selector(searchBarTextDidBeginEditing:)]) - [delegate searchBarTextDidBeginEditing:(UISearchBar *)self]; - - return true; - } - } - - return false; -} - -- (BOOL)resignFirstResponder -{ - return [_customTextField resignFirstResponder]; -} - -- (BOOL)canBecomeFirstResponder -{ - return _customTextField == nil || [_customTextField canBecomeFirstResponder]; -} - -- (BOOL)canResignFirstResponder -{ - return [_customTextField canResignFirstResponder]; -} - -- (BOOL)isFirstResponder { - return [_customTextField isFirstResponder]; -} - -#pragma mark - - -- (void)searchCancelButtonPressed -{ - id delegate = self.delegate; - - if ([delegate respondsToSelector:@selector(searchBarCancelButtonClicked:)]) - [delegate searchBarCancelButtonClicked:(UISearchBar *)self]; -} - -- (UIView *)customScopeButtonContainer -{ - if (_customScopeButtonContainer == nil) - { - CGRect frame = CGRectZero; - if (![self landscapeMode]) - frame = CGRectMake(7.0f, self.frame.size.height - 29.0f - 9.0f, self.frame.size.width - 14.0f, 29.0f); - else - frame = CGRectMake(0, 0, self.frame.size.width, 29.0f); - - _customScopeButtonContainer = [[UIView alloc] initWithFrame:frame]; - _customScopeButtonContainer.alpha = 0.0f; - [_wrappingView insertSubview:_customScopeButtonContainer aboveSubview:_customActiveBackgroundView]; - - _customSegmentedControl = [[UISegmentedControl alloc] initWithItems:self.customScopeButtonTitles]; - - [_customSegmentedControl setBackgroundImage:_pallete != nil ? _pallete.segmentedControlBackgroundImage : TGComponentsImageNamed(@"ModernSegmentedControlBackground.png") forState:UIControlStateNormal barMetrics:UIBarMetricsDefault]; - [_customSegmentedControl setBackgroundImage:_pallete != nil ? _pallete.segmentedControlSelectedImage : TGComponentsImageNamed(@"ModernSegmentedControlSelected.png") forState:UIControlStateSelected barMetrics:UIBarMetricsDefault]; - [_customSegmentedControl setBackgroundImage:_pallete != nil ? _pallete.segmentedControlSelectedImage : TGComponentsImageNamed(@"ModernSegmentedControlSelected.png") forState:UIControlStateSelected | UIControlStateHighlighted barMetrics:UIBarMetricsDefault]; - [_customSegmentedControl setBackgroundImage:_pallete != nil ? _pallete.segmentedControlHighlightedImage : TGComponentsImageNamed(@"ModernSegmentedControlHighlighted.png") forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault]; - [_customSegmentedControl setDividerImage:_pallete != nil ? _pallete.segmentedControlDividerImage : TGComponentsImageNamed(@"ModernSegmentedControlDivider.png") forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault]; - - [_customSegmentedControl setTitleTextAttributes:@{UITextAttributeTextColor:_pallete != nil ? _pallete.accentColor : TGAccentColor(), UITextAttributeTextShadowColor: [UIColor clearColor], UITextAttributeFont: TGSystemFontOfSize(13)} forState:UIControlStateNormal]; - [_customSegmentedControl setTitleTextAttributes:@{UITextAttributeTextColor:_pallete != nil ? _pallete.accentContrastColor : [UIColor whiteColor], UITextAttributeTextShadowColor: [UIColor clearColor], UITextAttributeFont: TGSystemFontOfSize(13)} forState:UIControlStateSelected]; - - _customSegmentedControl.frame = CGRectMake(0, _customScopeButtonContainer.frame.size.height - 29.0f, _customScopeButtonContainer.frame.size.width, 29.0f); - _customSegmentedControl.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin; - - [_customSegmentedControl setSelectedSegmentIndex:0]; - [_customSegmentedControl addTarget:self action:@selector(segmentedControlChanged) forControlEvents:UIControlEventValueChanged]; - - [_customScopeButtonContainer addSubview:_customSegmentedControl]; - } - - return _customScopeButtonContainer; -} - -- (void)backgroundTapGesture:(UITapGestureRecognizer *)recognizer -{ - if (recognizer.state == UIGestureRecognizerStateRecognized) - { - if (![_customTextField isFirstResponder]) - { - bool shouldBeginEditing = true; - id delegate = self.delegate; - if ([delegate respondsToSelector:@selector(searchBarShouldBeginEditing:)]) - shouldBeginEditing = [delegate searchBarShouldBeginEditing:(UISearchBar *)self]; - - if (shouldBeginEditing) - { - [self.customTextField becomeFirstResponder]; - - if ([delegate respondsToSelector:@selector(searchBarTextDidBeginEditing:)]) - [delegate searchBarTextDidBeginEditing:(UISearchBar *)self]; - } - } - } -} - -- (void)updatePlaceholder:(NSString *)text -{ - _placeholderLabel.hidden = text.length != 0; - _customClearButton.hidden = !_placeholderLabel.hidden && _prefixText.length == 0; -} - -- (void)textFieldDidChange:(UITextField *)textField -{ - if (textField == _customTextField) - { - NSString *text = textField.text; - - id delegate = self.delegate; - if ([delegate respondsToSelector:@selector(searchBar:textDidChange:)]) - [delegate searchBar:(UISearchBar *)self textDidChange:text]; - - [self updatePlaceholder:text]; - } -} - -- (BOOL)textFieldShouldReturn:(UITextField *)textField -{ - if (textField == _customTextField) - { - if (textField.text.length != 0) - { - id delegate = self.delegate; - if ([delegate respondsToSelector:@selector(searchBarSearchButtonClicked:)]) - [delegate searchBarSearchButtonClicked:(UISearchBar *)self]; - } - - [textField resignFirstResponder]; - - return false; - } - - return false; -} - -- (void)customClearButtonPressed -{ - if (_customTextField.text.length == 0) { - if (_prefixText.length != 0) { - if (_clearPrefix) { - _clearPrefix(true); - } - } - } else { - [_customTextField setText:@""]; - [self updatePlaceholder:@""]; - - [self becomeFirstResponder]; - - NSString *text = @""; - - id delegate = self.delegate; - if ([delegate respondsToSelector:@selector(searchBar:textDidChange:)]) - [delegate searchBar:(UISearchBar *)self textDidChange:text]; - } -} - -- (NSInteger)selectedScopeButtonIndex -{ - return _customSegmentedControl.selectedSegmentIndex; -} - -- (void)setSelectedScopeButtonIndex:(NSInteger)selectedScopeButtonIndex -{ - [self.customSegmentedControl setSelectedSegmentIndex:selectedScopeButtonIndex]; -} - -- (void)setPlaceholder:(NSString *)placeholder -{ - _placeholder = placeholder; - _placeholderLabel.text = placeholder; - - [self setNeedsLayout]; -} - -- (NSString *)text -{ - return _customTextField.text; -} - -- (void)setText:(NSString *)text -{ - bool layout = _customTextField == nil; - self.customTextField.text = text; - if (layout) - [self setNeedsLayout]; - - [self textFieldDidChange:_customTextField]; -} - -- (void)segmentedControlChanged -{ - if (_showsCustomCancelButton) - { - id delegate = self.delegate; - if ([delegate respondsToSelector:@selector(searchBar:selectedScopeButtonIndexDidChange:)]) - [delegate searchBar:(UISearchBar *)self selectedScopeButtonIndexDidChange:_customSegmentedControl.selectedSegmentIndex]; - } -} - -- (void)updateClipping:(CGFloat)clippedHeight -{ - CGFloat offset = self.frame.size.height + MAX(0.0f, MIN(clippedHeight, self.frame.size.height)); - - CGRect frame = _wrappingClip.frame; - frame.origin.y = offset - frame.size.height + 20.0f; - _wrappingClip.frame = frame; - - CGRect wrapFrame = _wrappingView.frame; - wrapFrame.origin.y = -offset + wrapFrame.size.height; - _wrappingView.frame = wrapFrame; -} - -- (void)localizationUpdated -{ - _placeholderLabel.text = TGLocalized(@"Common.Search"); - - _cancelButtonWidth = [TGLocalized(@"Common.Cancel") sizeWithFont:TGSystemFontOfSize(17.0f)].width + 11.0f; - - CGRect textFieldBackgroundFrame = _textFieldBackground.frame; - _customCancelButton.frame = CGRectMake(textFieldBackgroundFrame.origin.x + textFieldBackgroundFrame.size.width + 10, _customCancelButton.frame.origin.y, _cancelButtonWidth, [self baseHeight]); - [_customCancelButton setTitle:TGLocalized(@"Common.Cancel") forState:UIControlStateNormal]; - - [_customSegmentedControl removeAllSegments]; - int index = -1; - for (NSString *itemText in _customScopeButtonTitles) - { - index++; - [_customSegmentedControl insertSegmentWithTitle:itemText atIndex:(NSUInteger)index animated:false]; - } - - [self setNeedsLayout]; -} - -- (void)setShowActivity:(bool)showActivity -{ - if (_showActivity != showActivity) - { - [_searchActivityTimer invalidate]; - _searchActivityTimer = nil; - - _showActivity = showActivity; - - if (_delayActivity && showActivity) - { - _searchActivityTimer = [TGTimerTarget scheduledMainThreadTimerWithTarget:self action:@selector(searchActivityTimerEvent) interval:0.2 repeat:false]; - } - else - [self searchActivityTimerEvent]; - } -} - -- (void)searchActivityTimerEvent -{ - _customSearchIcon.hidden = _showActivity; - UIActivityIndicatorView *indicator = _customSearchActivityIndicator; - if (_showActivity) - { - if (indicator == nil) - { - indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:4]; - if (_pallete != nil) - indicator.color = _pallete.placeholderColor; - indicator.userInteractionEnabled = false; - indicator.hidden = true; - [_wrappingView addSubview:indicator]; - - _customSearchActivityIndicator = indicator; - } - - indicator.hidden = false; - indicator.frame = (CGRect){{CGFloor(_customSearchIcon.frame.origin.x + (_customSearchIcon.frame.size.width - indicator.frame.size.width) / 2.0f), CGFloor(_customSearchIcon.frame.origin.y + (_customSearchIcon.frame.size.height - indicator.frame.size.height) / 2.0f) + 1.0f}, indicator.frame.size}; - [indicator startAnimating]; - } - else - { - indicator.hidden = true; - [indicator stopAnimating]; - } -} - -- (void)setPrefixText:(NSAttributedString *)prefixText { - _prefixText = prefixText; - _prefixLabel.attributedText = prefixText; - _customClearButton.hidden = !_placeholderLabel.hidden && _prefixText.length == 0; - - [self setNeedsLayout]; -} - -@end - - -@implementation TGSearchBarPallete - -+ (instancetype)palleteWithDark:(bool)dark backgroundColor:(UIColor *)backgroundColor highContrastBackgroundColor:(UIColor *)highContrastBackgroundColor textColor:(UIColor *)textColor placeholderColor:(UIColor *)placeholderColor clearIcon:(UIImage *)clearIcon barBackgroundColor:(UIColor *)barBackgroundColor barSeparatorColor:(UIColor *)barSeparatorColor plainBackgroundColor:(UIColor *)plainBackgroundColor accentColor:(UIColor *)accentColor accentContrastColor:(UIColor *)accentContrastColor menuBackgroundColor:(UIColor *)menuBackgroundColor segmentedControlBackgroundImage:(UIImage *)segmentedControlBackgroundImage segmentedControlSelectedImage:(UIImage *)segmentedControlSelectedImage segmentedControlHighlightedImage:(UIImage *)segmentedControlHighlightedImage segmentedControlDividerImage:(UIImage *)segmentedControlDividerImage -{ - TGSearchBarPallete *pallete = [[TGSearchBarPallete alloc] init]; - pallete->_isDark = dark; - pallete->_backgroundColor = backgroundColor; - pallete->_highContrastBackgroundColor = highContrastBackgroundColor; - pallete->_textColor = textColor; - pallete->_placeholderColor = placeholderColor; - pallete->_clearIcon = clearIcon; - pallete->_barBackgroundColor = barBackgroundColor; - pallete->_barSeparatorColor = barSeparatorColor; - pallete->_plainBackgroundColor = plainBackgroundColor; - pallete->_accentColor = accentColor; - pallete->_accentContrastColor = accentContrastColor; - pallete->_menuBackgroundColor = menuBackgroundColor; - pallete->_segmentedControlBackgroundImage = segmentedControlBackgroundImage; - pallete->_segmentedControlSelectedImage = segmentedControlSelectedImage; - pallete->_segmentedControlHighlightedImage = segmentedControlHighlightedImage; - pallete->_segmentedControlDividerImage = segmentedControlDividerImage; - return pallete; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGSearchDisplayMixin.m b/submodules/LegacyComponents/Sources/TGSearchDisplayMixin.m deleted file mode 100644 index 25da3a30ac..0000000000 --- a/submodules/LegacyComponents/Sources/TGSearchDisplayMixin.m +++ /dev/null @@ -1,457 +0,0 @@ -#import "TGSearchDisplayMixin.h" - -#import "LegacyComponentsInternal.h" -#import "TGColor.h" -#import "TGHacks.h" - -#import "TGSearchBar.h" - -#import - -@interface TGSearchDisplayMixin () - -@property (nonatomic) UIEdgeInsets controllerInset; - -@property (nonatomic, strong) UIView *dimView; - -@property (nonatomic, strong) UIView *tableViewContainer; - -@end - -@implementation TGSearchDisplayMixin - -- (instancetype)init -{ - self = [super init]; - if (self != nil) - { - - } - return self; -} - -- (void)dealloc -{ - [self unload]; -} - -- (void)unload -{ - [self _unloadTableView]; -} - -- (void)_unloadTableView -{ - [_searchResultsTableView removeFromSuperview]; - - _searchResultsTableView.delegate = nil; - _searchResultsTableView.dataSource = nil; - _searchResultsTableView = nil; -} - -- (void)setSearchBar:(UISearchBar *)searchBar -{ - if (_searchBar != nil) - _searchBar.delegate = nil; - - _searchBar = (TGSearchBar *)searchBar; - _searchBar.delegate = self; -} - -- (void)setIsActive:(bool)isActive -{ - [self setIsActive:isActive animated:true]; -} - -- (void)setIsActive:(bool)isActive animated:(bool)animated -{ - if (_isActive != isActive) - { - _isActive = isActive; - - if (isActive || !self.alwaysShowsCancelButton) - [_searchBar setShowsCancelButton:isActive animated:animated]; - - if (isActive) - { - id delegate = _delegate; - - UIView *referenceView = [delegate referenceViewForSearchResults]; - - [self setSearchResultsTableViewHidden:true]; - _searchResultsTableView.alpha = 1.0f; - - if (_dimView == nil) - { - _dimView = [[UIView alloc] init]; - _dimView.backgroundColor = UIColorRGBA(0x000000, 0.4f); - _dimView.alpha = 0.0f; - _dimView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - } - - if (_tableViewContainer == nil) - { - _tableViewContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; - _tableViewContainer.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - - UIView *tapView = [[UIView alloc] initWithFrame:_tableViewContainer.bounds]; - tapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - [tapView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dimViewTapped:)]]; - [_tableViewContainer addSubview:tapView]; - } - - CGRect dimViewFrame = referenceView.bounds; - - if ([referenceView isKindOfClass:[UIScrollView class]]) - { - UIScrollView *referenceScrollView = (UIScrollView *)referenceView; - dimViewFrame.origin.y = -referenceScrollView.contentOffset.y + _searchBar.frame.size.height; - } - else - { - if (_simpleLayout) { - dimViewFrame.origin.y = _controllerInset.top; - } else { - CGRect searchBarReferenceFrame = [_searchBar convertRect:_searchBar.bounds toView:referenceView.superview]; - dimViewFrame.origin.y = searchBarReferenceFrame.origin.y + searchBarReferenceFrame.size.height; - } - } - - [[referenceView superview] insertSubview:_tableViewContainer aboveSubview:referenceView]; - - [[referenceView superview] insertSubview:_dimView aboveSubview:referenceView]; - - _dimView.frame = dimViewFrame; - - _dimView.layer.frame = dimViewFrame; - - CGRect tableViewContainerFrame = referenceView.frame; - if (_simpleLayout) { - tableViewContainerFrame.origin.y = _controllerInset.top; - } else { - tableViewContainerFrame.origin.y = _controllerInset.top + _searchBar.frame.size.height; - } - _tableViewContainer.frame = tableViewContainerFrame; - - _tableViewContainer.layer.frame = _tableViewContainer.frame; - - if (animated) - { - [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^ - { - _dimView.alpha = 1.0f; - } completion:nil]; - } - else - { - _dimView.alpha = 1.0f; - } - - [self _updateSearchBarLayout:animated]; - - if ([delegate respondsToSelector:@selector(searchMixinWillActivate:)]) - [delegate searchMixinWillActivate:animated]; - } - else - { - [self _updateSearchBarLayout:animated]; - - [_searchBar resignFirstResponder]; - [_searchBar setText:@""]; - - if (animated) - { - id delegate = _delegate; - if ([delegate respondsToSelector:@selector(searchMixinWillDeactivate:)]) - [delegate searchMixinWillDeactivate:animated]; - - [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^ - { - _dimView.alpha = 0.0f; - _searchResultsTableView.alpha = 0.0f; - } completion:^(BOOL finished) - { - if (finished) - { - [_dimView removeFromSuperview]; - [_tableViewContainer removeFromSuperview]; - [_searchResultsTableView removeFromSuperview]; - - [self _unloadTableView]; - } - }]; - } - else - { - id delegate = _delegate; - if ([delegate respondsToSelector:@selector(searchMixinWillDeactivate:)]) - [delegate searchMixinWillDeactivate:animated]; - - _dimView.alpha = 0.0f; - - [_dimView removeFromSuperview]; - [_tableViewContainer removeFromSuperview]; - [_searchResultsTableView removeFromSuperview]; - - [self _unloadTableView]; - } - } - } -} - -- (void)_updateSearchBarLayout:(bool)animated -{ - CGFloat currentHeight = _searchBar.frame.size.height; - - if (((TGSearchBar *)_searchBar).customScopeButtonTitles.count > 1) - { - bool updateSize = false; - - updateSize = true; - - if (updateSize) - [_searchBar sizeToFit]; - } - - if (ABS(currentHeight - _searchBar.frame.size.height) > FLT_EPSILON) - { - if (animated) - { - [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^ - { - [self searchBar:(TGSearchBar *)_searchBar willChangeHeight:_searchBar.frame.size.height]; - [_searchBar layoutSubviews]; - } completion:^(BOOL finished) - { - if (finished) - { - } - }]; - } - else - { - [self searchBar:(TGSearchBar *)_searchBar willChangeHeight:_searchBar.frame.size.height]; - [_searchBar layoutSubviews]; - } - } -} - -- (void)controllerInsetUpdated:(UIEdgeInsets)controllerInset -{ - _controllerInset = controllerInset; - - [self controllerLayoutUpdated:CGSizeZero]; -} - -- (void)controllerLayoutUpdated:(CGSize)__unused layoutSize -{ - [self _updateSearchBarLayout:false]; - - if (_dimView != nil && _dimView.superview != nil) - { - CGRect frame = _dimView.superview.bounds; - if (_simpleLayout) { - frame.origin.y = _controllerInset.top; - } else { - frame.origin.y = _controllerInset.top + _searchBar.frame.size.height; - } - _dimView.frame = frame; - } - - if (_tableViewContainer != nil && _tableViewContainer.superview != nil) - { - CGRect tableViewContainerFrame = _tableViewContainer.frame; - if (_simpleLayout) { - tableViewContainerFrame.origin.y = _controllerInset.top; - } else { - tableViewContainerFrame.origin.y = _controllerInset.top + _searchBar.frame.size.height; - } - _tableViewContainer.frame = tableViewContainerFrame; - } - - if (_searchResultsTableView != nil && _searchResultsTableView.superview != nil) - { - UIEdgeInsets tableInset = _controllerInset; - tableInset.bottom += tableInset.top + _searchBar.frame.size.height; - tableInset.top = 0; - _searchResultsTableView.contentInset = tableInset; - _searchResultsTableView.scrollIndicatorInsets = tableInset; - } - - if (_searchBar.showsScopeBar) - { - CATransition *transition = [CATransition animation]; - transition.duration = 0.2 * TGAnimationSpeedFactor(); - transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; - [_searchBar.layer addAnimation:transition forKey:@"content"]; - } -} - -- (void)searchBar:(TGSearchBar *)searchBar willChangeHeight:(CGFloat)newHeight -{ - if (searchBar == _searchBar) - { - id delegate = _delegate; - UIView *referenceView = [delegate referenceViewForSearchResults]; - - if ([referenceView isKindOfClass:[UITableView class]]) - { - static NSInvocation *invocation = nil; - - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^ - { - SEL selector = NSSelectorFromString(TGEncodeText(@"`ubcmfIfbefsIfjhiuEjeDibohfUpIfjhiu;", -1)); - - NSMethodSignature *signature = [[UITableView class] instanceMethodSignatureForSelector:selector]; - if (signature == nil) - { - TGLegacyLog(@"***** Method not found"); - } - else - { - invocation = [NSInvocation invocationWithMethodSignature:signature]; - [invocation setSelector:selector]; - } - }); - - if (invocation != nil) - { - [invocation setTarget:referenceView]; - CGFloat height = newHeight; - [invocation setArgument:&height atIndex:2]; - [invocation invoke]; - - [invocation setTarget:nil]; - } - } - } -} - -- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar -{ - if (searchBar == (UISearchBar *)_searchBar) - { - [self setIsActive:true animated:true]; - } -} - -- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText -{ - if (searchBar == (UISearchBar *)_searchBar) - { - id delegate = _delegate; - if ([delegate respondsToSelector:@selector(searchMixin:hasChangedSearchQuery:withScope:)]) - { - [delegate searchMixin:self hasChangedSearchQuery:searchText withScope:(int)_searchBar.selectedScopeButtonIndex]; - } - - //if (searchText.length == 0) - // [self setSearchResultsTableViewHidden:false]; - } -} - -- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar -{ - if (searchBar == (UISearchBar *)_searchBar) - { - [self setIsActive:false animated:true]; - } -} - -- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar -{ - if (searchBar == (UISearchBar *)_searchBar) - { - [_searchBar resignFirstResponder]; - } -} - -- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope -{ - if (searchBar == (UISearchBar *)_searchBar) - { - id delegate = _delegate; - if ([delegate respondsToSelector:@selector(searchMixin:hasChangedSearchQuery:withScope:)]) - [delegate searchMixin:self hasChangedSearchQuery:_searchBar.text withScope:(int)selectedScope]; - } -} - -- (void)dimViewTapped:(UITapGestureRecognizer *)recognizer -{ - if (recognizer.state == UIGestureRecognizerStateRecognized) - { - if (_searchResultsTableView == nil || _searchResultsTableView.hidden) - [self setIsActive:false animated:true]; - } -} - -#pragma mark - - -- (bool)searchResultsTableViewHidden -{ - return _searchResultsTableView == nil || _searchResultsTableView.hidden; -} - -- (void)setSearchResultsTableViewHidden:(bool)searchResultsTableViewHidden -{ - [self setSearchResultsTableViewHidden:searchResultsTableViewHidden animated:false]; -} - -- (void)setSearchResultsTableViewHidden:(bool)searchResultsTableViewHidden animated:(bool)animated -{ - bool wasHidden = _searchResultsTableView.hidden; - - _searchResultsTableView.hidden = searchResultsTableViewHidden; - _dimView.hidden = !searchResultsTableViewHidden; - - if (animated && wasHidden && !searchResultsTableViewHidden) - { - _searchResultsTableView.alpha = 0.0f; - [UIView animateWithDuration:0.25 animations:^ - { - _searchResultsTableView.alpha = 1.0f; - }]; - } -} - -- (void)reloadSearchResults -{ - if (_searchResultsTableView == nil) - { - id delegate = _delegate; - - _searchResultsTableView = [delegate createTableViewForSearchMixin:self]; - _searchResultsTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpartial-availability" - if (iosMajorVersion() >= 11) - _searchResultsTableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; -#pragma clang diagnostic pop - - [self setSearchResultsTableViewHidden:true]; - } - - if (_searchResultsTableView.superview == nil) - { - _searchResultsTableView.frame = _tableViewContainer.bounds; - - UIEdgeInsets tableInset = _controllerInset; - tableInset.bottom += tableInset.top + _searchBar.frame.size.height; - tableInset.top = 0; - _searchResultsTableView.contentInset = tableInset; - _searchResultsTableView.scrollIndicatorInsets = tableInset; - - [_tableViewContainer addSubview:_searchResultsTableView]; - } - - [_searchResultsTableView reloadData]; -} - -- (void)resignResponderIfAny -{ - [_searchBar resignFirstResponder]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGViewController.mm b/submodules/LegacyComponents/Sources/TGViewController.mm index bf00939383..d8dd2aad62 100644 --- a/submodules/LegacyComponents/Sources/TGViewController.mm +++ b/submodules/LegacyComponents/Sources/TGViewController.mm @@ -1026,7 +1026,7 @@ static id _defaultContext = nil; - (CGFloat)navigationBarHeightForInterfaceOrientation:(UIInterfaceOrientation)orientation { - static CGFloat portraitHeight = 44.0f; + static CGFloat portraitHeight = 56.0f; static CGFloat landscapeHeight = 32.0f; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^ @@ -1035,13 +1035,13 @@ static id _defaultContext = nil; CGFloat widescreenWidth = MAX(screenSize.width, screenSize.height); if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && ABS(widescreenWidth - 736) > FLT_EPSILON) { - portraitHeight = 44.0f; - landscapeHeight = 32.0f; + portraitHeight = 56.0f; + landscapeHeight = 56.0f; } else { - portraitHeight = 44.0f; - landscapeHeight = 44.0f; + portraitHeight = 56.0f; + landscapeHeight = 56.0f; } }); bool large = UIInterfaceOrientationIsPortrait(orientation) || self.alwaysUseTallNavigationBarHeight; @@ -1072,7 +1072,7 @@ static id _defaultContext = nil; + (UIEdgeInsets)safeAreaInsetForOrientation:(UIInterfaceOrientation)orientation hasOnScreenNavigation:(bool)hasOnScreenNavigation { int height = (int)TGScreenSize().height; - if (!TGIsPad() && (height != 812 && height != 896)) + if (!TGIsPad() && (height != 812 && height != 896 && height != 780 && height != 844 && height != 926)) return UIEdgeInsetsZero; if (TGIsPad()) { diff --git a/submodules/LegacyComponents/Sources/UIDevice+PlatformInfo.m b/submodules/LegacyComponents/Sources/UIDevice+PlatformInfo.m deleted file mode 100644 index ad7639756d..0000000000 --- a/submodules/LegacyComponents/Sources/UIDevice+PlatformInfo.m +++ /dev/null @@ -1,216 +0,0 @@ -#import "UIDevice+PlatformInfo.h" - -#include // Per msqr -#include -#include -#include - -@implementation UIDevice (PlatformInfo) - -/* - Platforms - - iFPGA -> ?? - - iPhone1,1 -> iPhone 1G, M68 - iPhone1,2 -> iPhone 3G, N82 - iPhone2,1 -> iPhone 3GS, N88 - iPhone3,1 -> iPhone 4/AT&T, N89 - iPhone3,2 -> iPhone 4/Other Carrier?, ?? - iPhone3,3 -> iPhone 4/Verizon, TBD - iPhone4,1 -> (iPhone 4S/GSM), TBD - iPhone4,2 -> (iPhone 4S/CDMA), TBD - iPhone4,3 -> (iPhone 4S/???) - iPhone5,1 -> iPhone Next Gen, TBD - iPhone5,1 -> iPhone Next Gen, TBD - iPhone5,1 -> iPhone Next Gen, TBD - - iPod1,1 -> iPod touch 1G, N45 - iPod2,1 -> iPod touch 2G, N72 - iPod2,2 -> Unknown, ?? - iPod3,1 -> iPod touch 3G, N18 - iPod4,1 -> iPod touch 4G, N80 - - // Thanks NSForge - iPad1,1 -> iPad 1G, WiFi and 3G, K48 - iPad2,1 -> iPad 2G, WiFi, K93 - iPad2,2 -> iPad 2G, GSM 3G, K94 - iPad2,3 -> iPad 2G, CDMA 3G, K95 - iPad3,1 -> (iPad 3G, WiFi) - iPad3,2 -> (iPad 3G, GSM) - iPad3,3 -> (iPad 3G, CDMA) - iPad4,1 -> (iPad 4G, WiFi) - iPad4,2 -> (iPad 4G, GSM) - iPad4,3 -> (iPad 4G, CDMA) - - AppleTV2,1 -> AppleTV 2, K66 - AppleTV3,1 -> AppleTV 3, ?? - - i386, x86_64 -> iPhone Simulator - */ - - -#pragma mark sysctlbyname utils -- (NSString *) getSysInfoByName:(char *)typeSpecifier -{ - size_t size; - sysctlbyname(typeSpecifier, NULL, &size, NULL, 0); - - char *answer = malloc(size); - sysctlbyname(typeSpecifier, answer, &size, NULL, 0); - - NSString *results = [NSString stringWithCString:answer encoding: NSUTF8StringEncoding]; - - free(answer); - return results; -} - -- (NSString *) platform -{ - return [self getSysInfoByName:"hw.machine"]; -} - -#pragma mark sysctl utils -- (NSUInteger) getSysInfo: (uint) typeSpecifier -{ - size_t size = sizeof(int); - int results; - int mib[2] = {CTL_HW, typeSpecifier}; - sysctl(mib, 2, &results, &size, NULL, 0); - return (NSUInteger) results; -} - -#pragma mark platform type and name utils -- (NSUInteger) platformType -{ - NSString *platform = [self platform]; - - // The ever mysterious iFPGA - if ([platform isEqualToString:@"iFPGA"]) return UIDeviceIFPGA; - - // iPhone - if ([platform isEqualToString:@"iPhone1,1"]) return UIDevice1GiPhone; - if ([platform isEqualToString:@"iPhone1,2"]) return UIDevice3GiPhone; - if ([platform hasPrefix:@"iPhone2"]) return UIDevice3GSiPhone; - if ([platform hasPrefix:@"iPhone3"]) return UIDevice4iPhone; - if ([platform hasPrefix:@"iPhone4"]) return UIDevice4SiPhone; - if ([platform hasPrefix:@"iPhone5"]) return UIDevice5iPhone; - if ([platform hasPrefix:@"iPhone6"]) return UIDevice5SiPhone; - - if ([platform isEqualToString:@"iPhone7,1"]) return UIDevice6PlusiPhone; - if ([platform isEqualToString:@"iPhone7,2"]) return UIDevice6iPhone; - if ([platform isEqualToString:@"iPhone8,1"]) return UIDevice6siPhone; - if ([platform isEqualToString:@"iPhone8,2"]) return UIDevice6SPlusiPhone; - - if ([platform isEqualToString:@"iPhone9,2"]) return UIDevice7PlusiPhone; - if ([platform isEqualToString:@"iPhone9,1"]) return UIDevice7iPhone; - if ([platform isEqualToString:@"iPhone9,3"]) return UIDevice7iPhone; - if ([platform isEqualToString:@"iPhone9,4"]) return UIDevice7PlusiPhone; - - if ([platform isEqualToString:@"iPhone8,4"]) return UIDeviceSEPhone; - - // iPod - if ([platform hasPrefix:@"iPod1"]) return UIDevice1GiPod; - if ([platform hasPrefix:@"iPod2"]) return UIDevice2GiPod; - if ([platform hasPrefix:@"iPod3"]) return UIDevice3GiPod; - if ([platform hasPrefix:@"iPod4"]) return UIDevice4GiPod; - if ([platform hasPrefix:@"iPod5"]) return UIDevice5GiPod; - if ([platform hasPrefix:@"iPod7"]) return UIDevice6GiPod; - - // iPad - if ([platform hasPrefix:@"iPad1"]) return UIDevice1GiPad; - if ([platform hasPrefix:@"iPad2"]) return UIDevice2GiPad; - if ([platform hasPrefix:@"iPad3"]) return UIDevice3GiPad; - if ([platform hasPrefix:@"iPad4"]) return UIDevice4GiPad; - if ([platform hasPrefix:@"iPad5"]) return UIDevice5GiPad; - if ([platform hasPrefix:@"iPad6"]) return UIDevice6GiPad; - - // Apple TV - if ([platform hasPrefix:@"AppleTV2"]) return UIDeviceAppleTV2; - if ([platform hasPrefix:@"AppleTV3"]) return UIDeviceAppleTV3; - - if ([platform hasPrefix:@"iPhone"]) return UIDeviceUnknowniPhone; - if ([platform hasPrefix:@"iPod"]) return UIDeviceUnknowniPod; - if ([platform hasPrefix:@"iPad"]) return UIDeviceUnknowniPad; - if ([platform hasPrefix:@"AppleTV"]) return UIDeviceUnknownAppleTV; - - // Simulator thanks Jordan Breeding - if ([platform hasSuffix:@"86"] || [platform isEqual:@"x86_64"]) - { - BOOL smallerScreen = [[UIScreen mainScreen] bounds].size.width < 768; - return smallerScreen ? UIDeviceSimulatoriPhone : UIDeviceSimulatoriPad; - } - - return UIDeviceUnknown; -} - -- (NSString *) platformString -{ - switch ([self platformType]) - { - case UIDevice1GiPhone: return IPHONE_1G_NAMESTRING; - case UIDevice3GiPhone: return IPHONE_3G_NAMESTRING; - case UIDevice3GSiPhone: return IPHONE_3GS_NAMESTRING; - case UIDevice4iPhone: return IPHONE_4_NAMESTRING; - case UIDevice4SiPhone: return IPHONE_4S_NAMESTRING; - case UIDevice5iPhone: return IPHONE_5_NAMESTRING; - case UIDevice5SiPhone: return IPHONE_5S_NAMESTRING; - case UIDevice6iPhone: return IPHONE_6_NAMESTRING; - case UIDevice6PlusiPhone: return IPHONE_6Plus_NAMESTRING; - case UIDevice6siPhone: return IPHONE_6S_NAMESTRING; - case UIDevice6SPlusiPhone: return IPHONE_6SPlus_NAMESTRING; - case UIDevice7iPhone: return IPHONE_7_NAMESTRING; - case UIDeviceSEPhone: return IPHONE_SE_NAMESTRING; - case UIDevice7PlusiPhone: return IPHONE_7Plus_NAMESTRING; - - case UIDeviceUnknowniPhone: return IPHONE_UNKNOWN_NAMESTRING; - - case UIDevice1GiPod: return IPOD_1G_NAMESTRING; - case UIDevice2GiPod: return IPOD_2G_NAMESTRING; - case UIDevice3GiPod: return IPOD_3G_NAMESTRING; - case UIDevice4GiPod: return IPOD_4G_NAMESTRING; - case UIDevice5GiPod: return IPOD_5G_NAMESTRING; - case UIDevice6GiPod: return IPOD_6G_NAMESTRING; - case UIDeviceUnknowniPod: return IPOD_UNKNOWN_NAMESTRING; - - case UIDevice1GiPad : return IPAD_1G_NAMESTRING; - case UIDevice2GiPad : return IPAD_2G_NAMESTRING; - case UIDevice3GiPad : return IPAD_3G_NAMESTRING; - case UIDevice4GiPad : return IPAD_4G_NAMESTRING; - case UIDevice5GiPad : return IPAD_5G_NAMESTRING; - case UIDevice6GiPad : return IPAD_6G_NAMESTRING; - case UIDeviceUnknowniPad : return IPAD_UNKNOWN_NAMESTRING; - - case UIDeviceAppleTV2 : return APPLETV_2G_NAMESTRING; - case UIDeviceAppleTV3 : return APPLETV_3G_NAMESTRING; - case UIDeviceAppleTV4 : return APPLETV_4G_NAMESTRING; - case UIDeviceUnknownAppleTV: return APPLETV_UNKNOWN_NAMESTRING; - - case UIDeviceSimulator: return SIMULATOR_NAMESTRING; - case UIDeviceSimulatoriPhone: return SIMULATOR_IPHONE_NAMESTRING; - case UIDeviceSimulatoriPad: return SIMULATOR_IPAD_NAMESTRING; - case UIDeviceSimulatorAppleTV: return SIMULATOR_APPLETV_NAMESTRING; - - case UIDeviceIFPGA: return IFPGA_NAMESTRING; - - default: return IOS_FAMILY_UNKNOWN_DEVICE; - } -} - -- (BOOL) hasRetinaDisplay -{ - return ([UIScreen mainScreen].scale == 2.0f); -} - -- (UIDeviceFamily) deviceFamily -{ - NSString *platform = [self platform]; - if ([platform hasPrefix:@"iPhone"]) return UIDeviceFamilyiPhone; - if ([platform hasPrefix:@"iPod"]) return UIDeviceFamilyiPod; - if ([platform hasPrefix:@"iPad"]) return UIDeviceFamilyiPad; - if ([platform hasPrefix:@"AppleTV"]) return UIDeviceFamilyAppleTV; - - return UIDeviceFamilyUnknown; -} - -@end diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift index 12c55fbd7e..67603bbb04 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift @@ -59,6 +59,60 @@ public enum LegacyAttachmentMenuMediaEditing { case file } +public func legacyMediaEditor(context: AccountContext, peer: Peer, media: AnyMediaReference, initialCaption: String, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, present: @escaping (ViewController, Any?) -> Void) { + let _ = (fetchMediaData(context: context, postbox: context.account.postbox, mediaReference: media) + |> deliverOnMainQueue).start(next: { (value, isImage) in + guard case let .data(data) = value, data.complete else { + return + } + + let item: TGMediaEditableItem & TGMediaSelectableItem + if let image = UIImage(contentsOfFile: data.path) { + item = TGCameraCapturedPhoto(existing: image) + } else { + item = TGCameraCapturedVideo(url: URL(fileURLWithPath: data.path)) + } + + let paintStickersContext = LegacyPaintStickersContext(context: context) + paintStickersContext.presentStickersController = { completion in + return presentStickers({ file, animated, view, rect in + let coder = PostboxEncoder() + coder.encodeRootObject(file) + completion?(coder.makeData(), animated, view, rect) + }) + } + + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + let recipientName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + + let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme, initialLayout: nil) + legacyController.blocksBackgroundWhenInOverlay = true + legacyController.acceptsFocusWhenInOverlay = true + legacyController.statusBar.statusBarStyle = .Ignore + legacyController.controllerLoaded = { [weak legacyController] in + legacyController?.view.disablesInteractiveTransitionGestureRecognizer = true + } + + let emptyController = LegacyEmptyController(context: legacyController.context)! + emptyController.navigationBarShouldBeHidden = true + let navigationController = makeLegacyNavigationController(rootController: emptyController) + navigationController.setNavigationBarHidden(true, animated: false) + legacyController.bind(controller: navigationController) + + legacyController.enableSizeClassSignal = true + + present(legacyController, nil) + + TGPhotoVideoEditor.present(with: legacyController.context, controller: emptyController, caption: initialCaption, entities: [], withItem: item, paint: true, recipientName: recipientName, stickersContext: paintStickersContext, completion: { result, editingContext in + let intent: TGMediaAssetsControllerIntent = TGMediaAssetsControllerSendMediaIntent + let signals = TGCameraController.resultSignals(for: nil, editingContext: editingContext, currentItem: result as! TGMediaSelectableItem, storeAssets: false, saveEditedPhotos: false, descriptionGenerator: legacyAssetPickerItemGenerator()) + sendMessagesWithSignals(signals, false, 0) + }, dismissed: { [weak legacyController] in + legacyController?.dismiss() + }) + }) +} + public func legacyAttachmentMenu(context: AccountContext, peer: Peer, chatLocation: ChatLocation, editMediaOptions: LegacyAttachmentMenuMediaEditing?, saveEditedPhotos: Bool, allowGrouping: Bool, hasSchedule: Bool, canSendPolls: Bool, presentationData: PresentationData, parentController: LegacyController, recentlyUsedInlineBots: [Peer], initialCaption: String, openGallery: @escaping () -> Void, openCamera: @escaping (TGAttachmentCameraView?, TGMenuSheetController?) -> Void, openFileGallery: @escaping () -> Void, openWebSearch: @escaping () -> Void, openMap: @escaping () -> Void, openContacts: @escaping () -> Void, openPoll: @escaping () -> Void, presentSelectionLimitExceeded: @escaping () -> Void, presentCantSendMultipleFiles: @escaping () -> Void, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, selectRecentlyUsedInlineBot: @escaping (Peer) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, present: @escaping (ViewController, Any?) -> Void) -> TGMenuSheetController { let defaultVideoPreset = defaultVideoPresetForContext(context) UserDefaults.standard.set(defaultVideoPreset.rawValue as NSNumber, forKey: "TG_preferredVideoPreset_v0") @@ -261,45 +315,14 @@ public func legacyAttachmentMenu(context: AccountContext, peer: Peer, chatLocati present(legacyController, nil) - TGPhotoVideoEditor.present(with: legacyController.context, controller: emptyController, caption: "", entities: [], withItem: item, recipientName: recipientName, stickersContext: paintStickersContext, completion: { result, editingContext in + TGPhotoVideoEditor.present(with: legacyController.context, controller: emptyController, caption: "", entities: [], withItem: item, paint: false, recipientName: recipientName, stickersContext: paintStickersContext, completion: { result, editingContext in let intent: TGMediaAssetsControllerIntent = TGMediaAssetsControllerSendMediaIntent let signals = TGCameraController.resultSignals(for: nil, editingContext: editingContext, currentItem: result as! TGMediaSelectableItem, storeAssets: false, saveEditedPhotos: false, descriptionGenerator: legacyAssetPickerItemGenerator()) sendMessagesWithSignals(signals, false, 0) - /* - [TGCameraController resultSignalsForSelectionContext:nil editingContext:editingContext currentItem:result storeAssets:false saveEditedPhotos:false descriptionGenerator:^id(id result, NSString *caption, NSArray *entities, NSString *hash) - { - __strong TGModernConversationController *strongSelf = weakSelf; - if (strongSelf == nil) - return nil; - - NSDictionary *desc = [strongSelf _descriptionForItem:result caption:caption entities:entities hash:hash allowRemoteCache:allowRemoteCache]; - return [strongSelf _descriptionForReplacingMedia:desc message:message]; - }]] - */ - //let signals = TGMediaAssetsController.resultSignals(for: nil, editingContext: editingContext, intent: intent, currentItem: result, storeAssets: true, useMediaCache: false, descriptionGenerator: legacyAssetPickerItemGenerator(), saveEditedPhotos: saveEditedPhotos) - //sendMessagesWithSignals(signals, silentPosting, scheduleTime) }, dismissed: { [weak legacyController] in legacyController?.dismiss() }) }) - /* - - - bool allowRemoteCache = [strongSelf->_companion controllerShouldCacheServerAssets]; - [TGPhotoVideoEditor presentWithContext:[TGLegacyComponentsContext shared] controller:strongSelf caption:text entities:entities withItem:item recipientName:[strongSelf->_companion title] completion:^(id result, TGMediaEditingContext *editingContext) - { - [strongSelf _asyncProcessMediaAssetSignals:[TGCameraController resultSignalsForSelectionContext:nil editingContext:editingContext currentItem:result storeAssets:false saveEditedPhotos:false descriptionGenerator:^id(id result, NSString *caption, NSArray *entities, NSString *hash) - { - __strong TGModernConversationController *strongSelf = weakSelf; - if (strongSelf == nil) - return nil; - - NSDictionary *desc = [strongSelf _descriptionForItem:result caption:caption entities:entities hash:hash allowRemoteCache:allowRemoteCache]; - return [strongSelf _descriptionForReplacingMedia:desc message:message]; - }]]; - [strongSelf endMessageEditing:true]; - }]; - */ })! itemViews.append(editCurrentItem) } diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyAvatarPicker.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyAvatarPicker.swift index a508bc1035..dc7ffe7c9d 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyAvatarPicker.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyAvatarPicker.swift @@ -6,32 +6,6 @@ import LegacyComponents import TelegramPresentationData import LegacyUI -public func presentLegacyAvatarEditor(theme: PresentationTheme, image: UIImage?, video: URL?, present: (ViewController, Any?) -> Void, imageCompletion: @escaping (UIImage) -> Void, videoCompletion: @escaping (UIImage, URL, TGVideoEditAdjustments?) -> Void) { - let legacyController = LegacyController(presentation: .custom, theme: theme) - legacyController.statusBar.statusBarStyle = .Ignore - - let emptyController = LegacyEmptyController(context: legacyController.context)! - let navigationController = makeLegacyNavigationController(rootController: emptyController) - navigationController.setNavigationBarHidden(true, animated: false) - navigationController.navigationBar.transform = CGAffineTransform(translationX: -1000.0, y: 0.0) - - legacyController.bind(controller: navigationController) - - present(legacyController, nil) - - TGPhotoVideoEditor.present(with: legacyController.context, parentController: emptyController, image: image, video: video, didFinishWithImage: { image in - if let image = image { - imageCompletion(image) - } - }, didFinishWithVideo: { image, asset, adjustments in - if let image = image { -// videoCompletion(image, url, adjustments) - } - }, dismissed: { [weak legacyController] in - legacyController?.dismiss() - }) -} - public func presentLegacyAvatarPicker(holder: Atomic, signup: Bool, theme: PresentationTheme, present: (ViewController, Any?) -> Void, openCurrent: (() -> Void)?, completion: @escaping (UIImage) -> Void, videoCompletion: @escaping (UIImage, Any?, TGVideoEditAdjustments?) -> Void = { _, _, _ in}) { let legacyController = LegacyController(presentation: .custom, theme: theme) legacyController.statusBar.statusBarStyle = .Ignore diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacySuggestionContext.swift b/submodules/LegacyMediaPickerUI/Sources/LegacySuggestionContext.swift index ab405bf084..53258c65b3 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacySuggestionContext.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacySuggestionContext.swift @@ -17,8 +17,8 @@ public func legacySuggestionContext(context: AccountContext, peerId: PeerId, cha let disposable = searchPeerMembers(context: context, peerId: peerId, chatLocation: chatLocation, query: query, scope: .mention).start(next: { peers in let users = NSMutableArray() for peer in peers { - let user = TGUser() if let peer = peer as? TelegramUser { + let user = TGUser() user.uid = peer.id.id user.firstName = peer.firstName user.lastName = peer.lastName diff --git a/submodules/LegacyUI/Sources/LegacyComponentsStickers.swift b/submodules/LegacyUI/Sources/LegacyComponentsStickers.swift deleted file mode 100644 index ddcdbe4018..0000000000 --- a/submodules/LegacyUI/Sources/LegacyComponentsStickers.swift +++ /dev/null @@ -1,221 +0,0 @@ -import Foundation -import UIKit -import LegacyComponents -import Postbox -import TelegramCore -import SyncCore -import SwiftSignalKit -import Display -import StickerResources - -public func stickerFromLegacyDocument(_ documentAttachment: TGDocumentMediaAttachment) -> TelegramMediaFile? { - if documentAttachment.isSticker() { - for case let sticker as TGDocumentAttributeSticker in documentAttachment.attributes { - var attributes: [TelegramMediaFileAttribute] = [] - var packReference: StickerPackReference? - if let legacyPackReference = sticker.packReference as? TGStickerPackIdReference { - packReference = .id(id: legacyPackReference.packId, accessHash: legacyPackReference.packAccessHash) - } else if let legacyPackReference = sticker.packReference as? TGStickerPackShortnameReference { - packReference = .name(legacyPackReference.shortName) - } - attributes.append(.Sticker(displayText: sticker.alt, packReference: packReference, maskData: nil)) - - var fileReference: Data? - if let originInfo = documentAttachment.originInfo, let data = originInfo.fileReference { - fileReference = data - } - - return TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudFile, id: documentAttachment.documentId), partialReference: nil, resource: CloudDocumentMediaResource(datacenterId: Int(documentAttachment.datacenterId), fileId: documentAttachment.documentId, accessHash: documentAttachment.accessHash, size: Int(documentAttachment.size), fileReference: fileReference, fileName: documentAttachment.fileName()), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: documentAttachment.mimeType, size: Int(documentAttachment.size), attributes: attributes) - } - } - return nil -} - -func legacyComponentsStickers(postbox: Postbox, namespace: Int32) -> SSignal { - return SSignal { subscriber in - let disposable = (postbox.itemCollectionsView(orderedItemListCollectionIds: [], namespaces: [namespace], aroundIndex: nil, count: 200 * 200)).start(next: { view in - var stickerPackDocuments: [ItemCollectionId: [Any]] = [:] - - for entry in view.entries { - if let item = entry.item as? StickerPackItem { - if item.file.isAnimatedSticker { - continue - } - let document = TGDocumentMediaAttachment() - document.documentId = item.file.fileId.id - if let resource = item.file.resource as? CloudDocumentMediaResource { - document.accessHash = resource.accessHash - document.datacenterId = Int32(resource.datacenterId) - var stickerPackId: Int64 = 0 - var accessHash: Int64 = 0 - for case let .Sticker(sticker) in item.file.attributes { - if let packReference = sticker.packReference, case let .id(id, h) = packReference { - stickerPackId = id - accessHash = h - } - break - } - document.originInfo = TGMediaOriginInfo(fileReference: resource.fileReference ?? Data(), fileReferences: [:], stickerPackId: stickerPackId, accessHash: accessHash) - } - document.mimeType = item.file.mimeType - if let size = item.file.size { - document.size = Int32(size) - } - if let thumbnail = item.file.previewRepresentations.first { - let imageInfo = TGImageInfo() - let encoder = PostboxEncoder() - encoder.encodeRootObject(thumbnail.resource) - let dataString = encoder.makeData().base64EncodedString(options: []) - imageInfo.addImage(with: thumbnail.dimensions.cgSize, url: dataString) - document.thumbnailInfo = imageInfo - } - var attributes: [Any] = [] - for attribute in item.file.attributes { - switch attribute { - case let .Sticker(displayText, _, maskData): - attributes.append(TGDocumentAttributeSticker(alt: displayText, packReference: nil, mask: maskData.flatMap { - return TGStickerMaskDescription(n: $0.n, point: CGPoint(x: CGFloat($0.x), y: CGFloat($0.y)), zoom: CGFloat($0.zoom)) - })) - case let .ImageSize(size): - attributes.append(TGDocumentAttributeImageSize(size: size.cgSize)) - default: - break - } - } - document.attributes = attributes - if stickerPackDocuments[entry.index.collectionId] == nil { - stickerPackDocuments[entry.index.collectionId] = [] - } - stickerPackDocuments[entry.index.collectionId]!.append(document) - } - } - - let stickerPacks = NSMutableArray() - for (id, info, _) in view.collectionInfos { - if let info = info as? StickerPackCollectionInfo, !info.flags.contains(.isAnimated) { - let pack = TGStickerPack(packReference: TGStickerPackIdReference(), title: info.title, stickerAssociations: [], documents: stickerPackDocuments[id] ?? [], packHash: info.hash, hidden: false, isMask: true, isFeatured: false, installedDate: 0)! - stickerPacks.add(pack) - } - } - - var dict: [AnyHashable: Any] = [:] - dict["packs"] = stickerPacks - subscriber?.putNext(dict) - }) - - return SBlockDisposable { - disposable.dispose() - } - } -} - -private final class LegacyStickerImageDataTask: NSObject { - private let disposable = DisposableSet() - - init(account: Account, file: TelegramMediaFile, small: Bool, fitSize: CGSize, completion: @escaping (UIImage?) -> Void) { - super.init() - - self.disposable.add(chatMessageLegacySticker(account: account, file: file, small: small, fitSize: fitSize, fetched: true, onlyFullSize: true).start(next: { generator in - if let image = generator(TransformImageArguments(corners: ImageCorners(), imageSize: fitSize, boundingSize: fitSize, intrinsicInsets: UIEdgeInsets()))?.generateImage() { - completion(image) - } - })) - } - - deinit { - self.disposable.dispose() - } - - func cancel() { - self.disposable.dispose() - } -} - -private let sharedImageCache = TGMemoryImageCache(softMemoryLimit: 2 * 1024 * 1024, hardMemoryLimit: 3 * 1024 * 1024)! - -final class LegacyStickerImageDataSource: TGImageDataSource { - private let account: () -> Account? - - init(account: @escaping () -> Account?) { - self.account = account - - super.init() - } - - override func canHandleUri(_ uri: String!) -> Bool { - if let uri = uri { - if uri.hasPrefix("sticker-preview://") { - return true - } else if uri.hasPrefix("sticker://") { - return true - } - } - return false - } - - override func loadDataSync(withUri uri: String!, canWait: Bool, acceptPartialData: Bool, asyncTaskId: AutoreleasingUnsafeMutablePointer!, progress: ((Float) -> Void)!, partialCompletion: ((TGDataResource?) -> Void)!, completion: ((TGDataResource?) -> Void)!) -> TGDataResource! { - if let image = sharedImageCache.image(forKey: uri, attributes: nil) { - return TGDataResource(image: image, decoded: true) - } - return nil - } - - override func loadDataAsync(withUri uri: String!, progress: ((Float) -> Void)!, partialCompletion: ((TGDataResource?) -> Void)!, completion: ((TGDataResource?) -> Void)!) -> Any! { - if let account = self.account() { - let args: [AnyHashable : Any] - var highQuality: Bool - if uri.hasPrefix("sticker-preview://") { - let argumentsString = String(uri[uri.index(uri.startIndex, offsetBy: "sticker-preview://?".count)...]) - args = TGStringUtils.argumentDictionary(inUrlString: argumentsString)! - highQuality = Int((args["highQuality"] as! String))! != 0 - } else if uri.hasPrefix("sticker://") { - let argumentsString = String(uri[uri.index(uri.startIndex, offsetBy: "sticker://?".count)...]) - args = TGStringUtils.argumentDictionary(inUrlString: argumentsString)! - highQuality = true - } else { - return nil - } - - let documentId = Int64((args["documentId"] as! String))! - let datacenterId = Int((args["datacenterId"] as! String))! - let accessHash = Int64((args["accessHash"] as! String))! - let size: Int? = nil - - let width = Int((args["width"] as! String))! - let height = Int((args["height"] as! String))! - - if width < 128 { - highQuality = false - } - - let fitSize = CGSize(width: CGFloat(width), height: CGFloat(height)) - - var attributes: [TelegramMediaFileAttribute] = [] - if let originInfoString = args["origin_info"] as? String, let originInfo = TGMediaOriginInfo(stringRepresentation: originInfoString), let stickerPackId = originInfo.stickerPackId?.int64Value, let stickerPackAccessHash = originInfo.stickerPackAccessHash?.int64Value { - attributes.append(.Sticker(displayText: "", packReference: .id(id: stickerPackId, accessHash: stickerPackAccessHash), maskData: nil)) - } - - var previewRepresentations: [TelegramMediaImageRepresentation] = [] - if let legacyThumbnailUri = args["legacyThumbnailUri"] as? String, let data = Data(base64Encoded: legacyThumbnailUri, options: []) { - if let resource = PostboxDecoder(buffer: MemoryBuffer(data: data)).decodeRootObject() as? TelegramMediaResource { - previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 140, height: 140), resource: resource, progressiveSizes: [])) - } - } - - return LegacyStickerImageDataTask(account: account, file: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.CloudFile, id: documentId), partialReference: nil, resource: CloudDocumentMediaResource(datacenterId: datacenterId, fileId: documentId, accessHash: accessHash, size: size, fileReference: nil, fileName: fileNameFromFileAttributes(attributes)), previewRepresentations: previewRepresentations, videoThumbnails: [], immediateThumbnailData: nil, mimeType: "image/webp", size: size, attributes: attributes), small: !highQuality, fitSize: fitSize, completion: { image in - if let image = image { - sharedImageCache.setImage(image, forKey: uri, attributes: nil) - completion?(TGDataResource(image: image, decoded: true)) - } - }) - } else { - return nil - } - } - - override func cancelTask(byId taskId: Any!) { - if let task = taskId as? LegacyStickerImageDataTask { - task.cancel() - } - } -} diff --git a/submodules/LegacyUI/Sources/LegacyHTTPOperationImpl.swift b/submodules/LegacyUI/Sources/LegacyHTTPOperationImpl.swift deleted file mode 100644 index 637d5f6aeb..0000000000 --- a/submodules/LegacyUI/Sources/LegacyHTTPOperationImpl.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation -import MtProtoKit - -import LegacyComponents - -@objc class LegacyHTTPOperationImpl: AFHTTPRequestOperation, LegacyHTTPRequestOperation { -} diff --git a/submodules/LegacyUI/Sources/LegacyLocationVenueIconDataSource.swift b/submodules/LegacyUI/Sources/LegacyLocationVenueIconDataSource.swift deleted file mode 100644 index 112d02e0cd..0000000000 --- a/submodules/LegacyUI/Sources/LegacyLocationVenueIconDataSource.swift +++ /dev/null @@ -1,193 +0,0 @@ -import Foundation -import UIKit -import LegacyComponents -import Postbox -import TelegramCore -import SyncCore -import SwiftSignalKit -import Display - -private let sharedImageCache = TGMemoryImageCache(softMemoryLimit: 2 * 1024 * 1024, hardMemoryLimit: 3 * 1024 * 1024)! - -private let placeholderImage = generateFilledCircleImage(diameter: 40.0, color: UIColor(rgb: 0xf2f2f2)) - -private final class LegacyLocationVenueIconTask: NSObject { - private let disposable = DisposableSet() - - init(account: Account, url: String, completion: @escaping (Data?) -> Void) { - super.init() - - let resource = HttpReferenceMediaResource(url: url, size: nil) - self.disposable.add(account.postbox.mediaBox.resourceData(resource).start(next: { data in - if data.complete { - if let loadedData = try? Data(contentsOf: URL(fileURLWithPath: data.path)) { - completion(loadedData) - } - } - })) - self.disposable.add(account.postbox.mediaBox.fetchedResource(resource, parameters: nil).start()) - } - - deinit { - self.disposable.dispose() - } - - func cancel() { - self.disposable.dispose() - } -} - -private let genericIconImage = TGComponentsImageNamed("LocationMessagePinIcon")?.precomposed() - -final class LegacyLocationVenueIconDataSource: TGImageDataSource { - private let account: () -> Account? - - init(account: @escaping () -> Account?) { - self.account = account - - super.init() - } - - override func canHandleUri(_ uri: String!) -> Bool { - if let uri = uri { - if uri.hasPrefix("location-venue-icon://") { - return true - } - } - return false - } - - override func loadAttributeSync(forUri uri: String!, attribute: String!) -> Any! { - if attribute == "placeholder" { - return placeholderImage - } - return nil - } - - override func loadDataSync(withUri uri: String!, canWait: Bool, acceptPartialData: Bool, asyncTaskId: AutoreleasingUnsafeMutablePointer!, progress: ((Float) -> Void)!, partialCompletion: ((TGDataResource?) -> Void)!, completion: ((TGDataResource?) -> Void)!) -> TGDataResource! { - if let image = sharedImageCache.image(forKey: uri, attributes: nil) { - return TGDataResource(image: image, decoded: true) - } - return nil - } - - private static func unavailableImage(for uri: String) -> TGDataResource? { - let args: [AnyHashable : Any] - let argumentsString = String(uri[uri.index(uri.startIndex, offsetBy: "location-venue-icon://".count)...]) - args = TGStringUtils.argumentDictionary(inUrlString: argumentsString)! - - guard let width = Int((args["width"] as! String)), width > 1 else { - return nil - } - guard let height = Int((args["height"] as! String)), height > 1 else { - return nil - } - - guard let colorN = (args["color"] as? String).flatMap({ Int($0) }) else { - return nil - } - - let color = UIColor(rgb: UInt32(colorN)) - - let size = CGSize(width: CGFloat(width), height: CGFloat(height)) - - guard let iconSourceImage = genericIconImage.flatMap({ generateTintedImage(image: $0, color: color) }) else { - return nil - } - - UIGraphicsBeginImageContextWithOptions(iconSourceImage.size, false, iconSourceImage.scale) - var context = UIGraphicsGetCurrentContext()! - iconSourceImage.draw(at: CGPoint()) - context.setBlendMode(.sourceAtop) - context.setFillColor(color.cgColor) - context.fill(CGRect(origin: CGPoint(), size: iconSourceImage.size)) - - let tintedIconImage = UIGraphicsGetImageFromCurrentImageContext() - UIGraphicsEndImageContext() - - UIGraphicsBeginImageContextWithOptions(size, false, 0.0) - context = UIGraphicsGetCurrentContext()! - let fitSize = CGSize(width: size.width - 4.0 * 2.0, height: size.height - 4.0 * 2.0) - let imageSize = iconSourceImage.size.aspectFitted(fitSize) - let imageRect = CGRect(origin: CGPoint(x: floor((size.width - imageSize.width) / 2.0), y: floor((size.height - imageSize.height) / 2.0)), size: imageSize) - tintedIconImage?.draw(in: imageRect) - - let iconImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext() - - if let iconImage = iconImage { - sharedImageCache.setImage(iconImage, forKey: uri, attributes: nil) - return TGDataResource(image: iconImage, decoded: true) - } - - return nil - } - - override func loadDataAsync(withUri uri: String!, progress: ((Float) -> Void)!, partialCompletion: ((TGDataResource?) -> Void)!, completion: ((TGDataResource?) -> Void)!) -> Any! { - if let account = self.account() { - let args: [AnyHashable : Any] - let argumentsString = String(uri[uri.index(uri.startIndex, offsetBy: "location-venue-icon://".count)...]) - args = TGStringUtils.argumentDictionary(inUrlString: argumentsString)! - - guard let width = Int((args["width"] as! String)), width > 1 else { - return nil - } - guard let height = Int((args["height"] as! String)), height > 1 else { - return nil - } - - guard let colorN = (args["color"] as? String).flatMap({ Int($0) }) else { - return nil - } - - guard let type = args["type"] as? String else { - return LegacyLocationVenueIconDataSource.unavailableImage(for: uri) - } - - let color = UIColor(rgb: UInt32(colorN)) - - let url = "https://ss3.4sqi.net/img/categories_v2/\(type)_88.png" - - let size = CGSize(width: CGFloat(width), height: CGFloat(height)) - - return LegacyLocationVenueIconTask(account: account, url: url, completion: { data in - if let data = data, let iconSourceImage = UIImage(data: data) { - UIGraphicsBeginImageContextWithOptions(iconSourceImage.size, false, iconSourceImage.scale) - var context = UIGraphicsGetCurrentContext()! - iconSourceImage.draw(at: CGPoint()) - context.setBlendMode(.sourceAtop) - context.setFillColor(color.cgColor) - context.fill(CGRect(origin: CGPoint(), size: iconSourceImage.size)) - - let tintedIconImage = UIGraphicsGetImageFromCurrentImageContext() - UIGraphicsEndImageContext() - - UIGraphicsBeginImageContextWithOptions(size, false, 0.0) - context = UIGraphicsGetCurrentContext()! - let imageRect = CGRect(x: 4.0, y: 4.0, width: size.width - 4.0 * 2.0, height: size.height - 4.0 * 2.0) - tintedIconImage?.draw(in: imageRect) - - let iconImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext() - - if let iconImage = iconImage { - sharedImageCache.setImage(iconImage, forKey: uri, attributes: nil) - completion?(TGDataResource(image: iconImage, decoded: true)) - } - } else { - if let image = LegacyLocationVenueIconDataSource.unavailableImage(for: uri) { - completion?(image) - } - } - }) - } else { - return nil - } - } - - override func cancelTask(byId taskId: Any!) { - if let disposable = taskId as? LegacyLocationVenueIconTask { - disposable.cancel() - } - } -} diff --git a/submodules/LegacyUI/Sources/TelegramInitializeLegacyComponents.swift b/submodules/LegacyUI/Sources/TelegramInitializeLegacyComponents.swift index 1c5d394d0a..19bf7578d7 100644 --- a/submodules/LegacyUI/Sources/TelegramInitializeLegacyComponents.swift +++ b/submodules/LegacyUI/Sources/TelegramInitializeLegacyComponents.swift @@ -196,30 +196,6 @@ private final class LegacyComponentsGlobalsProviderImpl: NSObject, LegacyCompone return LegacyComponentsAccessCheckerImpl(context: legacyContext) } - public func stickerPacksSignal() -> SSignal! { - if let legacyContext = legacyContext { - return legacyComponentsStickers(postbox: legacyContext.account.postbox, namespace: Namespaces.ItemCollection.CloudStickerPacks) - } else { - var dict: [AnyHashable: Any] = [:] - dict["packs"] = NSArray() - return SSignal.single(dict) - } - } - - public func maskStickerPacksSignal() -> SSignal! { - if let legacyContext = legacyContext { - return legacyComponentsStickers(postbox: legacyContext.account.postbox, namespace: Namespaces.ItemCollection.CloudMaskPacks) - } else { - var dict: [AnyHashable: Any] = [:] - dict["packs"] = NSArray() - return SSignal.single(dict) - } - } - - public func recentStickerMasksSignal() -> SSignal! { - return SSignal.single(NSArray()) - } - public func request(_ type: TGAudioSessionType, interrupted: (() -> Void)!) -> SDisposable! { if let legacyContext = legacyContext { let convertedType: ManagedAudioSessionType @@ -262,40 +238,6 @@ private final class LegacyComponentsGlobalsProviderImpl: NSObject, LegacyCompone return "" } - public func json(forHttpLocation httpLocation: String!) -> SSignal! { - return self.data(forHttpLocation: httpLocation).map(toSignal: { next in - if let next = next as? Data { - if let object = try? JSONSerialization.jsonObject(with: next, options: []) { - return SSignal.single(object) - } - } - return SSignal.fail(nil) - }) - } - - public func data(forHttpLocation httpLocation: String!) -> SSignal! { - return SSignal { subscriber in - if let httpLocation = httpLocation, let url = URL(string: httpLocation) { - let disposable = MTHttpRequestOperation.data(forHttpUrl: url).start(next: { next in - subscriber?.putNext(next) - }, error: { error in - subscriber?.putError(error) - }, completed: { - subscriber?.putCompletion() - }) - return SBlockDisposable(block: { - disposable?.dispose() - }) - } else { - return nil - } - } - } - - public func makeHTTPRequestOperation(with request: URLRequest!) -> (Operation & LegacyHTTPRequestOperation)! { - return LegacyHTTPOperationImpl(request: request) - } - public func pausePictureInPicturePlayback() { } @@ -377,15 +319,9 @@ public func initializeLegacyComponents(application: UIApplication?, currentSizeC TGRemoteImageView.setSharedCache(TGCache()) - TGImageDataSource.register(LegacyStickerImageDataSource(account: { - return legacyContext?.account - })) TGImageDataSource.register(LegacyPeerAvatarPlaceholderDataSource(account: { return legacyContext?.account })) - TGImageDataSource.register(LegacyLocationVenueIconDataSource(account: { - return legacyContext?.account - })) ASActor.registerClass(LegacyImageDownloadActor.self) LegacyComponentsGlobals.setProvider(LegacyComponentsGlobalsProviderImpl()) } diff --git a/submodules/LocationUI/Sources/LegacyLocationController.swift b/submodules/LocationUI/Sources/LegacyLocationController.swift deleted file mode 100644 index 3411e9a7ee..0000000000 --- a/submodules/LocationUI/Sources/LegacyLocationController.swift +++ /dev/null @@ -1,288 +0,0 @@ -import Foundation -import UIKit -import Display -import SwiftSignalKit -import LegacyComponents -import TelegramCore -import SyncCore -import Postbox -import TelegramPresentationData -import AccountContext -import ShareController -import LegacyUI -import OpenInExternalAppUI -import AppBundle -import LocationResources -import DeviceLocationManager - -private func generateClearIcon(color: UIColor) -> UIImage? { - return generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Clear"), color: color) -} - -func makeLegacyPeer(_ peer: Peer) -> AnyObject? { - if let user = peer as? TelegramUser { - let legacyUser = TGUser() - legacyUser.uid = user.id.id - legacyUser.firstName = user.firstName - legacyUser.lastName = user.lastName - if let representation = smallestImageRepresentation(user.photo) { - legacyUser.photoUrlSmall = legacyImageLocationUri(resource: representation.resource) - } - return legacyUser - } else if let channel = peer as? TelegramChannel { - let legacyConversation = TGConversation() - legacyConversation.conversationId = Int64(channel.id.id) - legacyConversation.chatTitle = channel.title - if let representation = smallestImageRepresentation(channel.photo) { - legacyConversation.chatPhotoSmall = legacyImageLocationUri(resource: representation.resource) - } - return legacyConversation - } else { - return nil - } -} - -private func makeLegacyMessage(_ message: Message) -> TGMessage { - let result = TGMessage() - result.mid = message.id.id - result.date = Double(message.timestamp) - if message.flags.contains(.Failed) { - result.deliveryState = TGMessageDeliveryStateFailed - } else if message.flags.contains(.Sending) { - result.deliveryState = TGMessageDeliveryStatePending - } else { - result.deliveryState = TGMessageDeliveryStateDelivered - } - - for attribute in message.attributes { - if let attribute = attribute as? EditedMessageAttribute { - result.editDate = Double(attribute.date) - } - } - - var media: [Any] = [] - for m in message.media { - if let mapMedia = m as? TelegramMediaMap { - let legacyLocation = TGLocationMediaAttachment() - legacyLocation.latitude = mapMedia.latitude - legacyLocation.longitude = mapMedia.longitude - if let venue = mapMedia.venue { - legacyLocation.venue = TGVenueAttachment(title: venue.title, address: venue.address, provider: venue.provider, venueId: venue.id, type: venue.type) - } - if let liveBroadcastingTimeout = mapMedia.liveBroadcastingTimeout { - legacyLocation.period = liveBroadcastingTimeout - } - - media.append(legacyLocation) - } - } - if !media.isEmpty { - result.mediaAttachments = media - } - - return result -} - -private func legacyRemainingTime(message: TGMessage) -> SSignal { - var liveBroadcastingTimeoutValue: Int32? - if let mediaAttachments = message.mediaAttachments { - for media in mediaAttachments { - if let m = media as? TGLocationMediaAttachment, m.period != 0 { - liveBroadcastingTimeoutValue = m.period - } - } - } - guard let liveBroadcastingTimeout = liveBroadcastingTimeoutValue else { - return SSignal.fail(nil) - } - - if message.deliveryState != TGMessageDeliveryStateDelivered { - return SSignal.single(liveBroadcastingTimeout as NSNumber) - } - - let remainingTime = SSignal.`defer`({ - let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) - let remainingTime = max(0, Int32(message.date) + liveBroadcastingTimeout - currentTime) - var signal = SSignal.single(remainingTime as NSNumber) - if remainingTime == 0 { - signal = signal?.then(SSignal.fail(nil)) - } - return signal - })! - - return (remainingTime.then(SSignal.complete().delay(5.0, on: SQueue.main()))).restart().`catch`({ _ in - return SSignal.complete() - }) -} - -private func telegramMap(for location: TGLocationMediaAttachment) -> TelegramMediaMap { - let mapVenue: MapVenue? - if let venue = location.venue { - mapVenue = MapVenue(title: venue.title ?? "", address: venue.address ?? "", provider: venue.provider ?? "", id: venue.venueId ?? "", type: venue.type ?? "") - } else { - mapVenue = nil - } - return TelegramMediaMap(latitude: location.latitude, longitude: location.longitude, heading: nil, accuracyRadius: nil, geoPlace: nil, venue: mapVenue, liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil) -} - -func legacyLocationPalette(from theme: PresentationTheme) -> TGLocationPallete { - let listTheme = theme.list - let searchTheme = theme.rootController.navigationSearchBar - return TGLocationPallete(backgroundColor: listTheme.plainBackgroundColor, selectionColor: listTheme.itemHighlightedBackgroundColor, separatorColor: listTheme.itemPlainSeparatorColor, textColor: listTheme.itemPrimaryTextColor, secondaryTextColor: listTheme.itemSecondaryTextColor, accentColor: listTheme.itemAccentColor, destructiveColor: listTheme.itemDestructiveColor, locationColor: UIColor(rgb: 0x008df2), liveLocationColor: UIColor(rgb: 0xff6464), iconColor: searchTheme.backgroundColor, sectionHeaderBackgroundColor: theme.chatList.sectionHeaderFillColor, sectionHeaderTextColor: theme.chatList.sectionHeaderTextColor, searchBarPallete: TGSearchBarPallete(dark: theme.overallDarkAppearance, backgroundColor: searchTheme.backgroundColor, highContrastBackgroundColor: searchTheme.backgroundColor, textColor: searchTheme.inputTextColor, placeholderColor: searchTheme.inputPlaceholderTextColor, clearIcon: generateClearIcon(color: theme.rootController.navigationSearchBar.inputClearButtonColor), barBackgroundColor: searchTheme.backgroundColor, barSeparatorColor: searchTheme.separatorColor, plainBackgroundColor: searchTheme.backgroundColor, accentColor: searchTheme.accentColor, accentContrastColor: searchTheme.backgroundColor, menuBackgroundColor: searchTheme.backgroundColor, segmentedControlBackgroundImage: nil, segmentedControlSelectedImage: nil, segmentedControlHighlightedImage: nil, segmentedControlDividerImage: nil), avatarPlaceholder: nil) -} - -public func legacyLocationController(message: Message?, mapMedia: TelegramMediaMap, context: AccountContext, openPeer: @escaping (Peer) -> Void, sendLiveLocation: @escaping (CLLocationCoordinate2D, Int32) -> Void, stopLiveLocation: @escaping () -> Void, openUrl: @escaping (String) -> Void) -> ViewController { - let legacyLocation = TGLocationMediaAttachment() - legacyLocation.latitude = mapMedia.latitude - legacyLocation.longitude = mapMedia.longitude - if let venue = mapMedia.venue { - legacyLocation.venue = TGVenueAttachment(title: venue.title, address: venue.address, provider: venue.provider, venueId: venue.id, type: venue.type) - } - - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - - let legacyController = LegacyController(presentation: .navigation, theme: presentationData.theme, strings: presentationData.strings) - legacyController.navigationPresentation = .modal - let controller: TGLocationViewController - - let venueColor = mapMedia.venue?.type.flatMap { venueIconColor(type: $0) } - if let message = message { - let legacyMessage = makeLegacyMessage(message) - let legacyAuthor: AnyObject? = message.author.flatMap(makeLegacyPeer) - - let updatedLocations = SSignal(generator: { subscriber in - let disposable = topPeerActiveLiveLocationMessages(viewTracker: context.account.viewTracker, accountPeerId: context.account.peerId, peerId: message.id.peerId).start(next: { (_, messages) in - var result: [Any] = [] - let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) - loop: for message in messages { - var liveBroadcastingTimeout: Int32 = 0 - - mediaLoop: for media in message.media { - if let map = media as? TelegramMediaMap, let timeout = map.liveBroadcastingTimeout { - liveBroadcastingTimeout = timeout - break mediaLoop - } - } - - let legacyMessage = makeLegacyMessage(message) - guard let legacyAuthor = message.author.flatMap(makeLegacyPeer) else { - continue loop - } - let remainingTime = max(0, message.timestamp + liveBroadcastingTimeout - currentTime) - if legacyMessage.locationAttachment?.period != 0 { - let hasOwnSession = message.localTags.contains(.OutgoingLiveLocation) - var isOwn = false - if !message.flags.contains(.Incoming) { - isOwn = true - } else if let peer = message.peers[message.id.peerId] as? TelegramChannel { - isOwn = peer.hasPermission(.sendMessages) - } - - let liveLocation = TGLiveLocation(message: legacyMessage, peer: legacyAuthor, hasOwnSession: hasOwnSession, isOwnLocation: isOwn, isExpired: remainingTime == 0)! - result.append(liveLocation) - } - } - subscriber?.putNext(result) - }) - - return SBlockDisposable(block: { - disposable.dispose() - }) - })! - - if let liveBroadcastingTimeout = mapMedia.liveBroadcastingTimeout { - let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) - let remainingTime = max(0, message.timestamp + liveBroadcastingTimeout - currentTime) - - let messageLiveLocation = TGLiveLocation(message: legacyMessage, peer: legacyAuthor, hasOwnSession: false, isOwnLocation: false, isExpired: remainingTime == 0)! - - controller = TGLocationViewController(context: legacyController.context, liveLocation: messageLiveLocation) - - if remainingTime == 0 { - let freezeLocations: [Any] = [messageLiveLocation] - controller.setLiveLocationsSignal(.single(freezeLocations)) - } else { - controller.setLiveLocationsSignal(updatedLocations) - if message.flags.contains(.Incoming) { - context.account.viewTracker.updateSeenLiveLocationForMessageIds(messageIds: Set([message.id])) - } - } - } else { - controller = TGLocationViewController(context: legacyController.context, message: legacyMessage, peer: legacyAuthor, color: venueColor)! - controller.receivingPeer = message.peers[message.id.peerId].flatMap(makeLegacyPeer) - controller.setLiveLocationsSignal(updatedLocations) - } - - let namespacesWithEnabledLiveLocation: Set = Set([ - Namespaces.Peer.CloudChannel, - Namespaces.Peer.CloudGroup, - Namespaces.Peer.CloudUser - ]) - if namespacesWithEnabledLiveLocation.contains(message.id.peerId.namespace) { - controller.allowLiveLocationSharing = true - } - } else { - let attachment = TGLocationMediaAttachment() - attachment.latitude = mapMedia.latitude - attachment.longitude = mapMedia.longitude - controller = TGLocationViewController(context: legacyController.context, locationAttachment: attachment, peer: nil, color: venueColor) - } - - controller.remainingTimeForMessage = { message in - return legacyRemainingTime(message: message!) - } - controller.liveLocationStarted = { [weak legacyController] coordinate, period in - sendLiveLocation(coordinate, period) - legacyController?.dismiss() - } - controller.liveLocationStopped = { [weak legacyController] in - stopLiveLocation() - legacyController?.dismiss() - } - - let theme = (context.sharedContext.currentPresentationData.with { $0 }).theme - controller.pallete = legacyLocationPalette(from: theme) - - controller.modalMode = true - controller.presentActionsMenu = { [weak legacyController] legacyLocation, directions in - if let strongLegacyController = legacyController, let location = legacyLocation { - let map = telegramMap(for: location) - - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - let shareAction = OpenInControllerAction(title: presentationData.strings.Conversation_ContextMenuShare, action: { - strongLegacyController.present(ShareController(context: context, subject: .mapMedia(map), externalShare: true), in: .window(.root), with: nil) - }) - - strongLegacyController.present(OpenInActionSheetController(context: context, item: .location(location: map, withDirections: directions), additionalAction: !directions ? shareAction : nil, openUrl: openUrl), in: .window(.root), with: nil) - } - } - - controller.onViewDidAppear = { [weak controller] in - if let strongController = controller { - strongController.view.disablesInteractiveModalDismiss = true - strongController.view.disablesInteractiveTransitionGestureRecognizer = true - strongController.locationMapView.interactiveTransitionGestureRecognizerTest = { point -> Bool in - return point.x > 30.0 - } - } - } - - legacyController.navigationItem.title = controller.navigationItem.title - controller.updateRightBarItem = { item, action, animated in - if action { - legacyController.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationShareIcon(theme), style: .plain, target: controller, action: #selector(controller.actionsButtonPressed)) - } else { - legacyController.navigationItem.setRightBarButton(item, animated: animated) - } - } - legacyController.bind(controller: controller) - - let presentationDisposable = context.sharedContext.presentationData.start(next: { [weak controller] presentationData in - if let controller = controller { - controller.pallete = legacyLocationPalette(from: presentationData.theme) - } - }) - legacyController.disposables.add(presentationDisposable) - - return legacyController -} diff --git a/submodules/LocationUI/Sources/LegacyLocationPicker.swift b/submodules/LocationUI/Sources/LegacyLocationPicker.swift deleted file mode 100644 index 108de5e611..0000000000 --- a/submodules/LocationUI/Sources/LegacyLocationPicker.swift +++ /dev/null @@ -1,113 +0,0 @@ -import Foundation -import UIKit -import Display -import LegacyComponents -import TelegramCore -import SyncCore -import Postbox -import SwiftSignalKit -import TelegramPresentationData -import AccountContext -import LegacyUI -import AppBundle - -private func generateClearIcon(color: UIColor) -> UIImage? { - return generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Clear"), color: color) -} - -public func legacyLocationPickerController(context: AccountContext, selfPeer: Peer, peer: Peer, sendLocation: @escaping (CLLocationCoordinate2D, MapVenue?, String?) -> Void, sendLiveLocation: @escaping (CLLocationCoordinate2D, Int32) -> Void, theme: PresentationTheme, customLocationPicker: Bool = false, hasLiveLocation: Bool = true, presentationCompleted: @escaping () -> Void = {}) -> ViewController { - let legacyController = LegacyController(presentation: .navigation, theme: theme) - legacyController.navigationPresentation = .modal - let controller = TGLocationPickerController(context: legacyController.context, intent: customLocationPicker ? TGLocationPickerControllerCustomLocationIntent : TGLocationPickerControllerDefaultIntent)! - legacyController.presentationCompleted = { [weak controller] in - presentationCompleted() - - controller?.view.disablesInteractiveModalDismiss = true - controller?.view.disablesInteractiveTransitionGestureRecognizer = true - } - controller.peer = makeLegacyPeer(selfPeer) - controller.receivingPeer = makeLegacyPeer(peer) - controller.pallete = legacyLocationPalette(from: theme) - let namespacesWithEnabledLiveLocation: Set = Set([ - Namespaces.Peer.CloudChannel, - Namespaces.Peer.CloudGroup, - Namespaces.Peer.CloudUser - ]) - if namespacesWithEnabledLiveLocation.contains(peer.id.namespace) && !customLocationPicker && hasLiveLocation { - controller.allowLiveLocationSharing = true - } - let navigationController = TGNavigationController(controllers: [controller])! - controller.navigation_setDismiss({ [weak legacyController] in - legacyController?.dismiss() - }, rootController: nil) - legacyController.bind(controller: navigationController) - legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait) - controller.locationPicked = { [weak legacyController] coordinate, venue, address in - sendLocation(coordinate, venue.flatMap { venue in - return MapVenue(title: venue.title, address: venue.address, provider: venue.provider, id: venue.venueId, type: venue.type) - }, address) - legacyController?.dismiss() - } - controller.liveLocationStarted = { [weak legacyController] coordinate, period in - sendLiveLocation(coordinate, period) - legacyController?.dismiss() - } - controller.nearbyPlacesSignal = { query, location in - return SSignal(generator: { subscriber in - let nearbyPlacesSignal: Signal<[TGLocationVenue], NoError> = resolvePeerByName(account: context.account, name: "foursquare") - |> take(1) - |> mapToSignal { peerId -> Signal in - guard let peerId = peerId else { - return .single(nil) - } - return requestChatContextResults(account: context.account, botId: peerId, peerId: selfPeer.id, query: query ?? "", location: .single((location?.coordinate.latitude ?? 0.0, location?.coordinate.longitude ?? 0.0)), offset: "") - |> map { results -> ChatContextResultCollection? in - return results?.results - } - |> `catch` { error -> Signal in - return .single(nil) - } - } - |> mapToSignal { contextResult -> Signal<[TGLocationVenue], NoError> in - guard let contextResult = contextResult else { - return .single([]) - } - - var list: [TGLocationVenue] = [] - for result in contextResult.results { - switch result.message { - case let .mapLocation(mapMedia, _): - let legacyLocation = TGLocationMediaAttachment() - legacyLocation.latitude = mapMedia.latitude - legacyLocation.longitude = mapMedia.longitude - if let venue = mapMedia.venue { - legacyLocation.venue = TGVenueAttachment(title: venue.title, address: venue.address, provider: venue.provider, venueId: venue.id, type: venue.type) - } - list.append(TGLocationVenue(locationAttachment: legacyLocation)) - default: - break - } - } - - return .single(list) - } - - let disposable = nearbyPlacesSignal.start(next: { next in - subscriber?.putNext(next as NSArray) - }, completed: { - subscriber?.putCompletion() - }) - - return SBlockDisposable(block: { - disposable.dispose() - }) - }) - } - let presentationDisposable = context.sharedContext.presentationData.start(next: { [weak controller] presentationData in - if let controller = controller { - controller.pallete = legacyLocationPalette(from: presentationData.theme) - } - }) - legacyController.disposables.add(presentationDisposable) - return legacyController -} diff --git a/submodules/LocationUI/Sources/LocationUtils.swift b/submodules/LocationUI/Sources/LocationUtils.swift index 30475fa14a..7d658b057c 100644 --- a/submodules/LocationUI/Sources/LocationUtils.swift +++ b/submodules/LocationUI/Sources/LocationUtils.swift @@ -81,7 +81,7 @@ func stringForEstimatedDuration(strings: PresentationStrings, eta: Double) -> St if hours == 1 && minutes == 0 { string = strings.Map_ETAHours(1) } else { - string = strings.Map_ETAHours(9999).replacingOccurrences(of: "9999", with: String(format: "%d:%02d", arguments: [hours, minutes])) + string = strings.Map_ETAHours(10).replacingOccurrences(of: "10", with: String(format: "%d:%02d", arguments: [hours, minutes])) } } else { string = strings.Map_ETAMinutes(minutes) diff --git a/submodules/MediaPlayer/Sources/MediaPlayer.swift b/submodules/MediaPlayer/Sources/MediaPlayer.swift index 1ac1ab6327..750330d180 100644 --- a/submodules/MediaPlayer/Sources/MediaPlayer.swift +++ b/submodules/MediaPlayer/Sources/MediaPlayer.swift @@ -870,12 +870,12 @@ private final class MediaPlayerContext { var statusTimestamp = CACurrentMediaTime() let playbackStatus: MediaPlayerPlaybackStatus + var isPlaying = false + if case .playing = self.state { + isPlaying = true + } if let bufferingProgress = bufferingProgress { - var whilePlaying = false - if case .playing = self.state { - whilePlaying = true - } - playbackStatus = .buffering(initial: false, whilePlaying: whilePlaying, progress: Float(bufferingProgress), display: true) + playbackStatus = .buffering(initial: false, whilePlaying: isPlaying, progress: Float(bufferingProgress), display: true) } else if !rate.isZero { if reportRate.isZero { //playbackStatus = .buffering(initial: false, whilePlaying: true) @@ -885,8 +885,13 @@ private final class MediaPlayerContext { playbackStatus = .playing } } else { - playbackStatus = .paused + if performActionAtEndNow && !self.stoppedAtEnd, case .loop = self.actionAtEnd, isPlaying { + playbackStatus = .playing + } else { + playbackStatus = .paused + } } + if self.lastStatusUpdateTimestamp == nil || self.lastStatusUpdateTimestamp! < statusTimestamp + 500 { lastStatusUpdateTimestamp = statusTimestamp var reportTimestamp = timestamp diff --git a/submodules/MtProtoKit/Sources/MTApiEnvironment.m b/submodules/MtProtoKit/Sources/MTApiEnvironment.m index ea79285863..e6e67a701e 100644 --- a/submodules/MtProtoKit/Sources/MTApiEnvironment.m +++ b/submodules/MtProtoKit/Sources/MTApiEnvironment.m @@ -36,6 +36,11 @@ #define IPHONE_11_NAMESTRING @"iPhone 11" #define IPHONE_11PRO_NAMESTRING @"iPhone 11 Pro" #define IPHONE_11PROMAX_NAMESTRING @"iPhone 11 Pro Max" +#define IPHONE_12MINI_NAMESTRING @"iPhone 12 mini" +#define IPHONE_12_NAMESTRING @"iPhone 12" +#define IPHONE_12PRO_NAMESTRING @"iPhone 12 Pro" +#define IPHONE_12PROMAX_NAMESTRING @"iPhone 12 Pro Max" + #define IPHONE_UNKNOWN_NAMESTRING @"Unknown iPhone" #define IPOD_1G_NAMESTRING @"iPod touch 1G" @@ -112,6 +117,10 @@ typedef enum { UIDevice11iPhone, UIDevice11ProiPhone, UIDevice11ProMaxiPhone, + UIDevice12MiniiPhone, + UIDevice12iPhone, + UIDevice12ProiPhone, + UIDevice12ProMaxiPhone, UIDevice1GiPod, UIDevice2GiPod, @@ -604,6 +613,10 @@ NSString *suffix = @""; case UIDevice11iPhone: return IPHONE_11_NAMESTRING; case UIDevice11ProiPhone: return IPHONE_11PRO_NAMESTRING; case UIDevice11ProMaxiPhone: return IPHONE_11PROMAX_NAMESTRING; + case UIDevice12MiniiPhone: return IPHONE_12MINI_NAMESTRING; + case UIDevice12iPhone: return IPHONE_12_NAMESTRING; + case UIDevice12ProiPhone: return IPHONE_12PRO_NAMESTRING; + case UIDevice12ProMaxiPhone: return IPHONE_12PROMAX_NAMESTRING; case UIDeviceUnknowniPhone: return IPHONE_UNKNOWN_NAMESTRING; case UIDevice1GiPod: return IPOD_1G_NAMESTRING; @@ -695,11 +708,14 @@ NSString *suffix = @""; if ([platform isEqualToString:@"iPhone11,6"]) return UIDeviceXSMaxiPhone; if ([platform isEqualToString:@"iPhone11,4"]) return UIDeviceXSMaxiPhone; if ([platform isEqualToString:@"iPhone11,8"]) return UIDeviceXRiPhone; - if ([platform isEqualToString:@"iPhone12,1"]) return UIDevice11iPhone; if ([platform isEqualToString:@"iPhone12,3"]) return UIDevice11ProiPhone; if ([platform isEqualToString:@"iPhone12,5"]) return UIDevice11ProMaxiPhone; if ([platform isEqualToString:@"iPhone12,8"]) return UIDeviceSE2Phone; + if ([platform isEqualToString:@"iPhone13,1"]) return UIDevice12MiniiPhone; + if ([platform isEqualToString:@"iPhone13,2"]) return UIDevice12iPhone; + if ([platform isEqualToString:@"iPhone13,3"]) return UIDevice12ProiPhone; + if ([platform isEqualToString:@"iPhone13,4"]) return UIDevice12ProMaxiPhone; if ([platform isEqualToString:@"iPhone8,4"]) return UIDeviceSEPhone; diff --git a/submodules/PassportUI/Sources/SecureIdDocumentGalleryController.swift b/submodules/PassportUI/Sources/SecureIdDocumentGalleryController.swift index 37c901c718..ce02da88e0 100644 --- a/submodules/PassportUI/Sources/SecureIdDocumentGalleryController.swift +++ b/submodules/PassportUI/Sources/SecureIdDocumentGalleryController.swift @@ -177,12 +177,13 @@ class SecureIdDocumentGalleryController: ViewController, StandalonePresentableCo if let strongSelf = self { strongSelf.present(controller, in: .window(.root), with: arguments, blockInteraction: true) } - }, dismissController: { [weak self] in - self?.dismiss(forceAway: true) - }, replaceRootController: { [weak self] controller, ready in - if let strongSelf = self { - strongSelf.replaceRootController(controller, ready) - } + }, dismissController: { [weak self] in + self?.dismiss(forceAway: true) + }, replaceRootController: { [weak self] controller, ready in + if let strongSelf = self { + strongSelf.replaceRootController(controller, ready) + } + }, editMedia: { _ in }) self.displayNode = GalleryControllerNode(controllerInteraction: controllerInteraction) self.displayNodeDidLoad() diff --git a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift index f1b913406f..4e6d60ce92 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift @@ -517,6 +517,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr if let strongSelf = self { strongSelf.replaceRootController(controller, ready) } + }, editMedia: { _ in }) self.displayNode = GalleryControllerNode(controllerInteraction: controllerInteraction) self.displayNodeDidLoad() diff --git a/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift b/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift index 2e451d1400..99240510c5 100644 --- a/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift +++ b/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift @@ -17,6 +17,18 @@ import ContactsPeerItem import ChatListSearchItemHeader import ItemListUI +enum ParticipantRevealActionType { + case promote + case restrict + case remove +} + +struct ParticipantRevealAction: Equatable { + let type: ItemListPeerItemRevealOptionType + let title: String + let action: ParticipantRevealActionType +} + public enum ChannelMembersSearchMode { case searchMembers case searchAdmins diff --git a/submodules/PeerInfoUI/Sources/GroupInfoController.swift b/submodules/PeerInfoUI/Sources/GroupInfoController.swift deleted file mode 100644 index 72f2de42d4..0000000000 --- a/submodules/PeerInfoUI/Sources/GroupInfoController.swift +++ /dev/null @@ -1,2555 +0,0 @@ -import Foundation -import UIKit -import AsyncDisplayKit -import Display -import SwiftSignalKit -import Postbox -import TelegramCore -import SyncCore -import LegacyComponents -import TelegramPresentationData -import SafariServices -import TelegramUIPreferences -import ItemListUI -import PresentationDataUtils -import TextFormat -import AccountContext -import TelegramStringFormatting -import TemporaryCachedPeerDataManager -import ShareController -import AlertUI -import PresentationDataUtils -import MediaResources -import PhotoResources -import LocationResources -import GalleryUI -import LegacyUI -import LocationUI -import ItemListPeerItem -import ContactListUI -import ItemListAvatarAndNameInfoItem -import ItemListPeerActionItem -import WebSearchUI -import Geocoding -import PeerAvatarGalleryUI -import Emoji -import NotificationMuteSettingsUI -import MapResourceToAvatarSizes -import NotificationSoundSelectionUI -import ItemListAddressItem -import AppBundle -import Markdown -import LocalizedPeerData - -private let maxParticipantsDisplayedLimit: Int32 = 50 -private let maxParticipantsDisplayedCollapseLimit: Int32 = 60 - -private final class GroupInfoArguments { - let context: AccountContext - - let avatarAndNameInfoContext: ItemListAvatarAndNameInfoItemContext - let tapAvatarAction: () -> Void - let changeProfilePhoto: () -> Void - let pushController: (ViewController) -> Void - let presentController: (ViewController, ViewControllerPresentationArguments) -> Void - let changeNotificationMuteSettings: () -> Void - let openPreHistory: () -> Void - let openSharedMedia: () -> Void - let openAdministrators: () -> Void - let openPermissions: () -> Void - let updateEditingName: (ItemListAvatarAndNameInfoItemName) -> Void - let updateEditingDescriptionText: (String) -> Void - let setPeerIdWithRevealedOptions: (PeerId?, PeerId?) -> Void - let addMember: () -> Void - let promotePeer: (RenderedChannelParticipant) -> Void - let restrictPeer: (RenderedChannelParticipant) -> Void - let removePeer: (PeerId) -> Void - let leave: () -> Void - let displayUsernameShareMenu: (String) -> Void - let displayUsernameContextMenu: (String) -> Void - let displayAboutContextMenu: (String) -> Void - let aboutLinkAction: (TextLinkItemActionType, TextLinkItem) -> Void - let openStickerPackSetup: () -> Void - let openGroupTypeSetup: () -> Void - let openLinkedChannelSetup: () -> Void - let openLocation: (PeerGeoLocation) -> Void - let changeLocation: () -> Void - let displayLocationContextMenu: (String) -> Void - let expandParticipants: () -> Void - - init(context: AccountContext, avatarAndNameInfoContext: ItemListAvatarAndNameInfoItemContext, tapAvatarAction: @escaping () -> Void, changeProfilePhoto: @escaping () -> Void, pushController: @escaping (ViewController) -> Void, presentController: @escaping (ViewController, ViewControllerPresentationArguments) -> Void, changeNotificationMuteSettings: @escaping () -> Void, openPreHistory: @escaping () -> Void, openSharedMedia: @escaping () -> Void, openAdministrators: @escaping () -> Void, openPermissions: @escaping () -> Void, updateEditingName: @escaping (ItemListAvatarAndNameInfoItemName) -> Void, updateEditingDescriptionText: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, addMember: @escaping () -> Void, promotePeer: @escaping (RenderedChannelParticipant) -> Void, restrictPeer: @escaping (RenderedChannelParticipant) -> Void, removePeer: @escaping (PeerId) -> Void, leave: @escaping () -> Void, displayUsernameShareMenu: @escaping (String) -> Void, displayUsernameContextMenu: @escaping (String) -> Void, displayAboutContextMenu: @escaping (String) -> Void, aboutLinkAction: @escaping (TextLinkItemActionType, TextLinkItem) -> Void, openStickerPackSetup: @escaping () -> Void, openGroupTypeSetup: @escaping () -> Void, openLinkedChannelSetup: @escaping () -> Void, openLocation: @escaping (PeerGeoLocation) -> Void, changeLocation: @escaping () -> Void, displayLocationContextMenu: @escaping (String) -> Void, expandParticipants: @escaping () -> Void) { - self.context = context - self.avatarAndNameInfoContext = avatarAndNameInfoContext - self.tapAvatarAction = tapAvatarAction - self.changeProfilePhoto = changeProfilePhoto - self.pushController = pushController - self.presentController = presentController - self.changeNotificationMuteSettings = changeNotificationMuteSettings - self.openPreHistory = openPreHistory - self.openSharedMedia = openSharedMedia - self.openAdministrators = openAdministrators - self.openPermissions = openPermissions - self.updateEditingName = updateEditingName - self.updateEditingDescriptionText = updateEditingDescriptionText - self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions - self.addMember = addMember - self.promotePeer = promotePeer - self.restrictPeer = restrictPeer - self.removePeer = removePeer - self.leave = leave - self.displayUsernameShareMenu = displayUsernameShareMenu - self.displayUsernameContextMenu = displayUsernameContextMenu - self.displayAboutContextMenu = displayAboutContextMenu - self.aboutLinkAction = aboutLinkAction - self.openStickerPackSetup = openStickerPackSetup - self.openGroupTypeSetup = openGroupTypeSetup - self.openLinkedChannelSetup = openLinkedChannelSetup - self.openLocation = openLocation - self.changeLocation = changeLocation - self.displayLocationContextMenu = displayLocationContextMenu - self.expandParticipants = expandParticipants - } -} - -private enum GroupInfoSection: ItemListSectionId { - case info - case about - case infoManagement - case sharedMediaAndNotifications - case memberManagement - case members - case leave -} - -private enum GroupInfoEntryTag { - case about - case link - case location -} - -private enum GroupInfoMemberStatus: Equatable { - case member - case admin(rank: String?) - case owner(rank: String?) -} - -private enum GroupEntryStableId: Hashable, Equatable { - case peer(PeerId) - case index(Int) - - static func ==(lhs: GroupEntryStableId, rhs: GroupEntryStableId) -> Bool { - switch lhs { - case let .peer(peerId): - if case .peer(peerId) = rhs { - return true - } else { - return false - } - case let .index(index): - if case .index(index) = rhs { - return true - } else { - return false - } - } - } - - var hashValue: Int { - switch self { - case let .peer(peerId): - return peerId.hashValue - case let .index(index): - return index.hashValue - } - } -} - -enum ParticipantRevealActionType { - case promote - case restrict - case remove -} - -struct ParticipantRevealAction: Equatable { - let type: ItemListPeerItemRevealOptionType - let title: String - let action: ParticipantRevealActionType -} - -private enum GroupInfoEntry: ItemListNodeEntry { - case info(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, peer: Peer?, cachedData: CachedPeerData?, state: ItemListAvatarAndNameInfoItemState, updatingAvatar: ItemListAvatarAndNameInfoItemUpdatingAvatar?) - case setGroupPhoto(PresentationTheme, String) - case groupDescriptionSetup(PresentationTheme, String, String) - case about(PresentationTheme, String) - case locationHeader(PresentationTheme, String) - case location(PresentationTheme, PeerGeoLocation) - case changeLocation(PresentationTheme, String) - case link(PresentationTheme, String) - case sharedMedia(PresentationTheme, String) - case notifications(PresentationTheme, String, String) - case stickerPack(PresentationTheme, String, String) - case groupTypeSetup(PresentationTheme, String, String) - case linkedChannelSetup(PresentationTheme, String, String) - case preHistory(PresentationTheme, String, String) - case administrators(PresentationTheme, String, String) - case permissions(PresentationTheme, String, String) - case addMember(PresentationTheme, String, editing: Bool) - case member(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, index: Int, peerId: PeerId, peer: Peer, participant: RenderedChannelParticipant?, presence: PeerPresence?, memberStatus: GroupInfoMemberStatus, editing: ItemListPeerItemEditing, revealActions: [ParticipantRevealAction], enabled: Bool, selectable: Bool) - case expand(PresentationTheme, String) - case leave(PresentationTheme, String) - - var section: ItemListSectionId { - switch self { - case .info, .setGroupPhoto, .groupDescriptionSetup, .about: - return GroupInfoSection.info.rawValue - case .locationHeader, .location, .changeLocation, .link: - return GroupInfoSection.about.rawValue - case .groupTypeSetup, .linkedChannelSetup, .preHistory, .stickerPack: - return GroupInfoSection.infoManagement.rawValue - case .sharedMedia, .notifications: - return GroupInfoSection.sharedMediaAndNotifications.rawValue - case .permissions, .administrators: - return GroupInfoSection.memberManagement.rawValue - case .addMember, .member, .expand: - return GroupInfoSection.members.rawValue - case .leave: - return GroupInfoSection.leave.rawValue - } - } - - static func ==(lhs: GroupInfoEntry, rhs: GroupInfoEntry) -> Bool { - switch lhs { - case let .info(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsPeer, lhsCachedData, lhsState, lhsUpdatingAvatar): - if case let .info(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsPeer, rhsCachedData, rhsState, rhsUpdatingAvatar) = rhs { - if lhsTheme !== rhsTheme { - return false - } - if lhsStrings !== rhsStrings { - return false - } - if lhsDateTimeFormat != rhsDateTimeFormat { - return false - } - if let lhsPeer = lhsPeer, let rhsPeer = rhsPeer { - if !lhsPeer.isEqual(rhsPeer) { - return false - } - } else if (lhsPeer == nil) != (rhsPeer != nil) { - return false - } - if let lhsCachedData = lhsCachedData, let rhsCachedData = rhsCachedData { - if !lhsCachedData.isEqual(to: rhsCachedData) { - return false - } - } else if (lhsCachedData != nil) != (rhsCachedData != nil) { - return false - } - if lhsState != rhsState { - return false - } - if lhsUpdatingAvatar != rhsUpdatingAvatar { - return false - } - return true - } else { - return false - } - case let .setGroupPhoto(lhsTheme, lhsText): - if case let .setGroupPhoto(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { - return true - } else { - return false - } - case let .groupDescriptionSetup(lhsTheme, lhsPlaceholder, lhsText): - if case let .groupDescriptionSetup(rhsTheme, rhsPlaceholder, rhsText) = rhs, lhsTheme === rhsTheme, lhsPlaceholder == rhsPlaceholder, lhsText == rhsText { - return true - } else { - return false - } - case let .sharedMedia(lhsTheme, lhsText): - if case let .sharedMedia(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { - return true - } else { - return false - } - case let .leave(lhsTheme, lhsText): - if case let .leave(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { - return true - } else { - return false - } - case let .about(lhsTheme, lhsText): - if case let .about(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { - return true - } else { - return false - } - case let .locationHeader(lhsTheme, lhsText): - if case let .locationHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { - return true - } else { - return false - } - case let .location(lhsTheme, lhsLocation): - if case let .location(rhsTheme, rhsLocation) = rhs, lhsTheme === rhsTheme, lhsLocation == rhsLocation { - return true - } else { - return false - } - case let .changeLocation(lhsTheme, lhsText): - if case let .changeLocation(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { - return true - } else { - return false - } - case let .link(lhsTheme, lhsText): - if case let .link(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { - return true - } else { - return false - } - case let .notifications(lhsTheme, lhsTitle, lhsText): - if case let .notifications(rhsTheme, rhsTitle, rhsText) = rhs { - if lhsTheme !== rhsTheme { - return false - } - if lhsTitle != rhsTitle { - return false - } - if lhsText != rhsText { - return false - } - return true - } else { - return false - } - case let .stickerPack(lhsTheme, lhsTitle, lhsValue): - if case let .stickerPack(rhsTheme, rhsTitle, rhsValue) = rhs { - if lhsTheme !== rhsTheme { - return false - } - if lhsTitle != rhsTitle { - return false - } - if lhsValue != rhsValue { - return false - } - return true - } else { - return false - } - case let .preHistory(lhsTheme, lhsTitle, lhsValue): - if case let .preHistory(rhsTheme, rhsTitle, rhsValue) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsValue == rhsValue { - return true - } else { - return false - } - case let .groupTypeSetup(lhsTheme, lhsTitle, lhsText): - if case let .groupTypeSetup(rhsTheme, rhsTitle, rhsText) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsText == rhsText { - return true - } else { - return false - } - case let .linkedChannelSetup(lhsTheme, lhsTitle, lhsText): - if case let .linkedChannelSetup(rhsTheme, rhsTitle, rhsText) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsText == rhsText { - return true - } else { - return false - } - case let .permissions(lhsTheme, lhsTitle, lhsText): - if case let .permissions(rhsTheme, rhsTitle, rhsText) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsText == rhsText { - return true - } else { - return false - } - case let .administrators(lhsTheme, lhsTitle, lhsText): - if case let .administrators(rhsTheme, rhsTitle, rhsText) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsText == rhsText { - return true - } else { - return false - } - case let .addMember(lhsTheme, lhsTitle, lhsEditing): - if case let .addMember(rhsTheme, rhsTitle, rhsEditing) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsEditing == rhsEditing { - return true - } else { - return false - } - case let .member(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsNameDisplayOrder, lhsIndex, lhsPeerId, lhsPeer, lhsParticipant, lhsPresence, lhsMemberStatus, lhsEditing, lhsActions, lhsEnabled, lhsSelectable): - if case let .member(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsNameDisplayOrder, rhsIndex, rhsPeerId, rhsPeer, rhsParticipant, rhsPresence, rhsMemberStatus, rhsEditing, rhsActions, rhsEnabled, rhsSelectable) = rhs { - if lhsTheme !== rhsTheme { - return false - } - if lhsStrings !== rhsStrings { - return false - } - if lhsDateTimeFormat != rhsDateTimeFormat { - return false - } - if lhsNameDisplayOrder != rhsNameDisplayOrder { - return false - } - if lhsIndex != rhsIndex { - return false - } - if lhsMemberStatus != rhsMemberStatus { - return false - } - if lhsPeerId != rhsPeerId { - return false - } - if !lhsPeer.isEqual(rhsPeer) { - return false - } - if lhsParticipant != rhsParticipant { - return false - } - if let lhsPresence = lhsPresence, let rhsPresence = rhsPresence { - if !lhsPresence.isEqual(to: rhsPresence) { - return false - } - } else if (lhsPresence != nil) != (rhsPresence != nil) { - return false - } - if lhsEditing != rhsEditing { - return false - } - if lhsActions != rhsActions { - return false - } - if lhsEnabled != rhsEnabled { - return false - } - if lhsSelectable != rhsSelectable { - return false - } - return true - } else { - return false - } - case let .expand(lhsTheme, lhsText): - if case let .expand(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { - return true - } else { - return false - } - } - } - - var stableId: GroupEntryStableId { - switch self { - case let .member(_, _, _, _, _, peerId, _, _, _, _, _, _, _, _): - return .peer(peerId) - default: - return .index(self.sortIndex) - } - } - - private var sortIndex: Int { - switch self { - case .info: - return 0 - case .setGroupPhoto: - return 1 - case .groupDescriptionSetup: - return 2 - case .about: - return 3 - case .locationHeader: - return 4 - case .location: - return 5 - case .changeLocation: - return 6 - case .link: - return 7 - case .groupTypeSetup: - return 8 - case .linkedChannelSetup: - return 9 - case .preHistory: - return 10 - case .stickerPack: - return 11 - case .notifications: - return 12 - case .sharedMedia: - return 13 - case .permissions: - return 14 - case .administrators: - return 15 - case .addMember: - return 16 - case let .member(_, _, _, _, index, _, _, _, _, _, _, _, _, _): - return 20 + index - case .expand: - return 200000 + 1 - case .leave: - return 200000 + 2 - } - } - - static func <(lhs: GroupInfoEntry, rhs: GroupInfoEntry) -> Bool { - return lhs.sortIndex < rhs.sortIndex - } - - func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem { - let arguments = arguments as! GroupInfoArguments - switch self { - case let .info(theme, strings, dateTimeFormat, peer, cachedData, state, updatingAvatar): - return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .generic, peer: peer, presence: nil, cachedData: cachedData, state: state, sectionId: self.section, style: .blocks(withTopInset: false, withExtendedBottomInset: false), editingNameUpdated: { editingName in - arguments.updateEditingName(editingName) - }, avatarTapped: { - arguments.tapAvatarAction() - }, context: arguments.avatarAndNameInfoContext, updatingImage: updatingAvatar) - case let .setGroupPhoto(theme, text): - return ItemListActionItem(presentationData: presentationData, title: text, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: { - arguments.changeProfilePhoto() - }) - case let .about(theme, text): - return ItemListMultilineTextItem(presentationData: presentationData, text: foldMultipleLineBreaks(text), enabledEntityTypes: [.allUrl, .mention, .hashtag], sectionId: self.section, style: .blocks, longTapAction: { - arguments.displayAboutContextMenu(text) - }, linkItemAction: { action, itemLink in - arguments.aboutLinkAction(action, itemLink) - }, tag: GroupInfoEntryTag.about) - case let .locationHeader(theme, text): - return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) - case let .location(theme, location): - let imageSignal = chatMapSnapshotImage(account: arguments.context.account, resource: MapSnapshotMediaResource(latitude: location.latitude, longitude: location.longitude, width: 90, height: 90)) - return ItemListAddressItem(theme: theme, label: "", text: location.address.replacingOccurrences(of: ", ", with: "\n"), imageSignal: imageSignal, selected: nil, sectionId: self.section, style: .blocks, action: { - arguments.openLocation(location) - }, longTapAction: { - arguments.displayLocationContextMenu(location.address.replacingOccurrences(of: "\n", with: ", ")) - }, tag: GroupInfoEntryTag.location) - case let .changeLocation(theme, text): - return ItemListActionItem(presentationData: presentationData, title: text, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: { - arguments.changeLocation() - }, clearHighlightAutomatically: false) - case let .link(theme, url): - return ItemListActionItem(presentationData: presentationData, title: url, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: { - arguments.displayUsernameShareMenu(url) - }, longTapAction: { - arguments.displayUsernameContextMenu(url) - }, tag: GroupInfoEntryTag.link) - case let .notifications(theme, title, text): - return ItemListDisclosureItem(presentationData: presentationData, title: title, label: text, sectionId: self.section, style: .blocks, action: { - arguments.changeNotificationMuteSettings() - }) - case let .stickerPack(theme, title, value): - return ItemListDisclosureItem(presentationData: presentationData, title: title, label: value, sectionId: self.section, style: .blocks, action: { - arguments.openStickerPackSetup() - }) - case let .preHistory(theme, title, value): - return ItemListDisclosureItem(presentationData: presentationData, title: title, label: value, sectionId: self.section, style: .blocks, action: { - arguments.openPreHistory() - }) - case let .sharedMedia(theme, title): - return ItemListDisclosureItem(presentationData: presentationData, title: title, label: "", sectionId: self.section, style: .blocks, action: { - arguments.openSharedMedia() - }) - case let .addMember(theme, title, editing): - return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.addPersonIcon(theme), title: title, sectionId: self.section, editing: editing, action: { - arguments.addMember() - }) - case let .groupTypeSetup(theme, title, text): - return ItemListDisclosureItem(presentationData: presentationData, title: title, label: text, sectionId: self.section, style: .blocks, action: { - arguments.openGroupTypeSetup() - }) - case let .linkedChannelSetup(theme, title, text): - return ItemListDisclosureItem(presentationData: presentationData, title: title, label: text, sectionId: self.section, style: .blocks, action: { - arguments.openLinkedChannelSetup() - }) - case let .groupDescriptionSetup(theme, placeholder, text): - return ItemListMultilineInputItem(presentationData: presentationData, text: text, placeholder: placeholder, maxLength: ItemListMultilineInputItemTextLimit(value: 255, display: true), sectionId: self.section, style: .blocks, textUpdated: { updatedText in - arguments.updateEditingDescriptionText(updatedText) - }) - case let .permissions(theme, title, text): - return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesChat.groupInfoPermissionsIcon(theme), title: title, label: text, sectionId: self.section, style: .blocks, action: { - arguments.openPermissions() - }) - case let .administrators(theme, title, text): - return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesChat.groupInfoAdminsIcon(theme), title: title, label: text, sectionId: self.section, style: .blocks, action: { - arguments.openAdministrators() - }) - case let .member(theme, strings, dateTimeFormat, nameDisplayOrder, _, _, peer, participant, presence, memberStatus, editing, actions, enabled, selectable): - let label: String? - switch memberStatus { - case let .owner(rank): - label = rank?.trimmingEmojis ?? strings.GroupInfo_LabelOwner - case let .admin(rank): - label = rank?.trimmingEmojis ?? strings.GroupInfo_LabelAdmin - case .member: - label = nil - } - var options: [ItemListPeerItemRevealOption] = [] - for action in actions { - options.append(ItemListPeerItemRevealOption(type: action.type, title: action.title, action: { - switch action.action { - case .promote: - if let participant = participant { - arguments.promotePeer(participant) - } - case .restrict: - if let participant = participant { - arguments.restrictPeer(participant) - } - case .remove: - arguments.removePeer(peer.id) - } - })) - } - 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, fromChat: false), selectable { - arguments.pushController(infoController) - } - }, setPeerIdWithRevealedOptions: { peerId, fromPeerId in - arguments.setPeerIdWithRevealedOptions(peerId, fromPeerId) - }, removePeer: { peerId in - arguments.removePeer(peerId) - }) - case let .expand(theme, title): - return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.downArrowImage(theme), title: title, sectionId: self.section, editing: false, action: { - arguments.expandParticipants() - }) - case let .leave(theme, title): - return ItemListActionItem(presentationData: presentationData, title: title, kind: .destructive, alignment: .center, sectionId: self.section, style: .blocks, action: { - arguments.leave() - }) - default: - preconditionFailure() - } - } -} - -private struct TemporaryParticipant: Equatable { - let peer: Peer - let presence: PeerPresence? - let timestamp: Int32 - - static func ==(lhs: TemporaryParticipant, rhs: TemporaryParticipant) -> Bool { - if !lhs.peer.isEqual(rhs.peer) { - return false - } - if let lhsPresence = lhs.presence, let rhsPresence = rhs.presence { - if !lhsPresence.isEqual(to: rhsPresence) { - return false - } - } else if (lhs.presence != nil) != (rhs.presence != nil) { - return false - } - return true - } -} - -private struct GroupInfoState: Equatable { - let updatingAvatar: ItemListAvatarAndNameInfoItemUpdatingAvatar? - let editingState: GroupInfoEditingState? - let updatingName: ItemListAvatarAndNameInfoItemName? - let peerIdWithRevealedOptions: PeerId? - let expandedParticipants: Bool - - let temporaryParticipants: [TemporaryParticipant] - let successfullyAddedParticipantIds: Set - let removingParticipantIds: Set - - let savingData: Bool - - let searchingMembers: Bool - - static func ==(lhs: GroupInfoState, rhs: GroupInfoState) -> Bool { - if lhs.updatingAvatar != rhs.updatingAvatar { - return false - } - if lhs.editingState != rhs.editingState { - return false - } - if lhs.updatingName != rhs.updatingName { - return false - } - if lhs.peerIdWithRevealedOptions != rhs.peerIdWithRevealedOptions { - return false - } - if lhs.expandedParticipants != rhs.expandedParticipants { - return false - } - if lhs.temporaryParticipants != rhs.temporaryParticipants { - return false - } - if lhs.successfullyAddedParticipantIds != rhs.successfullyAddedParticipantIds { - return false - } - if lhs.removingParticipantIds != rhs.removingParticipantIds { - return false - } - if lhs.savingData != rhs.savingData { - return false - } - if lhs.searchingMembers != rhs.searchingMembers { - return false - } - return true - } - - func withUpdatedUpdatingAvatar(_ updatingAvatar: ItemListAvatarAndNameInfoItemUpdatingAvatar?) -> GroupInfoState { - return GroupInfoState(updatingAvatar: updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers) - } - - func withUpdatedEditingState(_ editingState: GroupInfoEditingState?) -> GroupInfoState { - return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers) - } - - func withUpdatedUpdatingName(_ updatingName: ItemListAvatarAndNameInfoItemName?) -> GroupInfoState { - return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers) - } - - func withUpdatedPeerIdWithRevealedOptions(_ peerIdWithRevealedOptions: PeerId?) -> GroupInfoState { - return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers) - } - - func withUpdatedExpandedParticipants(_ expandedParticipants: Bool) -> GroupInfoState { - return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers) - } - - func withUpdatedTemporaryParticipants(_ temporaryParticipants: [TemporaryParticipant]) -> GroupInfoState { - return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers) - } - - func withUpdatedSuccessfullyAddedParticipantIds(_ successfullyAddedParticipantIds: Set) -> GroupInfoState { - return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers) - } - - func withUpdatedRemovingParticipantIds(_ removingParticipantIds: Set) -> GroupInfoState { - return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: removingParticipantIds, savingData: self.savingData, searchingMembers: self.searchingMembers) - } - - func withUpdatedSavingData(_ savingData: Bool) -> GroupInfoState { - return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: savingData, searchingMembers: self.searchingMembers) - } - - func withUpdatedSearchingMembers(_ searchingMembers: Bool) -> GroupInfoState { - return GroupInfoState(updatingAvatar: self.updatingAvatar, editingState: self.editingState, updatingName: self.updatingName, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, expandedParticipants: self.expandedParticipants, temporaryParticipants: self.temporaryParticipants, successfullyAddedParticipantIds: self.successfullyAddedParticipantIds, removingParticipantIds: self.removingParticipantIds, savingData: self.savingData, searchingMembers: searchingMembers) - } -} - -private struct GroupInfoEditingState: Equatable { - let editingName: ItemListAvatarAndNameInfoItemName? - let editingDescriptionText: String - - func withUpdatedEditingDescriptionText(_ editingDescriptionText: String) -> GroupInfoEditingState { - return GroupInfoEditingState(editingName: self.editingName, editingDescriptionText: editingDescriptionText) - } - - static func ==(lhs: GroupInfoEditingState, rhs: GroupInfoEditingState) -> Bool { - if lhs.editingName != rhs.editingName { - return false - } - if lhs.editingDescriptionText != rhs.editingDescriptionText { - return false - } - return true - } -} - -private func canRemoveParticipant(account: Account, isAdmin: Bool, participantId: PeerId, invitedBy: PeerId?) -> Bool { - if participantId == account.peerId { - return false - } - - if account.peerId == invitedBy { - return true - } - - return isAdmin -} - -private func canRemoveParticipant(account: Account, channel: TelegramChannel, participant: ChannelParticipant) -> Bool { - if participant.peerId == account.peerId { - return false - } - - if channel.flags.contains(.isCreator) { - return true - } - - switch participant { - case .creator: - return false - case let .member(_, _, adminInfo, _, _): - if channel.hasPermission(.banMembers) { - if let adminInfo = adminInfo { - return adminInfo.promotedBy == account.peerId - } else { - return false - } - } else { - return false - } - } -} - - -private func groupInfoEntries(account: Account, presentationData: PresentationData, view: PeerView, channelMembers: [RenderedChannelParticipant], globalNotificationSettings: GlobalNotificationSettings, state: GroupInfoState) -> [GroupInfoEntry] { - var entries: [GroupInfoEntry] = [] - - var canEditGroupInfo = false - var canEditMembers = false - var canAddMembers = false - var isPublic = false - var isCreator = false - if let group = view.peers[view.peerId] as? TelegramGroup { - 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 - } - } else if let channel = view.peers[view.peerId] as? TelegramChannel { - isPublic = channel.username != nil - if !isPublic, let cachedChannelData = view.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 - } - } - - if let peer = peerViewMainPeer(view) { - let infoState = ItemListAvatarAndNameInfoItemState(editingName: canEditGroupInfo ? state.editingState?.editingName : nil, updatingName: state.updatingName) - entries.append(.info(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, peer: peer, cachedData: view.cachedData, state: infoState, updatingAvatar: state.updatingAvatar)) - } - - let peerNotificationSettings: TelegramPeerNotificationSettings = (view.notificationSettings as? TelegramPeerNotificationSettings) ?? TelegramPeerNotificationSettings.defaultSettings - let notificationsText: String - - if case let .muted(until) = peerNotificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) { - if until < Int32.max - 1 { - notificationsText = stringForRemainingMuteInterval(strings: presentationData.strings, muteInterval: until) - } else { - notificationsText = presentationData.strings.UserInfo_NotificationsDisabled - } - } else if case .default = peerNotificationSettings.messageSound { - notificationsText = presentationData.strings.UserInfo_NotificationsEnabled - } else { - notificationsText = localizedPeerNotificationSoundString(strings: presentationData.strings, sound: peerNotificationSettings.messageSound, default: globalNotificationSettings.effective.channels.sound) - } - - if let editingState = state.editingState { - if canEditGroupInfo { - entries.append(GroupInfoEntry.setGroupPhoto(presentationData.theme, presentationData.strings.GroupInfo_SetGroupPhoto)) - - entries.append(GroupInfoEntry.groupDescriptionSetup(presentationData.theme, presentationData.strings.Channel_About_Placeholder, editingState.editingDescriptionText)) - } - - if let group = view.peers[view.peerId] as? TelegramGroup, let cachedGroupData = view.cachedData as? CachedGroupData { - if case .creator = group.role { - if cachedGroupData.flags.contains(.canChangeUsername) { - entries.append(GroupInfoEntry.groupTypeSetup(presentationData.theme, presentationData.strings.GroupInfo_GroupType, presentationData.strings.Channel_Setup_TypePrivate)) - } - entries.append(GroupInfoEntry.preHistory(presentationData.theme, presentationData.strings.GroupInfo_GroupHistory, presentationData.strings.GroupInfo_GroupHistoryHidden)) - - var activePermissionCount: Int? - if let defaultBannedRights = group.defaultBannedRights { - var count = 0 - for (right, _) in allGroupPermissionList { - if !defaultBannedRights.flags.contains(right) { - count += 1 - } - } - activePermissionCount = count - } - entries.append(GroupInfoEntry.permissions(presentationData.theme, presentationData.strings.GroupInfo_Permissions, activePermissionCount.flatMap({ "\($0)/\(allGroupPermissionList.count)" }) ?? "")) - entries.append(.administrators(presentationData.theme, presentationData.strings.GroupInfo_Administrators, "")) - } - } else if let channel = view.peers[view.peerId] as? TelegramChannel, let cachedChannelData = view.cachedData as? CachedChannelData { - if isCreator, let location = cachedChannelData.peerGeoLocation { - entries.append(.locationHeader(presentationData.theme, presentationData.strings.GroupInfo_Location.uppercased())) - entries.append(.location(presentationData.theme, location)) - if cachedChannelData.flags.contains(.canChangePeerGeoLocation) { - entries.append(.changeLocation(presentationData.theme, presentationData.strings.Group_Location_ChangeLocation)) - } - } - - if isCreator || (channel.adminRights != nil && channel.hasPermission(.pinMessages)) { - if cachedChannelData.peerGeoLocation != nil { - if isCreator { - entries.append(GroupInfoEntry.groupTypeSetup(presentationData.theme, presentationData.strings.GroupInfo_PublicLink, channel.addressName ?? presentationData.strings.GroupInfo_PublicLinkAdd)) - } - } else { - if cachedChannelData.flags.contains(.canChangeUsername) { - entries.append(GroupInfoEntry.groupTypeSetup(presentationData.theme, presentationData.strings.GroupInfo_GroupType, isPublic ? presentationData.strings.Channel_Setup_TypePublic : presentationData.strings.Channel_Setup_TypePrivate)) - if case let .known(maybeLinkedDiscussionPeerId) = cachedChannelData.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = view.peers[linkedDiscussionPeerId] { - let peerTitle: String - if let addressName = peer.addressName, !addressName.isEmpty { - peerTitle = "@\(addressName)" - } else { - peerTitle = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - } - entries.append(GroupInfoEntry.linkedChannelSetup(presentationData.theme, presentationData.strings.Group_LinkedChannel, peerTitle)) - } - } - if !isPublic && cachedChannelData.linkedDiscussionPeerId == nil { - entries.append(GroupInfoEntry.preHistory(presentationData.theme, presentationData.strings.GroupInfo_GroupHistory, cachedChannelData.flags.contains(.preHistoryEnabled) ? presentationData.strings.GroupInfo_GroupHistoryVisible : presentationData.strings.GroupInfo_GroupHistoryHidden)) - } - } - } - - if cachedChannelData.flags.contains(.canSetStickerSet) && canEditGroupInfo { - entries.append(GroupInfoEntry.stickerPack(presentationData.theme, presentationData.strings.Stickers_GroupStickers, cachedChannelData.stickerPack?.title ?? presentationData.strings.GroupInfo_SharedMediaNone)) - } - - var canViewAdminsAndBanned = false - if let channel = view.peers[view.peerId] as? TelegramChannel { - 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 - } - - entries.append(GroupInfoEntry.permissions(presentationData.theme, presentationData.strings.GroupInfo_Permissions, activePermissionCount.flatMap({ "\($0)/\(allGroupPermissionList.count)" }) ?? "")) - entries.append(GroupInfoEntry.administrators(presentationData.theme, presentationData.strings.GroupInfo_Administrators, cachedChannelData.participantsSummary.adminCount.flatMap { "\(presentationStringsFormattedNumber($0, presentationData.dateTimeFormat.groupingSeparator))" } ?? "")) - } - } - } else { - if let peer = peerViewMainPeer(view), peer.isScam { - entries.append(.about(presentationData.theme, presentationData.strings.GroupInfo_ScamGroupWarning)) - } - else if let cachedChannelData = view.cachedData as? CachedChannelData { - if let about = cachedChannelData.about, !about.isEmpty { - entries.append(.about(presentationData.theme, about)) - } - if let peer = view.peers[view.peerId] as? TelegramChannel { - if let location = cachedChannelData.peerGeoLocation { - entries.append(.locationHeader(presentationData.theme, presentationData.strings.GroupInfo_Location.uppercased())) - entries.append(.location(presentationData.theme, location)) - } - if let username = peer.username, !username.isEmpty { - entries.append(.link(presentationData.theme, "t.me/" + username)) - } - } - } else if let cachedGroupData = view.cachedData as? CachedGroupData { - if let about = cachedGroupData.about, !about.isEmpty { - entries.append(.about(presentationData.theme, about)) - } - } - - entries.append(GroupInfoEntry.notifications(presentationData.theme, presentationData.strings.GroupInfo_Notifications, notificationsText)) - entries.append(GroupInfoEntry.sharedMedia(presentationData.theme, presentationData.strings.GroupInfo_SharedMedia)) - } - - var canRemoveAnyMember = false - if let cachedGroupData = view.cachedData as? CachedGroupData, let participants = cachedGroupData.participants { - for participant in participants.participants { - if canRemoveParticipant(account: account, isAdmin: canEditMembers, participantId: participant.peerId, invitedBy: participant.invitedBy) { - canRemoveAnyMember = true - break - } - } - } else if let channel = view.peers[view.peerId] as? TelegramChannel { - for participant in channelMembers { - if canRemoveParticipant(account: account, channel: channel, participant: participant.participant) { - canRemoveAnyMember = true - break - } - } - } - - if canAddMembers { - entries.append(GroupInfoEntry.addMember(presentationData.theme, presentationData.strings.GroupInfo_AddParticipant, editing: state.editingState != nil && canRemoveAnyMember)) - } - - if let group = view.peers[view.peerId] as? TelegramGroup, let cachedGroupData = view.cachedData as? CachedGroupData, let participants = cachedGroupData.participants { - var updatedParticipants = participants.participants - let existingParticipantIds = Set(updatedParticipants.map { $0.peerId }) - - var peerPresences: [PeerId: PeerPresence] = view.peerPresences - var peers: [PeerId: Peer] = view.peers - var disabledPeerIds = state.removingParticipantIds - - if !state.temporaryParticipants.isEmpty { - for participant in state.temporaryParticipants { - if !existingParticipantIds.contains(participant.peer.id) { - updatedParticipants.append(.member(id: participant.peer.id, invitedBy: account.peerId, invitedAt: participant.timestamp)) - if let presence = participant.presence, peerPresences[participant.peer.id] == nil { - peerPresences[participant.peer.id] = presence - } - if peers[participant.peer.id] == nil { - peers[participant.peer.id] = participant.peer - } - disabledPeerIds.insert(participant.peer.id) - } - } - } - - let sortedParticipants = updatedParticipants.sorted(by: { lhs, rhs in - let lhsPresence = peerPresences[lhs.peerId] as? TelegramUserPresence - let rhsPresence = peerPresences[rhs.peerId] as? TelegramUserPresence - 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 - } - - switch lhs { - case .creator: - return false - case let .admin(lhsId, _, lhsInvitedAt): - switch rhs { - case .creator: - return true - case let .admin(rhsId, _, rhsInvitedAt): - if lhsInvitedAt == rhsInvitedAt { - return lhsId.id < rhsId.id - } - return lhsInvitedAt > rhsInvitedAt - case let .member(rhsId, _, rhsInvitedAt): - if lhsInvitedAt == rhsInvitedAt { - return lhsId.id < rhsId.id - } - return lhsInvitedAt > rhsInvitedAt - } - case let .member(lhsId, _, lhsInvitedAt): - switch rhs { - case .creator: - return true - case let .admin(rhsId, _, rhsInvitedAt): - if lhsInvitedAt == rhsInvitedAt { - return lhsId.id < rhsId.id - } - return lhsInvitedAt > rhsInvitedAt - case let .member(rhsId, _, rhsInvitedAt): - if lhsInvitedAt == rhsInvitedAt { - return lhsId.id < rhsId.id - } - return lhsInvitedAt > rhsInvitedAt - } - } - }) - - for i in 0 ..< sortedParticipants.count { - if let peer = peers[sortedParticipants[i].peerId] { - let memberStatus: GroupInfoMemberStatus - let participant: ChannelParticipant - switch sortedParticipants[i] { - case .creator: - participant = .creator(id: sortedParticipants[i].peerId, adminInfo: nil, rank: nil) - memberStatus = .owner(rank: nil) - case .admin: - participant = .member(id: sortedParticipants[i].peerId, invitedAt: 0, adminInfo: ChannelParticipantAdminInfo(rights: TelegramChatAdminRights(flags: .groupSpecific), promotedBy: account.peerId, canBeEditedByAccountPeer: true), banInfo: nil, rank: nil) - memberStatus = .admin(rank: nil) - case .member: - participant = .member(id: sortedParticipants[i].peerId, invitedAt: 0, adminInfo: nil, banInfo: nil, rank: nil) - memberStatus = .member - } - - var canPromote: Bool - var canRestrict: Bool - if sortedParticipants[i].peerId == account.peerId { - canPromote = false - canRestrict = false - } else { - switch group.role { - case .creator: - canPromote = true - canRestrict = true - case .member: - canPromote = false - switch sortedParticipants[i] { - case .creator, .admin: - canPromote = false - canRestrict = false - case let .member(member): - if member.invitedBy == account.peerId { - canRestrict = true - } else { - canRestrict = false - } - } - case .admin: - switch sortedParticipants[i] { - case .creator, .admin: - canPromote = false - canRestrict = false - case .member: - canPromote = false - canRestrict = true - } - } - } - - var peerActions: [ParticipantRevealAction] = [] - if canPromote { - peerActions.append(ParticipantRevealAction(type: .neutral, title: presentationData.strings.GroupInfo_ActionPromote, action: .promote)) - } - if canRestrict { - peerActions.append(ParticipantRevealAction(type: .warning, title: presentationData.strings.GroupInfo_ActionRestrict, action: .restrict)) - peerActions.append(ParticipantRevealAction(type: .destructive, title: presentationData.strings.Common_Delete, action: .remove)) - } - - entries.append(GroupInfoEntry.member(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, index: i, peerId: peer.id, peer: peer, participant: RenderedChannelParticipant(participant: participant, peer: peer), presence: peerPresences[peer.id], memberStatus: memberStatus, editing: ItemListPeerItemEditing(editable: canRemoveParticipant(account: account, isAdmin: canEditMembers, participantId: peer.id, invitedBy: sortedParticipants[i].invitedBy), editing: state.editingState != nil && canRemoveAnyMember, revealed: state.peerIdWithRevealedOptions == peer.id), revealActions: peerActions, enabled: !disabledPeerIds.contains(peer.id), selectable: peer.id != account.peerId)) - } - } - } else if let channel = view.peers[view.peerId] as? TelegramChannel, let cachedChannelData = view.cachedData as? CachedChannelData, let memberCount = cachedChannelData.participantsSummary.memberCount { - var updatedParticipants = channelMembers - let existingParticipantIds = Set(updatedParticipants.map { $0.peer.id }) - - var peerPresences: [PeerId: PeerPresence] = view.peerPresences - var peers: [PeerId: Peer] = view.peers - - if !state.temporaryParticipants.isEmpty { - for participant in state.temporaryParticipants { - if !existingParticipantIds.contains(participant.peer.id) { - updatedParticipants.append(RenderedChannelParticipant(participant: ChannelParticipant.member(id: participant.peer.id, invitedAt: participant.timestamp, adminInfo: nil, banInfo: nil, rank: nil), peer: participant.peer)) - if let presence = participant.presence, peerPresences[participant.peer.id] == nil { - peerPresences[participant.peer.id] = presence - } - if peers[participant.peer.id] == nil { - peers[participant.peer.id] = participant.peer - } - //disabledPeerIds.insert(participant.peer.id) - } - } - } - - let sortedParticipants: [RenderedChannelParticipant] - if memberCount < 200 { - sortedParticipants = updatedParticipants.sorted(by: { lhs, rhs in - let lhsPresence = lhs.presences[lhs.peer.id] as? TelegramUserPresence - let rhsPresence = rhs.presences[rhs.peer.id] as? TelegramUserPresence - 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 - } - - switch lhs.participant { - case .creator: - return false - case let .member(lhsId, lhsInvitedAt, _, _, _): - switch rhs.participant { - case .creator: - return true - case let .member(rhsId, rhsInvitedAt, _, _, _): - if lhsInvitedAt == rhsInvitedAt { - return lhsId.id < rhsId.id - } - return lhsInvitedAt > rhsInvitedAt - } - } - }) - } else { - sortedParticipants = updatedParticipants - } - - var expanded = state.expandedParticipants - let participants: [RenderedChannelParticipant] - if expanded { - participants = sortedParticipants - } else { - if sortedParticipants.count > maxParticipantsDisplayedCollapseLimit { - participants = Array(sortedParticipants.prefix(Int(maxParticipantsDisplayedLimit))) - } else { - participants = sortedParticipants - expanded = true - } - } - - for i in 0 ..< participants.count { - let participant = participants[i] - let memberStatus: GroupInfoMemberStatus - switch participant.participant { - case let .creator(_, _, rank): - memberStatus = .owner(rank: rank) - case let .member(_, _, adminInfo, _, rank): - if adminInfo != nil { - memberStatus = .admin(rank: rank) - } else { - memberStatus = .member - } - } - - var canPromote: Bool - var canRestrict: Bool - if participant.peer.id == account.peerId { - canPromote = false - canRestrict = false - } else { - switch participant.participant { - case .creator: - canPromote = false - canRestrict = false - case let .member(_, _, adminRights, bannedRights, _): - if channel.hasPermission(.addAdmins) { - canPromote = true - } else { - canPromote = false - } - if channel.hasPermission(.banMembers) { - canRestrict = true - } else { - canRestrict = false - } - if canPromote { - if let bannedRights = bannedRights { - if bannedRights.restrictedBy != account.peerId && !channel.flags.contains(.isCreator) { - canPromote = false - } - } - } - if canRestrict { - if let adminRights = adminRights { - if adminRights.promotedBy != account.peerId && !channel.flags.contains(.isCreator) { - canRestrict = false - } - } - } - } - } - - var peerActions: [ParticipantRevealAction] = [] - if canPromote { - peerActions.append(ParticipantRevealAction(type: .neutral, title: presentationData.strings.GroupInfo_ActionPromote, action: .promote)) - } - if canRestrict { - peerActions.append(ParticipantRevealAction(type: .warning, title: presentationData.strings.GroupInfo_ActionRestrict, action: .restrict)) - peerActions.append(ParticipantRevealAction(type: .destructive, title: presentationData.strings.Common_Delete, action: .remove)) - } - - entries.append(GroupInfoEntry.member(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, index: i, peerId: participant.peer.id, peer: participant.peer, participant: participant, presence: participant.presences[participant.peer.id], memberStatus: memberStatus, editing: ItemListPeerItemEditing(editable: !peerActions.isEmpty, editing: state.editingState != nil && canRemoveAnyMember, revealed: state.peerIdWithRevealedOptions == participant.peer.id), revealActions: peerActions, enabled: true, selectable: participant.peer.id != account.peerId)) - } - - if !expanded { - entries.append(GroupInfoEntry.expand(presentationData.theme, presentationData.strings.GroupInfo_ShowMoreMembers(Int32(memberCount - maxParticipantsDisplayedLimit)))) - } - } - - if let group = view.peers[view.peerId] as? TelegramGroup { - if case .Member = group.membership { - entries.append(.leave(presentationData.theme, presentationData.strings.Group_LeaveGroup)) - } - } else if let channel = view.peers[view.peerId] as? TelegramChannel { - if case .member = channel.participationStatus { - if channel.flags.contains(.isCreator) { - if let cachedChannelData = view.cachedData as? CachedChannelData, let memberCount = cachedChannelData.participantsSummary.memberCount, memberCount <= 200 { - if state.editingState != nil { - entries.append(.leave(presentationData.theme, presentationData.strings.ChannelInfo_DeleteGroup)) - } else { - entries.append(.leave(presentationData.theme, presentationData.strings.Group_LeaveGroup)) - } - } - } else { - entries.append(.leave(presentationData.theme, presentationData.strings.Group_LeaveGroup)) - } - } - } - - return entries -} - -private func valuesRequiringUpdate(state: GroupInfoState, view: PeerView) -> (title: String?, description: String?) { - if let peer = view.peers[view.peerId] as? TelegramGroup { - var titleValue: String? - var descriptionValue: String? - if let editingState = state.editingState { - if let title = editingState.editingName?.composedTitle, title != peer.title { - titleValue = title - } - if let cachedData = view.cachedData as? CachedGroupData { - if let about = cachedData.about { - if about != editingState.editingDescriptionText { - descriptionValue = editingState.editingDescriptionText - } - } else if !editingState.editingDescriptionText.isEmpty { - descriptionValue = editingState.editingDescriptionText - } - } - } - return (titleValue, descriptionValue) - } else if let peer = view.peers[view.peerId] as? TelegramChannel { - var titleValue: String? - var descriptionValue: String? - if let editingState = state.editingState { - if let title = editingState.editingName?.composedTitle, title != peer.title { - titleValue = title - } - if let cachedData = view.cachedData as? CachedChannelData { - if let about = cachedData.about { - if about != editingState.editingDescriptionText { - descriptionValue = editingState.editingDescriptionText - } - } else if !editingState.editingDescriptionText.isEmpty { - descriptionValue = editingState.editingDescriptionText - } - } - } - return (titleValue, descriptionValue) - } else { - return (nil, nil) - } -} - -public func groupInfoController(context: AccountContext, peerId originalPeerId: PeerId, membersLoaded: @escaping () -> Void = {}) -> ViewController { - let statePromise = ValuePromise(GroupInfoState(updatingAvatar: nil, editingState: nil, updatingName: nil, peerIdWithRevealedOptions: nil, expandedParticipants: false, temporaryParticipants: [], successfullyAddedParticipantIds: Set(), removingParticipantIds: Set(), savingData: false, searchingMembers: false), ignoreRepeated: true) - let stateValue = Atomic(value: GroupInfoState(updatingAvatar: nil, editingState: nil, updatingName: nil, peerIdWithRevealedOptions: nil, expandedParticipants: false, temporaryParticipants: [], successfullyAddedParticipantIds: Set(), removingParticipantIds: Set(), savingData: false, searchingMembers: false)) - let updateState: ((GroupInfoState) -> GroupInfoState) -> Void = { f in - statePromise.set(stateValue.modify { f($0) }) - } - - var pushControllerImpl: ((ViewController) -> Void)? - var presentControllerImpl: ((ViewController, Any?) -> Void)? - var replaceControllerImpl: ((ViewController?, ViewController) -> Void)? - var endEditingImpl: (() -> Void)? - var removePeerChatImpl: ((Peer, Bool) -> Void)? - var errorImpl: (() -> Void)? - var clearHighlightImpl: (() -> Void)? - var dismissInputImpl: (() -> Void)? - - let actionsDisposable = DisposableSet() - - let updatePeerNameDisposable = MetaDisposable() - actionsDisposable.add(updatePeerNameDisposable) - - let updatePeerDescriptionDisposable = MetaDisposable() - actionsDisposable.add(updatePeerDescriptionDisposable) - - let addMemberDisposable = MetaDisposable() - actionsDisposable.add(addMemberDisposable) - let selectAddMemberDisposable = MetaDisposable() - actionsDisposable.add(selectAddMemberDisposable) - - let removeMemberDisposable = MetaDisposable() - actionsDisposable.add(removeMemberDisposable) - - let changeMuteSettingsDisposable = MetaDisposable() - actionsDisposable.add(changeMuteSettingsDisposable) - - let hiddenAvatarRepresentationDisposable = MetaDisposable() - actionsDisposable.add(hiddenAvatarRepresentationDisposable) - - let updateAvatarDisposable = MetaDisposable() - actionsDisposable.add(updateAvatarDisposable) - let currentAvatarMixin = Atomic(value: nil) - - let navigateDisposable = MetaDisposable() - actionsDisposable.add(navigateDisposable) - - let upgradeDisposable = MetaDisposable() - actionsDisposable.add(upgradeDisposable) - - var avatarGalleryTransitionArguments: ((AvatarGalleryEntry) -> GalleryTransitionArguments?)? - let avatarAndNameInfoContext = ItemListAvatarAndNameInfoItemContext() - var updateHiddenAvatarImpl: (() -> Void)? - - var displayCopyContextMenuImpl: ((String, GroupInfoEntryTag) -> Void)? - var aboutLinkActionImpl: ((TextLinkItemActionType, TextLinkItem) -> Void)? - - var upgradedToSupergroupImpl: ((PeerId, @escaping () -> Void) -> Void)? - - let actualPeerId = Promise() - actualPeerId.set(context.account.viewTracker.peerView(originalPeerId) - |> map { peerView -> PeerId in - if let peer = peerView.peers[peerView.peerId] as? TelegramGroup, let migrationReference = peer.migrationReference { - return migrationReference.peerId - } else { - return originalPeerId - } - } - |> distinctUntilChanged) - - let peerView = Promise() - let peerViewSignal = actualPeerId.get() - |> distinctUntilChanged - |> mapToSignal { peerId -> Signal in - return context.account.viewTracker.peerView(peerId, updateData: true) - } - peerView.set(peerViewSignal) - - let arguments = GroupInfoArguments(context: context, avatarAndNameInfoContext: avatarAndNameInfoContext, tapAvatarAction: { - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { peerView in - guard let peer = peerView.peers[peerView.peerId] else { - return - } - if peer.profileImageRepresentations.isEmpty { - return - } - - let galleryController = AvatarGalleryController(context: context, peer: peer, replaceRootController: { controller, ready in - - }) - hiddenAvatarRepresentationDisposable.set((galleryController.hiddenMedia |> deliverOnMainQueue).start(next: { entry in - avatarAndNameInfoContext.hiddenAvatarRepresentation = entry?.representations.first?.representation - updateHiddenAvatarImpl?() - })) - presentControllerImpl?(galleryController, AvatarGalleryControllerPresentationArguments(transitionArguments: { entry in - return avatarGalleryTransitionArguments?(entry) - })) - }) - }, changeProfilePhoto: { - endEditingImpl?() - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { peerView in - let _ = (context.account.postbox.transaction { transaction -> (Peer?, SearchBotsConfiguration) in - return (transaction.getPeer(peerView.peerId), currentSearchBotsConfiguration(transaction: transaction)) - } |> deliverOnMainQueue).start(next: { peer, searchBotsConfiguration in - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - - 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) - - presentControllerImpl?(legacyController, nil) - - var hasPhotos = false - if let peer = peer, !peer.profileImageRepresentations.isEmpty { - hasPhotos = true - } - - let completedImpl: (UIImage) -> Void = { image in - if let data = image.jpegData(compressionQuality: 0.6) { - let resource = LocalFileMediaResource(fileId: arc4random64()) - context.account.postbox.mediaBox.storeResourceData(resource.id, data: data) - let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: resource, progressiveSizes: []) - updateState { - $0.withUpdatedUpdatingAvatar(.image(representation, true)) - } - updateAvatarDisposable.set((updatePeerPhoto(postbox: context.account.postbox, network: context.account.network, stateManager: context.account.stateManager, accountPeerId: context.account.peerId, peerId: peerView.peerId, photo: uploadedPeerPhoto(postbox: context.account.postbox, network: context.account.network, resource: resource), mapResourceToAvatarSizes: { resource, representations in - return mapResourceToAvatarSizes(postbox: context.account.postbox, resource: resource, representations: representations) - }) |> deliverOnMainQueue).start(next: { result in - switch result { - case .complete: - updateState { - $0.withUpdatedUpdatingAvatar(nil) - } - case .progress: - break - } - })) - } - } - - let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasSearchButton: true, hasDeleteButton: hasPhotos, hasViewButton: false, personalPhoto: false, isVideo: false, saveEditedPhotos: false, saveCapturedMedia: false, signup: true)! - let _ = currentAvatarMixin.swap(mixin) - mixin.requestSearchController = { assetsController in - let controller = WebSearchController(context: context, peer: peer, chatLocation: nil, configuration: searchBotsConfiguration, mode: .avatar(initialQuery: peer?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), completion: { result in - assetsController?.dismiss() - completedImpl(result) - })) - presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) - } - mixin.didFinishWithImage = { image in - if let image = image { - completedImpl(image) - } - } - mixin.didFinishWithDelete = { - let _ = currentAvatarMixin.swap(nil) - updateState { - if let profileImage = peer?.smallProfileImage { - return $0.withUpdatedUpdatingAvatar(.image(profileImage, false)) - } else { - return $0.withUpdatedUpdatingAvatar(.none) - } - } - updateAvatarDisposable.set((updatePeerPhoto(postbox: context.account.postbox, network: context.account.network, stateManager: context.account.stateManager, accountPeerId: context.account.peerId, peerId: peerView.peerId, photo: nil, mapResourceToAvatarSizes: { resource, representations in - return mapResourceToAvatarSizes(postbox: context.account.postbox, resource: resource, representations: representations) - }) |> deliverOnMainQueue).start(next: { result in - switch result { - case .complete: - updateState { - $0.withUpdatedUpdatingAvatar(nil) - } - case .progress: - break - } - })) - } - mixin.didDismiss = { [weak legacyController] in - let _ = currentAvatarMixin.swap(nil) - legacyController?.dismiss() - } - let menuController = mixin.present() - if let menuController = menuController { - menuController.customRemoveFromParentViewController = { [weak legacyController] in - legacyController?.dismiss() - } - } - }) - }) - }, pushController: { controller in - pushControllerImpl?(controller) - }, presentController: { controller, presentationArguments in - presentControllerImpl?(controller, presentationArguments) - }, changeNotificationMuteSettings: { - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { peerView in - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - let _ = (context.account.postbox.transaction { transaction -> (TelegramPeerNotificationSettings, GlobalNotificationSettings) in - let peerSettings: TelegramPeerNotificationSettings = (transaction.getPeerNotificationSettings(peerView.peerId) as? TelegramPeerNotificationSettings) ?? TelegramPeerNotificationSettings.defaultSettings - let globalSettings: GlobalNotificationSettings = (transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications) as? GlobalNotificationSettings) ?? GlobalNotificationSettings.defaultSettings - return (peerSettings, globalSettings) - } - |> deliverOnMainQueue).start(next: { peerSettings, globalSettings in - let soundSettings: NotificationSoundSettings? - if case .default = peerSettings.messageSound { - soundSettings = NotificationSoundSettings(value: nil) - } else { - soundSettings = NotificationSoundSettings(value: peerSettings.messageSound) - } - let controller = notificationMuteSettingsController(presentationData: presentationData, notificationSettings: globalSettings.effective.groupChats, soundSettings: soundSettings, openSoundSettings: { - let controller = notificationSoundSelectionController(context: context, isModal: true, currentSound: peerSettings.messageSound, defaultSound: globalSettings.effective.groupChats.sound, completion: { sound in - let _ = updatePeerNotificationSoundInteractive(account: context.account, peerId: peerView.peerId, sound: sound).start() - }) - presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) - }, updateSettings: { value in - changeMuteSettingsDisposable.set(updatePeerMuteSetting(account: context.account, peerId: peerView.peerId, muteInterval: value).start()) - }) - presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) - }) - }) - }, openPreHistory: { - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { peerView in - presentControllerImpl?(groupPreHistorySetupController(context: context, peerId: peerView.peerId, upgradedToSupergroup: { peerId, f in - upgradedToSupergroupImpl?(peerId, f) - }), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) - }) - }, openSharedMedia: { - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { peerView in - if let controller = context.sharedContext.makePeerSharedMediaController(context: context, peerId: peerView.peerId) { - pushControllerImpl?(controller) - } - }) - }, openAdministrators: { - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { peerView in - pushControllerImpl?(channelAdminsController(context: context, peerId: peerView.peerId)) - }) - }, openPermissions: { - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { peerView in - pushControllerImpl?(channelPermissionsController(context: context, peerId: peerView.peerId)) - }) - }, updateEditingName: { editingName in - updateState { state in - if let editingState = state.editingState { - return state.withUpdatedEditingState(GroupInfoEditingState(editingName: editingName, editingDescriptionText: editingState.editingDescriptionText)) - } else { - return state - } - } - }, updateEditingDescriptionText: { text in - updateState { state in - if let editingState = state.editingState { - return state.withUpdatedEditingState(editingState.withUpdatedEditingDescriptionText(text)) - } - return state - } - }, setPeerIdWithRevealedOptions: { peerId, fromPeerId in - updateState { state in - if (peerId == nil && fromPeerId == state.peerIdWithRevealedOptions) || (peerId != nil && fromPeerId == nil) { - return state.withUpdatedPeerIdWithRevealedOptions(peerId) - } else { - return state - } - } - }, addMember: { - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { peerView in - let members: Promise<[PeerId]> = Promise() - if peerView.peerId.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 - } else { - members.set(.single([])) - } - - let _ = (combineLatest(queue: .mainQueue(), context.account.postbox.loadedPeerWithId(peerView.peerId) - |> deliverOnMainQueue, members.get() |> take(1) |> deliverOnMainQueue)).start(next: { groupPeer, recentIds in - var confirmationImpl: ((PeerId) -> Signal)? - var options: [ContactListAdditionalOption] = [] - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - var inviteByLinkImpl: (() -> Void)? - - 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: { - inviteByLinkImpl?() - })) - } - - let contactsController: ViewController - if peerView.peerId.namespace == Namespaces.Peer.CloudGroup { - contactsController = context.sharedContext.makeContactSelectionController(ContactSelectionControllerParams(context: 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) - } - })) - } else { - contactsController = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .peerSelection(searchChatList: false, searchGroups: false, searchChannels: false), options: options, filters: [.excludeSelf, .disable(recentIds)])) - } - - 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 peerView.peerId.namespace == Namespaces.Peer.CloudChannel { - return context.peerChannelMemberCategoriesContextsManager.addMember(account: context.account, peerId: peerView.peerId, memberId: memberId) - |> map { _ -> Void in - return Void() - } - |> `catch` { _ -> Signal in - return .complete() - } - } - - if let peer = peerView.peers[memberId] { - updateState { state in - var found = false - for participant in state.temporaryParticipants { - if participant.peer.id == memberId { - found = true - break - } - } - if !found { - let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) - var temporaryParticipants = state.temporaryParticipants - temporaryParticipants.append(TemporaryParticipant(peer: peer, presence: peerView.peerPresences[memberId], timestamp: timestamp)) - return state.withUpdatedTemporaryParticipants(temporaryParticipants) - } else { - return state - } - } - } - - return addGroupMember(account: context.account, peerId: peerView.peerId, memberId: memberId) - |> deliverOnMainQueue - |> afterCompleted { - updateState { state in - var successfullyAddedParticipantIds = state.successfullyAddedParticipantIds - successfullyAddedParticipantIds.insert(memberId) - - return state.withUpdatedSuccessfullyAddedParticipantIds(successfullyAddedParticipantIds) - } - } - |> `catch` { error -> Signal in - switch error { - case .generic: - updateState { state in - var temporaryParticipants = state.temporaryParticipants - for i in 0 ..< temporaryParticipants.count { - if temporaryParticipants[i].peer.id == memberId { - temporaryParticipants.remove(at: i) - break - } - } - var successfullyAddedParticipantIds = state.successfullyAddedParticipantIds - successfullyAddedParticipantIds.remove(memberId) - - return state.withUpdatedTemporaryParticipants(temporaryParticipants).withUpdatedSuccessfullyAddedParticipantIds(successfullyAddedParticipantIds) - } - return .complete() - case .privacy, .notMutualContact: - let _ = (context.account.postbox.loadedPeerWithId(memberId) - |> deliverOnMainQueue).start(next: { peer in - presentControllerImpl?(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: {})]), nil) - }) - - updateState { state in - var temporaryParticipants = state.temporaryParticipants - for i in 0 ..< temporaryParticipants.count { - if temporaryParticipants[i].peer.id == memberId { - temporaryParticipants.remove(at: i) - break - } - } - var successfullyAddedParticipantIds = state.successfullyAddedParticipantIds - successfullyAddedParticipantIds.remove(memberId) - - return state.withUpdatedTemporaryParticipants(temporaryParticipants).withUpdatedSuccessfullyAddedParticipantIds(successfullyAddedParticipantIds) - } - return .complete() - case .tooManyChannels: - let _ = (context.account.postbox.loadedPeerWithId(memberId) - |> deliverOnMainQueue).start(next: { peer in - presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.Invite_ChannelsTooMuch, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), nil) - }) - - updateState { state in - var temporaryParticipants = state.temporaryParticipants - for i in 0 ..< temporaryParticipants.count { - if temporaryParticipants[i].peer.id == memberId { - temporaryParticipants.remove(at: i) - break - } - } - var successfullyAddedParticipantIds = state.successfullyAddedParticipantIds - successfullyAddedParticipantIds.remove(memberId) - - return state.withUpdatedTemporaryParticipants(temporaryParticipants).withUpdatedSuccessfullyAddedParticipantIds(successfullyAddedParticipantIds) - } - return .complete() - case .groupFull: - let signal = convertGroupToSupergroup(account: context.account, peerId: peerView.peerId) - |> map(Optional.init) - |> `catch` { error -> Signal in - switch error { - case .tooManyChannels: - Queue.mainQueue().async { - pushControllerImpl?(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 { upgradedPeerId -> Signal in - if let upgradedPeerId = upgradedPeerId { - upgradedToSupergroupImpl?(upgradedPeerId, {}) - } - 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: peerView.peerId, memberId: memberIds[0]) - |> map { _ -> Void in - return Void() - } - } else { - return context.peerChannelMemberCategoriesContextsManager.addMembers(account: context.account, peerId: peerView.peerId, memberIds: memberIds) |> map { _ in - updateState { state in - var state = state - for (memberId, peer) in view.peers { - var found = false - for participant in state.temporaryParticipants { - if participant.peer.id == memberId { - found = true - break - } - } - if !found { - let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) - var temporaryParticipants = state.temporaryParticipants - temporaryParticipants.append(TemporaryParticipant(peer: peer, presence: view.presences[memberId], timestamp: timestamp)) - state = state.withUpdatedTemporaryParticipants(temporaryParticipants) - } - } - - return state - } - } - } - } - } - - inviteByLinkImpl = { [weak contactsController] in - let mode: ChannelVisibilityControllerMode - if groupPeer.addressName != nil { - mode = .generic - } else { - mode = .privateLink - } - let controller = channelVisibilityController(context: context, peerId: peerView.peerId, mode: mode, upgradedToSupergroup: { updatedPeerId, f in - upgradedToSupergroupImpl?(updatedPeerId, f) - }) - controller.navigationPresentation = .modal - replaceControllerImpl?(contactsController, controller) - } - - presentControllerImpl?(contactsController, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) - 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] result in - var peers: [ContactListPeerId] = [] - if case let .result(peerIdsValue, _) = result { - peers = peerIdsValue - } - - 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 - presentControllerImpl?(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: {})]), nil) - }) - default: - break - } - } else if case .tooMuchJoined = error { - presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.Invite_ChannelsTooMuch, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), nil) - } - - contactsController?.dismiss() - },completed: { - contactsController?.dismiss() - })) - })) - contactsController.dismissed = { - selectAddMemberDisposable.set(nil) - addMemberDisposable.set(nil) - } - } - }) - }) - }, promotePeer: { participant in - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { peerView in - pushControllerImpl?(channelAdminController(context: context, peerId: peerView.peerId, adminId: participant.peer.id, initialParticipant: participant.participant, updated: { _ in - }, upgradedToSupergroup: { upgradedPeerId, f in - upgradedToSupergroupImpl?(upgradedPeerId, f) - }, transferedOwnership: { _ in })) - }) - }, restrictPeer: { participant in - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { peerView in - presentControllerImpl?(channelBannedMemberController(context: context, peerId: peerView.peerId, memberId: participant.peer.id, initialParticipant: participant.participant, updated: { _ in - }, upgradedToSupergroup: { upgradedPeerId, f in - upgradedToSupergroupImpl?(upgradedPeerId, f) - }), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) - }) - }, removePeer: { memberId in - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { peerView in - let signal = context.account.postbox.loadedPeerWithId(memberId) - |> deliverOnMainQueue - |> mapToSignal { peer -> Signal in - let result = ValuePromise() - result.set(true) - return result.get() - } - |> mapToSignal { value -> Signal in - if value { - updateState { state in - var temporaryParticipants = state.temporaryParticipants - for i in 0 ..< state.temporaryParticipants.count { - if state.temporaryParticipants[i].peer.id == memberId { - temporaryParticipants.remove(at: i) - break - } - } - var successfullyAddedParticipantIds = state.successfullyAddedParticipantIds - successfullyAddedParticipantIds.remove(memberId) - - var removingParticipantIds = state.removingParticipantIds - removingParticipantIds.insert(memberId) - - return state.withUpdatedTemporaryParticipants(temporaryParticipants).withUpdatedSuccessfullyAddedParticipantIds(successfullyAddedParticipantIds).withUpdatedRemovingParticipantIds(removingParticipantIds) - } - - if peerView.peerId.namespace == Namespaces.Peer.CloudChannel { - return context.peerChannelMemberCategoriesContextsManager.updateMemberBannedRights(account: context.account, peerId: peerView.peerId, memberId: memberId, bannedRights: TelegramChatBannedRights(flags: [.banReadMessages], untilDate: Int32.max)) - |> afterDisposed { - Queue.mainQueue().async { - updateState { state in - var removingParticipantIds = state.removingParticipantIds - removingParticipantIds.remove(memberId) - - return state.withUpdatedRemovingParticipantIds(removingParticipantIds) - } - } - } - } - - return removePeerMember(account: context.account, peerId: peerView.peerId, memberId: memberId) - |> deliverOnMainQueue - |> afterDisposed { - updateState { state in - var removingParticipantIds = state.removingParticipantIds - removingParticipantIds.remove(memberId) - - return state.withUpdatedRemovingParticipantIds(removingParticipantIds) - } - } - } else { - return .complete() - } - } - removeMemberDisposable.set(signal.start()) - }) - }, leave: { - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { peerView in - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - - if let channel = peerView.peers[peerView.peerId] as? TelegramChannel, channel.flags.contains(.isCreator), stateValue.with({ $0 }).editingState != nil { - let controller = ActionSheetController(presentationData: presentationData) - let dismissAction: () -> Void = { [weak controller] in - controller?.dismissAnimated() - } - - var items: [ActionSheetItem] = [] - items.append(ActionSheetTextItem(title: presentationData.strings.ChannelInfo_DeleteGroupConfirmation)) - items.append(ActionSheetButtonItem(title: presentationData.strings.ChannelInfo_DeleteGroup, color: .destructive, action: { - dismissAction() - removePeerChatImpl?(channel, true) - })) - controller.setItemGroups([ - ActionSheetItemGroup(items: items), - ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })]) - ]) - presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) - } else if let peer = peerView.peers[peerView.peerId] { - let controller = ActionSheetController(presentationData: presentationData) - let dismissAction: () -> Void = { [weak controller] in - controller?.dismissAnimated() - } - - var items: [ActionSheetItem] = [] - if peerView.peerId.namespace == Namespaces.Peer.CloudGroup { - items.append(ActionSheetTextItem(title: presentationData.strings.GroupInfo_DeleteAndExitConfirmation)) - } - items.append(ActionSheetButtonItem(title: presentationData.strings.Group_LeaveGroup, color: .destructive, action: { - dismissAction() - removePeerChatImpl?(peer, false) - })) - controller.setItemGroups([ - ActionSheetItemGroup(items: items), - ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })]) - ]) - presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) - } - }) - }, displayUsernameShareMenu: { text in - let shareController = ShareController(context: context, subject: .url(text)) - presentControllerImpl?(shareController, nil) - }, displayUsernameContextMenu: { text in - displayCopyContextMenuImpl?(text, .link) - }, displayAboutContextMenu: { text in - displayCopyContextMenuImpl?(text, .about) - }, aboutLinkAction: { action, itemLink in - aboutLinkActionImpl?(action, itemLink) - }, openStickerPackSetup: { - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { peerView in - let _ = (context.account.postbox.transaction { transaction -> StickerPackCollectionInfo? in - return (transaction.getPeerCachedData(peerId: peerView.peerId) as? CachedChannelData)?.stickerPack - } - |> deliverOnMainQueue).start(next: { stickerPack in - presentControllerImpl?(groupStickerPackSetupController(context: context, peerId: peerView.peerId, currentPackInfo: stickerPack), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) - }) - }) - }, openGroupTypeSetup: { - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { peerView in - presentControllerImpl?(channelVisibilityController(context: context, peerId: peerView.peerId, mode: .generic, upgradedToSupergroup: { updatedPeerId, f in - upgradedToSupergroupImpl?(updatedPeerId, f) - }), ViewControllerPresentationArguments(presentationAnimation: ViewControllerPresentationAnimation.modalSheet)) - }) - }, openLinkedChannelSetup: { - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { peerView in - pushControllerImpl?(channelDiscussionGroupSetupController(context: context, peerId: peerView.peerId)) - }) - }, openLocation: { location in - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { peerView in - guard let peer = peerView.peers[peerView.peerId] else { - return - } - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - let mapMedia = TelegramMediaMap(latitude: location.latitude, longitude: location.longitude, heading: nil, accuracyRadius: nil, geoPlace: nil, venue: MapVenue(title: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), address: location.address, provider: nil, id: nil, type: nil), liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil) - let controller = legacyLocationController(message: nil, mapMedia: mapMedia, context: context, openPeer: { _ in }, sendLiveLocation: { _, _ in }, stopLiveLocation: {}, openUrl: { url in - context.sharedContext.applicationBindings.openUrl(url) - }) - pushControllerImpl?(controller) - }) - }, changeLocation: { - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { peerView in - guard let peer = peerView.peers[peerView.peerId] else { - return - } - - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - let controller = legacyLocationPickerController(context: context, selfPeer: peer, peer: peer, sendLocation: { coordinate, _, address in - 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 _ = (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 - presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), nil) - }) - }, sendLiveLocation: { _, _ in }, theme: presentationData.theme, customLocationPicker: true, presentationCompleted: { - clearHighlightImpl?() - }) - pushControllerImpl?(controller) - }) - }, displayLocationContextMenu: { text in - displayCopyContextMenuImpl?(text, .location) - }, expandParticipants: { - updateState { - $0.withUpdatedExpandedParticipants(true) - } - }) - - let loadMoreControl = Atomic<(PeerId, PeerChannelMemberCategoryControl)?>(value: nil) - let channelMembersPromise = Promise<[RenderedChannelParticipant]>() - - let channelMembersDisposable = MetaDisposable() - actionsDisposable.add(channelMembersDisposable) - - var membersLoadedCalled = false - - actionsDisposable.add((actualPeerId.get() - |> distinctUntilChanged - |> deliverOnMainQueue).start(next: { peerId in - 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: { state in - channelMembersPromise.set(.single(state.list)) - if case .loading(true) = state.loadingState { - } else if !membersLoadedCalled { - membersLoadedCalled = true - membersLoaded() - } - }) - if let control = control { - let _ = loadMoreControl.swap((peerId, control)) - } else { - let _ = loadMoreControl.swap(nil) - } - channelMembersDisposable.set(disposable) - } else { - let _ = loadMoreControl.swap(nil) - channelMembersPromise.set(.single([])) - channelMembersDisposable.set(nil) - if !membersLoadedCalled { - membersLoadedCalled = true - membersLoaded() - } - } - })) - - let previousStateValue = Atomic(value: nil) - let previousChannelMembers = Atomic<[PeerId]?>(value: nil) - - let searchContext = GroupMembersSearchContext(context: context, peerId: originalPeerId) - - let globalNotificationsKey: PostboxViewKey = .preferences(keys: Set([PreferencesKeys.globalNotifications])) - let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, statePromise.get(), peerView.get(), context.account.postbox.combinedView(keys: [globalNotificationsKey]), channelMembersPromise.get()) - |> map { presentationData, state, view, combinedView, channelMembers -> (ItemListControllerState, (ItemListNodeState, Any)) in - let peer = peerViewMainPeer(view) - - var globalNotificationSettings: GlobalNotificationSettings = GlobalNotificationSettings.defaultSettings - if let preferencesView = combinedView.views[globalNotificationsKey] as? PreferencesView { - if let settings = preferencesView.values[PreferencesKeys.globalNotifications] as? GlobalNotificationSettings { - globalNotificationSettings = settings - } - } - - var canEditGroupInfo = false - if let group = view.peers[view.peerId] as? TelegramGroup { - switch group.role { - case .admin, .creator: - canEditGroupInfo = true - case .member: - break - } - if !group.hasBannedPermission(.banChangeInfo) { - canEditGroupInfo = true - } - } else if let channel = view.peers[view.peerId] as? TelegramChannel { - if channel.hasPermission(.changeInfo) || !(channel.adminRights?.flags ?? []).isEmpty { - canEditGroupInfo = true - } - } - - var rightNavigationButton: ItemListNavigationButton? - var secondaryRightNavigationButton: ItemListNavigationButton? - if let editingState = state.editingState { - var doneEnabled = true - if let editingName = editingState.editingName, editingName.isEmpty { - doneEnabled = false - } - if peer is TelegramChannel { - if (view.cachedData as? CachedChannelData) == nil { - doneEnabled = false - } - } - - if state.savingData { - rightNavigationButton = ItemListNavigationButton(content: .none, style: .activity, enabled: doneEnabled, action: {}) - } else { - rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: doneEnabled, action: { - var updateValues: (title: String?, description: String?) = (nil, nil) - var failed = false - updateState { state in - updateValues = valuesRequiringUpdate(state: state, view: view) - if updateValues.0 != nil || updateValues.1 != nil { - if (updateValues.description?.count ?? 0) > 255 { - failed = true - return state - } - return state.withUpdatedSavingData(true) - } else { - return state.withUpdatedEditingState(nil) - } - } - - guard !failed else { - errorImpl?() - return - } - - let updateTitle: Signal - if let titleValue = updateValues.title { - updateTitle = updatePeerTitle(account: context.account, peerId: view.peerId, title: titleValue) - |> mapError { _ in return Void() } - } else { - updateTitle = .complete() - } - - let updateDescription: Signal - if let descriptionValue = updateValues.description { - updateDescription = updatePeerDescription(account: context.account, peerId: view.peerId, description: descriptionValue.isEmpty ? nil : descriptionValue) - |> mapError { _ in return Void() } - } else { - updateDescription = .complete() - } - - let signal = combineLatest(queue: .mainQueue(), - updateTitle, - updateDescription - ) - - updatePeerNameDisposable.set((signal - |> deliverOnMainQueue).start(error: { _ in - updateState { state in - return state.withUpdatedSavingData(false) - } - }, completed: { - updateState { state in - return state.withUpdatedSavingData(false).withUpdatedEditingState(nil) - } - })) - }) - } - } else if canEditGroupInfo { - rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Edit), style: .regular, enabled: true, action: { - if let peer = peer as? TelegramGroup { - var text = "" - if let cachedData = view.cachedData as? CachedGroupData, let about = cachedData.about { - text = about - } - updateState { state in - return state.withUpdatedEditingState(GroupInfoEditingState(editingName: ItemListAvatarAndNameInfoItemName(peer), editingDescriptionText: text)) - } - } else if let channel = peer as? TelegramChannel, case .group = channel.info { - var text = "" - if let cachedData = view.cachedData as? CachedChannelData, let about = cachedData.about { - text = about - } - updateState { state in - return state.withUpdatedEditingState(GroupInfoEditingState(editingName: ItemListAvatarAndNameInfoItemName(channel), editingDescriptionText: text)) - } - } - }) - if peer is TelegramChannel { - secondaryRightNavigationButton = ItemListNavigationButton(content: .icon(.search), style: .regular, enabled: true, action: { - updateState { state in - return state.withUpdatedSearchingMembers(true) - } - }) - } - } else { - if peer is TelegramChannel { - rightNavigationButton = ItemListNavigationButton(content: .icon(.search), style: .regular, enabled: true, action: { - updateState { state in - return state.withUpdatedSearchingMembers(true) - } - }) - } - } - - var searchItem: ItemListControllerSearch? - if state.searchingMembers { - searchItem = ChannelMembersSearchItem(context: context, peerId: view.peerId, searchContext: searchContext, cancel: { - updateState { state in - return state.withUpdatedSearchingMembers(false) - } - }, openPeer: { peer, _ in - if let infoController = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false) { - arguments.pushController(infoController) - } - }, pushController: { c in - pushControllerImpl?(c) - }, dismissInput: { - dismissInputImpl?() - }) - } - - let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.GroupInfo_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, secondaryRightNavigationButton: secondaryRightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) - - let entries = groupInfoEntries(account: context.account, presentationData: presentationData, view: view, channelMembers: channelMembers, globalNotificationSettings: globalNotificationSettings, state: state) - var memberIds: [PeerId] = [] - for entry in entries { - switch entry { - case let .member(member): - memberIds.append(member.peerId) - default: - break - } - } - let previousState = previousStateValue.swap(state) - let previousMembers = previousChannelMembers.swap(memberIds) ?? [] - - var animateChanges = previousMembers.count > memberIds.count || (previousState != nil && (previousState!.editingState != nil) != (state.editingState != nil)) - if presentationData.disableAnimations { - if Set(memberIds) == Set(previousMembers) && memberIds != previousMembers { - animateChanges = false - } - } - - let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: entries, style: .blocks, searchItem: searchItem, animateChanges: animateChanges) - - return (controllerState, (listState, arguments)) - } - |> afterDisposed { - actionsDisposable.dispose() - } - - let controller = ItemListController(context: context, state: signal) - - pushControllerImpl = { [weak controller] value in - (controller?.navigationController as? NavigationController)?.pushViewController(value) - } - presentControllerImpl = { [weak controller] value, presentationArguments in - controller?.view.endEditing(true) - controller?.present(value, in: .window(.root), with: presentationArguments, blockInteraction: true) - } - replaceControllerImpl = { [weak controller] previous, updated in - if let navigationController = controller?.navigationController as? NavigationController { - var controllers = navigationController.viewControllers - if let previous = previous { - controllers.removeAll(where: { $0 === previous }) - } - controllers.append(updated) - navigationController.setViewControllers(controllers, animated: true) - } - } - dismissInputImpl = { [weak controller] in - controller?.view.endEditing(true) - } - upgradedToSupergroupImpl = { [weak controller] upgradedPeerId, f in - let _ = (context.account.postbox.transaction { transaction -> Peer? in - return transaction.getPeer(upgradedPeerId) - } - |> deliverOnMainQueue).start(next: { peer in - guard let controller = controller, let navigationController = controller.navigationController as? NavigationController, let _ = peer else { - return - } - let infoController = groupInfoController(context: context, peerId: upgradedPeerId, membersLoaded: { - f() - }) - let chatController = context.sharedContext.makeChatController(context: context, chatLocation: .peer(upgradedPeerId), subject: nil, botStart: nil, mode: .standard(previewing: false)) - var viewControllers: [UIViewController] = [] - if let first = navigationController.viewControllers.first { - viewControllers.append(first) - } - viewControllers.append(chatController) - viewControllers.append(infoController) - navigationController.setViewControllers(viewControllers, animated: false) - }) - } - removePeerChatImpl = { [weak controller] peer, deleteGloballyIfPossible in - guard let controller = 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), joined: false, deleteGloballyIfPossible: deleteGloballyIfPossible, completion: { [weak navigationController] removed in - if removed { - navigationController?.popToRoot(animated: true) - } - }, removed: { - }) - break - } - } - } - displayCopyContextMenuImpl = { [weak controller] text, tag in - if let strongController = controller { - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - var resultItemNode: ListViewItemNode? - let _ = strongController.frameForItemNode({ itemNode in - var itemTag: GroupInfoEntryTag? = nil - if let itemNode = itemNode as? ItemListMultilineTextItemNode { - if let tag = itemNode.tag as? GroupInfoEntryTag { - itemTag = tag - } - } - else if let itemNode = itemNode as? ItemListActionItemNode { - if let tag = itemNode.tag as? GroupInfoEntryTag { - itemTag = tag - } - } - else if let itemNode = itemNode as? ItemListAddressItemNode { - if let tag = itemNode.tag as? GroupInfoEntryTag { - itemTag = tag - } - } - if itemTag == tag { - resultItemNode = itemNode - return true - } - return false - }) - if let resultItemNode = resultItemNode { - let contextMenuController = ContextMenuController(actions: [ContextMenuAction(content: .text(title: presentationData.strings.Conversation_ContextMenuCopy, accessibilityLabel: presentationData.strings.Conversation_ContextMenuCopy), action: { - UIPasteboard.general.string = text - })]) - strongController.present(contextMenuController, in: .window(.root), with: ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak resultItemNode] in - if let strongController = controller, let resultItemNode = resultItemNode { - return (resultItemNode, resultItemNode.contentBounds.insetBy(dx: 0.0, dy: -2.0), strongController.displayNode, strongController.view.bounds) - } else { - return nil - } - })) - - } - } - } - - aboutLinkActionImpl = { [weak context, weak controller] action, itemLink in - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { peerView in - if let controller = controller, let context = context { - context.sharedContext.handleTextLinkAction(context: context, peerId: peerView.peerId, navigateDisposable: navigateDisposable, controller: controller, action: action, itemLink: itemLink) - } - }) - } - - avatarGalleryTransitionArguments = { [weak controller] entry in - if let controller = controller { - var result: ((ASDisplayNode, CGRect, () -> (UIView?, UIView?)), CGRect)? - controller.forEachItemNode { itemNode in - if let itemNode = itemNode as? ItemListAvatarAndNameInfoItemNode { - result = itemNode.avatarTransitionNode() - } - } - if let (node, _) = result { - return GalleryTransitionArguments(transitionNode: node, addToTransitionSurface: { _ in - }) - } - } - return nil - } - updateHiddenAvatarImpl = { [weak controller] in - if let controller = controller { - controller.forEachItemNode { itemNode in - if let itemNode = itemNode as? ItemListAvatarAndNameInfoItemNode { - itemNode.updateAvatarHidden() - } - } - } - } - endEditingImpl = { - [weak controller] in - controller?.view.endEditing(true) - } - clearHighlightImpl = { [weak controller] in - controller?.clearItemNodesHighlight(animated: true) - } - - let hapticFeedback = HapticFeedback() - errorImpl = { [weak controller] in - hapticFeedback.error() - controller?.forEachItemNode { itemNode in - if let itemNode = itemNode as? ItemListMultilineInputItemNode { - itemNode.animateError() - } - } - } - - controller.visibleBottomContentOffsetChanged = { offset in - if let (peerId, loadMoreControl) = loadMoreControl.with({ $0 }), case let .known(value) = offset, value < 40.0 { - if stateValue.with({ $0 }).expandedParticipants { - context.peerChannelMemberCategoriesContextsManager.loadMore(peerId: peerId, control: loadMoreControl) - } - } - } - return controller -} diff --git a/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift b/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift index e649afab06..2ac4929c00 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift @@ -522,15 +522,15 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting let twoStepAuthDataValue = Promise(nil) let hasTwoStepAuthDataValue = twoStepAuthDataValue.get() - |> map { data -> Bool? in + |> mapToSignal { data -> Signal in if let data = data { if case .set = data { - return true + return .single(true) } else { - return false + return .single(false) } } else { - return nil + return .complete() } } diff --git a/submodules/SettingsUI/Sources/Themes/WallpaperGalleryController.swift b/submodules/SettingsUI/Sources/Themes/WallpaperGalleryController.swift index c0fe85ad60..14d418621d 100644 --- a/submodules/SettingsUI/Sources/Themes/WallpaperGalleryController.swift +++ b/submodules/SettingsUI/Sources/Themes/WallpaperGalleryController.swift @@ -312,6 +312,7 @@ public class WallpaperGalleryController: ViewController { }, dismissController: { [weak self] in self?.dismiss(forceAway: true) }, replaceRootController: { controller, ready in + }, editMedia: { _ in }) self.displayNode = WallpaperGalleryControllerNode(controllerInteraction: controllerInteraction, pageGap: 0.0) self.displayNodeDidLoad() diff --git a/submodules/SolidRoundedButtonNode/Sources/SolidRoundedButtonNode.swift b/submodules/SolidRoundedButtonNode/Sources/SolidRoundedButtonNode.swift index c5c6f42d3f..671f2a3690 100644 --- a/submodules/SolidRoundedButtonNode/Sources/SolidRoundedButtonNode.swift +++ b/submodules/SolidRoundedButtonNode/Sources/SolidRoundedButtonNode.swift @@ -129,7 +129,7 @@ public final class SolidRoundedButtonNode: ASDisplayNode { } public func updateLayout(width: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat { - return self.updateLayout(width: width, previousSubtitle: nil, transition: transition) + return self.updateLayout(width: width, previousSubtitle: self.subtitle, transition: transition) } private func updateLayout(width: CGFloat, previousSubtitle: String?, transition: ContainedViewLayoutTransition) -> CGFloat { diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 945dca125c..08e6253e2b 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -296,6 +296,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-374917894] = { return Api.PhotoSize.parse_photoCachedSize($0) } dict[-525288402] = { return Api.PhotoSize.parse_photoStrippedSize($0) } dict[1520986705] = { return Api.PhotoSize.parse_photoSizeProgressive($0) } + dict[-668906175] = { return Api.PhotoSize.parse_photoPathSize($0) } dict[-244016606] = { return Api.messages.Stickers.parse_stickersNotModified($0) } dict[-463889475] = { return Api.messages.Stickers.parse_stickers($0) } dict[-1096616924] = { return Api.GlobalPrivacySettings.parse_globalPrivacySettings($0) } diff --git a/submodules/TelegramApi/Sources/Api1.swift b/submodules/TelegramApi/Sources/Api1.swift index 839d1773ca..b500198b76 100644 --- a/submodules/TelegramApi/Sources/Api1.swift +++ b/submodules/TelegramApi/Sources/Api1.swift @@ -9467,6 +9467,7 @@ public extension Api { case photoCachedSize(type: String, location: Api.FileLocation, w: Int32, h: Int32, bytes: Buffer) case photoStrippedSize(type: String, bytes: Buffer) case photoSizeProgressive(type: String, location: Api.FileLocation, w: Int32, h: Int32, sizes: [Int32]) + case photoPathSize(type: String, bytes: Buffer) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -9517,6 +9518,13 @@ public extension Api { serializeInt32(item, buffer: buffer, boxed: false) } break + case .photoPathSize(let type, let bytes): + if boxed { + buffer.appendInt32(-668906175) + } + serializeString(type, buffer: buffer, boxed: false) + serializeBytes(bytes, buffer: buffer, boxed: false) + break } } @@ -9532,6 +9540,8 @@ public extension Api { return ("photoStrippedSize", [("type", type), ("bytes", bytes)]) case .photoSizeProgressive(let type, let location, let w, let h, let sizes): return ("photoSizeProgressive", [("type", type), ("location", location), ("w", w), ("h", h), ("sizes", sizes)]) + case .photoPathSize(let type, let bytes): + return ("photoPathSize", [("type", type), ("bytes", bytes)]) } } @@ -9637,6 +9647,20 @@ public extension Api { return nil } } + public static func parse_photoPathSize(_ reader: BufferReader) -> PhotoSize? { + var _1: String? + _1 = parseString(reader) + var _2: Buffer? + _2 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.PhotoSize.photoPathSize(type: _1!, bytes: _2!) + } + else { + return nil + } + } } public enum GlobalPrivacySettings: TypeConstructorDescription { diff --git a/submodules/TelegramCore/Sources/EnqueueMessage.swift b/submodules/TelegramCore/Sources/EnqueueMessage.swift index cfee4712d7..78e7581da3 100644 --- a/submodules/TelegramCore/Sources/EnqueueMessage.swift +++ b/submodules/TelegramCore/Sources/EnqueueMessage.swift @@ -31,6 +31,15 @@ public enum EnqueueMessage { return .forward(source: source, grouping: grouping, attributes: f(attributes)) } } + + public func withUpdatedGroupingKey(_ f: (Int64?) -> Int64?) -> EnqueueMessage { + switch self { + case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey): + return .message(text: text, attributes: attributes, mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: f(localGroupingKey)) + case .forward: + return self + } + } } func augmentMediaWithReference(_ mediaReference: AnyMediaReference) -> Media { @@ -192,7 +201,7 @@ public func enqueueMessagesToMultiplePeers(account: Account, peerIds: [PeerId], return account.postbox.transaction { transaction -> [MessageId] in var messageIds: [MessageId] = [] for peerId in peerIds { - for id in enqueueMessages(transaction: transaction, account: account, peerId: peerId, messages: messages, disableAutoremove: false) { + for id in enqueueMessages(transaction: transaction, account: account, peerId: peerId, messages: messages, disableAutoremove: false, transformGroupingKeysWithPeerId: true) { if let id = id { messageIds.append(id) } @@ -233,12 +242,22 @@ public func resendMessages(account: Account, messageIds: [MessageId]) -> Signal< } } -func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId, messages: [(Bool, EnqueueMessage)], disableAutoremove: Bool = false) -> [MessageId?] { +func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId, messages: [(Bool, EnqueueMessage)], disableAutoremove: Bool = false, transformGroupingKeysWithPeerId: Bool = false) -> [MessageId?] { var updatedMessages: [(Bool, EnqueueMessage)] = [] outer: for (transformedMedia, message) in messages { + var updatedMessage = message + if transformGroupingKeysWithPeerId { + updatedMessage = updatedMessage.withUpdatedGroupingKey { groupingKey -> Int64? in + if let groupingKey = groupingKey { + return groupingKey &+ peerId.toInt64() + } else { + return nil + } + } + } switch message { - case let .message(desc): - if let replyToMessageId = desc.replyToMessageId, replyToMessageId.peerId != peerId, let replyMessage = transaction.getMessage(replyToMessageId) { + case let .message(_, _, _, replyToMessageId, _): + if let replyToMessageId = replyToMessageId, replyToMessageId.peerId != peerId, let replyMessage = transaction.getMessage(replyToMessageId) { var canBeForwarded = true if replyMessage.id.namespace != Namespaces.Message.Cloud { canBeForwarded = false @@ -265,7 +284,7 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId, continue outer } } - updatedMessages.append((transformedMedia, message)) + updatedMessages.append((transformedMedia, updatedMessage)) } if let peer = transaction.getPeer(peerId), let accountPeer = transaction.getPeer(account.peerId) { diff --git a/submodules/TelegramCore/Sources/StickerPack.swift b/submodules/TelegramCore/Sources/StickerPack.swift index 97f3245721..5d60dce51a 100644 --- a/submodules/TelegramCore/Sources/StickerPack.swift +++ b/submodules/TelegramCore/Sources/StickerPack.swift @@ -5,7 +5,7 @@ import SwiftSignalKit import SyncCore import MtProtoKit -func telegramStickerPachThumbnailRepresentationFromApiSize(datacenterId: Int32, size: Api.PhotoSize) -> TelegramMediaImageRepresentation? { +func telegramStickerPackThumbnailRepresentationFromApiSize(datacenterId: Int32, size: Api.PhotoSize) -> TelegramMediaImageRepresentation? { switch size { case let .photoCachedSize(_, location, w, h, _): switch location { @@ -25,6 +25,8 @@ func telegramStickerPachThumbnailRepresentationFromApiSize(datacenterId: Int32, let resource = CloudStickerPackThumbnailMediaResource(datacenterId: datacenterId, volumeId: volumeId, localId: localId) return TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: resource, progressiveSizes: sizes) } + case let .photoPathSize(_, data): + return nil case .photoStrippedSize: return nil case .photoSizeEmpty: @@ -49,7 +51,7 @@ extension StickerPackCollectionInfo { var thumbnailRepresentation: TelegramMediaImageRepresentation? if let thumb = thumb, let thumbDcId = thumbDcId { - thumbnailRepresentation = telegramStickerPachThumbnailRepresentationFromApiSize(datacenterId: thumbDcId, size: thumb) + thumbnailRepresentation = telegramStickerPackThumbnailRepresentationFromApiSize(datacenterId: thumbDcId, size: thumb) } self.init(id: ItemCollectionId(namespace: namespace, id: id), flags: setFlags, accessHash: accessHash, title: title, shortName: shortName, thumbnail: thumbnailRepresentation, hash: nHash, count: count) diff --git a/submodules/TelegramCore/Sources/TelegramMediaFile.swift b/submodules/TelegramCore/Sources/TelegramMediaFile.swift index d1285decc8..d75d737956 100644 --- a/submodules/TelegramCore/Sources/TelegramMediaFile.swift +++ b/submodules/TelegramCore/Sources/TelegramMediaFile.swift @@ -143,6 +143,8 @@ func telegramMediaFileThumbnailRepresentationsFromApiSizes(datacenterId: Int32, let resource = CloudDocumentSizeMediaResource(datacenterId: datacenterId, documentId: documentId, accessHash: accessHash, sizeSpec: type, volumeId: volumeId, localId: localId, fileReference: fileReference) representations.append(TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: w, height: h), resource: resource, progressiveSizes: sizes)) } + case let .photoPathSize(_, data): + immediateThumbnailData = data.makeData() case let .photoStrippedSize(_, data): immediateThumbnailData = data.makeData() case .photoSizeEmpty: diff --git a/submodules/TelegramCore/Sources/TelegramMediaImage.swift b/submodules/TelegramCore/Sources/TelegramMediaImage.swift index 674c5afd12..5dca93ac69 100644 --- a/submodules/TelegramCore/Sources/TelegramMediaImage.swift +++ b/submodules/TelegramCore/Sources/TelegramMediaImage.swift @@ -31,6 +31,8 @@ func telegramMediaImageRepresentationsFromApiSizes(datacenterId: Int32, photoId: } case let .photoStrippedSize(_, data): immediateThumbnailData = data.makeData() + case .photoPathSize: + break case .photoSizeEmpty: break } diff --git a/submodules/TelegramPresentationData/Sources/PresentationStrings.swift b/submodules/TelegramPresentationData/Sources/PresentationStrings.swift index 7f30643b51..0c92bd4737 100644 --- a/submodules/TelegramPresentationData/Sources/PresentationStrings.swift +++ b/submodules/TelegramPresentationData/Sources/PresentationStrings.swift @@ -514,5380 +514,5382 @@ public final class PresentationStrings: Equatable { public var Channel_Info_Management: String { return self._s[309]! } public var Passport_Language_hr: String { return self._s[310]! } public var EditTheme_Edit_Preview_IncomingText: String { return self._s[312]! } - public var Conversation_SecretChatContextBotAlert: String { return self._s[314]! } - public var GroupInfo_Permissions_SlowmodeValue_Off: String { return self._s[315]! } - public var Privacy_Calls_P2PContacts: String { return self._s[316]! } - public var Appearance_PickAccentColor: String { return self._s[317]! } - public var MediaPicker_TapToUngroupDescription: String { return self._s[318]! } - public var Localization_EnglishLanguageName: String { return self._s[319]! } - public var Stickers_SuggestStickers: String { return self._s[320]! } - public var Passport_Language_ko: String { return self._s[321]! } - public var Settings_ProxyDisabled: String { return self._s[322]! } - public var PrivacySettings_PasscodeOff: String { return self._s[323]! } - public var Undo_LeftChannel: String { return self._s[324]! } - public var Appearance_AutoNightThemeDisabled: String { return self._s[325]! } - public var TextFormat_Bold: String { return self._s[326]! } - public var Login_InfoTitle: String { return self._s[327]! } - public var Channel_BanUser_PermissionSendPolls: String { return self._s[328]! } - public var Settings_AddAnotherAccount: String { return self._s[329]! } - public var GroupPermission_NewTitle: String { return self._s[330]! } - public var Login_SelectCountry_Title: String { return self._s[331]! } - public var Cache_ServiceFiles: String { return self._s[332]! } - public var Passport_Language_nl: String { return self._s[333]! } - public var Contacts_TopSection: String { return self._s[334]! } - public var Passport_Identity_DateOfBirthPlaceholder: String { return self._s[335]! } - public var Conversation_ContextMenuReport: String { return self._s[337]! } + public var OpenFile_Proceed: String { return self._s[313]! } + public var Conversation_SecretChatContextBotAlert: String { return self._s[315]! } + public var GroupInfo_Permissions_SlowmodeValue_Off: String { return self._s[316]! } + public var Privacy_Calls_P2PContacts: String { return self._s[317]! } + public var Appearance_PickAccentColor: String { return self._s[318]! } + public var MediaPicker_TapToUngroupDescription: String { return self._s[319]! } + public var Localization_EnglishLanguageName: String { return self._s[320]! } + public var Stickers_SuggestStickers: String { return self._s[321]! } + public var Passport_Language_ko: String { return self._s[322]! } + public var Settings_ProxyDisabled: String { return self._s[323]! } + public var PrivacySettings_PasscodeOff: String { return self._s[324]! } + public var Undo_LeftChannel: String { return self._s[325]! } + public var Appearance_AutoNightThemeDisabled: String { return self._s[326]! } + public var TextFormat_Bold: String { return self._s[327]! } + public var Login_InfoTitle: String { return self._s[328]! } + public var Channel_BanUser_PermissionSendPolls: String { return self._s[329]! } + public var Settings_AddAnotherAccount: String { return self._s[330]! } + public var GroupPermission_NewTitle: String { return self._s[331]! } + public var Login_SelectCountry_Title: String { return self._s[332]! } + public var Cache_ServiceFiles: String { return self._s[333]! } + public var Passport_Language_nl: String { return self._s[334]! } + public var Contacts_TopSection: String { return self._s[335]! } + public var Passport_Identity_DateOfBirthPlaceholder: String { return self._s[336]! } + public var Conversation_ContextMenuReport: String { return self._s[338]! } public func Login_BannedPhoneBody(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[338]!, self._r[338]!, [_0]) + return formatWithArgumentRanges(self._s[339]!, self._r[339]!, [_0]) } - public var Conversation_Search: String { return self._s[339]! } - public var Group_Setup_HistoryVisibleHelp: String { return self._s[341]! } - public var ReportPeer_AlertSuccess: String { return self._s[343]! } - public var AutoNightTheme_Title: String { return self._s[345]! } + public var Conversation_Search: String { return self._s[340]! } + public var Group_Setup_HistoryVisibleHelp: String { return self._s[342]! } + public var ReportPeer_AlertSuccess: String { return self._s[344]! } + public var AutoNightTheme_Title: String { return self._s[346]! } public func Notification_PinnedTextMessage(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[347]!, self._r[347]!, [_0, _1]) + return formatWithArgumentRanges(self._s[348]!, self._r[348]!, [_0, _1]) } public func Conversation_OpenBotLinkText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[348]!, self._r[348]!, [_0]) + return formatWithArgumentRanges(self._s[349]!, self._r[349]!, [_0]) } - public var Conversation_ShareBotContactConfirmation: String { return self._s[349]! } - public var TwoStepAuth_RecoveryCode: String { return self._s[350]! } - public var SocksProxySetup_ConnectAndSave: String { return self._s[351]! } + public var Conversation_ShareBotContactConfirmation: String { return self._s[350]! } + public var TwoStepAuth_RecoveryCode: String { return self._s[351]! } + public var SocksProxySetup_ConnectAndSave: String { return self._s[352]! } public func MESSAGE_INVOICE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[352]!, self._r[352]!, [_1, _2]) + return formatWithArgumentRanges(self._s[353]!, self._r[353]!, [_1, _2]) } public func Channel_AdminLog_MessageChangedGroupUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[353]!, self._r[353]!, [_0]) + return formatWithArgumentRanges(self._s[354]!, self._r[354]!, [_0]) } - public var Replies_BlockAndDeleteRepliesActionTitle: String { return self._s[354]! } + public var Replies_BlockAndDeleteRepliesActionTitle: String { return self._s[355]! } public func Notification_GroupInviter(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[355]!, self._r[355]!, [_0]) + return formatWithArgumentRanges(self._s[356]!, self._r[356]!, [_0]) } - public var Conversation_InfoGroup: String { return self._s[356]! } + public var Conversation_InfoGroup: String { return self._s[357]! } public func Map_AccurateTo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[358]!, self._r[358]!, [_0]) + return formatWithArgumentRanges(self._s[359]!, self._r[359]!, [_0]) } - public var Conversation_ChatBackground: String { return self._s[359]! } - public var PhotoEditor_Set: String { return self._s[360]! } + public var Conversation_ChatBackground: String { return self._s[360]! } + public var PhotoEditor_Set: String { return self._s[361]! } public func Channel_Management_PromotedBy(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[362]!, self._r[362]!, [_0]) + return formatWithArgumentRanges(self._s[363]!, self._r[363]!, [_0]) } - public var IntentsSettings_SuggestedChatsContacts: String { return self._s[363]! } - public var Passport_Phone_Title: String { return self._s[365]! } - public var Conversation_EditingMessageMediaChange: String { return self._s[366]! } - public var Channel_LinkItem: String { return self._s[367]! } + public var IntentsSettings_SuggestedChatsContacts: String { return self._s[364]! } + public var Passport_Phone_Title: String { return self._s[366]! } + public var Conversation_EditingMessageMediaChange: String { return self._s[367]! } + public var Channel_LinkItem: String { return self._s[368]! } public func PUSH_CHAT_DELETE_MEMBER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[368]!, self._r[368]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[369]!, self._r[369]!, [_1, _2, _3]) } - public var Conversation_DeleteManyMessages: String { return self._s[369]! } - public var Notifications_Badge_IncludeMutedChats: String { return self._s[370]! } - public var AuthSessions_AddedDeviceTitle: String { return self._s[373]! } - public var Privacy_Calls_NeverAllow_Placeholder: String { return self._s[374]! } - public var Settings_ProxyConnecting: String { return self._s[375]! } - public var Theme_Colors_Accent: String { return self._s[376]! } - public var Theme_Colors_ColorWallpaperWarning: String { return self._s[377]! } + public var Conversation_DeleteManyMessages: String { return self._s[370]! } + public var Notifications_Badge_IncludeMutedChats: String { return self._s[371]! } + public var AuthSessions_AddedDeviceTitle: String { return self._s[374]! } + public var Privacy_Calls_NeverAllow_Placeholder: String { return self._s[375]! } + public var Settings_ProxyConnecting: String { return self._s[376]! } + public var Theme_Colors_Accent: String { return self._s[377]! } + public var Theme_Colors_ColorWallpaperWarning: String { return self._s[378]! } public func PUSH_PHONE_CALL_MISSED(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[378]!, self._r[378]!, [_1]) + return formatWithArgumentRanges(self._s[379]!, self._r[379]!, [_1]) } - public var Passport_Language_lo: String { return self._s[379]! } - public var Wallet_WordCheck_Continue: String { return self._s[380]! } + public var Passport_Language_lo: String { return self._s[380]! } + public var Wallet_WordCheck_Continue: String { return self._s[381]! } public func Watch_Time_ShortWeekdayAt(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[382]!, self._r[382]!, [_1, _2]) + return formatWithArgumentRanges(self._s[383]!, self._r[383]!, [_1, _2]) } - public var Permissions_NotificationsText_v0: String { return self._s[383]! } - public var ChatList_Context_RemoveFromRecents: String { return self._s[384]! } - public var Watch_GroupInfo_Title: String { return self._s[385]! } - public var Settings_AddDevice: String { return self._s[387]! } - public var WallpaperPreview_SwipeColorsTopText: String { return self._s[388]! } + public var Permissions_NotificationsText_v0: String { return self._s[384]! } + public var ChatList_Context_RemoveFromRecents: String { return self._s[385]! } + public var Watch_GroupInfo_Title: String { return self._s[386]! } + public var Settings_AddDevice: String { return self._s[388]! } + public var WallpaperPreview_SwipeColorsTopText: String { return self._s[389]! } public func PUSH_CHANNEL_ALBUM(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[389]!, self._r[389]!, [_1]) + return formatWithArgumentRanges(self._s[390]!, self._r[390]!, [_1]) } - public var TwoStepAuth_Disable: String { return self._s[391]! } + public var TwoStepAuth_Disable: String { return self._s[392]! } public func Conversation_AddNameToContacts(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[392]!, self._r[392]!, [_0]) + return formatWithArgumentRanges(self._s[393]!, self._r[393]!, [_0]) } public func Time_PreciseDate_m10(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[393]!, self._r[393]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[394]!, self._r[394]!, [_1, _2, _3]) } public func Login_WillSendSms(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[394]!, self._r[394]!, [_0]) + return formatWithArgumentRanges(self._s[395]!, self._r[395]!, [_0]) } - public var Channel_AdminLog_BanReadMessages: String { return self._s[395]! } - public var Undo_ChatDeleted: String { return self._s[396]! } - public var ContactInfo_URLLabelHomepage: String { return self._s[397]! } + public var Channel_AdminLog_BanReadMessages: String { return self._s[396]! } + public var Undo_ChatDeleted: String { return self._s[397]! } + public var ContactInfo_URLLabelHomepage: String { return self._s[398]! } public func PUSH_CHAT_MESSAGE_STICKER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[398]!, self._r[398]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[399]!, self._r[399]!, [_1, _2, _3]) } - public var FastTwoStepSetup_EmailHelp: String { return self._s[399]! } - public var Contacts_SelectAll: String { return self._s[400]! } - public var Privacy_ContactsReset: String { return self._s[401]! } - public var AttachmentMenu_File: String { return self._s[403]! } - public var PasscodeSettings_EncryptData: String { return self._s[404]! } - public var EditTheme_ThemeTemplateAlertText: String { return self._s[405]! } + public var FastTwoStepSetup_EmailHelp: String { return self._s[400]! } + public var Contacts_SelectAll: String { return self._s[401]! } + public var Privacy_ContactsReset: String { return self._s[402]! } + public var AttachmentMenu_File: String { return self._s[404]! } + public var PasscodeSettings_EncryptData: String { return self._s[405]! } + public var EditTheme_ThemeTemplateAlertText: String { return self._s[406]! } public func Wallet_Time_PreciseDate_m6(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[407]!, self._r[407]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[408]!, self._r[408]!, [_1, _2, _3]) } public func Privacy_GroupsAndChannels_InviteToChannelError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[408]!, self._r[408]!, [_0, _1]) - } - public func Profile_CreateEncryptedChatOutdatedError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[409]!, self._r[409]!, [_0, _1]) } - public var PhotoEditor_ShadowsTint: String { return self._s[411]! } - public var GroupInfo_ChatAdmins: String { return self._s[412]! } - public var ArchivedChats_IntroTitle2: String { return self._s[413]! } - public var Cache_LowDiskSpaceText: String { return self._s[414]! } - public var CreatePoll_Anonymous: String { return self._s[415]! } - public var Wallet_Created_ExportErrorText: String { return self._s[416]! } - public var Checkout_PaymentMethod_New: String { return self._s[417]! } - public var Wallet_Info_RefreshErrorText: String { return self._s[418]! } - public var Invitation_JoinGroup: String { return self._s[419]! } + public func Profile_CreateEncryptedChatOutdatedError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[410]!, self._r[410]!, [_0, _1]) + } + public var PhotoEditor_ShadowsTint: String { return self._s[412]! } + public var GroupInfo_ChatAdmins: String { return self._s[413]! } + public var ArchivedChats_IntroTitle2: String { return self._s[414]! } + public var Cache_LowDiskSpaceText: String { return self._s[415]! } + public var CreatePoll_Anonymous: String { return self._s[416]! } + public var Wallet_Created_ExportErrorText: String { return self._s[417]! } + public var Checkout_PaymentMethod_New: String { return self._s[418]! } + public var Wallet_Info_RefreshErrorText: String { return self._s[419]! } + public var Invitation_JoinGroup: String { return self._s[420]! } public func Time_MonthOfYear_m4(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[422]!, self._r[422]!, [_0]) + return formatWithArgumentRanges(self._s[423]!, self._r[423]!, [_0]) } - public var CheckoutInfo_SaveInfoHelp: String { return self._s[423]! } - public var Notification_Reply: String { return self._s[425]! } - public var Wallet_Month_GenSeptember: String { return self._s[426]! } + public var CheckoutInfo_SaveInfoHelp: String { return self._s[424]! } + public var Notification_Reply: String { return self._s[426]! } + public var Wallet_Month_GenSeptember: String { return self._s[427]! } public func Login_PhoneBannedEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[427]!, self._r[427]!, [_0]) + return formatWithArgumentRanges(self._s[428]!, self._r[428]!, [_0]) } - public var Login_PhoneTitle: String { return self._s[428]! } - public var VoiceOver_Media_PlaybackRateNormal: String { return self._s[429]! } + public var Login_PhoneTitle: String { return self._s[429]! } + public var VoiceOver_Media_PlaybackRateNormal: String { return self._s[430]! } public func PUSH_CHAT_MESSAGE_INVOICE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[430]!, self._r[430]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[431]!, self._r[431]!, [_1, _2, _3]) } - public var Appearance_TextSize_Title: String { return self._s[431]! } - public var NetworkUsageSettings_MediaImageDataSection: String { return self._s[433]! } - public var VoiceOver_Navigation_Compose: String { return self._s[434]! } - public var Passport_InfoText: String { return self._s[435]! } - public var ApplyLanguage_ApplyLanguageAction: String { return self._s[436]! } - public var MessagePoll_LabelClosed: String { return self._s[438]! } - public var AttachmentMenu_SendAsFiles: String { return self._s[439]! } - public var KeyCommand_FocusOnInputField: String { return self._s[440]! } - public var Conversation_ContextViewThread: String { return self._s[441]! } - public var Privacy_SecretChatsLinkPreviews: String { return self._s[443]! } - public var Permissions_PeopleNearbyAllow_v0: String { return self._s[444]! } - public var Conversation_ContextMenuMention: String { return self._s[446]! } - public var CreatePoll_QuizInfo: String { return self._s[447]! } - public var Appearance_ThemePreview_ChatList_2_Name: String { return self._s[448]! } - public var Username_LinkCopied: String { return self._s[449]! } - public var IntentsSettings_SuggestedAndSpotlightChatsInfo: String { return self._s[450]! } - public var TwoStepAuth_ChangePassword: String { return self._s[451]! } - public var Watch_Suggestion_Thanks: String { return self._s[452]! } - public var Channel_TitleInfo: String { return self._s[453]! } - public var ChatList_ChatTypesSection: String { return self._s[454]! } + public var Appearance_TextSize_Title: String { return self._s[432]! } + public var NetworkUsageSettings_MediaImageDataSection: String { return self._s[434]! } + public var VoiceOver_Navigation_Compose: String { return self._s[435]! } + public var Passport_InfoText: String { return self._s[436]! } + public var ApplyLanguage_ApplyLanguageAction: String { return self._s[437]! } + public var MessagePoll_LabelClosed: String { return self._s[439]! } + public var AttachmentMenu_SendAsFiles: String { return self._s[440]! } + public var KeyCommand_FocusOnInputField: String { return self._s[441]! } + public var Conversation_ContextViewThread: String { return self._s[442]! } + public var Privacy_SecretChatsLinkPreviews: String { return self._s[444]! } + public var Permissions_PeopleNearbyAllow_v0: String { return self._s[445]! } + public var Conversation_ContextMenuMention: String { return self._s[447]! } + public var CreatePoll_QuizInfo: String { return self._s[448]! } + public var Appearance_ThemePreview_ChatList_2_Name: String { return self._s[449]! } + public var Username_LinkCopied: String { return self._s[450]! } + public var IntentsSettings_SuggestedAndSpotlightChatsInfo: String { return self._s[451]! } + public var TwoStepAuth_ChangePassword: String { return self._s[452]! } + public var Watch_Suggestion_Thanks: String { return self._s[453]! } + public var Channel_TitleInfo: String { return self._s[454]! } + public var ChatList_ChatTypesSection: String { return self._s[455]! } public func Watch_LastSeen_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[455]!, self._r[455]!, [_0]) - } - public func Channel_AdminLog_PollStopped(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[456]!, self._r[456]!, [_0]) } - public var AuthSessions_AddDevice_InvalidQRCode: String { return self._s[457]! } + public func Channel_AdminLog_PollStopped(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[457]!, self._r[457]!, [_0]) + } + public var AuthSessions_AddDevice_InvalidQRCode: String { return self._s[458]! } public func Call_MicrophoneOff(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[458]!, self._r[458]!, [_0]) + return formatWithArgumentRanges(self._s[459]!, self._r[459]!, [_0]) } - public var Channel_AdminLogFilter_ChannelEventsInfo: String { return self._s[459]! } - public var Profile_MessageLifetimeForever: String { return self._s[460]! } - public var ArchivedChats_IntroText1: String { return self._s[461]! } - public var Notifications_ChannelNotificationsPreview: String { return self._s[462]! } - public var Map_PullUpForPlaces: String { return self._s[464]! } - public var UserInfo_TelegramCall: String { return self._s[465]! } - public var Conversation_ShareMyContactInfo: String { return self._s[466]! } - public var ChatList_Tabs_All: String { return self._s[467]! } - public var Notification_PassportValueEmail: String { return self._s[468]! } - public var Notification_VideoCallIncoming: String { return self._s[469]! } - public var SettingsSearch_Synonyms_Appearance_AutoNightTheme: String { return self._s[470]! } - public var Channel_Username_InvalidTaken: String { return self._s[471]! } - public var GroupPermission_EditingDisabled: String { return self._s[472]! } - public var ChatContextMenu_TextSelectionTip: String { return self._s[473]! } - public var Passport_Language_pl: String { return self._s[475]! } - public var Call_Accept: String { return self._s[476]! } - public var ChatListFolder_NameSectionHeader: String { return self._s[477]! } + public var Channel_AdminLogFilter_ChannelEventsInfo: String { return self._s[460]! } + public var Profile_MessageLifetimeForever: String { return self._s[461]! } + public var ArchivedChats_IntroText1: String { return self._s[462]! } + public var Notifications_ChannelNotificationsPreview: String { return self._s[463]! } + public var Map_PullUpForPlaces: String { return self._s[465]! } + public var UserInfo_TelegramCall: String { return self._s[466]! } + public var Conversation_ShareMyContactInfo: String { return self._s[467]! } + public var ChatList_Tabs_All: String { return self._s[468]! } + public var Notification_PassportValueEmail: String { return self._s[469]! } + public var Notification_VideoCallIncoming: String { return self._s[470]! } + public var SettingsSearch_Synonyms_Appearance_AutoNightTheme: String { return self._s[471]! } + public var Channel_Username_InvalidTaken: String { return self._s[472]! } + public var GroupPermission_EditingDisabled: String { return self._s[473]! } + public var ChatContextMenu_TextSelectionTip: String { return self._s[474]! } + public var Passport_Language_pl: String { return self._s[476]! } + public var Call_Accept: String { return self._s[477]! } + public var ChatListFolder_NameSectionHeader: String { return self._s[478]! } public func Passport_Identity_NativeNameTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[478]!, self._r[478]!, [_0]) + return formatWithArgumentRanges(self._s[479]!, self._r[479]!, [_0]) } - public var ClearCache_Forever: String { return self._s[479]! } + public var ClearCache_Forever: String { return self._s[480]! } public func ChannelInfo_AddParticipantConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[481]!, self._r[481]!, [_0]) + return formatWithArgumentRanges(self._s[482]!, self._r[482]!, [_0]) } - public var Group_EditAdmin_RankAdminPlaceholder: String { return self._s[482]! } - public var Calls_SubmitRating: String { return self._s[483]! } - public var Location_LiveLocationRequired_ShareLocation: String { return self._s[484]! } + public var Group_EditAdmin_RankAdminPlaceholder: String { return self._s[483]! } + public var Calls_SubmitRating: String { return self._s[484]! } + public var Location_LiveLocationRequired_ShareLocation: String { return self._s[485]! } public func ChatList_AddedToFolderTooltip(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[485]!, self._r[485]!, [_1, _2]) + return formatWithArgumentRanges(self._s[486]!, self._r[486]!, [_1, _2]) } - public var IntentsSettings_MainAccountInfo: String { return self._s[486]! } - public var Map_Hybrid: String { return self._s[488]! } - public var ChatList_Context_Archive: String { return self._s[489]! } - public var Message_PinnedDocumentMessage: String { return self._s[490]! } - public var State_ConnectingToProxyInfo: String { return self._s[491]! } - public var Wallet_Month_GenDecember: String { return self._s[492]! } - public var Passport_Identity_NativeNameGenericTitle: String { return self._s[494]! } - public var Settings_AppLanguage: String { return self._s[495]! } + public var IntentsSettings_MainAccountInfo: String { return self._s[487]! } + public var Map_Hybrid: String { return self._s[489]! } + public var ChatList_Context_Archive: String { return self._s[490]! } + public var Message_PinnedDocumentMessage: String { return self._s[491]! } + public var State_ConnectingToProxyInfo: String { return self._s[492]! } + public var Wallet_Month_GenDecember: String { return self._s[493]! } + public var Passport_Identity_NativeNameGenericTitle: String { return self._s[495]! } + public var Settings_AppLanguage: String { return self._s[496]! } public func Checkout_SavePasswordTimeoutAndFaceId(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[496]!, self._r[496]!, [_0]) + return formatWithArgumentRanges(self._s[497]!, self._r[497]!, [_0]) } - public var Notifications_PermissionsEnable: String { return self._s[498]! } - public var CheckoutInfo_ShippingInfoAddress1Placeholder: String { return self._s[499]! } + public var Notifications_PermissionsEnable: String { return self._s[499]! } + public var CheckoutInfo_ShippingInfoAddress1Placeholder: String { return self._s[500]! } public func UserInfo_BlockActionTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[500]!, self._r[500]!, [_0]) - } - public func AuthSessions_Message(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[501]!, self._r[501]!, [_0]) } - public var NotificationsSound_Aurora: String { return self._s[504]! } - public var ScheduledMessages_ClearAll: String { return self._s[507]! } + public func AuthSessions_Message(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[502]!, self._r[502]!, [_0]) + } + public var NotificationsSound_Aurora: String { return self._s[505]! } + public var ScheduledMessages_ClearAll: String { return self._s[508]! } public func CancelResetAccount_TextSMS(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[508]!, self._r[508]!, [_0]) + return formatWithArgumentRanges(self._s[509]!, self._r[509]!, [_0]) } - public var Settings_BlockedUsers: String { return self._s[510]! } + public var Settings_BlockedUsers: String { return self._s[511]! } public func UserInfo_StartSecretChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[512]!, self._r[512]!, [_0]) + return formatWithArgumentRanges(self._s[513]!, self._r[513]!, [_0]) } - public var Passport_Language_hu: String { return self._s[513]! } + public var Passport_Language_hu: String { return self._s[514]! } public func Conversation_ScheduleMessage_SendTomorrow(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[514]!, self._r[514]!, [_0]) + return formatWithArgumentRanges(self._s[515]!, self._r[515]!, [_0]) } - public var StickerPack_Share: String { return self._s[515]! } - public var Checkout_NewCard_SaveInfoEnableHelp: String { return self._s[516]! } + public var StickerPack_Share: String { return self._s[516]! } + public var Checkout_NewCard_SaveInfoEnableHelp: String { return self._s[517]! } public func ForwardedAuthors2(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[517]!, self._r[517]!, [_0, _1]) + return formatWithArgumentRanges(self._s[518]!, self._r[518]!, [_0, _1]) } - public var Privacy_ContactsResetConfirmation: String { return self._s[518]! } - public var AppleWatch_ReplyPresets: String { return self._s[519]! } - public var Bot_GenericBotStatus: String { return self._s[520]! } - public var Appearance_ShareThemeColor: String { return self._s[521]! } - public var AuthSessions_AddDevice_UrlLoginHint: String { return self._s[522]! } - public var ReportGroupLocation_Title: String { return self._s[523]! } + public var Privacy_ContactsResetConfirmation: String { return self._s[519]! } + public var AppleWatch_ReplyPresets: String { return self._s[520]! } + public var Bot_GenericBotStatus: String { return self._s[521]! } + public var Appearance_ShareThemeColor: String { return self._s[522]! } + public var AuthSessions_AddDevice_UrlLoginHint: String { return self._s[523]! } + public var ReportGroupLocation_Title: String { return self._s[524]! } public func Activity_RemindAboutUser(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[524]!, self._r[524]!, [_0]) + return formatWithArgumentRanges(self._s[525]!, self._r[525]!, [_0]) } - public var Profile_CreateEncryptedChatError: String { return self._s[525]! } - public var Channel_EditAdmin_TransferOwnership: String { return self._s[526]! } - public var Wallpaper_ErrorNotFound: String { return self._s[527]! } - public var Bot_GenericSupportStatus: String { return self._s[528]! } - public var Activity_UploadingPhoto: String { return self._s[530]! } - public var Watch_UserInfo_Title: String { return self._s[532]! } - public var SocksProxySetup_ProxyTelegram: String { return self._s[533]! } - public var Appearance_ThemeDay: String { return self._s[534]! } + public var Profile_CreateEncryptedChatError: String { return self._s[526]! } + public var Channel_EditAdmin_TransferOwnership: String { return self._s[527]! } + public var Wallpaper_ErrorNotFound: String { return self._s[528]! } + public var Bot_GenericSupportStatus: String { return self._s[529]! } + public var Activity_UploadingPhoto: String { return self._s[531]! } + public var Watch_UserInfo_Title: String { return self._s[533]! } + public var SocksProxySetup_ProxyTelegram: String { return self._s[534]! } + public var Appearance_ThemeDay: String { return self._s[535]! } public func ApplyLanguage_ChangeLanguageOfficialText(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[535]!, self._r[535]!, [_1]) + return formatWithArgumentRanges(self._s[536]!, self._r[536]!, [_1]) } public func FileSize_B(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[536]!, self._r[536]!, [_0]) + return formatWithArgumentRanges(self._s[537]!, self._r[537]!, [_0]) } - public var Passport_Title: String { return self._s[539]! } + public var Passport_Title: String { return self._s[540]! } public func Time_PreciseDate_m3(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[541]!, self._r[541]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[542]!, self._r[542]!, [_1, _2, _3]) } - public var Wallet_Sent_Title: String { return self._s[542]! } - public var CheckoutInfo_ShippingInfoCountryPlaceholder: String { return self._s[543]! } - public var SocksProxySetup_ShareLink: String { return self._s[546]! } - public var AuthSessions_OtherDevices: String { return self._s[547]! } - public var IntentsSettings_SuggestedChatsGroups: String { return self._s[548]! } - public var Watch_MessageView_Reply: String { return self._s[549]! } - public var Camera_FlashOn: String { return self._s[551]! } + public var Wallet_Sent_Title: String { return self._s[543]! } + public var CheckoutInfo_ShippingInfoCountryPlaceholder: String { return self._s[544]! } + public var SocksProxySetup_ShareLink: String { return self._s[547]! } + public var AuthSessions_OtherDevices: String { return self._s[548]! } + public var IntentsSettings_SuggestedChatsGroups: String { return self._s[549]! } + public var Watch_MessageView_Reply: String { return self._s[550]! } + public var Camera_FlashOn: String { return self._s[552]! } public func PUSH_MESSAGE_STICKER(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[552]!, self._r[552]!, [_1, _2]) + return formatWithArgumentRanges(self._s[553]!, self._r[553]!, [_1, _2]) } - public var Conversation_ContextMenuBlock: String { return self._s[554]! } - public var Channel_EditAdmin_PermissionEditMessages: String { return self._s[555]! } - public var Privacy_Calls_NeverAllow: String { return self._s[556]! } - public var SharedMedia_CategoryLinks: String { return self._s[557]! } - public var Conversation_PinMessageAlertGroup: String { return self._s[560]! } - public var Passport_Identity_ScansHelp: String { return self._s[561]! } - public var ShareMenu_CopyShareLink: String { return self._s[562]! } - public var StickerSettings_MaskContextInfo: String { return self._s[563]! } - public var SocksProxySetup_ProxyStatusChecking: String { return self._s[564]! } - public var Conversation_WalletRequiredText: String { return self._s[565]! } - public var AutoDownloadSettings_AutodownloadPhotos: String { return self._s[567]! } - public var Checkout_ErrorPrecheckoutFailed: String { return self._s[569]! } - public var NotificationsSound_Popcorn: String { return self._s[570]! } - public var FeatureDisabled_Oops: String { return self._s[571]! } + public var Conversation_ContextMenuBlock: String { return self._s[555]! } + public var Channel_EditAdmin_PermissionEditMessages: String { return self._s[556]! } + public var Privacy_Calls_NeverAllow: String { return self._s[557]! } + public var SharedMedia_CategoryLinks: String { return self._s[558]! } + public var Conversation_PinMessageAlertGroup: String { return self._s[561]! } + public var Passport_Identity_ScansHelp: String { return self._s[562]! } + public var ShareMenu_CopyShareLink: String { return self._s[563]! } + public var StickerSettings_MaskContextInfo: String { return self._s[564]! } + public var SocksProxySetup_ProxyStatusChecking: String { return self._s[565]! } + public var Conversation_WalletRequiredText: String { return self._s[566]! } + public var AutoDownloadSettings_AutodownloadPhotos: String { return self._s[568]! } + public var Checkout_ErrorPrecheckoutFailed: String { return self._s[570]! } + public var NotificationsSound_Popcorn: String { return self._s[571]! } + public var FeatureDisabled_Oops: String { return self._s[572]! } public func Channel_AdminLog_MessageChangedChannelAbout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[572]!, self._r[572]!, [_0]) + return formatWithArgumentRanges(self._s[573]!, self._r[573]!, [_0]) } - public var Notification_PinnedMessage: String { return self._s[573]! } - public var Tour_Title4: String { return self._s[574]! } - public var Watch_Suggestion_OK: String { return self._s[575]! } - public var Compose_TokenListPlaceholder: String { return self._s[576]! } - public var EditTheme_Edit_TopInfo: String { return self._s[577]! } - public var Gif_NoGifsFound: String { return self._s[578]! } - public var Login_InvalidCountryCode: String { return self._s[579]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsExceptions: String { return self._s[580]! } + public var Notification_PinnedMessage: String { return self._s[574]! } + public var Tour_Title4: String { return self._s[575]! } + public var Watch_Suggestion_OK: String { return self._s[576]! } + public var Compose_TokenListPlaceholder: String { return self._s[577]! } + public var EditTheme_Edit_TopInfo: String { return self._s[578]! } + public var Gif_NoGifsFound: String { return self._s[579]! } + public var Login_InvalidCountryCode: String { return self._s[580]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsExceptions: String { return self._s[581]! } public func PUSH_LOCKED_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[582]!, self._r[582]!, [_1]) + return formatWithArgumentRanges(self._s[583]!, self._r[583]!, [_1]) } - public var Profile_CreateNewContact: String { return self._s[583]! } - public var AutoDownloadSettings_DataUsageLow: String { return self._s[584]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsPreview: String { return self._s[585]! } - public var Group_Setup_TypePublic: String { return self._s[586]! } - public var Weekday_ShortSaturday: String { return self._s[587]! } + public var Profile_CreateNewContact: String { return self._s[584]! } + public var AutoDownloadSettings_DataUsageLow: String { return self._s[585]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsPreview: String { return self._s[586]! } + public var Group_Setup_TypePublic: String { return self._s[587]! } + public var Weekday_ShortSaturday: String { return self._s[588]! } public func Time_MonthOfYear_m12(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[588]!, self._r[588]!, [_0]) + return formatWithArgumentRanges(self._s[589]!, self._r[589]!, [_0]) } - public var LiveLocation_MenuStopAll: String { return self._s[589]! } + public var LiveLocation_MenuStopAll: String { return self._s[590]! } public func DialogList_EncryptedChatStartedIncoming(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[590]!, self._r[590]!, [_0]) + return formatWithArgumentRanges(self._s[591]!, self._r[591]!, [_0]) } - public var ChatListFolder_NamePlaceholder: String { return self._s[591]! } - public var Channel_OwnershipTransfer_ErrorPublicChannelsTooMuch: String { return self._s[592]! } + public var ChatListFolder_NamePlaceholder: String { return self._s[592]! } + public var Channel_OwnershipTransfer_ErrorPublicChannelsTooMuch: String { return self._s[593]! } public func PUSH_CHAT_MESSAGE_GAME(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[593]!, self._r[593]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[594]!, self._r[594]!, [_1, _2, _3]) } public func Wallet_SecureStorageChanged_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[595]!, self._r[595]!, [_0]) + return formatWithArgumentRanges(self._s[596]!, self._r[596]!, [_0]) } - public var Chat_GenericPsaTooltip: String { return self._s[596]! } + public var Chat_GenericPsaTooltip: String { return self._s[597]! } public func Message_ForwardedMessageShort(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[597]!, self._r[597]!, [_0]) + return formatWithArgumentRanges(self._s[598]!, self._r[598]!, [_0]) } - public var PrivacyLastSeenSettings_AlwaysShareWith_Placeholder: String { return self._s[598]! } - public var Login_PhoneAndCountryHelp: String { return self._s[599]! } - public var SaveIncomingPhotosSettings_From: String { return self._s[600]! } - public var Conversation_JumpToDate: String { return self._s[601]! } - public var AuthSessions_AddDevice: String { return self._s[602]! } - public var Settings_FAQ: String { return self._s[604]! } - public var Username_Title: String { return self._s[605]! } - public var DialogList_Read: String { return self._s[606]! } - public var Conversation_InstantPagePreview: String { return self._s[607]! } - public var Login_ResetAccountProtected_Title: String { return self._s[609]! } - public var CallFeedback_ReasonDistortedSpeech: String { return self._s[610]! } - public var Channel_EditAdmin_PermissionChangeInfo: String { return self._s[611]! } + public var PrivacyLastSeenSettings_AlwaysShareWith_Placeholder: String { return self._s[599]! } + public var Login_PhoneAndCountryHelp: String { return self._s[600]! } + public var SaveIncomingPhotosSettings_From: String { return self._s[601]! } + public var Conversation_JumpToDate: String { return self._s[602]! } + public var AuthSessions_AddDevice: String { return self._s[603]! } + public var Settings_FAQ: String { return self._s[605]! } + public var Username_Title: String { return self._s[606]! } + public var DialogList_Read: String { return self._s[607]! } + public var Conversation_InstantPagePreview: String { return self._s[608]! } + public var Login_ResetAccountProtected_Title: String { return self._s[610]! } + public var CallFeedback_ReasonDistortedSpeech: String { return self._s[611]! } + public var Channel_EditAdmin_PermissionChangeInfo: String { return self._s[612]! } public func Channel_AdminLog_MessageRankUsername(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[612]!, self._r[612]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[613]!, self._r[613]!, [_1, _2, _3]) } - public var WallpaperPreview_PreviewBottomText: String { return self._s[614]! } - public var Privacy_SecretChatsTitle: String { return self._s[617]! } + public var WallpaperPreview_PreviewBottomText: String { return self._s[615]! } + public var Privacy_SecretChatsTitle: String { return self._s[618]! } public func Notification_PassportValuesSentMessage(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[618]!, self._r[618]!, [_1, _2]) + return formatWithArgumentRanges(self._s[619]!, self._r[619]!, [_1, _2]) } - public var Checkout_NewCard_SaveInfoHelp: String { return self._s[619]! } - public var Conversation_ClousStorageInfo_Description4: String { return self._s[620]! } - public var PasscodeSettings_TurnPasscodeOn: String { return self._s[621]! } - public var Message_ReplyActionButtonShowReceipt: String { return self._s[622]! } + public var Checkout_NewCard_SaveInfoHelp: String { return self._s[620]! } + public var Conversation_ClousStorageInfo_Description4: String { return self._s[621]! } + public var PasscodeSettings_TurnPasscodeOn: String { return self._s[622]! } + public var Message_ReplyActionButtonShowReceipt: String { return self._s[623]! } public func PrivacyPolicy_AgeVerificationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[623]!, self._r[623]!, [_0]) + return formatWithArgumentRanges(self._s[624]!, self._r[624]!, [_0]) } - public var GroupInfo_DeleteAndExitConfirmation: String { return self._s[625]! } - public var TwoStepAuth_ConfirmationAbort: String { return self._s[626]! } - public var PrivacySettings_LastSeenEverybody: String { return self._s[627]! } - public var CallFeedback_ReasonDropped: String { return self._s[628]! } + public var GroupInfo_DeleteAndExitConfirmation: String { return self._s[626]! } + public var TwoStepAuth_ConfirmationAbort: String { return self._s[627]! } + public var PrivacySettings_LastSeenEverybody: String { return self._s[628]! } + public var CallFeedback_ReasonDropped: String { return self._s[629]! } public func ScheduledMessages_ScheduledDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[629]!, self._r[629]!, [_0]) + return formatWithArgumentRanges(self._s[630]!, self._r[630]!, [_0]) } - public var WebSearch_Images: String { return self._s[630]! } - public var Passport_Identity_Surname: String { return self._s[631]! } - public var Channel_Stickers_CreateYourOwn: String { return self._s[632]! } - public var TwoFactorSetup_Email_Title: String { return self._s[633]! } - public var Cache_ClearEmpty: String { return self._s[634]! } - public var AuthSessions_AddDeviceIntro_Action: String { return self._s[635]! } - public var Theme_Context_Apply: String { return self._s[636]! } - public var GroupInfo_Permissions_SearchPlaceholder: String { return self._s[637]! } - public var Wallet_Send_ErrorNotEnoughFundsText: String { return self._s[638]! } - public var AutoDownloadSettings_DocumentsTitle: String { return self._s[639]! } + public var WebSearch_Images: String { return self._s[631]! } + public var Passport_Identity_Surname: String { return self._s[632]! } + public var Channel_Stickers_CreateYourOwn: String { return self._s[633]! } + public var TwoFactorSetup_Email_Title: String { return self._s[634]! } + public var Cache_ClearEmpty: String { return self._s[635]! } + public var AuthSessions_AddDeviceIntro_Action: String { return self._s[636]! } + public var Theme_Context_Apply: String { return self._s[637]! } + public var GroupInfo_Permissions_SearchPlaceholder: String { return self._s[638]! } + public var Wallet_Send_ErrorNotEnoughFundsText: String { return self._s[639]! } + public var AutoDownloadSettings_DocumentsTitle: String { return self._s[640]! } public func NetworkUsageSettings_CellularUsageSince(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[640]!, self._r[640]!, [_0]) + return formatWithArgumentRanges(self._s[641]!, self._r[641]!, [_0]) } - public var Call_StatusRinging: String { return self._s[641]! } + public var Call_StatusRinging: String { return self._s[642]! } public func Map_DistanceAway(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[642]!, self._r[642]!, [_0]) - } - public func DialogList_SingleTypingSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[643]!, self._r[643]!, [_0]) } - public var Cache_ClearNone: String { return self._s[644]! } - public var Wallet_Receive_CopyAddress: String { return self._s[645]! } - public var PrivacyPolicy_Accept: String { return self._s[646]! } - public var Wallet_TransactionInfo_SenderHeader: String { return self._s[647]! } - public var Contacts_PhoneNumber: String { return self._s[648]! } - public var Passport_Identity_OneOfTypePassport: String { return self._s[649]! } - public var PhotoEditor_HighlightsTint: String { return self._s[651]! } - public var AutoDownloadSettings_AutodownloadVideos: String { return self._s[652]! } - public var Checkout_PaymentMethod_Title: String { return self._s[655]! } - public var Month_GenAugust: String { return self._s[657]! } - public var DialogList_Draft: String { return self._s[658]! } - public var ChatList_EmptyChatListFilterText: String { return self._s[659]! } - public var PeopleNearby_Description: String { return self._s[660]! } - public var WallpaperPreview_SwipeColorsBottomText: String { return self._s[661]! } - public var AppWallet_TransactionInfo_FeeInfoURL: String { return self._s[662]! } - public var SettingsSearch_Synonyms_Privacy_Data_TopPeers: String { return self._s[664]! } - public var Watch_Message_ForwardedFrom: String { return self._s[665]! } - public var Wallet_Words_NotDoneOk: String { return self._s[666]! } - public var Notification_Mute1h: String { return self._s[667]! } - public var Appearance_ThemePreview_Chat_3_TextWithLink: String { return self._s[668]! } - public var SettingsSearch_Synonyms_Privacy_AuthSessions: String { return self._s[670]! } - public var Channel_Edit_LinkItem: String { return self._s[671]! } - public var Presence_online: String { return self._s[672]! } - public var AutoDownloadSettings_Title: String { return self._s[673]! } - public var Conversation_MessageDialogRetry: String { return self._s[674]! } - public var SettingsSearch_Synonyms_ChatSettings_OpenLinksIn: String { return self._s[676]! } - public var Channel_About_Placeholder: String { return self._s[678]! } - public var Passport_Language_sl: String { return self._s[679]! } - public var AppleWatch_Title: String { return self._s[681]! } - public var RepliesChat_DescriptionText: String { return self._s[683]! } - public var Settings_ViewPhoto: String { return self._s[684]! } - public var Stats_Message_PrivateShares: String { return self._s[685]! } - public var ChatList_DeleteSavedMessagesConfirmation: String { return self._s[686]! } - public var Cache_ClearProgress: String { return self._s[687]! } - public var Cache_Music: String { return self._s[688]! } - public var Conversation_ContextMenuShare: String { return self._s[690]! } - public var AutoDownloadSettings_Unlimited: String { return self._s[691]! } - public var Channel_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[692]! } - public var Contacts_PermissionsAllow: String { return self._s[693]! } - public var Passport_Language_vi: String { return self._s[695]! } + public func DialogList_SingleTypingSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[644]!, self._r[644]!, [_0]) + } + public var Cache_ClearNone: String { return self._s[645]! } + public var Wallet_Receive_CopyAddress: String { return self._s[646]! } + public var PrivacyPolicy_Accept: String { return self._s[647]! } + public var Wallet_TransactionInfo_SenderHeader: String { return self._s[648]! } + public var Contacts_PhoneNumber: String { return self._s[649]! } + public var Passport_Identity_OneOfTypePassport: String { return self._s[650]! } + public var PhotoEditor_HighlightsTint: String { return self._s[652]! } + public var AutoDownloadSettings_AutodownloadVideos: String { return self._s[653]! } + public var Checkout_PaymentMethod_Title: String { return self._s[656]! } + public var Month_GenAugust: String { return self._s[658]! } + public var DialogList_Draft: String { return self._s[659]! } + public var ChatList_EmptyChatListFilterText: String { return self._s[660]! } + public var PeopleNearby_Description: String { return self._s[661]! } + public var WallpaperPreview_SwipeColorsBottomText: String { return self._s[662]! } + public var AppWallet_TransactionInfo_FeeInfoURL: String { return self._s[663]! } + public var SettingsSearch_Synonyms_Privacy_Data_TopPeers: String { return self._s[665]! } + public var Watch_Message_ForwardedFrom: String { return self._s[666]! } + public var Wallet_Words_NotDoneOk: String { return self._s[667]! } + public var Notification_Mute1h: String { return self._s[668]! } + public var Appearance_ThemePreview_Chat_3_TextWithLink: String { return self._s[669]! } + public var SettingsSearch_Synonyms_Privacy_AuthSessions: String { return self._s[671]! } + public var Channel_Edit_LinkItem: String { return self._s[672]! } + public var Presence_online: String { return self._s[673]! } + public var AutoDownloadSettings_Title: String { return self._s[674]! } + public var Conversation_MessageDialogRetry: String { return self._s[675]! } + public var SettingsSearch_Synonyms_ChatSettings_OpenLinksIn: String { return self._s[677]! } + public var Channel_About_Placeholder: String { return self._s[679]! } + public var Passport_Language_sl: String { return self._s[680]! } + public var AppleWatch_Title: String { return self._s[682]! } + public var RepliesChat_DescriptionText: String { return self._s[684]! } + public var Settings_ViewPhoto: String { return self._s[685]! } + public var Stats_Message_PrivateShares: String { return self._s[686]! } + public var ChatList_DeleteSavedMessagesConfirmation: String { return self._s[687]! } + public var Cache_ClearProgress: String { return self._s[688]! } + public var Cache_Music: String { return self._s[689]! } + public var Conversation_ContextMenuShare: String { return self._s[691]! } + public var AutoDownloadSettings_Unlimited: String { return self._s[692]! } + public var Channel_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[693]! } + public var Contacts_PermissionsAllow: String { return self._s[694]! } + public var Passport_Language_vi: String { return self._s[696]! } public func PUSH_MESSAGE_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[698]!, self._r[698]!, [_1, _2]) + return formatWithArgumentRanges(self._s[699]!, self._r[699]!, [_1, _2]) } - public var Passport_Language_de: String { return self._s[699]! } - public var Notifications_PermissionsText: String { return self._s[701]! } - public var GroupRemoved_AddToGroup: String { return self._s[702]! } - public var Appearance_ThemePreview_ChatList_4_Text: String { return self._s[703]! } - public var ChangePhoneNumberCode_RequestingACall: String { return self._s[704]! } - public var Login_TermsOfServiceAgree: String { return self._s[705]! } - public var VoiceOver_Navigation_ProxySettings: String { return self._s[706]! } + public var Passport_Language_de: String { return self._s[700]! } + public var Notifications_PermissionsText: String { return self._s[702]! } + public var GroupRemoved_AddToGroup: String { return self._s[703]! } + public var Appearance_ThemePreview_ChatList_4_Text: String { return self._s[704]! } + public var ChangePhoneNumberCode_RequestingACall: String { return self._s[705]! } + public var Login_TermsOfServiceAgree: String { return self._s[706]! } + public var VoiceOver_Navigation_ProxySettings: String { return self._s[707]! } public func PUSH_CHAT_JOINED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[707]!, self._r[707]!, [_1, _2]) + return formatWithArgumentRanges(self._s[708]!, self._r[708]!, [_1, _2]) } - public var SettingsSearch_Synonyms_Data_CallsUseLessData: String { return self._s[709]! } - public var ChatListFolder_NameGroups: String { return self._s[710]! } - public var SocksProxySetup_ProxyDetailsTitle: String { return self._s[711]! } + public var SettingsSearch_Synonyms_Data_CallsUseLessData: String { return self._s[710]! } + public var ChatListFolder_NameGroups: String { return self._s[711]! } + public var SocksProxySetup_ProxyDetailsTitle: String { return self._s[712]! } public func Channel_AdminLog_MessageChangedLinkedGroup(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[712]!, self._r[712]!, [_1, _2]) + return formatWithArgumentRanges(self._s[713]!, self._r[713]!, [_1, _2]) } - public var Watch_Suggestion_TalkLater: String { return self._s[713]! } - public var Checkout_ShippingOption_Title: String { return self._s[714]! } - public var Conversation_TitleRepliesEmpty: String { return self._s[715]! } - public var CreatePoll_TextHeader: String { return self._s[716]! } - public var VoiceOver_Chat_Message: String { return self._s[718]! } - public var InfoPlist_NSLocationWhenInUseUsageDescription: String { return self._s[719]! } - public var ContactInfo_Note: String { return self._s[721]! } - public var Channel_AdminLog_InfoPanelAlertText: String { return self._s[722]! } - public var Wallet_Receive_AmountHeader: String { return self._s[723]! } - public var Checkout_NewCard_CardholderNameTitle: String { return self._s[724]! } - public var AutoDownloadSettings_Photos: String { return self._s[725]! } - public var UserInfo_NotificationsDefaultDisabled: String { return self._s[726]! } - public var Channel_Info_Subscribers: String { return self._s[727]! } - public var ChatList_DeleteForCurrentUser: String { return self._s[728]! } - public var ChatListFolderSettings_FoldersSection: String { return self._s[729]! } + public var Watch_Suggestion_TalkLater: String { return self._s[714]! } + public var Checkout_ShippingOption_Title: String { return self._s[715]! } + public var Conversation_TitleRepliesEmpty: String { return self._s[716]! } + public var CreatePoll_TextHeader: String { return self._s[717]! } + public var VoiceOver_Chat_Message: String { return self._s[719]! } + public var InfoPlist_NSLocationWhenInUseUsageDescription: String { return self._s[720]! } + public var ContactInfo_Note: String { return self._s[722]! } + public var Channel_AdminLog_InfoPanelAlertText: String { return self._s[723]! } + public var Wallet_Receive_AmountHeader: String { return self._s[724]! } + public var Checkout_NewCard_CardholderNameTitle: String { return self._s[725]! } + public var AutoDownloadSettings_Photos: String { return self._s[726]! } + public var UserInfo_NotificationsDefaultDisabled: String { return self._s[727]! } + public var Channel_Info_Subscribers: String { return self._s[728]! } + public var ChatList_DeleteForCurrentUser: String { return self._s[729]! } + public var ChatListFolderSettings_FoldersSection: String { return self._s[730]! } public func Time_PreciseDate_m9(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[733]!, self._r[733]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[734]!, self._r[734]!, [_1, _2, _3]) } - public var AutoNightTheme_System: String { return self._s[734]! } - public var Call_StatusWaiting: String { return self._s[735]! } - public var GroupInfo_GroupHistoryHidden: String { return self._s[736]! } + public var AutoNightTheme_System: String { return self._s[735]! } + public var Call_StatusWaiting: String { return self._s[736]! } + public var GroupInfo_GroupHistoryHidden: String { return self._s[737]! } public func CHAT_MESSAGE_INVOICE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[737]!, self._r[737]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[738]!, self._r[738]!, [_1, _2, _3]) } - public var Conversation_ContextMenuCopy: String { return self._s[739]! } - public var Notifications_MessageNotificationsPreview: String { return self._s[740]! } - public var Notifications_InAppNotificationsVibrate: String { return self._s[741]! } + public var Conversation_ContextMenuCopy: String { return self._s[740]! } + public var Notifications_MessageNotificationsPreview: String { return self._s[741]! } + public var Notifications_InAppNotificationsVibrate: String { return self._s[742]! } public func Conversation_RestrictedTextTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[742]!, self._r[742]!, [_0]) + return formatWithArgumentRanges(self._s[743]!, self._r[743]!, [_0]) } - public var Group_Status: String { return self._s[744]! } - public var Group_Setup_HistoryVisible: String { return self._s[745]! } - public var Conversation_DiscardVoiceMessageAction: String { return self._s[746]! } - public var Paint_Edit: String { return self._s[747]! } - public var Channel_EditAdmin_CannotEdit: String { return self._s[749]! } - public var Username_InvalidTooShort: String { return self._s[750]! } - public var ClearCache_StorageOtherApps: String { return self._s[751]! } - public var Wallet_Configuration_SourceJSON: String { return self._s[752]! } - public var Conversation_ViewMessage: String { return self._s[753]! } - public var GroupInfo_PublicLinkAdd: String { return self._s[755]! } + public var Group_Status: String { return self._s[745]! } + public var Group_Setup_HistoryVisible: String { return self._s[746]! } + public var Conversation_DiscardVoiceMessageAction: String { return self._s[747]! } + public var Paint_Edit: String { return self._s[748]! } + public var Channel_EditAdmin_CannotEdit: String { return self._s[750]! } + public var Username_InvalidTooShort: String { return self._s[751]! } + public var ClearCache_StorageOtherApps: String { return self._s[752]! } + public var Wallet_Configuration_SourceJSON: String { return self._s[753]! } + public var Conversation_ViewMessage: String { return self._s[754]! } + public var GroupInfo_PublicLinkAdd: String { return self._s[756]! } public func Notification_RemovedGroupPhoto(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[756]!, self._r[756]!, [_0]) + return formatWithArgumentRanges(self._s[757]!, self._r[757]!, [_0]) } - public var CallSettings_Title: String { return self._s[757]! } + public var CallSettings_Title: String { return self._s[758]! } public func Conversation_BotInteractiveUrlAlert(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[758]!, self._r[758]!, [_0]) + return formatWithArgumentRanges(self._s[759]!, self._r[759]!, [_0]) } public func VoiceOver_Chat_ContactFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[761]!, self._r[761]!, [_0]) + return formatWithArgumentRanges(self._s[762]!, self._r[762]!, [_0]) } - public var PUSH_SENDER_YOU: String { return self._s[764]! } - public var Profile_ShareContactButton: String { return self._s[765]! } - public var GroupInfo_Permissions_SectionTitle: String { return self._s[766]! } - public var Map_ShareLiveLocation: String { return self._s[767]! } - public var ChatListFolder_TitleEdit: String { return self._s[768]! } - public var Wallet_Send_ErrorInvalidAddress: String { return self._s[769]! } - public var Passport_Address_Address: String { return self._s[771]! } - public var LastSeen_JustNow: String { return self._s[773]! } + public var PUSH_SENDER_YOU: String { return self._s[765]! } + public var Profile_ShareContactButton: String { return self._s[766]! } + public var GroupInfo_Permissions_SectionTitle: String { return self._s[767]! } + public var Map_ShareLiveLocation: String { return self._s[768]! } + public var ChatListFolder_TitleEdit: String { return self._s[769]! } + public var Wallet_Send_ErrorInvalidAddress: String { return self._s[770]! } + public var Passport_Address_Address: String { return self._s[772]! } + public var LastSeen_JustNow: String { return self._s[774]! } public func SecretImage_NotViewedYet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[774]!, self._r[774]!, [_0]) + return formatWithArgumentRanges(self._s[775]!, self._r[775]!, [_0]) } - public var ContactInfo_PhoneLabelOther: String { return self._s[775]! } - public var PasscodeSettings_DoNotMatch: String { return self._s[776]! } - public var Weekday_Today: String { return self._s[779]! } - public var DialogList_Title: String { return self._s[780]! } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsPreview: String { return self._s[781]! } - public var Cache_ClearCache: String { return self._s[782]! } - public var CreatePoll_ExplanationInfo: String { return self._s[783]! } - public var Notifications_ResetAllNotificationsHelp: String { return self._s[785]! } - public var Stats_MessageTitle: String { return self._s[786]! } - public var Passport_Address_Street: String { return self._s[788]! } - public var Wallet_Receive_ShareUrlInfo: String { return self._s[789]! } + public var ContactInfo_PhoneLabelOther: String { return self._s[776]! } + public var PasscodeSettings_DoNotMatch: String { return self._s[777]! } + public var Weekday_Today: String { return self._s[780]! } + public var DialogList_Title: String { return self._s[781]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsPreview: String { return self._s[782]! } + public var Cache_ClearCache: String { return self._s[783]! } + public var CreatePoll_ExplanationInfo: String { return self._s[784]! } + public var Notifications_ResetAllNotificationsHelp: String { return self._s[786]! } + public var Stats_MessageTitle: String { return self._s[787]! } + public var Passport_Address_Street: String { return self._s[789]! } + public var Wallet_Receive_ShareUrlInfo: String { return self._s[790]! } public func Channel_AdminLog_MessageRemovedGroupUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[790]!, self._r[790]!, [_0]) + return formatWithArgumentRanges(self._s[791]!, self._r[791]!, [_0]) } - public var Channel_AdminLog_ChannelEmptyText: String { return self._s[791]! } + public var Channel_AdminLog_ChannelEmptyText: String { return self._s[792]! } public func Login_PhoneGenericEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[792]!, self._r[792]!, [_0]) + return formatWithArgumentRanges(self._s[793]!, self._r[793]!, [_0]) } - public var TwoStepAuth_Email: String { return self._s[794]! } - public var Wallet_Words_Text: String { return self._s[795]! } - public var Conversation_SecretLinkPreviewAlert: String { return self._s[796]! } - public var PrivacySettings_PasscodeOn: String { return self._s[797]! } - public var Wallet_Receive_CopyInvoiceUrl: String { return self._s[799]! } - public var Wallet_Send_AddressInfo: String { return self._s[800]! } - public var Camera_SquareMode: String { return self._s[801]! } - public var Wallet_Month_ShortJuly: String { return self._s[802]! } - public var SocksProxySetup_Port: String { return self._s[803]! } - public var Watch_LastSeen_JustNow: String { return self._s[805]! } + public var TwoStepAuth_Email: String { return self._s[795]! } + public var Wallet_Words_Text: String { return self._s[796]! } + public var Conversation_SecretLinkPreviewAlert: String { return self._s[797]! } + public var PrivacySettings_PasscodeOn: String { return self._s[798]! } + public var Wallet_Receive_CopyInvoiceUrl: String { return self._s[800]! } + public var Wallet_Send_AddressInfo: String { return self._s[801]! } + public var Camera_SquareMode: String { return self._s[802]! } + public var Wallet_Month_ShortJuly: String { return self._s[803]! } + public var SocksProxySetup_Port: String { return self._s[804]! } + public var Watch_LastSeen_JustNow: String { return self._s[806]! } public func PUSH_MESSAGE_GAME(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[806]!, self._r[806]!, [_1, _2]) + return formatWithArgumentRanges(self._s[807]!, self._r[807]!, [_1, _2]) } public func Watch_LastSeen_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[807]!, self._r[807]!, [_0]) + return formatWithArgumentRanges(self._s[808]!, self._r[808]!, [_0]) } public func Location_ProximityAlertSetText(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[808]!, self._r[808]!, [_1, _2]) + return formatWithArgumentRanges(self._s[809]!, self._r[809]!, [_1, _2]) } - public var EditTheme_Expand_Preview_OutgoingText: String { return self._s[809]! } - public var Channel_AdminLogFilter_EventsTitle: String { return self._s[810]! } - public var Wallet_AccessDenied_Settings: String { return self._s[812]! } - public var Watch_Suggestion_HoldOn: String { return self._s[814]! } + public var EditTheme_Expand_Preview_OutgoingText: String { return self._s[810]! } + public var Channel_AdminLogFilter_EventsTitle: String { return self._s[811]! } + public var Wallet_AccessDenied_Settings: String { return self._s[813]! } + public var Watch_Suggestion_HoldOn: String { return self._s[815]! } public func PUSH_CHANNEL_MESSAGE_GEOLIVE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[815]!, self._r[815]!, [_1]) + return formatWithArgumentRanges(self._s[816]!, self._r[816]!, [_1]) } - public var CallSettings_TabIcon: String { return self._s[816]! } - public var ScheduledMessages_SendNow: String { return self._s[817]! } - public var Stats_GroupTopWeekdaysTitle: String { return self._s[818]! } - public var Wallet_WordImport_IncorrectTitle: String { return self._s[819]! } - public var UserInfo_PhoneCall: String { return self._s[820]! } - public var Month_GenMarch: String { return self._s[821]! } - public var Camera_Discard: String { return self._s[822]! } - public var InfoPlist_NSFaceIDUsageDescription: String { return self._s[823]! } - public var Passport_RequestedInformation: String { return self._s[824]! } - public var Passport_Language_ro: String { return self._s[826]! } + public var CallSettings_TabIcon: String { return self._s[817]! } + public var ScheduledMessages_SendNow: String { return self._s[818]! } + public var Stats_GroupTopWeekdaysTitle: String { return self._s[819]! } + public var Wallet_WordImport_IncorrectTitle: String { return self._s[820]! } + public var UserInfo_PhoneCall: String { return self._s[821]! } + public var Month_GenMarch: String { return self._s[822]! } + public var Camera_Discard: String { return self._s[823]! } + public var InfoPlist_NSFaceIDUsageDescription: String { return self._s[824]! } + public var Passport_RequestedInformation: String { return self._s[825]! } + public var Passport_Language_ro: String { return self._s[827]! } public func Notification_ProximityYouReached(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[827]!, self._r[827]!, [_1, _2]) - } - public func PUSH_CHAT_MESSAGE_DOC(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[828]!, self._r[828]!, [_1, _2]) } - public var AutoDownloadSettings_ResetHelp: String { return self._s[829]! } - public var Passport_Identity_DocumentDetails: String { return self._s[831]! } - public var Passport_Address_ScansHelp: String { return self._s[832]! } - public var Location_LiveLocationRequired_Title: String { return self._s[833]! } - public var ClearCache_StorageCache: String { return self._s[834]! } - public var Theme_Colors_ColorWallpaperWarningProceed: String { return self._s[835]! } - public var Conversation_RestrictedText: String { return self._s[836]! } - public var Notifications_MessageNotifications: String { return self._s[838]! } - public var Passport_Scans: String { return self._s[839]! } - public var TwoStepAuth_SetupHintTitle: String { return self._s[841]! } - public var LogoutOptions_ContactSupportTitle: String { return self._s[842]! } - public var Passport_Identity_SelfieHelp: String { return self._s[843]! } - public var Permissions_NotificationsUnreachableText_v0: String { return self._s[844]! } - public var Privacy_PaymentsClear_PaymentInfo: String { return self._s[845]! } - public var ShareMenu_CopyShareLinkGame: String { return self._s[846]! } - public var PeerInfo_ButtonSearch: String { return self._s[847]! } + public func PUSH_CHAT_MESSAGE_DOC(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[829]!, self._r[829]!, [_1, _2]) + } + public var AutoDownloadSettings_ResetHelp: String { return self._s[830]! } + public var Passport_Identity_DocumentDetails: String { return self._s[832]! } + public var Passport_Address_ScansHelp: String { return self._s[833]! } + public var Location_LiveLocationRequired_Title: String { return self._s[834]! } + public var ClearCache_StorageCache: String { return self._s[835]! } + public var Theme_Colors_ColorWallpaperWarningProceed: String { return self._s[836]! } + public var Conversation_RestrictedText: String { return self._s[837]! } + public var Notifications_MessageNotifications: String { return self._s[839]! } + public var Passport_Scans: String { return self._s[840]! } + public var TwoStepAuth_SetupHintTitle: String { return self._s[842]! } + public var LogoutOptions_ContactSupportTitle: String { return self._s[843]! } + public var Passport_Identity_SelfieHelp: String { return self._s[844]! } + public var Permissions_NotificationsUnreachableText_v0: String { return self._s[845]! } + public var Privacy_PaymentsClear_PaymentInfo: String { return self._s[846]! } + public var ShareMenu_CopyShareLinkGame: String { return self._s[847]! } + public var PeerInfo_ButtonSearch: String { return self._s[848]! } public func Notification_ProximityReachedYou(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[850]!, self._r[850]!, [_1, _2]) + return formatWithArgumentRanges(self._s[851]!, self._r[851]!, [_1, _2]) } - public var SettingsSearch_Synonyms_Privacy_Data_ClearPaymentsInfo: String { return self._s[851]! } - public var Passport_FieldIdentityTranslationHelp: String { return self._s[853]! } - public var Conversation_InputTextSilentBroadcastPlaceholder: String { return self._s[854]! } - public var Month_GenSeptember: String { return self._s[855]! } + public var SettingsSearch_Synonyms_Privacy_Data_ClearPaymentsInfo: String { return self._s[852]! } + public var Passport_FieldIdentityTranslationHelp: String { return self._s[854]! } + public var Conversation_InputTextSilentBroadcastPlaceholder: String { return self._s[855]! } + public var Month_GenSeptember: String { return self._s[856]! } public func Call_GroupFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[857]!, self._r[857]!, [_1, _2]) + return formatWithArgumentRanges(self._s[858]!, self._r[858]!, [_1, _2]) } - public var StickerPacksSettings_ArchivedPacks: String { return self._s[858]! } + public var StickerPacksSettings_ArchivedPacks: String { return self._s[859]! } public func Channel_Username_LinkHint(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[860]!, self._r[860]!, [_0]) + return formatWithArgumentRanges(self._s[861]!, self._r[861]!, [_0]) } public func PUSH_PINNED_CONTACT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[862]!, self._r[862]!, [_1, _2]) + return formatWithArgumentRanges(self._s[863]!, self._r[863]!, [_1, _2]) } - public var LogoutOptions_LogOutWalletInfo: String { return self._s[863]! } + public var LogoutOptions_LogOutWalletInfo: String { return self._s[864]! } public func PUSH_MESSAGE_VIDEOS(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[864]!, self._r[864]!, [_1, _2]) + return formatWithArgumentRanges(self._s[865]!, self._r[865]!, [_1, _2]) } - public var Calls_NotNow: String { return self._s[866]! } - public var Wallet_Completed_Text: String { return self._s[869]! } - public var Settings_ChatFolders: String { return self._s[871]! } - public var Login_PadPhoneHelpTitle: String { return self._s[872]! } - public var TwoStepAuth_EnterPasswordInvalid: String { return self._s[873]! } - public var Settings_ChatBackground: String { return self._s[874]! } + public var Calls_NotNow: String { return self._s[867]! } + public var Wallet_Completed_Text: String { return self._s[870]! } + public var Settings_ChatFolders: String { return self._s[872]! } + public var Login_PadPhoneHelpTitle: String { return self._s[873]! } + public var TwoStepAuth_EnterPasswordInvalid: String { return self._s[874]! } + public var Settings_ChatBackground: String { return self._s[875]! } public func PUSH_CHAT_MESSAGE_CONTACT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[876]!, self._r[876]!, [_1, _2]) + return formatWithArgumentRanges(self._s[877]!, self._r[877]!, [_1, _2]) } - public var ProxyServer_VoiceOver_Active: String { return self._s[877]! } - public var Call_StatusBusy: String { return self._s[878]! } - public var Conversation_MessageDeliveryFailed: String { return self._s[879]! } - public var Login_NetworkError: String { return self._s[881]! } - public var TwoStepAuth_SetupPasswordDescription: String { return self._s[882]! } - public var Privacy_Calls_Integration: String { return self._s[883]! } - public var DialogList_SearchSectionMessages: String { return self._s[884]! } - public var AutoDownloadSettings_VideosTitle: String { return self._s[885]! } - public var Preview_DeletePhoto: String { return self._s[886]! } - public var PrivacySettings_PhoneNumber: String { return self._s[888]! } - public var Forward_ErrorDisabledForChat: String { return self._s[889]! } - public var Watch_Compose_CurrentLocation: String { return self._s[890]! } - public var Wallet_Info_TransactionFrom: String { return self._s[891]! } - public var Settings_CallSettings: String { return self._s[892]! } - public var AutoDownloadSettings_TypePrivateChats: String { return self._s[893]! } - public var ChatList_Context_MarkAllAsRead: String { return self._s[894]! } - public var ChatSettings_AutoPlayAnimations: String { return self._s[895]! } - public var SaveIncomingPhotosSettings_Title: String { return self._s[896]! } - public var OwnershipTransfer_SecurityRequirements: String { return self._s[897]! } - public var Map_LiveLocationFor1Hour: String { return self._s[898]! } + public var ProxyServer_VoiceOver_Active: String { return self._s[878]! } + public var Call_StatusBusy: String { return self._s[879]! } + public var Conversation_MessageDeliveryFailed: String { return self._s[880]! } + public var Login_NetworkError: String { return self._s[882]! } + public var TwoStepAuth_SetupPasswordDescription: String { return self._s[883]! } + public var Privacy_Calls_Integration: String { return self._s[884]! } + public var DialogList_SearchSectionMessages: String { return self._s[885]! } + public var AutoDownloadSettings_VideosTitle: String { return self._s[886]! } + public var Preview_DeletePhoto: String { return self._s[887]! } + public var PrivacySettings_PhoneNumber: String { return self._s[889]! } + public var Forward_ErrorDisabledForChat: String { return self._s[890]! } + public var Watch_Compose_CurrentLocation: String { return self._s[891]! } + public var Wallet_Info_TransactionFrom: String { return self._s[892]! } + public var Settings_CallSettings: String { return self._s[893]! } + public var AutoDownloadSettings_TypePrivateChats: String { return self._s[894]! } + public var ChatList_Context_MarkAllAsRead: String { return self._s[895]! } + public var ChatSettings_AutoPlayAnimations: String { return self._s[896]! } + public var SaveIncomingPhotosSettings_Title: String { return self._s[897]! } + public var OwnershipTransfer_SecurityRequirements: String { return self._s[898]! } + public var Map_LiveLocationFor1Hour: String { return self._s[899]! } public func Privacy_GroupsAndChannels_InviteToGroupError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[899]!, self._r[899]!, [_0, _1]) + return formatWithArgumentRanges(self._s[900]!, self._r[900]!, [_0, _1]) } public func Notification_PinnedLiveLocationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[900]!, self._r[900]!, [_0]) + return formatWithArgumentRanges(self._s[901]!, self._r[901]!, [_0]) } - public var Conversation_UnvotePoll: String { return self._s[901]! } - public var TwoStepAuth_EnterEmailCode: String { return self._s[902]! } + public var Conversation_UnvotePoll: String { return self._s[902]! } + public var TwoStepAuth_EnterEmailCode: String { return self._s[903]! } public func LOCAL_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[903]!, self._r[903]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[904]!, self._r[904]!, [_1, "\(_2)"]) } - public var Passport_InfoTitle: String { return self._s[904]! } + public var Passport_InfoTitle: String { return self._s[905]! } public func Conversation_Bytes(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[905]!, self._r[905]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[906]!, self._r[906]!, ["\(_0)"]) } - public var AccentColor_Title: String { return self._s[906]! } + public var AccentColor_Title: String { return self._s[907]! } public func PUSH_MESSAGE_INVOICE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[907]!, self._r[907]!, [_1, _2]) + return formatWithArgumentRanges(self._s[908]!, self._r[908]!, [_1, _2]) } public func Notification_JoinedChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[910]!, self._r[910]!, [_0]) + return formatWithArgumentRanges(self._s[911]!, self._r[911]!, [_0]) } - public var AutoDownloadSettings_DataUsageCustom: String { return self._s[911]! } - public var Conversation_ShareBotLocationConfirmation: String { return self._s[912]! } - public var PrivacyPhoneNumberSettings_WhoCanSeeMyPhoneNumber: String { return self._s[913]! } - public var VoiceOver_Editing_ClearText: String { return self._s[914]! } - public var Conversation_Unarchive: String { return self._s[915]! } - public var Notification_CallOutgoing: String { return self._s[916]! } - public var Channel_Setup_PublicNoLink: String { return self._s[917]! } - public var Passport_Identity_GenderPlaceholder: String { return self._s[918]! } - public var Message_Animation: String { return self._s[919]! } - public var SettingsSearch_Synonyms_Appearance_Animations: String { return self._s[920]! } - public var ChatSettings_ConnectionType_Title: String { return self._s[921]! } + public var AutoDownloadSettings_DataUsageCustom: String { return self._s[912]! } + public var Conversation_ShareBotLocationConfirmation: String { return self._s[913]! } + public var PrivacyPhoneNumberSettings_WhoCanSeeMyPhoneNumber: String { return self._s[914]! } + public var VoiceOver_Editing_ClearText: String { return self._s[915]! } + public var Conversation_Unarchive: String { return self._s[916]! } + public var Notification_CallOutgoing: String { return self._s[917]! } + public var Channel_Setup_PublicNoLink: String { return self._s[918]! } + public var Passport_Identity_GenderPlaceholder: String { return self._s[919]! } + public var Message_Animation: String { return self._s[920]! } + public var SettingsSearch_Synonyms_Appearance_Animations: String { return self._s[921]! } + public var ChatSettings_ConnectionType_Title: String { return self._s[922]! } public func Watch_Time_ShortFullAt(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[922]!, self._r[922]!, [_1, _2]) + return formatWithArgumentRanges(self._s[923]!, self._r[923]!, [_1, _2]) } - public var Notification_CallBack: String { return self._s[924]! } - public var Appearance_Title: String { return self._s[926]! } - public var NotificationsSound_Glass: String { return self._s[928]! } - public var AutoDownloadSettings_CellularTitle: String { return self._s[930]! } - public var Notifications_PermissionsSuppressWarningTitle: String { return self._s[932]! } - public var ChatSearch_SearchPlaceholder: String { return self._s[933]! } - public var Passport_Identity_AddPassport: String { return self._s[934]! } + public var Notification_CallBack: String { return self._s[925]! } + public var Appearance_Title: String { return self._s[927]! } + public var NotificationsSound_Glass: String { return self._s[929]! } + public var AutoDownloadSettings_CellularTitle: String { return self._s[931]! } + public var Notifications_PermissionsSuppressWarningTitle: String { return self._s[933]! } + public var ChatSearch_SearchPlaceholder: String { return self._s[934]! } + public var Passport_Identity_AddPassport: String { return self._s[935]! } public func Wallet_Time_PreciseDate_m1(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[936]!, self._r[936]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[937]!, self._r[937]!, [_1, _2, _3]) } - public var GroupPermission_NoAddMembers: String { return self._s[937]! } - public var ContactList_Context_SendMessage: String { return self._s[938]! } - public var PhotoEditor_GrainTool: String { return self._s[939]! } - public var Settings_CopyPhoneNumber: String { return self._s[940]! } - public var Passport_Address_City: String { return self._s[941]! } - public var ChannelRemoved_RemoveInfo: String { return self._s[942]! } - public var SocksProxySetup_Password: String { return self._s[944]! } - public var Wallet_Configuration_ApplyErrorTextJSONInvalidData: String { return self._s[945]! } - public var Settings_Passport: String { return self._s[946]! } - public var Channel_MessagePhotoUpdated: String { return self._s[948]! } - public var Stats_LanguagesTitle: String { return self._s[949]! } - public var ChatList_PeerTypeGroup: String { return self._s[950]! } - public var Privacy_Calls_P2PHelp: String { return self._s[951]! } - public var VoiceOver_Chat_PollNoVotes: String { return self._s[952]! } - public var Embed_PlayingInPIP: String { return self._s[953]! } - public var BlockedUsers_BlockUser: String { return self._s[956]! } - public var Login_CancelPhoneVerificationContinue: String { return self._s[957]! } + public var GroupPermission_NoAddMembers: String { return self._s[938]! } + public var ContactList_Context_SendMessage: String { return self._s[939]! } + public var PhotoEditor_GrainTool: String { return self._s[940]! } + public var Settings_CopyPhoneNumber: String { return self._s[941]! } + public var Passport_Address_City: String { return self._s[942]! } + public var ChannelRemoved_RemoveInfo: String { return self._s[943]! } + public var SocksProxySetup_Password: String { return self._s[945]! } + public var Wallet_Configuration_ApplyErrorTextJSONInvalidData: String { return self._s[946]! } + public var Settings_Passport: String { return self._s[947]! } + public var Channel_MessagePhotoUpdated: String { return self._s[949]! } + public var Stats_LanguagesTitle: String { return self._s[950]! } + public var ChatList_PeerTypeGroup: String { return self._s[951]! } + public var Privacy_Calls_P2PHelp: String { return self._s[952]! } + public var VoiceOver_Chat_PollNoVotes: String { return self._s[953]! } + public var Embed_PlayingInPIP: String { return self._s[954]! } + public var BlockedUsers_BlockUser: String { return self._s[957]! } + public var Login_CancelPhoneVerificationContinue: String { return self._s[958]! } public func PUSH_CHANNEL_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[958]!, self._r[958]!, [_1]) + return formatWithArgumentRanges(self._s[959]!, self._r[959]!, [_1]) } - public var AuthSessions_LoggedIn: String { return self._s[959]! } - public var Channel_AdminLog_MessagePreviousCaption: String { return self._s[960]! } - public var Wallet_SecureStorageReset_PasscodeText: String { return self._s[961]! } - public var Activity_UploadingDocument: String { return self._s[962]! } - public var PeopleNearby_NoMembers: String { return self._s[963]! } - public var SettingsSearch_Synonyms_Stickers_Masks: String { return self._s[966]! } - public var ChatSettings_AutoPlayVideos: String { return self._s[967]! } - public var VoiceOver_Chat_OpenLinkHint: String { return self._s[968]! } - public var Settings_ViewVideo: String { return self._s[970]! } - public var Map_ShowPlaces: String { return self._s[972]! } - public var Passport_Phone_UseTelegramNumberHelp: String { return self._s[973]! } - public var SettingsSearch_Synonyms_Appearance_ChatBackground_Custom: String { return self._s[974]! } + public var AuthSessions_LoggedIn: String { return self._s[960]! } + public var Channel_AdminLog_MessagePreviousCaption: String { return self._s[961]! } + public var Wallet_SecureStorageReset_PasscodeText: String { return self._s[962]! } + public var Activity_UploadingDocument: String { return self._s[963]! } + public var PeopleNearby_NoMembers: String { return self._s[964]! } + public var SettingsSearch_Synonyms_Stickers_Masks: String { return self._s[967]! } + public var ChatSettings_AutoPlayVideos: String { return self._s[968]! } + public var VoiceOver_Chat_OpenLinkHint: String { return self._s[969]! } + public var Settings_ViewVideo: String { return self._s[971]! } + public var Map_ShowPlaces: String { return self._s[973]! } + public var Passport_Phone_UseTelegramNumberHelp: String { return self._s[974]! } + public var SettingsSearch_Synonyms_Appearance_ChatBackground_Custom: String { return self._s[975]! } public func PrivacySettings_LastSeenContactsPlus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[975]!, self._r[975]!, [_0]) + return formatWithArgumentRanges(self._s[976]!, self._r[976]!, [_0]) } - public var Wallet_Month_ShortNovember: String { return self._s[976]! } - public var Conversation_StatusLeftGroup: String { return self._s[977]! } - public var Theme_Colors_Messages: String { return self._s[978]! } - public var AuthSessions_EmptyText: String { return self._s[979]! } + public var Wallet_Month_ShortNovember: String { return self._s[977]! } + public var Conversation_StatusLeftGroup: String { return self._s[978]! } + public var Theme_Colors_Messages: String { return self._s[979]! } + public var AuthSessions_EmptyText: String { return self._s[980]! } public func PUSH_MESSAGE_CONTACT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[980]!, self._r[980]!, [_1]) + return formatWithArgumentRanges(self._s[981]!, self._r[981]!, [_1]) } - public var UserInfo_StartSecretChat: String { return self._s[981]! } - public var ChatListFolderSettings_EditFoldersInfo: String { return self._s[982]! } - public var Channel_Edit_PrivatePublicLinkAlert: String { return self._s[983]! } - public var Conversation_ReportSpamGroupConfirmation: String { return self._s[984]! } - public var Conversation_PrivateMessageLinkCopied: String { return self._s[986]! } - public var PeerInfo_PaneFiles: String { return self._s[987]! } - public var PrivacySettings_AutoArchive: String { return self._s[988]! } - public var Camera_VideoMode: String { return self._s[989]! } - public var NotificationsSound_Alert: String { return self._s[990]! } - public var Privacy_Forwards_NeverAllow_Title: String { return self._s[991]! } - public var Appearance_AutoNightTheme: String { return self._s[992]! } - public var Passport_Language_he: String { return self._s[993]! } - public var Wallet_Configuration_BlockchainNameChangedText: String { return self._s[994]! } - public var Passport_InvalidPasswordError: String { return self._s[995]! } - public var Conversation_PinMessageAlert_OnlyPin: String { return self._s[996]! } - public var UserInfo_InviteBotToGroup: String { return self._s[997]! } - public var Conversation_SilentBroadcastTooltipOff: String { return self._s[998]! } - public var Common_TakePhoto: String { return self._s[999]! } - public var Passport_Email_UseTelegramEmailHelp: String { return self._s[1000]! } - public var Wallet_Configuration_ApplyErrorTextURLInvalid: String { return self._s[1001]! } - public var ChatList_Context_JoinChannel: String { return self._s[1002]! } - public var MediaPlayer_UnknownArtist: String { return self._s[1003]! } - public var KeyCommand_JumpToPreviousUnreadChat: String { return self._s[1006]! } - public var Channel_OwnershipTransfer_Title: String { return self._s[1007]! } - public var EditTheme_UploadEditedTheme: String { return self._s[1008]! } - public var Settings_SetProfilePhotoOrVideo: String { return self._s[1010]! } - public var Passport_FieldOneOf_Delimeter: String { return self._s[1011]! } - public var MessagePoll_ViewResults: String { return self._s[1012]! } - public var Group_Setup_TypePrivateHelp: String { return self._s[1013]! } - public var Passport_Address_OneOfTypeUtilityBill: String { return self._s[1014]! } - public var ChatList_Search_ShowLess: String { return self._s[1015]! } - public var UserInfo_ShareBot: String { return self._s[1016]! } - public var Privacy_Calls_P2P: String { return self._s[1018]! } - public var WebBrowser_InAppSafari: String { return self._s[1019]! } - public var SharedMedia_EmptyFilesText: String { return self._s[1020]! } - public var Channel_AdminLog_MessagePreviousMessage: String { return self._s[1022]! } - public var GroupInfo_SetSound: String { return self._s[1023]! } - public var Permissions_PeopleNearbyAllowInSettings_v0: String { return self._s[1024]! } - public var Channel_AdminLog_MessagePreviousDescription: String { return self._s[1025]! } - public var Channel_AdminLogFilter_EventsAll: String { return self._s[1026]! } - public var CallSettings_UseLessData: String { return self._s[1027]! } - public var InfoPlist_NSCameraUsageDescription: String { return self._s[1028]! } - public var NotificationsSound_Chord: String { return self._s[1029]! } - public var PhotoEditor_CurvesTool: String { return self._s[1030]! } - public var Appearance_ThemePreview_Chat_2_Text: String { return self._s[1031]! } - public var Resolve_ErrorNotFound: String { return self._s[1032]! } - public var Activity_PlayingGame: String { return self._s[1033]! } - public var Wallet_Send_UninitializedText: String { return self._s[1036]! } - public var StickerPacksSettings_AnimatedStickersInfo: String { return self._s[1037]! } + public var UserInfo_StartSecretChat: String { return self._s[982]! } + public var ChatListFolderSettings_EditFoldersInfo: String { return self._s[983]! } + public var Channel_Edit_PrivatePublicLinkAlert: String { return self._s[984]! } + public var Conversation_ReportSpamGroupConfirmation: String { return self._s[985]! } + public var Conversation_PrivateMessageLinkCopied: String { return self._s[987]! } + public var PeerInfo_PaneFiles: String { return self._s[988]! } + public var PrivacySettings_AutoArchive: String { return self._s[989]! } + public var Camera_VideoMode: String { return self._s[990]! } + public var NotificationsSound_Alert: String { return self._s[991]! } + public var Privacy_Forwards_NeverAllow_Title: String { return self._s[992]! } + public var Appearance_AutoNightTheme: String { return self._s[993]! } + public var Passport_Language_he: String { return self._s[994]! } + public var Wallet_Configuration_BlockchainNameChangedText: String { return self._s[995]! } + public var Passport_InvalidPasswordError: String { return self._s[996]! } + public var Conversation_PinMessageAlert_OnlyPin: String { return self._s[997]! } + public var UserInfo_InviteBotToGroup: String { return self._s[998]! } + public var Conversation_SilentBroadcastTooltipOff: String { return self._s[999]! } + public var Common_TakePhoto: String { return self._s[1000]! } + public var Passport_Email_UseTelegramEmailHelp: String { return self._s[1001]! } + public var Wallet_Configuration_ApplyErrorTextURLInvalid: String { return self._s[1002]! } + public var ChatList_Context_JoinChannel: String { return self._s[1003]! } + public var MediaPlayer_UnknownArtist: String { return self._s[1004]! } + public var KeyCommand_JumpToPreviousUnreadChat: String { return self._s[1007]! } + public var Channel_OwnershipTransfer_Title: String { return self._s[1008]! } + public var EditTheme_UploadEditedTheme: String { return self._s[1009]! } + public var Settings_SetProfilePhotoOrVideo: String { return self._s[1011]! } + public var Passport_FieldOneOf_Delimeter: String { return self._s[1012]! } + public var MessagePoll_ViewResults: String { return self._s[1013]! } + public var Group_Setup_TypePrivateHelp: String { return self._s[1014]! } + public var Passport_Address_OneOfTypeUtilityBill: String { return self._s[1015]! } + public var ChatList_Search_ShowLess: String { return self._s[1016]! } + public var UserInfo_ShareBot: String { return self._s[1017]! } + public var Privacy_Calls_P2P: String { return self._s[1019]! } + public var WebBrowser_InAppSafari: String { return self._s[1020]! } + public var SharedMedia_EmptyFilesText: String { return self._s[1021]! } + public var Channel_AdminLog_MessagePreviousMessage: String { return self._s[1023]! } + public var GroupInfo_SetSound: String { return self._s[1024]! } + public var Permissions_PeopleNearbyAllowInSettings_v0: String { return self._s[1025]! } + public var Channel_AdminLog_MessagePreviousDescription: String { return self._s[1026]! } + public var Channel_AdminLogFilter_EventsAll: String { return self._s[1027]! } + public var CallSettings_UseLessData: String { return self._s[1028]! } + public var InfoPlist_NSCameraUsageDescription: String { return self._s[1029]! } + public var NotificationsSound_Chord: String { return self._s[1030]! } + public var PhotoEditor_CurvesTool: String { return self._s[1031]! } + public var Appearance_ThemePreview_Chat_2_Text: String { return self._s[1032]! } + public var Resolve_ErrorNotFound: String { return self._s[1033]! } + public var Activity_PlayingGame: String { return self._s[1034]! } + public var Wallet_Send_UninitializedText: String { return self._s[1037]! } + public var StickerPacksSettings_AnimatedStickersInfo: String { return self._s[1038]! } public func PUSH_CHANNEL_MESSAGE_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1038]!, self._r[1038]!, [_1]) + return formatWithArgumentRanges(self._s[1039]!, self._r[1039]!, [_1]) } - public var Conversation_ShareBotContactConfirmationTitle: String { return self._s[1039]! } - public var Notification_CallIncoming: String { return self._s[1040]! } - public var Stats_EnabledNotifications: String { return self._s[1041]! } - public var Notifications_PermissionsOpenSettings: String { return self._s[1042]! } - public var Checkout_ErrorProviderAccountTimeout: String { return self._s[1043]! } + public var Conversation_ShareBotContactConfirmationTitle: String { return self._s[1040]! } + public var Notification_CallIncoming: String { return self._s[1041]! } + public var Stats_EnabledNotifications: String { return self._s[1042]! } + public var Notifications_PermissionsOpenSettings: String { return self._s[1043]! } + public var Checkout_ErrorProviderAccountTimeout: String { return self._s[1044]! } public func Activity_RemindAboutChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1044]!, self._r[1044]!, [_0]) + return formatWithArgumentRanges(self._s[1045]!, self._r[1045]!, [_0]) } - public var VoiceOver_Chat_ReplyToYourMessage: String { return self._s[1045]! } - public var Channel_DiscussionGroup_MakeHistoryPublic: String { return self._s[1046]! } - public var StickerPacksSettings_Title: String { return self._s[1047]! } + public var VoiceOver_Chat_ReplyToYourMessage: String { return self._s[1046]! } + public var Channel_DiscussionGroup_MakeHistoryPublic: String { return self._s[1047]! } + public var StickerPacksSettings_Title: String { return self._s[1048]! } public func Channel_AdminLog_MessageGroupPreHistoryVisible(_ _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 Watch_NoConnection: String { return self._s[1049]! } - public var EncryptionKey_Title: String { return self._s[1050]! } - public var Widget_AuthRequired: String { return self._s[1051]! } + public var Watch_NoConnection: String { return self._s[1050]! } + public var EncryptionKey_Title: String { return self._s[1051]! } + public var Widget_AuthRequired: String { return self._s[1052]! } public func PUSH_MESSAGE_ROUND(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1052]!, self._r[1052]!, [_1]) + return formatWithArgumentRanges(self._s[1053]!, self._r[1053]!, [_1]) } - public var Notifications_ExceptionsTitle: String { return self._s[1053]! } - public var EditTheme_Expand_TopInfo: String { return self._s[1054]! } + public var Notifications_ExceptionsTitle: String { return self._s[1054]! } + public var EditTheme_Expand_TopInfo: String { return self._s[1055]! } public func Contacts_AddPhoneNumber(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1055]!, self._r[1055]!, [_0]) + return formatWithArgumentRanges(self._s[1056]!, self._r[1056]!, [_0]) } - public var Channel_AdminLogFilter_EventsRestrictions: String { return self._s[1057]! } - public var Notifications_GroupNotificationsSound: String { return self._s[1058]! } - public var Passport_Email_EnterOtherEmail: String { return self._s[1059]! } - public var Conversation_AddToContacts: String { return self._s[1062]! } - public var AutoDownloadSettings_DataUsageMedium: String { return self._s[1063]! } - public var AuthSessions_LogOutApplications: String { return self._s[1065]! } - public var ChatList_Context_Unpin: String { return self._s[1066]! } - public var PeopleNearby_DiscoverDescription: String { return self._s[1067]! } - public var Notification_MessageLifetime1d: String { return self._s[1068]! } - public var PrivacyLastSeenSettings_NeverShareWith_Title: String { return self._s[1069]! } - public var ChatListFolder_CategoryChannels: String { return self._s[1070]! } - public var VoiceOver_Chat_SeenByRecipient: String { return self._s[1071]! } - public var Notifications_PermissionsAllow: String { return self._s[1072]! } - public var Undo_ScheduledMessagesCleared: String { return self._s[1073]! } - public var AutoDownloadSettings_PrivateChats: String { return self._s[1075]! } - public var ApplyLanguage_ChangeLanguageAction: String { return self._s[1076]! } + public var Channel_AdminLogFilter_EventsRestrictions: String { return self._s[1058]! } + public var Notifications_GroupNotificationsSound: String { return self._s[1059]! } + public var Passport_Email_EnterOtherEmail: String { return self._s[1060]! } + public var Conversation_AddToContacts: String { return self._s[1063]! } + public var AutoDownloadSettings_DataUsageMedium: String { return self._s[1064]! } + public var AuthSessions_LogOutApplications: String { return self._s[1066]! } + public var ChatList_Context_Unpin: String { return self._s[1067]! } + public var PeopleNearby_DiscoverDescription: String { return self._s[1068]! } + public var Notification_MessageLifetime1d: String { return self._s[1069]! } + public var PrivacyLastSeenSettings_NeverShareWith_Title: String { return self._s[1070]! } + public var ChatListFolder_CategoryChannels: String { return self._s[1071]! } + public var VoiceOver_Chat_SeenByRecipient: String { return self._s[1072]! } + public var Notifications_PermissionsAllow: String { return self._s[1073]! } + public var Undo_ScheduledMessagesCleared: String { return self._s[1074]! } + public var AutoDownloadSettings_PrivateChats: String { return self._s[1076]! } + public var ApplyLanguage_ChangeLanguageAction: String { return self._s[1077]! } public func PrivacySettings_LastSeenNobodyPlus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1077]!, self._r[1077]!, [_0]) + return formatWithArgumentRanges(self._s[1078]!, self._r[1078]!, [_0]) } - public var Wallet_WordImport_Title: String { return self._s[1078]! } - public var Notifications_MessageNotificationsHelp: String { return self._s[1081]! } - public var WallpaperSearch_ColorPink: String { return self._s[1082]! } - public var ContactInfo_PhoneNumberHidden: String { return self._s[1083]! } - public var Passport_Identity_IssueDate: String { return self._s[1085]! } + public var Wallet_WordImport_Title: String { return self._s[1079]! } + public var Notifications_MessageNotificationsHelp: String { return self._s[1082]! } + public var WallpaperSearch_ColorPink: String { return self._s[1083]! } + public var ContactInfo_PhoneNumberHidden: String { return self._s[1084]! } + public var Passport_Identity_IssueDate: String { return self._s[1086]! } public func PUSH_CHAT_MESSAGE_GIF(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1086]!, self._r[1086]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1087]!, self._r[1087]!, [_1, _2]) } - public var PrivacySettings_DeleteAccountIfAwayFor: String { return self._s[1087]! } - public var Channel_Info_Description: String { return self._s[1088]! } - public var Common_Back: String { return self._s[1089]! } - public var Weekday_ShortTuesday: String { return self._s[1090]! } - public var Chat_PinnedMessagesHiddenTitle: String { return self._s[1092]! } - public var ChatListFolder_AddChats: String { return self._s[1093]! } - public var Common_Close: String { return self._s[1095]! } - public var Map_OpenIn: String { return self._s[1096]! } - public var Group_Setup_HistoryTitle: String { return self._s[1097]! } + public var PrivacySettings_DeleteAccountIfAwayFor: String { return self._s[1088]! } + public var Channel_Info_Description: String { return self._s[1089]! } + public var Common_Back: String { return self._s[1090]! } + public var Weekday_ShortTuesday: String { return self._s[1091]! } + public var Chat_PinnedMessagesHiddenTitle: String { return self._s[1093]! } + public var ChatListFolder_AddChats: String { return self._s[1094]! } + public var Common_Close: String { return self._s[1096]! } + public var Map_OpenIn: String { return self._s[1097]! } + public var Group_Setup_HistoryTitle: String { return self._s[1098]! } public func Wallet_Info_TransactionDateHeaderYear(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1098]!, self._r[1098]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1099]!, self._r[1099]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Data_AutoDownloadUsingWifi: String { return self._s[1099]! } - public var Notification_MessageLifetime1h: String { return self._s[1100]! } + public var SettingsSearch_Synonyms_Data_AutoDownloadUsingWifi: String { return self._s[1100]! } + public var Notification_MessageLifetime1h: String { return self._s[1101]! } public func CancelResetAccount_Success(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1101]!, self._r[1101]!, [_0]) + return formatWithArgumentRanges(self._s[1102]!, self._r[1102]!, [_0]) } - public var Watch_Contacts_NoResults: String { return self._s[1103]! } - public var TwoStepAuth_SetupResendEmailCode: String { return self._s[1104]! } - public var Checkout_Phone: String { return self._s[1105]! } - public var OwnershipTransfer_ComeBackLater: String { return self._s[1106]! } + public var Watch_Contacts_NoResults: String { return self._s[1104]! } + public var TwoStepAuth_SetupResendEmailCode: String { return self._s[1105]! } + public var Checkout_Phone: String { return self._s[1106]! } + public var OwnershipTransfer_ComeBackLater: String { return self._s[1107]! } public func DialogList_MultipleTypingSuffix(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1107]!, self._r[1107]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[1108]!, self._r[1108]!, ["\(_0)"]) } public func Channel_CommentsGroup_HeaderGroupSet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1108]!, self._r[1108]!, [_0]) + return formatWithArgumentRanges(self._s[1109]!, self._r[1109]!, [_0]) } - public var ChatAdmins_Title: String { return self._s[1109]! } - public var Appearance_ThemePreview_Chat_7_Text: String { return self._s[1110]! } + public var ChatAdmins_Title: String { return self._s[1110]! } + public var Appearance_ThemePreview_Chat_7_Text: String { return self._s[1111]! } public func PUSH_CHANNEL_MESSAGE_POLL(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1111]!, self._r[1111]!, [_1]) + return formatWithArgumentRanges(self._s[1112]!, self._r[1112]!, [_1]) } - public var Common_Done: String { return self._s[1112]! } - public var Wallet_Send_AddressHeader: String { return self._s[1115]! } + public var Common_Done: String { return self._s[1113]! } + public var Wallet_Send_AddressHeader: String { return self._s[1116]! } public func PUSH_PINNED_VIDEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1117]!, self._r[1117]!, [_1]) + return formatWithArgumentRanges(self._s[1118]!, self._r[1118]!, [_1]) } - public var Appearance_ThemeCarouselNight: String { return self._s[1118]! } - public var Preview_OpenInInstagram: String { return self._s[1120]! } - public var Wallpaper_SetColor: String { return self._s[1124]! } - public var VoiceOver_Media_PlaybackRate: String { return self._s[1125]! } - public var ChatSettings_Groups: String { return self._s[1126]! } + public var Appearance_ThemeCarouselNight: String { return self._s[1119]! } + public var Preview_OpenInInstagram: String { return self._s[1121]! } + public var Wallpaper_SetColor: String { return self._s[1125]! } + public var VoiceOver_Media_PlaybackRate: String { return self._s[1126]! } + public var ChatSettings_Groups: String { return self._s[1127]! } public func VoiceOver_Chat_VoiceMessageFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1127]!, self._r[1127]!, [_0]) + return formatWithArgumentRanges(self._s[1128]!, self._r[1128]!, [_0]) } - public var Contacts_SortedByName: String { return self._s[1128]! } - public var SettingsSearch_Synonyms_Notifications_ContactJoined: String { return self._s[1129]! } - public var Wallet_Send_Title: String { return self._s[1130]! } - public var Channel_Management_LabelCreator: String { return self._s[1131]! } - public var Contacts_PermissionsSuppressWarningTitle: String { return self._s[1132]! } + public var Contacts_SortedByName: String { return self._s[1129]! } + public var SettingsSearch_Synonyms_Notifications_ContactJoined: String { return self._s[1130]! } + public var Wallet_Send_Title: String { return self._s[1131]! } + public var Channel_Management_LabelCreator: String { return self._s[1132]! } + public var Contacts_PermissionsSuppressWarningTitle: String { return self._s[1133]! } public func PrivacySettings_LastSeenContactsMinusPlus(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1133]!, self._r[1133]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1134]!, self._r[1134]!, [_0, _1]) } - public var Group_PublicLink_Title: String { return self._s[1134]! } - public var Channel_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[1135]! } - public var VoiceOver_Chat_Photo: String { return self._s[1136]! } - public var TwoFactorSetup_EmailVerification_Placeholder: String { return self._s[1137]! } - public var IntentsSettings_SuggestBy: String { return self._s[1138]! } - public var Privacy_Calls_AlwaysAllow_Placeholder: String { return self._s[1139]! } - public var Appearance_ThemePreview_ChatList_1_Name: String { return self._s[1140]! } - public var PhoneNumberHelp_ChangeNumber: String { return self._s[1141]! } - public var LogoutOptions_SetPasscodeText: String { return self._s[1142]! } - public var Map_OpenInMaps: String { return self._s[1143]! } - public var ContactInfo_PhoneLabelWorkFax: String { return self._s[1144]! } - public var BlockedUsers_Unblock: String { return self._s[1145]! } + public var Group_PublicLink_Title: String { return self._s[1135]! } + public var Channel_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[1136]! } + public var VoiceOver_Chat_Photo: String { return self._s[1137]! } + public var TwoFactorSetup_EmailVerification_Placeholder: String { return self._s[1138]! } + public var IntentsSettings_SuggestBy: String { return self._s[1139]! } + public var Privacy_Calls_AlwaysAllow_Placeholder: String { return self._s[1140]! } + public var Appearance_ThemePreview_ChatList_1_Name: String { return self._s[1141]! } + public var PhoneNumberHelp_ChangeNumber: String { return self._s[1142]! } + public var LogoutOptions_SetPasscodeText: String { return self._s[1143]! } + public var Map_OpenInMaps: String { return self._s[1144]! } + public var ContactInfo_PhoneLabelWorkFax: String { return self._s[1145]! } + public var BlockedUsers_Unblock: String { return self._s[1146]! } public func Settings_ApplyProxyAlert(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1146]!, self._r[1146]!, [_1, _2]) - } - public func Channel_AdminLog_MessageRestrictedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1147]!, self._r[1147]!, [_1, _2]) } - public var Conversation_Block: String { return self._s[1149]! } - public var Passport_Scans_UploadNew: String { return self._s[1150]! } - public var Share_Title: String { return self._s[1151]! } - public var Wallet_Send_SendAnyway: String { return self._s[1152]! } + public func Channel_AdminLog_MessageRestrictedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1148]!, self._r[1148]!, [_1, _2]) + } + public var Conversation_Block: String { return self._s[1150]! } + public var Passport_Scans_UploadNew: String { return self._s[1151]! } + public var Share_Title: String { return self._s[1152]! } + public var Wallet_Send_SendAnyway: String { return self._s[1153]! } public func Wallet_Time_PreciseDate_m8(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1153]!, self._r[1153]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1154]!, self._r[1154]!, [_1, _2, _3]) } - public var Conversation_ApplyLocalization: String { return self._s[1154]! } - public var SharedMedia_EmptyLinksText: String { return self._s[1155]! } - public var Settings_NotificationsAndSounds: String { return self._s[1156]! } - public var Stats_ViewsByHoursTitle: String { return self._s[1157]! } - public var PhotoEditor_QualityMedium: String { return self._s[1158]! } - public var Conversation_ContextMenuCancelSending: String { return self._s[1159]! } + public var Conversation_ApplyLocalization: String { return self._s[1155]! } + public var SharedMedia_EmptyLinksText: String { return self._s[1156]! } + public var Settings_NotificationsAndSounds: String { return self._s[1157]! } + public var Stats_ViewsByHoursTitle: String { return self._s[1158]! } + public var PhotoEditor_QualityMedium: String { return self._s[1159]! } + public var Conversation_ContextMenuCancelSending: String { return self._s[1160]! } public func PUSH_CHANNEL_MESSAGE_GAME(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1160]!, self._r[1160]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1161]!, self._r[1161]!, [_1, _2]) } - public var Conversation_RestrictedInline: String { return self._s[1161]! } - public var Passport_Language_tr: String { return self._s[1162]! } - public var Call_Mute: String { return self._s[1163]! } + public var Conversation_RestrictedInline: String { return self._s[1162]! } + public var Passport_Language_tr: String { return self._s[1163]! } + public var Call_Mute: String { return self._s[1164]! } public func Conversation_NoticeInvitedByInGroup(_ _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 Passport_Language_bn: String { return self._s[1165]! } - public var AccessDenied_LocationTracking: String { return self._s[1167]! } - public var Month_ShortOctober: String { return self._s[1168]! } - public var AutoDownloadSettings_WiFi: String { return self._s[1169]! } - public var ProfilePhoto_SetMainPhoto: String { return self._s[1171]! } - public var ChangePhoneNumberNumber_NewNumber: String { return self._s[1172]! } + public var Passport_Language_bn: String { return self._s[1166]! } + public var AccessDenied_LocationTracking: String { return self._s[1168]! } + public var Month_ShortOctober: String { return self._s[1169]! } + public var AutoDownloadSettings_WiFi: String { return self._s[1170]! } + public var ProfilePhoto_SetMainPhoto: String { return self._s[1172]! } + public var ChangePhoneNumberNumber_NewNumber: String { return self._s[1173]! } public func Time_MonthOfYear_m3(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1173]!, self._r[1173]!, [_0]) + return formatWithArgumentRanges(self._s[1174]!, self._r[1174]!, [_0]) } - public var Watch_ChannelInfo_Title: String { return self._s[1174]! } - public var State_Updating: String { return self._s[1175]! } - public var Conversation_UnblockUser: String { return self._s[1176]! } - public var Notifications_ChannelNotificationsSound: String { return self._s[1177]! } - public var Map_GetDirections: String { return self._s[1178]! } - public var Watch_Compose_AddContact: String { return self._s[1180]! } - public var Conversation_Dice_u26BD: String { return self._s[1181]! } - public var AccessDenied_PhotosRestricted: String { return self._s[1182]! } + public var Watch_ChannelInfo_Title: String { return self._s[1175]! } + public var State_Updating: String { return self._s[1176]! } + public var Conversation_UnblockUser: String { return self._s[1177]! } + public var Notifications_ChannelNotificationsSound: String { return self._s[1178]! } + public var Map_GetDirections: String { return self._s[1179]! } + public var Watch_Compose_AddContact: String { return self._s[1181]! } + public var Conversation_Dice_u26BD: String { return self._s[1182]! } + public var AccessDenied_PhotosRestricted: String { return self._s[1183]! } public func Channel_AdminLog_MessageRank(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1183]!, self._r[1183]!, [_1]) + return formatWithArgumentRanges(self._s[1184]!, self._r[1184]!, [_1]) } - public var Wallet_UnknownError: String { return self._s[1185]! } - public var Map_LoadError: String { return self._s[1186]! } - public var SettingsSearch_Synonyms_Privacy_Calls: String { return self._s[1187]! } - public var PhotoEditor_CropAuto: String { return self._s[1188]! } - public var Wallet_Month_ShortApril: String { return self._s[1191]! } + public var Wallet_UnknownError: String { return self._s[1186]! } + public var Map_LoadError: String { return self._s[1187]! } + public var SettingsSearch_Synonyms_Privacy_Calls: String { return self._s[1188]! } + public var PhotoEditor_CropAuto: String { return self._s[1189]! } + public var Wallet_Month_ShortApril: String { return self._s[1192]! } public func Target_ShareGameConfirmationPrivate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1192]!, self._r[1192]!, [_0]) + return formatWithArgumentRanges(self._s[1193]!, self._r[1193]!, [_0]) } public func PUSH_PINNED_GAME(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1194]!, self._r[1194]!, [_1]) + return formatWithArgumentRanges(self._s[1195]!, self._r[1195]!, [_1]) } - public var Username_TooManyPublicUsernamesError: String { return self._s[1195]! } - public var Settings_PhoneNumber: String { return self._s[1196]! } + public var Username_TooManyPublicUsernamesError: String { return self._s[1196]! } + public var Settings_PhoneNumber: String { return self._s[1197]! } public func Channel_AdminLog_MessageTransferedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1197]!, self._r[1197]!, [_1]) + return formatWithArgumentRanges(self._s[1198]!, self._r[1198]!, [_1]) } - public var Month_GenJune: String { return self._s[1199]! } - public var Notifications_ExceptionsGroupPlaceholder: String { return self._s[1200]! } - public var ChatListFolder_CategoryRead: String { return self._s[1201]! } - public var LoginPassword_ResetAccount: String { return self._s[1202]! } + public var Month_GenJune: String { return self._s[1200]! } + public var Notifications_ExceptionsGroupPlaceholder: String { return self._s[1201]! } + public var ChatListFolder_CategoryRead: String { return self._s[1202]! } + public var LoginPassword_ResetAccount: String { return self._s[1203]! } public func DialogList_SingleUploadingFileSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1203]!, self._r[1203]!, [_0]) + return formatWithArgumentRanges(self._s[1204]!, self._r[1204]!, [_0]) } - public var Call_CameraConfirmationConfirm: String { return self._s[1204]! } - public var Notification_RenamedChannel: String { return self._s[1205]! } + public var Call_CameraConfirmationConfirm: String { return self._s[1205]! } + public var Notification_RenamedChannel: String { return self._s[1206]! } public func Channel_AdminLog_MessageUnpinned(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1206]!, self._r[1206]!, [_0]) + return formatWithArgumentRanges(self._s[1207]!, self._r[1207]!, [_0]) } - public var Channel_AdminLogFilter_EventsAdmins: String { return self._s[1207]! } - public var IntentsSettings_Title: String { return self._s[1209]! } - public var Settings_AppleWatch: String { return self._s[1210]! } - public var DialogList_NoMessagesText: String { return self._s[1211]! } - public var GroupPermission_NoChangeInfo: String { return self._s[1212]! } - public var Channel_ErrorAccessDenied: String { return self._s[1214]! } - public var ScheduledMessages_EmptyPlaceholder: String { return self._s[1215]! } + public var Channel_AdminLogFilter_EventsAdmins: String { return self._s[1208]! } + public var IntentsSettings_Title: String { return self._s[1210]! } + public var Settings_AppleWatch: String { return self._s[1211]! } + public var DialogList_NoMessagesText: String { return self._s[1212]! } + public var GroupPermission_NoChangeInfo: String { return self._s[1213]! } + public var Channel_ErrorAccessDenied: String { return self._s[1215]! } + public var ScheduledMessages_EmptyPlaceholder: String { return self._s[1216]! } public func Message_StickerText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1217]!, self._r[1217]!, [_0]) + return formatWithArgumentRanges(self._s[1218]!, self._r[1218]!, [_0]) } - public var AuthSessions_TerminateOtherSessionsHelp: String { return self._s[1218]! } - public var StickerPacksSettings_AnimatedStickers: String { return self._s[1219]! } - public var Month_ShortJanuary: String { return self._s[1220]! } - public var Conversation_UnreadMessages: String { return self._s[1221]! } - public var Conversation_PrivateChannelTooltip: String { return self._s[1223]! } - public var PrivacySettings_DeleteAccountTitle: String { return self._s[1225]! } - public var Channel_Members_AddBannedErrorAdmin: String { return self._s[1226]! } + public var AuthSessions_TerminateOtherSessionsHelp: String { return self._s[1219]! } + public var StickerPacksSettings_AnimatedStickers: String { return self._s[1220]! } + public var Month_ShortJanuary: String { return self._s[1221]! } + public var Conversation_UnreadMessages: String { return self._s[1222]! } + public var Conversation_PrivateChannelTooltip: String { return self._s[1224]! } + public var PrivacySettings_DeleteAccountTitle: String { return self._s[1226]! } + public var Channel_Members_AddBannedErrorAdmin: String { return self._s[1227]! } public func Conversation_ShareMyPhoneNumberConfirmation(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1229]!, self._r[1229]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1230]!, self._r[1230]!, [_1, _2]) } - public var Widget_ApplicationLocked: String { return self._s[1230]! } + public var Widget_ApplicationLocked: String { return self._s[1231]! } public func TextFormat_AddLinkText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1231]!, self._r[1231]!, [_0]) + return formatWithArgumentRanges(self._s[1232]!, self._r[1232]!, [_0]) } - public var Common_TakePhotoOrVideo: String { return self._s[1232]! } - public var Passport_Language_ru: String { return self._s[1233]! } - public var MediaPicker_VideoMuteDescription: String { return self._s[1234]! } - public var EditTheme_ErrorLinkTaken: String { return self._s[1235]! } + public var Common_TakePhotoOrVideo: String { return self._s[1233]! } + public var Passport_Language_ru: String { return self._s[1234]! } + public var MediaPicker_VideoMuteDescription: String { return self._s[1235]! } + public var EditTheme_ErrorLinkTaken: String { return self._s[1236]! } public func Group_EditAdmin_RankInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1237]!, self._r[1237]!, [_0]) + return formatWithArgumentRanges(self._s[1238]!, self._r[1238]!, [_0]) } - public var Channel_Members_AddAdminErrorBlacklisted: String { return self._s[1238]! } - public var Conversation_Owner: String { return self._s[1240]! } - public var Settings_FAQ_Intro: String { return self._s[1241]! } - public var PhotoEditor_QualityLow: String { return self._s[1243]! } - public var Widget_GalleryTitle: String { return self._s[1244]! } - public var Call_End: String { return self._s[1245]! } - public var StickerPacksSettings_FeaturedPacks: String { return self._s[1247]! } - public var Privacy_ContactsSyncHelp: String { return self._s[1248]! } - public var OldChannels_NoticeUpgradeText: String { return self._s[1252]! } - public var Conversation_Call: String { return self._s[1254]! } - public var Watch_MessageView_Title: String { return self._s[1255]! } + public var Channel_Members_AddAdminErrorBlacklisted: String { return self._s[1239]! } + public var Conversation_Owner: String { return self._s[1241]! } + public var Settings_FAQ_Intro: String { return self._s[1242]! } + public var PhotoEditor_QualityLow: String { return self._s[1244]! } + public var Widget_GalleryTitle: String { return self._s[1245]! } + public var Call_End: String { return self._s[1246]! } + public var StickerPacksSettings_FeaturedPacks: String { return self._s[1248]! } + public var Privacy_ContactsSyncHelp: String { return self._s[1249]! } + public var OldChannels_NoticeUpgradeText: String { return self._s[1253]! } + public var Conversation_Call: String { return self._s[1255]! } + public var Watch_MessageView_Title: String { return self._s[1256]! } public func Notification_RenamedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1256]!, self._r[1256]!, [_0]) + return formatWithArgumentRanges(self._s[1257]!, self._r[1257]!, [_0]) } - public var Passport_PasswordCompleteSetup: String { return self._s[1257]! } + public var Passport_PasswordCompleteSetup: String { return self._s[1258]! } public func Notification_ChangedGroupVideo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1258]!, self._r[1258]!, [_0]) + return formatWithArgumentRanges(self._s[1259]!, self._r[1259]!, [_0]) } public func TwoFactorSetup_EmailVerification_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1260]!, self._r[1260]!, [_0]) + return formatWithArgumentRanges(self._s[1261]!, self._r[1261]!, [_0]) } - public var Map_Location: String { return self._s[1261]! } - public var Watch_MessageView_ViewOnPhone: String { return self._s[1262]! } - public var Login_CountryCode: String { return self._s[1263]! } - public var Wallet_Settings_ConfigurationInfo: String { return self._s[1264]! } - public var Channel_DiscussionGroup_PrivateGroup: String { return self._s[1265]! } - public var ChatState_ConnectingToProxy: String { return self._s[1266]! } - public var Login_CallRequestState3: String { return self._s[1267]! } - public var NetworkUsageSettings_MediaAudioDataSection: String { return self._s[1269]! } - public var SocksProxySetup_ProxyStatusConnecting: String { return self._s[1270]! } - public var PrivacyLastSeenSettings_NeverShareWith_Placeholder: String { return self._s[1273]! } - public var Call_StatusEnded: String { return self._s[1274]! } - public var MusicPlayer_VoiceNote: String { return self._s[1277]! } + public var Map_Location: String { return self._s[1262]! } + public var Watch_MessageView_ViewOnPhone: String { return self._s[1263]! } + public var Login_CountryCode: String { return self._s[1264]! } + public var Wallet_Settings_ConfigurationInfo: String { return self._s[1265]! } + public var Channel_DiscussionGroup_PrivateGroup: String { return self._s[1266]! } + public var ChatState_ConnectingToProxy: String { return self._s[1267]! } + public var Login_CallRequestState3: String { return self._s[1268]! } + public var NetworkUsageSettings_MediaAudioDataSection: String { return self._s[1270]! } + public var SocksProxySetup_ProxyStatusConnecting: String { return self._s[1271]! } + public var PrivacyLastSeenSettings_NeverShareWith_Placeholder: String { return self._s[1274]! } + public var Call_StatusEnded: String { return self._s[1275]! } + public var MusicPlayer_VoiceNote: String { return self._s[1278]! } public func PUSH_CHANNEL_MESSAGE_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1278]!, self._r[1278]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1279]!, self._r[1279]!, [_1, _2]) } - public var VoiceOver_MessageContextShare: String { return self._s[1279]! } - public var ProfilePhoto_SearchWeb: String { return self._s[1280]! } - public var EditProfile_Title: String { return self._s[1281]! } + public var VoiceOver_MessageContextShare: String { return self._s[1280]! } + public var ProfilePhoto_SearchWeb: String { return self._s[1281]! } + public var EditProfile_Title: String { return self._s[1282]! } public func Notification_PinnedQuizMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1282]!, self._r[1282]!, [_0]) + return formatWithArgumentRanges(self._s[1283]!, self._r[1283]!, [_0]) } - public var ChangePhoneNumberCode_CodePlaceholder: String { return self._s[1283]! } - public var NetworkUsageSettings_ResetStats: String { return self._s[1285]! } - public var Wallet_Qr_ScanCode: String { return self._s[1286]! } - public var NetworkUsageSettings_GeneralDataSection: String { return self._s[1287]! } - public var StickerPackActionInfo_AddedTitle: String { return self._s[1288]! } - public var Channel_BanUser_PermissionSendStickersAndGifs: String { return self._s[1289]! } + public var ChangePhoneNumberCode_CodePlaceholder: String { return self._s[1284]! } + public var NetworkUsageSettings_ResetStats: String { return self._s[1286]! } + public var Wallet_Qr_ScanCode: String { return self._s[1287]! } + public var NetworkUsageSettings_GeneralDataSection: String { return self._s[1288]! } + public var StickerPackActionInfo_AddedTitle: String { return self._s[1289]! } + public var Channel_BanUser_PermissionSendStickersAndGifs: String { return self._s[1290]! } public func Call_ParticipantVideoVersionOutdatedError(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1290]!, self._r[1290]!, [_0]) + return formatWithArgumentRanges(self._s[1291]!, self._r[1291]!, [_0]) } - public var AuthSessions_AddDeviceIntro_Text1: String { return self._s[1292]! } - public var Location_ProximityNotification_Title: String { return self._s[1294]! } - public var Passport_Identity_LatinNameHelp: String { return self._s[1295]! } - public var AuthSessions_AddDeviceIntro_Text2: String { return self._s[1296]! } - public var Stats_GroupMembersTitle: String { return self._s[1297]! } - public var AuthSessions_AddDeviceIntro_Text3: String { return self._s[1298]! } - public var Contacts_PermissionsSuppressWarningText: String { return self._s[1299]! } - public var OpenFile_PotentiallyDangerousContentAlert: String { return self._s[1300]! } - public var Wallet_Info_Address: String { return self._s[1301]! } - public var Settings_SetUsername: String { return self._s[1302]! } - public var GroupInfo_ActionRestrict: String { return self._s[1303]! } + public var AuthSessions_AddDeviceIntro_Text1: String { return self._s[1293]! } + public var Location_ProximityNotification_Title: String { return self._s[1295]! } + public var Passport_Identity_LatinNameHelp: String { return self._s[1296]! } + public var AuthSessions_AddDeviceIntro_Text2: String { return self._s[1297]! } + public var Stats_GroupMembersTitle: String { return self._s[1298]! } + public var AuthSessions_AddDeviceIntro_Text3: String { return self._s[1299]! } + public var Contacts_PermissionsSuppressWarningText: String { return self._s[1300]! } + public var OpenFile_PotentiallyDangerousContentAlert: String { return self._s[1301]! } + public var Wallet_Info_Address: String { return self._s[1302]! } + public var Settings_SetUsername: String { return self._s[1303]! } + public var GroupInfo_ActionRestrict: String { return self._s[1304]! } public func Wallet_Configuration_ApplyErrorTextURLUnreachable(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1304]!, self._r[1304]!, [_0]) + return formatWithArgumentRanges(self._s[1305]!, self._r[1305]!, [_0]) } - public var SettingsSearch_Synonyms_SavedMessages: String { return self._s[1305]! } + public var SettingsSearch_Synonyms_SavedMessages: String { return self._s[1306]! } public func Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1306]!, self._r[1306]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1307]!, self._r[1307]!, [_1, _2, _3]) } - public var Notifications_DisplayNamesOnLockScreenInfoWithLink: String { return self._s[1307]! } - public var Notification_Exceptions_AlwaysOff: String { return self._s[1308]! } - public var Conversation_ContextMenuDelete: String { return self._s[1309]! } - public var Privacy_Calls_WhoCanCallMe: String { return self._s[1310]! } - public var ChatList_PsaAlert_covid: String { return self._s[1313]! } - public var DialogList_Pin: String { return self._s[1314]! } - public var PrivacySettings_SecurityTitle: String { return self._s[1315]! } - public var GroupPermission_NotAvailableInPublicGroups: String { return self._s[1316]! } - public var PeopleNearby_Groups: String { return self._s[1317]! } - public var Message_File: String { return self._s[1318]! } - public var Calls_NoCallsPlaceholder: String { return self._s[1319]! } - public var ChatList_GenericPsaLabel: String { return self._s[1321]! } - public var UserInfo_LastNamePlaceholder: String { return self._s[1322]! } - public var IntentsSettings_Reset: String { return self._s[1324]! } - public var Call_ConnectionErrorTitle: String { return self._s[1325]! } - public var PhotoEditor_SaturationTool: String { return self._s[1326]! } - public var ChatSettings_AutomaticVideoMessageDownload: String { return self._s[1327]! } - public var SettingsSearch_Synonyms_Stickers_ArchivedPacks: String { return self._s[1328]! } - public var Conversation_SearchNoResults: String { return self._s[1329]! } - public var Channel_DiscussionGroup_PrivateChannel: String { return self._s[1330]! } - public var Map_OpenInWaze: String { return self._s[1331]! } - public var WallpaperPreview_Title: String { return self._s[1332]! } + public var Notifications_DisplayNamesOnLockScreenInfoWithLink: String { return self._s[1308]! } + public var Notification_Exceptions_AlwaysOff: String { return self._s[1309]! } + public var Conversation_ContextMenuDelete: String { return self._s[1310]! } + public var Privacy_Calls_WhoCanCallMe: String { return self._s[1311]! } + public var ChatList_PsaAlert_covid: String { return self._s[1314]! } + public var DialogList_Pin: String { return self._s[1315]! } + public var PrivacySettings_SecurityTitle: String { return self._s[1316]! } + public var GroupPermission_NotAvailableInPublicGroups: String { return self._s[1317]! } + public var PeopleNearby_Groups: String { return self._s[1318]! } + public var Message_File: String { return self._s[1319]! } + public var Calls_NoCallsPlaceholder: String { return self._s[1320]! } + public var ChatList_GenericPsaLabel: String { return self._s[1322]! } + public var UserInfo_LastNamePlaceholder: String { return self._s[1323]! } + public var IntentsSettings_Reset: String { return self._s[1325]! } + public var Call_ConnectionErrorTitle: String { return self._s[1326]! } + public var PhotoEditor_SaturationTool: String { return self._s[1327]! } + public var ChatSettings_AutomaticVideoMessageDownload: String { return self._s[1328]! } + public var SettingsSearch_Synonyms_Stickers_ArchivedPacks: String { return self._s[1329]! } + public var Conversation_SearchNoResults: String { return self._s[1330]! } + public var Channel_DiscussionGroup_PrivateChannel: String { return self._s[1331]! } + public var Map_OpenInWaze: String { return self._s[1332]! } + public var WallpaperPreview_Title: String { return self._s[1333]! } public func Passport_AcceptHelp(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1334]!, self._r[1334]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1335]!, self._r[1335]!, [_1, _2]) } - public var AuthSessions_AddDeviceIntro_Title: String { return self._s[1335]! } - public var VoiceOver_Chat_RecordModeVideoMessageInfo: String { return self._s[1336]! } - public var Wallet_Month_ShortMay: String { return self._s[1337]! } - public var Wallet_Send_OwnAddressAlertTitle: String { return self._s[1338]! } - public var Passport_Identity_OneOfTypeInternalPassport: String { return self._s[1339]! } - public var Notifications_PermissionsUnreachableTitle: String { return self._s[1341]! } - public var Stats_Total: String { return self._s[1344]! } - public var Stats_GroupMessages: String { return self._s[1345]! } - public var TwoFactorSetup_Email_SkipAction: String { return self._s[1346]! } - public var CheckoutInfo_ErrorPhoneInvalid: String { return self._s[1347]! } - public var Wallet_TransactionInfo_OtherFeeInfoUrl: String { return self._s[1348]! } - public var Passport_Identity_Translation: String { return self._s[1349]! } - public var Notifications_TextTone: String { return self._s[1351]! } - public var Settings_RemoveConfirmation: String { return self._s[1353]! } - public var ScheduledMessages_Delete: String { return self._s[1354]! } - public var Channel_AdminLog_BanEmbedLinks: String { return self._s[1355]! } - public var Passport_PasswordNext: String { return self._s[1356]! } + public var AuthSessions_AddDeviceIntro_Title: String { return self._s[1336]! } + public var VoiceOver_Chat_RecordModeVideoMessageInfo: String { return self._s[1337]! } + public var Wallet_Month_ShortMay: String { return self._s[1338]! } + public var Wallet_Send_OwnAddressAlertTitle: String { return self._s[1339]! } + public var Passport_Identity_OneOfTypeInternalPassport: String { return self._s[1340]! } + public var Notifications_PermissionsUnreachableTitle: String { return self._s[1342]! } + public var Stats_Total: String { return self._s[1345]! } + public var Stats_GroupMessages: String { return self._s[1346]! } + public var TwoFactorSetup_Email_SkipAction: String { return self._s[1347]! } + public var CheckoutInfo_ErrorPhoneInvalid: String { return self._s[1348]! } + public var Wallet_TransactionInfo_OtherFeeInfoUrl: String { return self._s[1349]! } + public var Passport_Identity_Translation: String { return self._s[1350]! } + public var Notifications_TextTone: String { return self._s[1352]! } + public var Settings_RemoveConfirmation: String { return self._s[1354]! } + public var ScheduledMessages_Delete: String { return self._s[1355]! } + public var Channel_AdminLog_BanEmbedLinks: String { return self._s[1356]! } + public var Passport_PasswordNext: String { return self._s[1357]! } public func PUSH_ENCRYPTED_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1357]!, self._r[1357]!, [_1]) + return formatWithArgumentRanges(self._s[1358]!, self._r[1358]!, [_1]) } - public var Passport_Address_EditBankStatement: String { return self._s[1358]! } - public var PhotoEditor_ShadowsTool: String { return self._s[1359]! } - public var Notification_VideoCallMissed: String { return self._s[1360]! } - public var Wallet_WordCheck_IncorrectText: String { return self._s[1361]! } - public var AccessDenied_CameraDisabled: String { return self._s[1362]! } - public var AuthSessions_AddDevice_ScanInfo: String { return self._s[1363]! } - public var Notifications_ExceptionsMuted: String { return self._s[1364]! } - public var Conversation_ScheduleMessage_SendWhenOnline: String { return self._s[1365]! } - public var Wallet_Receive_ShareInvoiceUrl: String { return self._s[1366]! } - public var Channel_BlackList_Title: String { return self._s[1367]! } - public var PasscodeSettings_4DigitCode: String { return self._s[1368]! } - public var NotificationsSound_Bamboo: String { return self._s[1369]! } - public var PrivacySettings_LastSeenContacts: String { return self._s[1370]! } - public var Passport_Address_TypeUtilityBill: String { return self._s[1371]! } - public var Passport_Address_CountryPlaceholder: String { return self._s[1372]! } - public var GroupPermission_SectionTitle: String { return self._s[1373]! } + public var Passport_Address_EditBankStatement: String { return self._s[1359]! } + public var PhotoEditor_ShadowsTool: String { return self._s[1360]! } + public var Notification_VideoCallMissed: String { return self._s[1361]! } + public var Wallet_WordCheck_IncorrectText: String { return self._s[1362]! } + public var AccessDenied_CameraDisabled: String { return self._s[1363]! } + public var AuthSessions_AddDevice_ScanInfo: String { return self._s[1364]! } + public var Notifications_ExceptionsMuted: String { return self._s[1365]! } + public var Conversation_ScheduleMessage_SendWhenOnline: String { return self._s[1366]! } + public var Wallet_Receive_ShareInvoiceUrl: String { return self._s[1367]! } + public var Channel_BlackList_Title: String { return self._s[1368]! } + public var PasscodeSettings_4DigitCode: String { return self._s[1369]! } + public var NotificationsSound_Bamboo: String { return self._s[1370]! } + public var PrivacySettings_LastSeenContacts: String { return self._s[1371]! } + public var Passport_Address_TypeUtilityBill: String { return self._s[1372]! } + public var Passport_Address_CountryPlaceholder: String { return self._s[1373]! } + public var GroupPermission_SectionTitle: String { return self._s[1374]! } public func Notification_InvitedMultiple(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1374]!, self._r[1374]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1375]!, self._r[1375]!, [_0, _1]) } - public var CheckoutInfo_ShippingInfoStatePlaceholder: String { return self._s[1375]! } - public var Channel_LeaveChannel: String { return self._s[1376]! } - public var Watch_Notification_Joined: String { return self._s[1377]! } - public var PeerInfo_ButtonMore: String { return self._s[1378]! } - public var Passport_FieldEmailHelp: String { return self._s[1379]! } - public var ChatList_Context_Pin: String { return self._s[1380]! } + public var CheckoutInfo_ShippingInfoStatePlaceholder: String { return self._s[1376]! } + public var Channel_LeaveChannel: String { return self._s[1377]! } + public var Watch_Notification_Joined: String { return self._s[1378]! } + public var PeerInfo_ButtonMore: String { return self._s[1379]! } + public var Passport_FieldEmailHelp: String { return self._s[1380]! } + public var ChatList_Context_Pin: String { return self._s[1381]! } public func Time_MonthOfYear_m9(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1381]!, self._r[1381]!, [_0]) + return formatWithArgumentRanges(self._s[1382]!, self._r[1382]!, [_0]) } - public var Group_Location_CreateInThisPlace: String { return self._s[1382]! } - public var PhotoEditor_QualityVeryHigh: String { return self._s[1383]! } - public var Wallet_Receive_CreateInvoiceInfo: String { return self._s[1384]! } - public var Wallet_TransactionInfo_StorageFeeInfoUrl: String { return self._s[1385]! } + public var Group_Location_CreateInThisPlace: String { return self._s[1383]! } + public var PhotoEditor_QualityVeryHigh: String { return self._s[1384]! } + public var Wallet_Receive_CreateInvoiceInfo: String { return self._s[1385]! } + public var Wallet_TransactionInfo_StorageFeeInfoUrl: String { return self._s[1386]! } public func PUSH_CHAT_MESSAGE_FWD(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1386]!, self._r[1386]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1387]!, self._r[1387]!, [_1, _2]) } - public var Tour_Title5: String { return self._s[1387]! } - public var Wallet_Navigation_Back: String { return self._s[1388]! } - public var Passport_Language_en: String { return self._s[1389]! } - public var Checkout_Name: String { return self._s[1390]! } + public var Tour_Title5: String { return self._s[1388]! } + public var Wallet_Navigation_Back: String { return self._s[1389]! } + public var Passport_Language_en: String { return self._s[1390]! } + public var Checkout_Name: String { return self._s[1391]! } public func NetworkUsageSettings_WifiUsageSince(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1391]!, self._r[1391]!, [_0]) + return formatWithArgumentRanges(self._s[1392]!, self._r[1392]!, [_0]) } - public var Wallet_Send_Confirmation: String { return self._s[1392]! } - public var PhotoEditor_EnhanceTool: String { return self._s[1393]! } + public var Wallet_Send_Confirmation: String { return self._s[1393]! } + public var PhotoEditor_EnhanceTool: String { return self._s[1394]! } public func PUSH_CHAT_DELETE_YOU(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1394]!, self._r[1394]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1395]!, self._r[1395]!, [_1, _2]) } public func Login_TermsOfService_ProceedBot(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1395]!, self._r[1395]!, [_0]) + return formatWithArgumentRanges(self._s[1396]!, self._r[1396]!, [_0]) } - public var Group_ErrorSendRestrictedMedia: String { return self._s[1396]! } + public var Group_ErrorSendRestrictedMedia: String { return self._s[1397]! } public func UserInfo_NotificationsDefaultSound(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1397]!, self._r[1397]!, [_0]) + return formatWithArgumentRanges(self._s[1398]!, self._r[1398]!, [_0]) } - public var Login_UnknownError: String { return self._s[1398]! } - public var Passport_Identity_TypeDriversLicense: String { return self._s[1401]! } - public var ChatList_AutoarchiveSuggestion_Title: String { return self._s[1402]! } - public var Watch_PhotoView_Title: String { return self._s[1403]! } - public var Appearance_ThemePreview_ChatList_3_Text: String { return self._s[1404]! } - public var Checkout_TotalAmount: String { return self._s[1405]! } - public var ChatList_RemoveFolderAction: String { return self._s[1406]! } - public var GroupInfo_SetGroupPhoto: String { return self._s[1407]! } - public var Watch_AppName: String { return self._s[1408]! } + public var Login_UnknownError: String { return self._s[1399]! } + public var Passport_Identity_TypeDriversLicense: String { return self._s[1402]! } + public var ChatList_AutoarchiveSuggestion_Title: String { return self._s[1403]! } + public var Watch_PhotoView_Title: String { return self._s[1404]! } + public var Appearance_ThemePreview_ChatList_3_Text: String { return self._s[1405]! } + public var Checkout_TotalAmount: String { return self._s[1406]! } + public var ChatList_RemoveFolderAction: String { return self._s[1407]! } + public var GroupInfo_SetGroupPhoto: String { return self._s[1408]! } + public var Watch_AppName: String { return self._s[1409]! } public func PUSH_PINNED_GAME_SCORE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1409]!, self._r[1409]!, [_1]) + return formatWithArgumentRanges(self._s[1410]!, self._r[1410]!, [_1]) } - public var Channel_Username_CheckingUsername: String { return self._s[1410]! } - public var ContactList_Context_Call: String { return self._s[1411]! } - public var ChatList_ReorderTabs: String { return self._s[1412]! } - public var Watch_ChatList_Compose: String { return self._s[1413]! } + public var Channel_Username_CheckingUsername: String { return self._s[1411]! } + public var ContactList_Context_Call: String { return self._s[1412]! } + public var ChatList_ReorderTabs: String { return self._s[1413]! } + public var Watch_ChatList_Compose: String { return self._s[1414]! } public func Conversation_LiveLocationYouAnd(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1414]!, self._r[1414]!, [_0]) + return formatWithArgumentRanges(self._s[1415]!, self._r[1415]!, [_0]) } - public var Channel_AdminLog_EmptyFilterTitle: String { return self._s[1415]! } - public var ArchivedChats_IntroTitle1: String { return self._s[1416]! } + public var Channel_AdminLog_EmptyFilterTitle: String { return self._s[1416]! } + public var ArchivedChats_IntroTitle1: String { return self._s[1417]! } public func PUSH_ENCRYPTION_ACCEPT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1417]!, self._r[1417]!, [_1]) + return formatWithArgumentRanges(self._s[1418]!, self._r[1418]!, [_1]) } - public var Call_StatusRequesting: String { return self._s[1419]! } - public var Checkout_TotalPaidAmount: String { return self._s[1420]! } - public var Weekday_Friday: String { return self._s[1422]! } - public var CreateGroup_ChannelsTooMuch: String { return self._s[1423]! } - public var Watch_ChatList_NoConversationsText: String { return self._s[1424]! } + public var Call_StatusRequesting: String { return self._s[1420]! } + public var Checkout_TotalPaidAmount: String { return self._s[1421]! } + public var Weekday_Friday: String { return self._s[1423]! } + public var CreateGroup_ChannelsTooMuch: String { return self._s[1424]! } + public var Watch_ChatList_NoConversationsText: String { return self._s[1425]! } public func Channel_AdminLog_MessageChangedGroupStickerPack(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1425]!, self._r[1425]!, [_0]) + return formatWithArgumentRanges(self._s[1426]!, self._r[1426]!, [_0]) } - public var SecretVideo_Title: String { return self._s[1426]! } + public var SecretVideo_Title: String { return self._s[1427]! } public func Notification_PinnedStickerMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1429]!, self._r[1429]!, [_0]) + return formatWithArgumentRanges(self._s[1430]!, self._r[1430]!, [_0]) } - public var Undo_Undo: String { return self._s[1430]! } - public var Watch_Microphone_Access: String { return self._s[1431]! } + public var Undo_Undo: String { return self._s[1431]! } + public var Watch_Microphone_Access: String { return self._s[1432]! } public func PUSH_CHAT_MESSAGE_PHOTO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1432]!, self._r[1432]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1433]!, self._r[1433]!, [_1, _2]) } public func ChatList_Search_NoResultsQueryDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1433]!, self._r[1433]!, [_0]) + return formatWithArgumentRanges(self._s[1434]!, self._r[1434]!, [_0]) } - public var Wallet_Configuration_SourceURL: String { return self._s[1434]! } - public var Wallet_Intro_CreateErrorTitle: String { return self._s[1435]! } - public var Checkout_NewCard_PostcodeTitle: String { return self._s[1436]! } - public var TwoFactorSetup_Intro_Action: String { return self._s[1437]! } - public var Passport_Language_ne: String { return self._s[1439]! } - public var TwoStepAuth_EmailHelp: String { return self._s[1441]! } - public var Profile_MessageLifetime2s: String { return self._s[1442]! } + public var Wallet_Configuration_SourceURL: String { return self._s[1435]! } + public var Wallet_Intro_CreateErrorTitle: String { return self._s[1436]! } + public var Checkout_NewCard_PostcodeTitle: String { return self._s[1437]! } + public var TwoFactorSetup_Intro_Action: String { return self._s[1438]! } + public var Passport_Language_ne: String { return self._s[1440]! } + public var TwoStepAuth_EmailHelp: String { return self._s[1442]! } + public var Profile_MessageLifetime2s: String { return self._s[1443]! } public func Conversation_MessageDialogRetryAll(_ _1: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1443]!, self._r[1443]!, ["\(_1)"]) + return formatWithArgumentRanges(self._s[1444]!, self._r[1444]!, ["\(_1)"]) } public func Items_NOfM(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1444]!, self._r[1444]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1445]!, self._r[1445]!, [_1, _2]) } - public var GroupPermission_NoPinMessages: String { return self._s[1445]! } + public var GroupPermission_NoPinMessages: String { return self._s[1446]! } public func PUSH_CHAT_TITLE_EDITED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1446]!, self._r[1446]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1447]!, self._r[1447]!, [_1, _2]) } - public var Wallet_Month_GenJuly: String { return self._s[1447]! } + public var Wallet_Month_GenJuly: String { return self._s[1448]! } public func Notification_CreatedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1448]!, self._r[1448]!, [_0]) + return formatWithArgumentRanges(self._s[1449]!, self._r[1449]!, [_0]) } - public var FastTwoStepSetup_HintHelp: String { return self._s[1449]! } - public var WallpaperSearch_ColorRed: String { return self._s[1450]! } - public var Watch_ConnectionDescription: String { return self._s[1451]! } - public var Notification_Exceptions_AddException: String { return self._s[1452]! } - public var LocalGroup_IrrelevantWarning: String { return self._s[1453]! } - public var VoiceOver_MessageContextDelete: String { return self._s[1454]! } - public var LogoutOptions_AlternativeOptionsSection: String { return self._s[1455]! } - public var Passport_PasswordPlaceholder: String { return self._s[1456]! } - public var TwoStepAuth_RecoveryEmailAddDescription: String { return self._s[1457]! } - public var Stats_MessageInteractionsTitle: String { return self._s[1458]! } - public var Appearance_ThemeCarouselClassic: String { return self._s[1459]! } - public var TwoFactorSetup_Email_SkipConfirmationText: String { return self._s[1461]! } - public var Channel_AdminLog_PinMessages: String { return self._s[1462]! } - public var Passport_Address_AddRentalAgreement: String { return self._s[1463]! } - public var Watch_Message_Game: String { return self._s[1464]! } - public var PrivacyLastSeenSettings_NeverShareWith: String { return self._s[1465]! } - public var PrivacyPolicy_DeclineLastWarning: String { return self._s[1466]! } - public var EditTheme_FileReadError: String { return self._s[1467]! } - public var Group_ErrorAddBlocked: String { return self._s[1468]! } - public var CallSettings_UseLessDataLongDescription: String { return self._s[1469]! } + public var FastTwoStepSetup_HintHelp: String { return self._s[1450]! } + public var WallpaperSearch_ColorRed: String { return self._s[1451]! } + public var Watch_ConnectionDescription: String { return self._s[1452]! } + public var Notification_Exceptions_AddException: String { return self._s[1453]! } + public var LocalGroup_IrrelevantWarning: String { return self._s[1454]! } + public var VoiceOver_MessageContextDelete: String { return self._s[1455]! } + public var LogoutOptions_AlternativeOptionsSection: String { return self._s[1456]! } + public var Passport_PasswordPlaceholder: String { return self._s[1457]! } + public var TwoStepAuth_RecoveryEmailAddDescription: String { return self._s[1458]! } + public var Stats_MessageInteractionsTitle: String { return self._s[1459]! } + public var Appearance_ThemeCarouselClassic: String { return self._s[1460]! } + public var TwoFactorSetup_Email_SkipConfirmationText: String { return self._s[1462]! } + public var Channel_AdminLog_PinMessages: String { return self._s[1463]! } + public var Passport_Address_AddRentalAgreement: String { return self._s[1464]! } + public var Watch_Message_Game: String { return self._s[1465]! } + public var PrivacyLastSeenSettings_NeverShareWith: String { return self._s[1466]! } + public var PrivacyPolicy_DeclineLastWarning: String { return self._s[1467]! } + public var EditTheme_FileReadError: String { return self._s[1468]! } + public var Group_ErrorAddBlocked: String { return self._s[1469]! } + public var CallSettings_UseLessDataLongDescription: String { return self._s[1470]! } public func PUSH_MESSAGE_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1471]!, self._r[1471]!, [_1]) + return formatWithArgumentRanges(self._s[1472]!, self._r[1472]!, [_1]) } public func UserInfo_BlockConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1472]!, self._r[1472]!, [_0]) + return formatWithArgumentRanges(self._s[1473]!, self._r[1473]!, [_0]) } - public var CheckoutInfo_ShippingInfoAddress2Placeholder: String { return self._s[1473]! } - public var TwoFactorSetup_EmailVerification_Action: String { return self._s[1474]! } + public var CheckoutInfo_ShippingInfoAddress2Placeholder: String { return self._s[1474]! } + public var TwoFactorSetup_EmailVerification_Action: String { return self._s[1475]! } public func Username_LinkHint(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1475]!, self._r[1475]!, [_0]) + return formatWithArgumentRanges(self._s[1476]!, self._r[1476]!, [_0]) } - public var ConversationProfile_ErrorCreatingConversation: String { return self._s[1476]! } - public var Bot_GroupStatusReadsHistory: String { return self._s[1477]! } - public var PhotoEditor_CurvesRed: String { return self._s[1478]! } - public var InstantPage_TapToOpenLink: String { return self._s[1479]! } - public var FastTwoStepSetup_PasswordHelp: String { return self._s[1480]! } - public var Conversation_DiscussionNotStarted: String { return self._s[1481]! } - public var Notification_CallMissedShort: String { return self._s[1482]! } + public var ConversationProfile_ErrorCreatingConversation: String { return self._s[1477]! } + public var Bot_GroupStatusReadsHistory: String { return self._s[1478]! } + public var PhotoEditor_CurvesRed: String { return self._s[1479]! } + public var InstantPage_TapToOpenLink: String { return self._s[1480]! } + public var FastTwoStepSetup_PasswordHelp: String { return self._s[1481]! } + public var Conversation_DiscussionNotStarted: String { return self._s[1482]! } + public var Notification_CallMissedShort: String { return self._s[1483]! } public func Notification_JoinedGroupByLink(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1483]!, self._r[1483]!, [_0]) + return formatWithArgumentRanges(self._s[1484]!, self._r[1484]!, [_0]) } - public var Conversation_DeleteMessagesForEveryone: String { return self._s[1484]! } - public var Wallet_Words_NotDoneTitle: String { return self._s[1485]! } - public var Permissions_SiriTitle_v0: String { return self._s[1486]! } - public var GroupInfo_AddUserLeftError: String { return self._s[1487]! } - public var Conversation_SendMessage_SendSilently: String { return self._s[1488]! } - public var Paint_Duplicate: String { return self._s[1489]! } - public var AttachmentMenu_WebSearch: String { return self._s[1490]! } - public var Bot_Stop: String { return self._s[1492]! } - public var Conversation_PrivateChannelTimeLimitedAlertTitle: String { return self._s[1493]! } - public var Wallet_TransactionInfo_SendGrams: String { return self._s[1494]! } - public var ReportGroupLocation_Report: String { return self._s[1495]! } - public var Compose_Create: String { return self._s[1496]! } - public var Stats_GroupViewers: String { return self._s[1497]! } - public var AutoDownloadSettings_Channels: String { return self._s[1498]! } - public var PhotoEditor_QualityHigh: String { return self._s[1499]! } - public var Call_Speaker: String { return self._s[1500]! } + public var Conversation_DeleteMessagesForEveryone: String { return self._s[1485]! } + public var Wallet_Words_NotDoneTitle: String { return self._s[1486]! } + public var Permissions_SiriTitle_v0: String { return self._s[1487]! } + public var GroupInfo_AddUserLeftError: String { return self._s[1488]! } + public var Conversation_SendMessage_SendSilently: String { return self._s[1489]! } + public var Paint_Duplicate: String { return self._s[1490]! } + public var AttachmentMenu_WebSearch: String { return self._s[1491]! } + public var Bot_Stop: String { return self._s[1493]! } + public var Conversation_PrivateChannelTimeLimitedAlertTitle: String { return self._s[1494]! } + public var Wallet_TransactionInfo_SendGrams: String { return self._s[1495]! } + public var ReportGroupLocation_Report: String { return self._s[1496]! } + public var Compose_Create: String { return self._s[1497]! } + public var Stats_GroupViewers: String { return self._s[1498]! } + public var AutoDownloadSettings_Channels: String { return self._s[1499]! } + public var PhotoEditor_QualityHigh: String { return self._s[1500]! } + public var Call_Speaker: String { return self._s[1501]! } public func ChatList_LeaveGroupConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1501]!, self._r[1501]!, [_0]) + return formatWithArgumentRanges(self._s[1502]!, self._r[1502]!, [_0]) } - public var Conversation_CloudStorage_ChatStatus: String { return self._s[1502]! } - public var Chat_AttachmentMultipleFilesDisabled: String { return self._s[1503]! } - public var ChatList_Context_AddToFolder: String { return self._s[1504]! } + public var Conversation_CloudStorage_ChatStatus: String { return self._s[1503]! } + public var Chat_AttachmentMultipleFilesDisabled: String { return self._s[1504]! } + public var ChatList_Context_AddToFolder: String { return self._s[1505]! } public func Wallet_SecureStorageReset_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1505]!, self._r[1505]!, [_0]) + return formatWithArgumentRanges(self._s[1506]!, self._r[1506]!, [_0]) } - public var Conversation_Unblock: String { return self._s[1506]! } - public var SettingsSearch_Synonyms_Proxy_UseForCalls: String { return self._s[1507]! } + public var Conversation_Unblock: String { return self._s[1507]! } + public var SettingsSearch_Synonyms_Proxy_UseForCalls: String { return self._s[1508]! } public func Time_PreciseDate_m8(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1508]!, self._r[1508]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1509]!, self._r[1509]!, [_1, _2, _3]) } - public var Conversation_ContextMenuReply: String { return self._s[1509]! } - public var Contacts_SearchLabel: String { return self._s[1510]! } - public var Forward_ErrorPublicQuizDisabledInChannels: String { return self._s[1511]! } - public var Stats_GroupMessagesTitle: String { return self._s[1513]! } - public var Wallet_Send_UninitializedTitle: String { return self._s[1514]! } - public var Notification_CallCanceled: String { return self._s[1515]! } - public var VoiceOver_Chat_Selected: String { return self._s[1516]! } - public var NotificationsSound_Tremolo: String { return self._s[1518]! } - public var ChatList_Search_NoResultsDescription: String { return self._s[1519]! } - public var AccessDenied_PhotosAndVideos: String { return self._s[1520]! } - public var AppWallet_Intro_Text: String { return self._s[1521]! } - public var LogoutOptions_ClearCacheText: String { return self._s[1523]! } - public var ChatListFolder_NameUnread: String { return self._s[1524]! } - public var PeerInfo_ButtonMessage: String { return self._s[1526]! } - public var InfoPlist_NSPhotoLibraryAddUsageDescription: String { return self._s[1527]! } - public var BlockedUsers_SelectUserTitle: String { return self._s[1528]! } - public var ChatSettings_Other: String { return self._s[1529]! } - public var UserInfo_NotificationsEnabled: String { return self._s[1530]! } - public var CreatePoll_OptionsHeader: String { return self._s[1531]! } - public var Wallet_Created_Title: String { return self._s[1534]! } - public var Appearance_RemoveThemeColorConfirmation: String { return self._s[1535]! } - public var Channel_Moderator_Title: String { return self._s[1536]! } - public var Channel_AdminLog_MessageRestrictedForever: String { return self._s[1537]! } - public var WallpaperColors_Title: String { return self._s[1538]! } - public var PrivacyPolicy_DeclineMessage: String { return self._s[1540]! } - public var AutoDownloadSettings_VoiceMessagesTitle: String { return self._s[1541]! } - public var Your_card_was_declined: String { return self._s[1542]! } - public var SettingsSearch_FAQ: String { return self._s[1544]! } - public var EditTheme_Expand_Preview_IncomingReplyName: String { return self._s[1545]! } - public var Conversation_ReportSpamConfirmation: String { return self._s[1546]! } - public var OwnershipTransfer_SecurityCheck: String { return self._s[1548]! } - public var PrivacySettings_DataSettingsHelp: String { return self._s[1549]! } - public var Settings_About_Help: String { return self._s[1550]! } + public var Conversation_ContextMenuReply: String { return self._s[1510]! } + public var Contacts_SearchLabel: String { return self._s[1511]! } + public var Forward_ErrorPublicQuizDisabledInChannels: String { return self._s[1512]! } + public var Stats_GroupMessagesTitle: String { return self._s[1514]! } + public var Wallet_Send_UninitializedTitle: String { return self._s[1515]! } + public var Notification_CallCanceled: String { return self._s[1516]! } + public var VoiceOver_Chat_Selected: String { return self._s[1517]! } + public var NotificationsSound_Tremolo: String { return self._s[1519]! } + public var ChatList_Search_NoResultsDescription: String { return self._s[1520]! } + public var AccessDenied_PhotosAndVideos: String { return self._s[1521]! } + public var AppWallet_Intro_Text: String { return self._s[1522]! } + public var LogoutOptions_ClearCacheText: String { return self._s[1524]! } + public var ChatListFolder_NameUnread: String { return self._s[1525]! } + public var PeerInfo_ButtonMessage: String { return self._s[1527]! } + public var InfoPlist_NSPhotoLibraryAddUsageDescription: String { return self._s[1528]! } + public var BlockedUsers_SelectUserTitle: String { return self._s[1529]! } + public var ChatSettings_Other: String { return self._s[1530]! } + public var UserInfo_NotificationsEnabled: String { return self._s[1531]! } + public var CreatePoll_OptionsHeader: String { return self._s[1532]! } + public var Wallet_Created_Title: String { return self._s[1535]! } + public var Appearance_RemoveThemeColorConfirmation: String { return self._s[1536]! } + public var Channel_Moderator_Title: String { return self._s[1537]! } + public var Channel_AdminLog_MessageRestrictedForever: String { return self._s[1538]! } + public var WallpaperColors_Title: String { return self._s[1539]! } + public var PrivacyPolicy_DeclineMessage: String { return self._s[1541]! } + public var AutoDownloadSettings_VoiceMessagesTitle: String { return self._s[1542]! } + public var Your_card_was_declined: String { return self._s[1543]! } + public var SettingsSearch_FAQ: String { return self._s[1545]! } + public var EditTheme_Expand_Preview_IncomingReplyName: String { return self._s[1546]! } + public var Conversation_ReportSpamConfirmation: String { return self._s[1547]! } + public var OwnershipTransfer_SecurityCheck: String { return self._s[1549]! } + public var PrivacySettings_DataSettingsHelp: String { return self._s[1550]! } + public var Settings_About_Help: String { return self._s[1551]! } public func Channel_DiscussionGroup_HeaderGroupSet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1551]!, self._r[1551]!, [_0]) + return formatWithArgumentRanges(self._s[1552]!, self._r[1552]!, [_0]) } - public var Wallet_Settings_Title: String { return self._s[1552]! } - public var Settings_Proxy: String { return self._s[1553]! } - public var TwoStepAuth_ResetAccountConfirmation: String { return self._s[1554]! } - public var Passport_Identity_TypePassportUploadScan: String { return self._s[1556]! } - public var NotificationsSound_Bell: String { return self._s[1557]! } - public var PrivacySettings_Title: String { return self._s[1559]! } - public var PrivacySettings_DataSettings: String { return self._s[1560]! } - public var ConversationMedia_Title: String { return self._s[1561]! } + public var Wallet_Settings_Title: String { return self._s[1553]! } + public var Settings_Proxy: String { return self._s[1554]! } + public var TwoStepAuth_ResetAccountConfirmation: String { return self._s[1555]! } + public var Passport_Identity_TypePassportUploadScan: String { return self._s[1557]! } + public var NotificationsSound_Bell: String { return self._s[1558]! } + public var PrivacySettings_Title: String { return self._s[1560]! } + public var PrivacySettings_DataSettings: String { return self._s[1561]! } + public var ConversationMedia_Title: String { return self._s[1562]! } public func Conversation_EncryptedPlaceholderTitleIncoming(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1562]!, self._r[1562]!, [_0]) + return formatWithArgumentRanges(self._s[1563]!, self._r[1563]!, [_0]) } - public var PrivacySettings_BlockedPeersEmpty: String { return self._s[1563]! } - public var ReportPeer_ReasonPornography: String { return self._s[1565]! } - public var Privacy_Calls: String { return self._s[1566]! } - public var TwoFactorSetup_Email_Text: String { return self._s[1567]! } - public var Conversation_EncryptedDescriptionTitle: String { return self._s[1568]! } + public var PrivacySettings_BlockedPeersEmpty: String { return self._s[1564]! } + public var ReportPeer_ReasonPornography: String { return self._s[1566]! } + public var Privacy_Calls: String { return self._s[1567]! } + public var TwoFactorSetup_Email_Text: String { return self._s[1568]! } + public var Conversation_EncryptedDescriptionTitle: String { return self._s[1569]! } public func VoiceOver_Chat_MusicTitle(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1569]!, self._r[1569]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1570]!, self._r[1570]!, [_1, _2]) } - public var Passport_Identity_FrontSideHelp: String { return self._s[1570]! } - public var GroupInfo_Permissions_SlowmodeHeader: String { return self._s[1572]! } - public var ContactList_Context_VideoCall: String { return self._s[1573]! } - public var Settings_SaveIncomingPhotos: String { return self._s[1574]! } - public var Passport_Identity_MiddleName: String { return self._s[1575]! } - public var MessagePoll_QuizNoUsers: String { return self._s[1576]! } - public var OldChannels_ChannelFormat: String { return self._s[1577]! } - public var Watch_Message_Call: String { return self._s[1578]! } - public var Wallpaper_Title: String { return self._s[1579]! } - public var PasscodeSettings_TurnPasscodeOff: String { return self._s[1580]! } - public var IntentsSettings_SuggestedChatsSavedMessages: String { return self._s[1581]! } - public var ReportGroupLocation_Text: String { return self._s[1582]! } - public var InviteText_URL: String { return self._s[1583]! } - public var ClearCache_StorageServiceFiles: String { return self._s[1584]! } - public var MessageTimer_Custom: String { return self._s[1585]! } - public var Message_PinnedLocationMessage: String { return self._s[1586]! } + public var Passport_Identity_FrontSideHelp: String { return self._s[1571]! } + public var GroupInfo_Permissions_SlowmodeHeader: String { return self._s[1573]! } + public var ContactList_Context_VideoCall: String { return self._s[1574]! } + public var Settings_SaveIncomingPhotos: String { return self._s[1575]! } + public var Passport_Identity_MiddleName: String { return self._s[1576]! } + public var MessagePoll_QuizNoUsers: String { return self._s[1577]! } + public var OldChannels_ChannelFormat: String { return self._s[1578]! } + public var Watch_Message_Call: String { return self._s[1579]! } + public var Wallpaper_Title: String { return self._s[1580]! } + public var PasscodeSettings_TurnPasscodeOff: String { return self._s[1581]! } + public var IntentsSettings_SuggestedChatsSavedMessages: String { return self._s[1582]! } + public var ReportGroupLocation_Text: String { return self._s[1583]! } + public var InviteText_URL: String { return self._s[1584]! } + public var ClearCache_StorageServiceFiles: String { return self._s[1585]! } + public var MessageTimer_Custom: String { return self._s[1586]! } + public var Message_PinnedLocationMessage: String { return self._s[1587]! } public func VoiceOver_Chat_ContactOrganization(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1587]!, self._r[1587]!, [_0]) + return formatWithArgumentRanges(self._s[1588]!, self._r[1588]!, [_0]) } - public var EditTheme_UploadNewTheme: String { return self._s[1588]! } + public var EditTheme_UploadNewTheme: String { return self._s[1589]! } public func AutoDownloadSettings_UpToForAll(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1590]!, self._r[1590]!, [_0]) + return formatWithArgumentRanges(self._s[1591]!, self._r[1591]!, [_0]) } - public var Login_CodeSentCall: String { return self._s[1592]! } - public var Conversation_Report: String { return self._s[1593]! } - public var NotificationSettings_ContactJoined: String { return self._s[1594]! } + public var Login_CodeSentCall: String { return self._s[1593]! } + public var Conversation_Report: String { return self._s[1594]! } + public var NotificationSettings_ContactJoined: String { return self._s[1595]! } public func PUSH_MESSAGE_SCREENSHOT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1595]!, self._r[1595]!, [_1]) + return formatWithArgumentRanges(self._s[1596]!, self._r[1596]!, [_1]) } - public var StickerPacksSettings_ShowStickersButtonHelp: String { return self._s[1596]! } - public var IntentsSettings_SuggestByAll: String { return self._s[1597]! } - public var StickerPacksSettings_ShowStickersButton: String { return self._s[1598]! } - public var AuthSessions_Title: String { return self._s[1599]! } - public var Channel_AdminLog_TitleAllEvents: String { return self._s[1600]! } - public var Wallet_Completed_ViewWallet: String { return self._s[1601]! } - public var KeyCommand_JumpToNextUnreadChat: String { return self._s[1602]! } - public var Passport_Address_AddPassportRegistration: String { return self._s[1606]! } - public var AutoDownloadSettings_MaxVideoSize: String { return self._s[1607]! } - public var ExplicitContent_AlertTitle: String { return self._s[1608]! } - public var Channel_UpdatePhotoItem: String { return self._s[1609]! } - public var ChatList_AutoarchiveSuggestion_Text: String { return self._s[1611]! } - public var Channel_DiscussionGroup_LinkGroup: String { return self._s[1612]! } + public var StickerPacksSettings_ShowStickersButtonHelp: String { return self._s[1597]! } + public var IntentsSettings_SuggestByAll: String { return self._s[1598]! } + public var StickerPacksSettings_ShowStickersButton: String { return self._s[1599]! } + public var AuthSessions_Title: String { return self._s[1600]! } + public var Channel_AdminLog_TitleAllEvents: String { return self._s[1601]! } + public var Wallet_Completed_ViewWallet: String { return self._s[1602]! } + public var KeyCommand_JumpToNextUnreadChat: String { return self._s[1603]! } + public var Passport_Address_AddPassportRegistration: String { return self._s[1607]! } + public var AutoDownloadSettings_MaxVideoSize: String { return self._s[1608]! } + public var ExplicitContent_AlertTitle: String { return self._s[1609]! } + public var Channel_UpdatePhotoItem: String { return self._s[1610]! } + public var ChatList_AutoarchiveSuggestion_Text: String { return self._s[1612]! } + public var Channel_DiscussionGroup_LinkGroup: String { return self._s[1613]! } public func Call_BatteryLow(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1613]!, self._r[1613]!, [_0]) + return formatWithArgumentRanges(self._s[1614]!, self._r[1614]!, [_0]) } - public var Login_HaveNotReceivedCodeInternal: String { return self._s[1614]! } - public var WallpaperPreview_PatternPaternApply: String { return self._s[1615]! } - public var Notifications_MessageNotificationsSound: String { return self._s[1616]! } - public var CommentsGroup_ErrorAccessDenied: String { return self._s[1617]! } - public var Appearance_AccentColor: String { return self._s[1619]! } - public var GroupInfo_SharedMedia: String { return self._s[1620]! } - public var Login_PhonePlaceholder: String { return self._s[1621]! } - public var Appearance_TextSize_Automatic: String { return self._s[1622]! } - public var EmptyGroupInfo_Line2: String { return self._s[1623]! } + public var Login_HaveNotReceivedCodeInternal: String { return self._s[1615]! } + public var WallpaperPreview_PatternPaternApply: String { return self._s[1616]! } + public var Notifications_MessageNotificationsSound: String { return self._s[1617]! } + public var CommentsGroup_ErrorAccessDenied: String { return self._s[1618]! } + public var Appearance_AccentColor: String { return self._s[1620]! } + public var GroupInfo_SharedMedia: String { return self._s[1621]! } + public var Login_PhonePlaceholder: String { return self._s[1622]! } + public var Appearance_TextSize_Automatic: String { return self._s[1623]! } + public var EmptyGroupInfo_Line2: String { return self._s[1624]! } public func PUSH_CHAT_CREATED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1624]!, self._r[1624]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1625]!, self._r[1625]!, [_1, _2]) } - public var Conversation_WalletRequiredNotNow: String { return self._s[1626]! } - public var Appearance_AppIconDefaultX: String { return self._s[1627]! } - public var EditProfile_NameAndPhotoOrVideoHelp: String { return self._s[1628]! } - public var CheckoutInfo_ShippingInfoPostcodePlaceholder: String { return self._s[1629]! } - public var Notifications_GroupNotificationsHelp: String { return self._s[1630]! } + public var Conversation_WalletRequiredNotNow: String { return self._s[1627]! } + public var Appearance_AppIconDefaultX: String { return self._s[1628]! } + public var EditProfile_NameAndPhotoOrVideoHelp: String { return self._s[1629]! } + public var CheckoutInfo_ShippingInfoPostcodePlaceholder: String { return self._s[1630]! } + public var Notifications_GroupNotificationsHelp: String { return self._s[1631]! } public func PUSH_CHAT_MESSAGE_NOTEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1631]!, self._r[1631]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1632]!, self._r[1632]!, [_1, _2]) } - public var ChatList_EmptyChatListEditFilter: String { return self._s[1632]! } - public var ChatSettings_ConnectionType_UseProxy: String { return self._s[1635]! } - public var Chat_PinnedMessagesHiddenText: String { return self._s[1636]! } + public var ChatList_EmptyChatListEditFilter: String { return self._s[1633]! } + public var ChatSettings_ConnectionType_UseProxy: String { return self._s[1636]! } + public var Chat_PinnedMessagesHiddenText: String { return self._s[1637]! } public func Message_PinnedGenericMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1637]!, self._r[1637]!, [_0]) - } - public func Location_ProximityTip(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1638]!, self._r[1638]!, [_0]) } - public var UserInfo_NotificationsEnable: String { return self._s[1639]! } - public var Checkout_PayWithTouchId: String { return self._s[1640]! } - public var SharedMedia_ViewInChat: String { return self._s[1641]! } - public func Notification_CreatedChatWithTitle(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1642]!, self._r[1642]!, [_0, _1]) + public func Location_ProximityTip(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1639]!, self._r[1639]!, [_0]) } - public var ChatSettings_AutoDownloadSettings_OffForAll: String { return self._s[1643]! } + public var UserInfo_NotificationsEnable: String { return self._s[1640]! } + public var Checkout_PayWithTouchId: String { return self._s[1641]! } + public var SharedMedia_ViewInChat: String { return self._s[1642]! } + public func Notification_CreatedChatWithTitle(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1643]!, self._r[1643]!, [_0, _1]) + } + public var ChatSettings_AutoDownloadSettings_OffForAll: String { return self._s[1644]! } public func Channel_DiscussionGroup_PublicChannelLink(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1644]!, self._r[1644]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1645]!, self._r[1645]!, [_1, _2]) } public func Cache_Clear(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1646]!, self._r[1646]!, [_0]) + return formatWithArgumentRanges(self._s[1647]!, self._r[1647]!, [_0]) } - public var Conversation_PeerNearbyText: String { return self._s[1648]! } - public var Conversation_StopPollConfirmationTitle: String { return self._s[1649]! } - public var PhotoEditor_Skip: String { return self._s[1650]! } - public var SettingsSearch_Synonyms_Appearance_ChatBackground_SetColor: String { return self._s[1651]! } - public var ChatList_EmptyChatList: String { return self._s[1652]! } - public var Channel_BanUser_Unban: String { return self._s[1653]! } + public var Conversation_PeerNearbyText: String { return self._s[1649]! } + public var Conversation_StopPollConfirmationTitle: String { return self._s[1650]! } + public var PhotoEditor_Skip: String { return self._s[1651]! } + public var SettingsSearch_Synonyms_Appearance_ChatBackground_SetColor: String { return self._s[1652]! } + public var ChatList_EmptyChatList: String { return self._s[1653]! } + public var Channel_BanUser_Unban: String { return self._s[1654]! } public func Message_GenericForwardedPsa(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1654]!, self._r[1654]!, [_0]) + return formatWithArgumentRanges(self._s[1655]!, self._r[1655]!, [_0]) } - public var Appearance_TextSize_Apply: String { return self._s[1655]! } - public var Wallet_Send_SyncInProgress: String { return self._s[1656]! } + public var Appearance_TextSize_Apply: String { return self._s[1656]! } + public var Wallet_Send_SyncInProgress: String { return self._s[1657]! } public func Conversation_MessageViewCommentsFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1657]!, self._r[1657]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1658]!, self._r[1658]!, [_1, _2]) } - public var Login_InfoFirstNamePlaceholder: String { return self._s[1658]! } - public var Wallet_Configuration_SourceHeader: String { return self._s[1659]! } - public var TwoStepAuth_HintPlaceholder: String { return self._s[1660]! } - public var TwoStepAuth_EmailSkip: String { return self._s[1662]! } - public var ChatList_UndoArchiveMultipleTitle: String { return self._s[1663]! } - public var TwoFactorSetup_Email_SkipConfirmationTitle: String { return self._s[1664]! } + public var Login_InfoFirstNamePlaceholder: String { return self._s[1659]! } + public var Wallet_Configuration_SourceHeader: String { return self._s[1660]! } + public var TwoStepAuth_HintPlaceholder: String { return self._s[1661]! } + public var TwoStepAuth_EmailSkip: String { return self._s[1663]! } + public var ChatList_UndoArchiveMultipleTitle: String { return self._s[1664]! } + public var TwoFactorSetup_Email_SkipConfirmationTitle: String { return self._s[1665]! } public func PUSH_MESSAGE_QUIZ(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1665]!, self._r[1665]!, [_1]) + return formatWithArgumentRanges(self._s[1666]!, self._r[1666]!, [_1]) } - public var State_WaitingForNetwork: String { return self._s[1667]! } - public var AccessDenied_CameraRestricted: String { return self._s[1668]! } - public var ChatSettings_Appearance: String { return self._s[1669]! } - public var ScheduledMessages_BotActionUnavailable: String { return self._s[1670]! } + public var State_WaitingForNetwork: String { return self._s[1668]! } + public var AccessDenied_CameraRestricted: String { return self._s[1669]! } + public var ChatSettings_Appearance: String { return self._s[1670]! } + public var ScheduledMessages_BotActionUnavailable: String { return self._s[1671]! } public func Wallet_Time_PreciseDate_m3(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1671]!, self._r[1671]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1672]!, self._r[1672]!, [_1, _2, _3]) } - public var GroupInfo_InviteLink_CopyAlert_Success: String { return self._s[1672]! } - public var Channel_DiscussionGroupAdd: String { return self._s[1673]! } - public var Map_NoPlacesNearby: String { return self._s[1675]! } - public var AuthSessions_IncompleteAttemptsInfo: String { return self._s[1676]! } - public var GroupRemoved_Title: String { return self._s[1677]! } - public var TwoStepAuth_EnterPasswordHelp: String { return self._s[1679]! } - public var Paint_Marker: String { return self._s[1680]! } + public var GroupInfo_InviteLink_CopyAlert_Success: String { return self._s[1673]! } + public var Channel_DiscussionGroupAdd: String { return self._s[1674]! } + public var Map_NoPlacesNearby: String { return self._s[1676]! } + public var AuthSessions_IncompleteAttemptsInfo: String { return self._s[1677]! } + public var GroupRemoved_Title: String { return self._s[1678]! } + public var TwoStepAuth_EnterPasswordHelp: String { return self._s[1680]! } + public var Paint_Marker: String { return self._s[1681]! } public func AddContact_ContactWillBeSharedAfterMutual(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1681]!, self._r[1681]!, [_1]) + return formatWithArgumentRanges(self._s[1682]!, self._r[1682]!, [_1]) } - public var SocksProxySetup_ShareProxyList: String { return self._s[1682]! } - public var GroupInfo_InvitationLinkDoesNotExist: String { return self._s[1683]! } + public var SocksProxySetup_ShareProxyList: String { return self._s[1683]! } + public var GroupInfo_InvitationLinkDoesNotExist: String { return self._s[1684]! } public func VoiceOver_Chat_Size(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1684]!, self._r[1684]!, [_0]) + return formatWithArgumentRanges(self._s[1685]!, self._r[1685]!, [_0]) } - public var EditTheme_ErrorInvalidCharacters: String { return self._s[1685]! } - public var Appearance_ThemePreview_ChatList_7_Name: String { return self._s[1686]! } - public var Notifications_GroupNotificationsAlert: String { return self._s[1687]! } - public var SocksProxySetup_ShareQRCode: String { return self._s[1688]! } - public var Compose_NewGroup: String { return self._s[1689]! } + public var EditTheme_ErrorInvalidCharacters: String { return self._s[1686]! } + public var Appearance_ThemePreview_ChatList_7_Name: String { return self._s[1687]! } + public var Notifications_GroupNotificationsAlert: String { return self._s[1688]! } + public var SocksProxySetup_ShareQRCode: String { return self._s[1689]! } + public var Compose_NewGroup: String { return self._s[1690]! } public func Passport_Address_UploadOneOfScan(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1690]!, self._r[1690]!, [_0]) + return formatWithArgumentRanges(self._s[1691]!, self._r[1691]!, [_0]) } - public var Conversation_ClearGroupHistory: String { return self._s[1692]! } - public var Location_LiveLocationRequired_Description: String { return self._s[1693]! } - public var GroupInfo_InviteLink_Help: String { return self._s[1696]! } - public var Channel_BanUser_BlockFor: String { return self._s[1697]! } - public var Bot_Start: String { return self._s[1698]! } - public var Your_card_has_expired: String { return self._s[1699]! } - public var Channel_About_Title: String { return self._s[1700]! } - public var Passport_Identity_ExpiryDatePlaceholder: String { return self._s[1701]! } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsExceptions: String { return self._s[1703]! } - public var Wallet_Info_Updating: String { return self._s[1704]! } - public var Conversation_FileDropbox: String { return self._s[1705]! } - public var Conversation_WalletRequiredTitle: String { return self._s[1706]! } - public var ChatList_Search_NoResultsFitlerMusic: String { return self._s[1707]! } - public var Month_GenNovember: String { return self._s[1708]! } - public var IntentsSettings_SuggestByShare: String { return self._s[1709]! } + public var Conversation_ClearGroupHistory: String { return self._s[1693]! } + public var Location_LiveLocationRequired_Description: String { return self._s[1694]! } + public var GroupInfo_InviteLink_Help: String { return self._s[1697]! } + public var Channel_BanUser_BlockFor: String { return self._s[1698]! } + public var Bot_Start: String { return self._s[1699]! } + public var Your_card_has_expired: String { return self._s[1700]! } + public var Channel_About_Title: String { return self._s[1701]! } + public var Passport_Identity_ExpiryDatePlaceholder: String { return self._s[1702]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsExceptions: String { return self._s[1704]! } + public var Wallet_Info_Updating: String { return self._s[1705]! } + public var Conversation_FileDropbox: String { return self._s[1706]! } + public var Conversation_WalletRequiredTitle: String { return self._s[1707]! } + public var ChatList_Search_NoResultsFitlerMusic: String { return self._s[1708]! } + public var Month_GenNovember: String { return self._s[1709]! } + public var IntentsSettings_SuggestByShare: String { return self._s[1710]! } public func Call_PrivacyErrorMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1710]!, self._r[1710]!, [_0]) + return formatWithArgumentRanges(self._s[1711]!, self._r[1711]!, [_0]) } - public var StickerPack_Add: String { return self._s[1711]! } - public var Theme_ErrorNotFound: String { return self._s[1712]! } - public var Wallpaper_SearchShort: String { return self._s[1714]! } - public var Channel_BanUser_PermissionsHeader: String { return self._s[1715]! } - public var ConversationProfile_UsersTooMuchError: String { return self._s[1716]! } - public var ChatList_FolderAllChats: String { return self._s[1717]! } - public var Passport_Authorize: String { return self._s[1718]! } + public var StickerPack_Add: String { return self._s[1712]! } + public var Theme_ErrorNotFound: String { return self._s[1713]! } + public var Wallpaper_SearchShort: String { return self._s[1715]! } + public var Channel_BanUser_PermissionsHeader: String { return self._s[1716]! } + public var ConversationProfile_UsersTooMuchError: String { return self._s[1717]! } + public var ChatList_FolderAllChats: String { return self._s[1718]! } + public var Passport_Authorize: String { return self._s[1719]! } public func Channel_AdminLog_MessageChangedLinkedChannel(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1719]!, self._r[1719]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1720]!, self._r[1720]!, [_1, _2]) } - public var GroupInfo_GroupHistoryVisible: String { return self._s[1720]! } + public var GroupInfo_GroupHistoryVisible: String { return self._s[1721]! } public func PUSH_MESSAGE_VIDEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1721]!, self._r[1721]!, [_1]) + return formatWithArgumentRanges(self._s[1722]!, self._r[1722]!, [_1]) } - public var LocalGroup_ButtonTitle: String { return self._s[1722]! } - public var UserInfo_GroupsInCommon: String { return self._s[1724]! } - public var Wallpaper_Set: String { return self._s[1725]! } - public var LoginPassword_Title: String { return self._s[1726]! } - public var Stats_InteractionsTitle: String { return self._s[1727]! } - public var Wallet_TransactionInfo_StorageFeeHeader: String { return self._s[1729]! } + public var LocalGroup_ButtonTitle: String { return self._s[1723]! } + public var UserInfo_GroupsInCommon: String { return self._s[1725]! } + public var Wallpaper_Set: String { return self._s[1726]! } + public var LoginPassword_Title: String { return self._s[1727]! } + public var Stats_InteractionsTitle: String { return self._s[1728]! } + public var Wallet_TransactionInfo_StorageFeeHeader: String { return self._s[1730]! } public func SecretGIF_NotViewedYet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1730]!, self._r[1730]!, [_0]) + return formatWithArgumentRanges(self._s[1731]!, self._r[1731]!, [_0]) } - public var Conversation_MessageDialogEdit: String { return self._s[1731]! } - public var Paint_Outlined: String { return self._s[1732]! } + public var Conversation_MessageDialogEdit: String { return self._s[1732]! } + public var Paint_Outlined: String { return self._s[1733]! } public func Login_ResetAccountProtected_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1733]!, self._r[1733]!, [_0]) - } - public func Conversation_SetReminder_RemindTomorrow(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1734]!, self._r[1734]!, [_0]) } - public var Invite_LargeRecipientsCountWarning: String { return self._s[1735]! } - public var Passport_Address_Street1Placeholder: String { return self._s[1736]! } - public var Appearance_ColorThemeNight: String { return self._s[1737]! } - public var ChannelInfo_Stats: String { return self._s[1738]! } - public var TwoStepAuth_RecoveryTitle: String { return self._s[1739]! } - public var MediaPicker_TimerTooltip: String { return self._s[1740]! } - public var Common_ChoosePhoto: String { return self._s[1741]! } - public var ChatSettings_AutoDownloadVideos: String { return self._s[1742]! } - public var PeerInfo_PaneGroups: String { return self._s[1743]! } - public var Wallet_Month_ShortMarch: String { return self._s[1745]! } - public var ChangePhoneNumberNumber_Title: String { return self._s[1746]! } - public var SocksProxySetup_UsernamePlaceholder: String { return self._s[1747]! } - public var ContactInfo_PhoneLabelMobile: String { return self._s[1748]! } - public var OldChannels_ChannelsHeader: String { return self._s[1749]! } - public var MuteFor_Forever: String { return self._s[1750]! } - public var Passport_Address_PostcodePlaceholder: String { return self._s[1751]! } - public var SettingsSearch_Synonyms_Appearance_ChatBackground: String { return self._s[1752]! } - public var MessagePoll_LabelAnonymous: String { return self._s[1753]! } - public var ContactInfo_Job: String { return self._s[1754]! } - public var Passport_Language_mk: String { return self._s[1755]! } - public var EditTheme_ShortLink: String { return self._s[1756]! } - public var AutoDownloadSettings_PhotosTitle: String { return self._s[1758]! } - public var Wallet_Send_Send: String { return self._s[1759]! } - public var Month_GenApril: String { return self._s[1761]! } - public var Channel_DiscussionGroup_HeaderLabel: String { return self._s[1763]! } - public var NetworkUsageSettings_TotalSection: String { return self._s[1764]! } - public var EditTheme_Create_Preview_OutgoingText: String { return self._s[1765]! } - public var EditTheme_Title: String { return self._s[1766]! } - public var Conversation_LinkDialogCopy: String { return self._s[1767]! } + public func Conversation_SetReminder_RemindTomorrow(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1735]!, self._r[1735]!, [_0]) + } + public var Invite_LargeRecipientsCountWarning: String { return self._s[1736]! } + public var Passport_Address_Street1Placeholder: String { return self._s[1737]! } + public var Appearance_ColorThemeNight: String { return self._s[1738]! } + public var ChannelInfo_Stats: String { return self._s[1739]! } + public var TwoStepAuth_RecoveryTitle: String { return self._s[1740]! } + public var MediaPicker_TimerTooltip: String { return self._s[1741]! } + public var Common_ChoosePhoto: String { return self._s[1742]! } + public var ChatSettings_AutoDownloadVideos: String { return self._s[1743]! } + public var PeerInfo_PaneGroups: String { return self._s[1744]! } + public var Wallet_Month_ShortMarch: String { return self._s[1746]! } + public var ChangePhoneNumberNumber_Title: String { return self._s[1747]! } + public var SocksProxySetup_UsernamePlaceholder: String { return self._s[1748]! } + public var ContactInfo_PhoneLabelMobile: String { return self._s[1749]! } + public var OldChannels_ChannelsHeader: String { return self._s[1750]! } + public var MuteFor_Forever: String { return self._s[1751]! } + public var Passport_Address_PostcodePlaceholder: String { return self._s[1752]! } + public var SettingsSearch_Synonyms_Appearance_ChatBackground: String { return self._s[1753]! } + public var MessagePoll_LabelAnonymous: String { return self._s[1754]! } + public var ContactInfo_Job: String { return self._s[1755]! } + public var Passport_Language_mk: String { return self._s[1756]! } + public var EditTheme_ShortLink: String { return self._s[1757]! } + public var AutoDownloadSettings_PhotosTitle: String { return self._s[1759]! } + public var Wallet_Send_Send: String { return self._s[1760]! } + public var Month_GenApril: String { return self._s[1762]! } + public var Channel_DiscussionGroup_HeaderLabel: String { return self._s[1764]! } + public var NetworkUsageSettings_TotalSection: String { return self._s[1765]! } + public var EditTheme_Create_Preview_OutgoingText: String { return self._s[1766]! } + public var EditTheme_Title: String { return self._s[1767]! } + public var Conversation_LinkDialogCopy: String { return self._s[1768]! } public func Channel_AdminLog_MessageInvitedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1768]!, self._r[1768]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1769]!, self._r[1769]!, [_1, _2]) } - public var Passport_ForgottenPassword: String { return self._s[1769]! } - public var WallpaperSearch_Recent: String { return self._s[1770]! } - public var ChatSettings_Title: String { return self._s[1775]! } - public var Appearance_ReduceMotionInfo: String { return self._s[1776]! } + public var Passport_ForgottenPassword: String { return self._s[1770]! } + public var WallpaperSearch_Recent: String { return self._s[1771]! } + public var ChatSettings_Title: String { return self._s[1776]! } + public var Appearance_ReduceMotionInfo: String { return self._s[1777]! } public func StickerPackActionInfo_AddedText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1777]!, self._r[1777]!, [_0]) + return formatWithArgumentRanges(self._s[1778]!, self._r[1778]!, [_0]) } - public var SocksProxySetup_UseForCallsHelp: String { return self._s[1778]! } - public var LastSeen_WithinAMonth: String { return self._s[1779]! } - public var PeerInfo_ButtonCall: String { return self._s[1780]! } - public var SettingsSearch_Synonyms_Appearance_Title: String { return self._s[1781]! } - public var Group_Username_InvalidStartsWithNumber: String { return self._s[1782]! } - public var Call_AudioRouteHide: String { return self._s[1783]! } - public var DialogList_SavedMessages: String { return self._s[1784]! } - public var ChatList_Context_Mute: String { return self._s[1785]! } - public var Conversation_StatusKickedFromChannel: String { return self._s[1786]! } + public var SocksProxySetup_UseForCallsHelp: String { return self._s[1779]! } + public var LastSeen_WithinAMonth: String { return self._s[1780]! } + public var PeerInfo_ButtonCall: String { return self._s[1781]! } + public var SettingsSearch_Synonyms_Appearance_Title: String { return self._s[1782]! } + public var Group_Username_InvalidStartsWithNumber: String { return self._s[1783]! } + public var Call_AudioRouteHide: String { return self._s[1784]! } + public var DialogList_SavedMessages: String { return self._s[1785]! } + public var ChatList_Context_Mute: String { return self._s[1786]! } + public var Conversation_StatusKickedFromChannel: String { return self._s[1787]! } public func Notification_Exceptions_MutedUntil(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1787]!, self._r[1787]!, [_0]) + return formatWithArgumentRanges(self._s[1788]!, self._r[1788]!, [_0]) } - public var Passport_Language_et: String { return self._s[1788]! } - public var Conversation_MessageLeaveCommentShort: String { return self._s[1789]! } - public var PhotoEditor_CropReset: String { return self._s[1790]! } - public var Wallet_Send_TransactionInProgress: String { return self._s[1791]! } - public var Privacy_GroupsAndChannels_AlwaysAllow: String { return self._s[1792]! } - public var SocksProxySetup_HostnamePlaceholder: String { return self._s[1793]! } - public var CreateGroup_ErrorLocatedGroupsTooMuch: String { return self._s[1794]! } - public var WallpaperSearch_ColorWhite: String { return self._s[1797]! } - public var Channel_AdminLog_CanEditMessages: String { return self._s[1799]! } - public var Privacy_PaymentsClearInfoDoneHelp: String { return self._s[1800]! } - public var Channel_Username_InvalidStartsWithNumber: String { return self._s[1802]! } - public var CheckoutInfo_ReceiverInfoName: String { return self._s[1804]! } - public var Map_YouAreHere: String { return self._s[1806]! } - public var Core_ServiceUserStatus: String { return self._s[1807]! } - public var Channel_Setup_TypePrivateHelp: String { return self._s[1810]! } - public var SettingsSearch_Synonyms_Notifications_BadgeCountUnreadMessages: String { return self._s[1811]! } - public var MediaPicker_Videos: String { return self._s[1813]! } - public var Map_LiveLocationFor15Minutes: String { return self._s[1815]! } - public var Passport_Identity_TranslationsHelp: String { return self._s[1816]! } - public var SharedMedia_CategoryMedia: String { return self._s[1817]! } - public var Wallet_Month_ShortJanuary: String { return self._s[1818]! } + public var Passport_Language_et: String { return self._s[1789]! } + public var Conversation_MessageLeaveCommentShort: String { return self._s[1790]! } + public var PhotoEditor_CropReset: String { return self._s[1791]! } + public var Wallet_Send_TransactionInProgress: String { return self._s[1792]! } + public var Privacy_GroupsAndChannels_AlwaysAllow: String { return self._s[1793]! } + public var SocksProxySetup_HostnamePlaceholder: String { return self._s[1794]! } + public var CreateGroup_ErrorLocatedGroupsTooMuch: String { return self._s[1795]! } + public var WallpaperSearch_ColorWhite: String { return self._s[1798]! } + public var Channel_AdminLog_CanEditMessages: String { return self._s[1800]! } + public var Privacy_PaymentsClearInfoDoneHelp: String { return self._s[1801]! } + public var Channel_Username_InvalidStartsWithNumber: String { return self._s[1803]! } + public var CheckoutInfo_ReceiverInfoName: String { return self._s[1805]! } + public var Map_YouAreHere: String { return self._s[1807]! } + public var Core_ServiceUserStatus: String { return self._s[1808]! } + public var Channel_Setup_TypePrivateHelp: String { return self._s[1811]! } + public var SettingsSearch_Synonyms_Notifications_BadgeCountUnreadMessages: String { return self._s[1812]! } + public var MediaPicker_Videos: String { return self._s[1814]! } + public var Map_LiveLocationFor15Minutes: String { return self._s[1816]! } + public var Passport_Identity_TranslationsHelp: String { return self._s[1817]! } + public var SharedMedia_CategoryMedia: String { return self._s[1818]! } + public var Wallet_Month_ShortJanuary: String { return self._s[1819]! } public func MediaPicker_Nof(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1819]!, self._r[1819]!, [_0]) + return formatWithArgumentRanges(self._s[1820]!, self._r[1820]!, [_0]) } - public var ChatSettings_AutoPlayGifs: String { return self._s[1820]! } - public var Passport_Identity_CountryPlaceholder: String { return self._s[1821]! } - public var Bot_GroupStatusDoesNotReadHistory: String { return self._s[1822]! } - public var Notification_Exceptions_RemoveFromExceptions: String { return self._s[1823]! } + public var ChatSettings_AutoPlayGifs: String { return self._s[1821]! } + public var Passport_Identity_CountryPlaceholder: String { return self._s[1822]! } + public var Bot_GroupStatusDoesNotReadHistory: String { return self._s[1823]! } + public var Notification_Exceptions_RemoveFromExceptions: String { return self._s[1824]! } public func Chat_SlowmodeTooltip(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1824]!, self._r[1824]!, [_0]) + return formatWithArgumentRanges(self._s[1825]!, self._r[1825]!, [_0]) } - public var Web_Error: String { return self._s[1825]! } - public var PhotoEditor_SkinTool: String { return self._s[1826]! } - public var ApplyLanguage_UnsufficientDataTitle: String { return self._s[1827]! } - public var ChatSettings_ConnectionType_UseSocks5: String { return self._s[1828]! } - public var PasscodeSettings_Help: String { return self._s[1829]! } - public var Appearance_ColorTheme: String { return self._s[1830]! } + public var Web_Error: String { return self._s[1826]! } + public var PhotoEditor_SkinTool: String { return self._s[1827]! } + public var ApplyLanguage_UnsufficientDataTitle: String { return self._s[1828]! } + public var ChatSettings_ConnectionType_UseSocks5: String { return self._s[1829]! } + public var PasscodeSettings_Help: String { return self._s[1830]! } + public var Appearance_ColorTheme: String { return self._s[1831]! } public func Channel_AdminLog_MessageRestrictedNewSetting(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1831]!, self._r[1831]!, [_0]) + return formatWithArgumentRanges(self._s[1832]!, self._r[1832]!, [_0]) } public func PUSH_PINNED_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1832]!, self._r[1832]!, [_1]) + return formatWithArgumentRanges(self._s[1833]!, self._r[1833]!, [_1]) } - public var GroupInfo_LeftStatus: String { return self._s[1833]! } - public var EditTheme_Preview: String { return self._s[1834]! } - public var Watch_Suggestion_WhatsUp: String { return self._s[1835]! } + public var GroupInfo_LeftStatus: String { return self._s[1834]! } + public var EditTheme_Preview: String { return self._s[1835]! } + public var Watch_Suggestion_WhatsUp: String { return self._s[1836]! } public func AutoDownloadSettings_PreloadVideoInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1836]!, self._r[1836]!, [_0]) + return formatWithArgumentRanges(self._s[1837]!, self._r[1837]!, [_0]) } - public var NotificationsSound_Keys: String { return self._s[1837]! } - public var PasscodeSettings_UnlockWithTouchId: String { return self._s[1838]! } - public var ChatList_Context_MarkAsUnread: String { return self._s[1839]! } - public var DialogList_AdNoticeAlert: String { return self._s[1840]! } - public var UserInfo_Invite: String { return self._s[1841]! } - public var Checkout_Email: String { return self._s[1842]! } - public var Stats_GroupActionsTitle: String { return self._s[1843]! } - public var Wallet_Navigation_Done: String { return self._s[1844]! } - public var Coub_TapForSound: String { return self._s[1845]! } - public var Theme_ThemeChangedText: String { return self._s[1846]! } - public var Call_ExternalCallInProgressMessage: String { return self._s[1847]! } - public var Settings_ApplyProxyAlertEnable: String { return self._s[1848]! } - public var ScheduledMessages_ScheduledToday: String { return self._s[1849]! } - public var Channel_AdminLog_DefaultRestrictionsUpdated: String { return self._s[1850]! } - public var Call_ReportIncludeLogDescription: String { return self._s[1851]! } - public var Settings_FrequentlyAskedQuestions: String { return self._s[1853]! } - public var Wallet_Words_NotDoneText: String { return self._s[1854]! } - public var Channel_MessagePhotoRemoved: String { return self._s[1855]! } - public var Passport_Email_Delete: String { return self._s[1856]! } + public var NotificationsSound_Keys: String { return self._s[1838]! } + public var PasscodeSettings_UnlockWithTouchId: String { return self._s[1839]! } + public var ChatList_Context_MarkAsUnread: String { return self._s[1840]! } + public var DialogList_AdNoticeAlert: String { return self._s[1841]! } + public var UserInfo_Invite: String { return self._s[1842]! } + public var Checkout_Email: String { return self._s[1843]! } + public var Stats_GroupActionsTitle: String { return self._s[1844]! } + public var Wallet_Navigation_Done: String { return self._s[1845]! } + public var Coub_TapForSound: String { return self._s[1846]! } + public var Theme_ThemeChangedText: String { return self._s[1847]! } + public var Call_ExternalCallInProgressMessage: String { return self._s[1848]! } + public var Settings_ApplyProxyAlertEnable: String { return self._s[1849]! } + public var ScheduledMessages_ScheduledToday: String { return self._s[1850]! } + public var Channel_AdminLog_DefaultRestrictionsUpdated: String { return self._s[1851]! } + public var Call_ReportIncludeLogDescription: String { return self._s[1852]! } + public var Settings_FrequentlyAskedQuestions: String { return self._s[1854]! } + public var Wallet_Words_NotDoneText: String { return self._s[1855]! } + public var Channel_MessagePhotoRemoved: String { return self._s[1856]! } + public var Passport_Email_Delete: String { return self._s[1857]! } public func PUSH_PINNED_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1857]!, self._r[1857]!, [_1]) + return formatWithArgumentRanges(self._s[1858]!, self._r[1858]!, [_1]) } - public var NotificationSettings_ShowNotificationsAllAccountsInfoOn: String { return self._s[1858]! } - public var Channel_AdminLog_CanAddAdmins: String { return self._s[1859]! } - public var SocksProxySetup_FailedToConnect: String { return self._s[1861]! } - public var SettingsSearch_Synonyms_Data_NetworkUsage: String { return self._s[1862]! } - public var Wallet_Month_GenMay: String { return self._s[1863]! } - public var Common_of: String { return self._s[1864]! } - public var PeerInfo_ButtonUnmute: String { return self._s[1867]! } + public var NotificationSettings_ShowNotificationsAllAccountsInfoOn: String { return self._s[1859]! } + public var Channel_AdminLog_CanAddAdmins: String { return self._s[1860]! } + public var SocksProxySetup_FailedToConnect: String { return self._s[1862]! } + public var SettingsSearch_Synonyms_Data_NetworkUsage: String { return self._s[1863]! } + public var Wallet_Month_GenMay: String { return self._s[1864]! } + public var Common_of: String { return self._s[1865]! } + public var PeerInfo_ButtonUnmute: String { return self._s[1868]! } public func ChatSettings_AutoDownloadSettings_TypeFile(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1868]!, self._r[1868]!, [_0]) + return formatWithArgumentRanges(self._s[1869]!, self._r[1869]!, [_0]) } - public var ChatList_AddChatsToFolder: String { return self._s[1869]! } - public var Login_ResetAccountProtected_LimitExceeded: String { return self._s[1870]! } - public var Settings_Title: String { return self._s[1872]! } - public var AutoDownloadSettings_Contacts: String { return self._s[1874]! } - public var Appearance_BubbleCornersSetting: String { return self._s[1875]! } - public var Privacy_Calls_AlwaysAllow: String { return self._s[1876]! } - public var Privacy_Forwards_AlwaysAllow_Title: String { return self._s[1878]! } - public var WallpaperPreview_CropBottomText: String { return self._s[1879]! } - public var SecretTimer_VideoDescription: String { return self._s[1880]! } - public var WallpaperPreview_Blurred: String { return self._s[1881]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsExceptions: String { return self._s[1882]! } - public var ChatListFolder_ExcludedSectionHeader: String { return self._s[1884]! } - public var DialogList_PasscodeLockHelp: String { return self._s[1885]! } - public var SocksProxySetup_SecretPlaceholder: String { return self._s[1886]! } - public var NetworkUsageSettings_CallDataSection: String { return self._s[1887]! } - public var SettingsSearch_Synonyms_Wallet: String { return self._s[1888]! } - public var TwoStepAuth_PasswordRemovePassportConfirmation: String { return self._s[1889]! } - public var Passport_FieldAddressTranslationHelp: String { return self._s[1890]! } - public var SocksProxySetup_Connection: String { return self._s[1891]! } - public var Passport_Address_TypePassportRegistration: String { return self._s[1892]! } - public var Contacts_PermissionsAllowInSettings: String { return self._s[1893]! } - public var Conversation_Unpin: String { return self._s[1894]! } - public var Notifications_MessageNotificationsExceptionsHelp: String { return self._s[1895]! } - public var TwoFactorSetup_Hint_Placeholder: String { return self._s[1896]! } - public var Call_ReportSkip: String { return self._s[1897]! } + public var ChatList_AddChatsToFolder: String { return self._s[1870]! } + public var Login_ResetAccountProtected_LimitExceeded: String { return self._s[1871]! } + public var Settings_Title: String { return self._s[1873]! } + public var AutoDownloadSettings_Contacts: String { return self._s[1875]! } + public var Appearance_BubbleCornersSetting: String { return self._s[1876]! } + public var Privacy_Calls_AlwaysAllow: String { return self._s[1877]! } + public var Privacy_Forwards_AlwaysAllow_Title: String { return self._s[1879]! } + public var WallpaperPreview_CropBottomText: String { return self._s[1880]! } + public var SecretTimer_VideoDescription: String { return self._s[1881]! } + public var WallpaperPreview_Blurred: String { return self._s[1882]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsExceptions: String { return self._s[1883]! } + public var ChatListFolder_ExcludedSectionHeader: String { return self._s[1885]! } + public var DialogList_PasscodeLockHelp: String { return self._s[1886]! } + public var SocksProxySetup_SecretPlaceholder: String { return self._s[1887]! } + public var NetworkUsageSettings_CallDataSection: String { return self._s[1888]! } + public var SettingsSearch_Synonyms_Wallet: String { return self._s[1889]! } + public var TwoStepAuth_PasswordRemovePassportConfirmation: String { return self._s[1890]! } + public var Passport_FieldAddressTranslationHelp: String { return self._s[1891]! } + public var SocksProxySetup_Connection: String { return self._s[1892]! } + public var Passport_Address_TypePassportRegistration: String { return self._s[1893]! } + public var Contacts_PermissionsAllowInSettings: String { return self._s[1894]! } + public var Conversation_Unpin: String { return self._s[1895]! } + public var Notifications_MessageNotificationsExceptionsHelp: String { return self._s[1896]! } + public var TwoFactorSetup_Hint_Placeholder: String { return self._s[1897]! } + public var Call_ReportSkip: String { return self._s[1898]! } public func VoiceOver_Chat_PhotoFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1898]!, self._r[1898]!, [_0]) + return formatWithArgumentRanges(self._s[1899]!, self._r[1899]!, [_0]) } public func VoiceOver_Chat_Caption(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1900]!, self._r[1900]!, [_0]) + return formatWithArgumentRanges(self._s[1901]!, self._r[1901]!, [_0]) } - public var AutoNightTheme_Automatic: String { return self._s[1901]! } - public var Wallet_TransactionInfo_AddressCopied: String { return self._s[1902]! } - public var Wallet_Month_GenMarch: String { return self._s[1903]! } - public var Passport_Language_az: String { return self._s[1904]! } - public var SettingsSearch_Synonyms_Data_Storage_ClearCache: String { return self._s[1905]! } - public var Watch_UserInfo_Unmute: String { return self._s[1906]! } - public var Channel_Stickers_YourStickers: String { return self._s[1907]! } - public var Channel_DiscussionGroup_UnlinkChannel: String { return self._s[1908]! } - public var Tour_Text1: String { return self._s[1909]! } - public var Common_Delete: String { return self._s[1910]! } - public var Settings_EditPhoto: String { return self._s[1911]! } - public var Common_Edit: String { return self._s[1912]! } - public var ShareMenu_ShareTo: String { return self._s[1914]! } - public var Passport_Identity_ExpiryDate: String { return self._s[1915]! } - public var Preview_DeleteGif: String { return self._s[1916]! } - public var WallpaperPreview_PatternPaternDiscard: String { return self._s[1917]! } - public var ChatSettings_AutoDownloadUsingCellular: String { return self._s[1918]! } - public var Conversation_ViewReply: String { return self._s[1919]! } - public var Stats_LoadingText: String { return self._s[1920]! } - public var Channel_EditAdmin_PermissinAddAdminOn: String { return self._s[1921]! } - public var CheckoutInfo_ReceiverInfoEmailPlaceholder: String { return self._s[1922]! } - public var Channel_AdminLog_CanChangeInfo: String { return self._s[1923]! } + public var AutoNightTheme_Automatic: String { return self._s[1902]! } + public var Wallet_TransactionInfo_AddressCopied: String { return self._s[1903]! } + public var Wallet_Month_GenMarch: String { return self._s[1904]! } + public var Passport_Language_az: String { return self._s[1905]! } + public var SettingsSearch_Synonyms_Data_Storage_ClearCache: String { return self._s[1906]! } + public var Watch_UserInfo_Unmute: String { return self._s[1907]! } + public var Channel_Stickers_YourStickers: String { return self._s[1908]! } + public var Channel_DiscussionGroup_UnlinkChannel: String { return self._s[1909]! } + public var Tour_Text1: String { return self._s[1910]! } + public var Common_Delete: String { return self._s[1911]! } + public var Settings_EditPhoto: String { return self._s[1912]! } + public var Common_Edit: String { return self._s[1913]! } + public var ShareMenu_ShareTo: String { return self._s[1915]! } + public var Passport_Identity_ExpiryDate: String { return self._s[1916]! } + public var Preview_DeleteGif: String { return self._s[1917]! } + public var WallpaperPreview_PatternPaternDiscard: String { return self._s[1918]! } + public var ChatSettings_AutoDownloadUsingCellular: String { return self._s[1919]! } + public var Conversation_ViewReply: String { return self._s[1920]! } + public var Stats_LoadingText: String { return self._s[1921]! } + public var Channel_EditAdmin_PermissinAddAdminOn: String { return self._s[1922]! } + public var CheckoutInfo_ReceiverInfoEmailPlaceholder: String { return self._s[1923]! } + public var Channel_AdminLog_CanChangeInfo: String { return self._s[1924]! } public func Passport_Phone_UseTelegramNumber(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1924]!, self._r[1924]!, [_0]) - } - public func Time_MonthOfYear_m2(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1925]!, self._r[1925]!, [_0]) } + public func Time_MonthOfYear_m2(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1926]!, self._r[1926]!, [_0]) + } public func VoiceOver_Chat_VideoMessageFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1927]!, self._r[1927]!, [_0]) + return formatWithArgumentRanges(self._s[1928]!, self._r[1928]!, [_0]) } - public var Passport_Address_OneOfTypeRentalAgreement: String { return self._s[1928]! } - public var Wallet_SecureStorageChanged_ImportWallet: String { return self._s[1931]! } - public var IntentsSettings_MainAccount: String { return self._s[1932]! } - public var Group_MessagePhotoRemoved: String { return self._s[1935]! } - public var Conversation_ContextMenuSelect: String { return self._s[1936]! } - public var GroupInfo_Permissions_Exceptions: String { return self._s[1938]! } - public var GroupRemoved_UsersSectionTitle: String { return self._s[1939]! } - public var Contacts_PermissionsEnable: String { return self._s[1940]! } - public var Channel_EditAdmin_PermissionDeleteMessagesOfOthers: String { return self._s[1941]! } - public var Common_NotNow: String { return self._s[1942]! } - public var Notification_CreatedChannel: String { return self._s[1943]! } - public var Stats_ViewsBySourceTitle: String { return self._s[1945]! } - public var Appearance_AppIconClassic: String { return self._s[1946]! } - public var PhotoEditor_QualityTool: String { return self._s[1947]! } - public var ClearCache_ClearCache: String { return self._s[1948]! } - public var TwoFactorSetup_Password_PlaceholderConfirmPassword: String { return self._s[1949]! } - public var AutoDownloadSettings_Videos: String { return self._s[1950]! } - public var GroupPermission_Duration: String { return self._s[1951]! } - public var ChatList_Read: String { return self._s[1952]! } + public var Passport_Address_OneOfTypeRentalAgreement: String { return self._s[1929]! } + public var Wallet_SecureStorageChanged_ImportWallet: String { return self._s[1932]! } + public var IntentsSettings_MainAccount: String { return self._s[1933]! } + public var Group_MessagePhotoRemoved: String { return self._s[1936]! } + public var Conversation_ContextMenuSelect: String { return self._s[1937]! } + public var GroupInfo_Permissions_Exceptions: String { return self._s[1939]! } + public var GroupRemoved_UsersSectionTitle: String { return self._s[1940]! } + public var Contacts_PermissionsEnable: String { return self._s[1941]! } + public var Channel_EditAdmin_PermissionDeleteMessagesOfOthers: String { return self._s[1942]! } + public var Common_NotNow: String { return self._s[1943]! } + public var Notification_CreatedChannel: String { return self._s[1944]! } + public var Stats_ViewsBySourceTitle: String { return self._s[1946]! } + public var Appearance_AppIconClassic: String { return self._s[1947]! } + public var PhotoEditor_QualityTool: String { return self._s[1948]! } + public var ClearCache_ClearCache: String { return self._s[1949]! } + public var TwoFactorSetup_Password_PlaceholderConfirmPassword: String { return self._s[1950]! } + public var AutoDownloadSettings_Videos: String { return self._s[1951]! } + public var GroupPermission_Duration: String { return self._s[1952]! } + public var ChatList_Read: String { return self._s[1953]! } public func Group_OwnershipTransfer_DescriptionInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1953]!, self._r[1953]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1954]!, self._r[1954]!, [_1, _2]) } - public var CallFeedback_Send: String { return self._s[1954]! } - public var Channel_Stickers_Searching: String { return self._s[1955]! } - public var ScheduledMessages_ReminderNotification: String { return self._s[1956]! } - public var FastTwoStepSetup_HintSection: String { return self._s[1957]! } - public var ChatSettings_AutoDownloadVideoMessages: String { return self._s[1958]! } - public var EditTheme_CreateTitle: String { return self._s[1959]! } - public var Application_Name: String { return self._s[1960]! } - public var Paint_Stickers: String { return self._s[1961]! } - public var Appearance_ThemePreview_Chat_1_Text: String { return self._s[1962]! } - public var Call_StatusFailed: String { return self._s[1963]! } - public var Stickers_FavoriteStickers: String { return self._s[1964]! } - public var ClearCache_Clear: String { return self._s[1965]! } - public var Passport_Language_mn: String { return self._s[1966]! } - public var WallpaperPreview_PreviewTopText: String { return self._s[1967]! } - public var LogoutOptions_ClearCacheTitle: String { return self._s[1968]! } - public var TwoFactorSetup_Hint_Text: String { return self._s[1971]! } - public var WallpaperPreview_PatternIntensity: String { return self._s[1972]! } - public var CheckoutInfo_ErrorShippingNotAvailable: String { return self._s[1973]! } - public var Wallet_RestoreFailed_CreateWallet: String { return self._s[1974]! } - public var Passport_Address_AddBankStatement: String { return self._s[1975]! } + public var CallFeedback_Send: String { return self._s[1955]! } + public var Channel_Stickers_Searching: String { return self._s[1956]! } + public var ScheduledMessages_ReminderNotification: String { return self._s[1957]! } + public var FastTwoStepSetup_HintSection: String { return self._s[1958]! } + public var ChatSettings_AutoDownloadVideoMessages: String { return self._s[1959]! } + public var EditTheme_CreateTitle: String { return self._s[1960]! } + public var Application_Name: String { return self._s[1961]! } + public var Paint_Stickers: String { return self._s[1962]! } + public var Appearance_ThemePreview_Chat_1_Text: String { return self._s[1963]! } + public var Call_StatusFailed: String { return self._s[1964]! } + public var Stickers_FavoriteStickers: String { return self._s[1965]! } + public var ClearCache_Clear: String { return self._s[1966]! } + public var Passport_Language_mn: String { return self._s[1967]! } + public var WallpaperPreview_PreviewTopText: String { return self._s[1968]! } + public var LogoutOptions_ClearCacheTitle: String { return self._s[1969]! } + public var TwoFactorSetup_Hint_Text: String { return self._s[1972]! } + public var WallpaperPreview_PatternIntensity: String { return self._s[1973]! } + public var CheckoutInfo_ErrorShippingNotAvailable: String { return self._s[1974]! } + public var Wallet_RestoreFailed_CreateWallet: String { return self._s[1975]! } + public var Passport_Address_AddBankStatement: String { return self._s[1976]! } public func Conversation_TitleRepliesFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1977]!, self._r[1977]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1978]!, self._r[1978]!, [_1, _2]) } - public var ChatListFolderSettings_RecommendedNewFolder: String { return self._s[1978]! } - public var UserInfo_ShareContact: String { return self._s[1979]! } - public var Passport_Identity_NamePlaceholder: String { return self._s[1980]! } - public var Wallet_Receive_InvoiceUrlCopied: String { return self._s[1982]! } - public var Call_RateCall: String { return self._s[1983]! } - public var Contacts_AccessDeniedError: String { return self._s[1984]! } - public var Invite_ChannelsTooMuch: String { return self._s[1985]! } - public var CheckoutInfo_ShippingInfoPostcode: String { return self._s[1986]! } - public var Channel_BanUser_PermissionReadMessages: String { return self._s[1987]! } - public var Cache_NoLimit: String { return self._s[1989]! } - public var Conversation_EmptyPlaceholder: String { return self._s[1993]! } - public var Privacy_GroupsAndChannels_AlwaysAllow_Placeholder: String { return self._s[1994]! } - public var GroupRemoved_RemoveInfo: String { return self._s[1996]! } - public var Privacy_Calls_IntegrationHelp: String { return self._s[1997]! } + public var ChatListFolderSettings_RecommendedNewFolder: String { return self._s[1979]! } + public var UserInfo_ShareContact: String { return self._s[1980]! } + public var Passport_Identity_NamePlaceholder: String { return self._s[1981]! } + public var Wallet_Receive_InvoiceUrlCopied: String { return self._s[1983]! } + public var Call_RateCall: String { return self._s[1984]! } + public var Contacts_AccessDeniedError: String { return self._s[1985]! } + public var Invite_ChannelsTooMuch: String { return self._s[1986]! } + public var CheckoutInfo_ShippingInfoPostcode: String { return self._s[1987]! } + public var Channel_BanUser_PermissionReadMessages: String { return self._s[1988]! } + public var Cache_NoLimit: String { return self._s[1990]! } + public var Conversation_EmptyPlaceholder: String { return self._s[1994]! } + public var Privacy_GroupsAndChannels_AlwaysAllow_Placeholder: String { return self._s[1995]! } + public var GroupRemoved_RemoveInfo: String { return self._s[1997]! } + public var Privacy_Calls_IntegrationHelp: String { return self._s[1998]! } public func PUSH_VIDEO_CALL_MISSED(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1998]!, self._r[1998]!, [_1]) + return formatWithArgumentRanges(self._s[1999]!, self._r[1999]!, [_1]) } - public var VoiceOver_Media_PlaybackRateFast: String { return self._s[1999]! } - public var Theme_ThemeChanged: String { return self._s[2000]! } - public var Privacy_GroupsAndChannels_NeverAllow: String { return self._s[2002]! } - public var AutoDownloadSettings_MediaTypes: String { return self._s[2003]! } + public var VoiceOver_Media_PlaybackRateFast: String { return self._s[2000]! } + public var Theme_ThemeChanged: String { return self._s[2001]! } + public var Privacy_GroupsAndChannels_NeverAllow: String { return self._s[2003]! } + public var AutoDownloadSettings_MediaTypes: String { return self._s[2004]! } public func Notification_PinnedDocumentMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2004]!, self._r[2004]!, [_0]) + return formatWithArgumentRanges(self._s[2005]!, self._r[2005]!, [_0]) } - public var Channel_AdminLog_InfoPanelTitle: String { return self._s[2005]! } - public var Passport_Language_da: String { return self._s[2007]! } - public var Wallet_Receive_AmountText: String { return self._s[2008]! } - public var Chat_SlowmodeSendError: String { return self._s[2009]! } - public var Application_Update: String { return self._s[2011]! } - public var SocksProxySetup_SaveProxy: String { return self._s[2012]! } + public var Channel_AdminLog_InfoPanelTitle: String { return self._s[2006]! } + public var Passport_Language_da: String { return self._s[2008]! } + public var Wallet_Receive_AmountText: String { return self._s[2009]! } + public var Chat_SlowmodeSendError: String { return self._s[2010]! } + public var Application_Update: String { return self._s[2012]! } + public var SocksProxySetup_SaveProxy: String { return self._s[2013]! } public func PUSH_AUTH_REGION(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2013]!, self._r[2013]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2014]!, self._r[2014]!, [_1, _2]) } - public var Wallet_Receive_ShareAddress: String { return self._s[2015]! } - public var Privacy_AddNewPeer: String { return self._s[2016]! } - public var Channel_DiscussionGroup_MakeHistoryPublicProceed: String { return self._s[2018]! } - public var Wallet_Receive_CommentInfo: String { return self._s[2019]! } - public var Channel_Members_Title: String { return self._s[2020]! } - public var Settings_LogoutConfirmationText: String { return self._s[2021]! } - public var Chat_UnsendMyMessages: String { return self._s[2022]! } - public var Conversation_EditingMessageMediaEditCurrentVideo: String { return self._s[2024]! } - public var ChatListFilter_AddChatsTitle: String { return self._s[2025]! } - public var Passport_FloodError: String { return self._s[2026]! } - public var NotificationSettings_ContactJoinedInfo: String { return self._s[2027]! } - public var SettingsSearch_Synonyms_Privacy_Data_SecretChatLinkPreview: String { return self._s[2028]! } - public var CallSettings_TabIconDescription: String { return self._s[2029]! } - public var Wallet_Intro_Text: String { return self._s[2030]! } - public var Group_Setup_HistoryHeader: String { return self._s[2032]! } - public var TwoStepAuth_EmailTitle: String { return self._s[2033]! } - public var GroupInfo_Permissions_Removed: String { return self._s[2034]! } - public var DialogList_ClearHistoryConfirmation: String { return self._s[2035]! } - public var Contacts_Title: String { return self._s[2037]! } + public var Wallet_Receive_ShareAddress: String { return self._s[2016]! } + public var Privacy_AddNewPeer: String { return self._s[2017]! } + public var Channel_DiscussionGroup_MakeHistoryPublicProceed: String { return self._s[2019]! } + public var Wallet_Receive_CommentInfo: String { return self._s[2020]! } + public var Channel_Members_Title: String { return self._s[2021]! } + public var Settings_LogoutConfirmationText: String { return self._s[2022]! } + public var Chat_UnsendMyMessages: String { return self._s[2023]! } + public var Conversation_EditingMessageMediaEditCurrentVideo: String { return self._s[2025]! } + public var ChatListFilter_AddChatsTitle: String { return self._s[2026]! } + public var Passport_FloodError: String { return self._s[2027]! } + public var NotificationSettings_ContactJoinedInfo: String { return self._s[2028]! } + public var SettingsSearch_Synonyms_Privacy_Data_SecretChatLinkPreview: String { return self._s[2029]! } + public var CallSettings_TabIconDescription: String { return self._s[2030]! } + public var Wallet_Intro_Text: String { return self._s[2031]! } + public var Group_Setup_HistoryHeader: String { return self._s[2033]! } + public var TwoStepAuth_EmailTitle: String { return self._s[2034]! } + public var GroupInfo_Permissions_Removed: String { return self._s[2035]! } + public var DialogList_ClearHistoryConfirmation: String { return self._s[2036]! } + public var Contacts_Title: String { return self._s[2038]! } public func Notification_Invited(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2038]!, self._r[2038]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2039]!, self._r[2039]!, [_0, _1]) } - public var ChatList_PeerTypeBot: String { return self._s[2041]! } + public var ChatList_PeerTypeBot: String { return self._s[2042]! } public func Channel_AdminLog_SetSlowmode(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2042]!, self._r[2042]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2043]!, self._r[2043]!, [_1, _2]) } - public var Appearance_ThemePreview_Chat_6_Text: String { return self._s[2043]! } + public var Appearance_ThemePreview_Chat_6_Text: String { return self._s[2044]! } public func Time_PreciseDate_m1(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2044]!, self._r[2044]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2045]!, self._r[2045]!, [_1, _2, _3]) } - public var Camera_PhotoMode: String { return self._s[2046]! } + public var Camera_PhotoMode: String { return self._s[2047]! } public func PUSH_MESSAGE_GAME_SCORE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2047]!, self._r[2047]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2048]!, self._r[2048]!, [_1, _2, _3]) } - public var ContactInfo_PhoneLabelPager: String { return self._s[2048]! } - public var SettingsSearch_Synonyms_FAQ: String { return self._s[2049]! } - public var Call_CallAgain: String { return self._s[2050]! } - public var TwoStepAuth_PasswordSet: String { return self._s[2051]! } + public var ContactInfo_PhoneLabelPager: String { return self._s[2049]! } + public var SettingsSearch_Synonyms_FAQ: String { return self._s[2050]! } + public var Call_CallAgain: String { return self._s[2051]! } + public var TwoStepAuth_PasswordSet: String { return self._s[2052]! } public func Channel_Management_RestrictedBy(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2052]!, self._r[2052]!, [_0]) + return formatWithArgumentRanges(self._s[2053]!, self._r[2053]!, [_0]) } - public var GroupInfo_InviteLink_RevokeAlert_Success: String { return self._s[2053]! } - public var ClearCache_FreeSpaceDescription: String { return self._s[2054]! } - public var Permissions_ContactsAllowInSettings_v0: String { return self._s[2055]! } - public var Group_LeaveGroup: String { return self._s[2056]! } - public var Wallet_WordImport_IncorrectText: String { return self._s[2059]! } - public var GroupInfo_LabelAdmin: String { return self._s[2060]! } - public var CheckoutInfo_ErrorStateInvalid: String { return self._s[2062]! } - public var Notification_PassportValuePersonalDetails: String { return self._s[2063]! } + public var GroupInfo_InviteLink_RevokeAlert_Success: String { return self._s[2054]! } + public var ClearCache_FreeSpaceDescription: String { return self._s[2055]! } + public var Permissions_ContactsAllowInSettings_v0: String { return self._s[2056]! } + public var Group_LeaveGroup: String { return self._s[2057]! } + public var Wallet_WordImport_IncorrectText: String { return self._s[2060]! } + public var GroupInfo_LabelAdmin: String { return self._s[2061]! } + public var CheckoutInfo_ErrorStateInvalid: String { return self._s[2063]! } + public var Notification_PassportValuePersonalDetails: String { return self._s[2064]! } public func WebSearch_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2064]!, self._r[2064]!, [_0]) + return formatWithArgumentRanges(self._s[2065]!, self._r[2065]!, [_0]) } - public var Stats_GroupNewMembersBySourceTitle: String { return self._s[2065]! } - public var Appearance_Preview: String { return self._s[2066]! } - public var VoiceOver_Chat_Contact: String { return self._s[2067]! } - public var Passport_Language_th: String { return self._s[2068]! } - public var PhotoEditor_CropAspectRatioOriginal: String { return self._s[2071]! } - public var LastSeen_Offline: String { return self._s[2074]! } - public var Map_OpenInHereMaps: String { return self._s[2075]! } - public var SettingsSearch_Synonyms_Data_AutoplayVideos: String { return self._s[2076]! } - public var AutoDownloadSettings_Reset: String { return self._s[2078]! } - public var Wallet_Month_GenFebruary: String { return self._s[2079]! } - public var Conversation_SendMessage_SetReminder: String { return self._s[2080]! } - public var Channel_AdminLog_EmptyMessageText: String { return self._s[2081]! } + public var Stats_GroupNewMembersBySourceTitle: String { return self._s[2066]! } + public var Appearance_Preview: String { return self._s[2067]! } + public var VoiceOver_Chat_Contact: String { return self._s[2068]! } + public var Passport_Language_th: String { return self._s[2069]! } + public var PhotoEditor_CropAspectRatioOriginal: String { return self._s[2072]! } + public var LastSeen_Offline: String { return self._s[2075]! } + public var Map_OpenInHereMaps: String { return self._s[2076]! } + public var SettingsSearch_Synonyms_Data_AutoplayVideos: String { return self._s[2077]! } + public var AutoDownloadSettings_Reset: String { return self._s[2079]! } + public var Wallet_Month_GenFebruary: String { return self._s[2080]! } + public var Conversation_SendMessage_SetReminder: String { return self._s[2081]! } + public var Channel_AdminLog_EmptyMessageText: String { return self._s[2082]! } public func AddContact_StatusSuccess(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2082]!, self._r[2082]!, [_0]) - } - public func AuthCode_Alert(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2083]!, self._r[2083]!, [_0]) } - public var Passport_Identity_EditDriversLicense: String { return self._s[2084]! } - public var ChatListFolder_NameNonMuted: String { return self._s[2085]! } - public var Username_Placeholder: String { return self._s[2086]! } + public func AuthCode_Alert(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2084]!, self._r[2084]!, [_0]) + } + public var Passport_Identity_EditDriversLicense: String { return self._s[2085]! } + public var ChatListFolder_NameNonMuted: String { return self._s[2086]! } + public var Username_Placeholder: String { return self._s[2087]! } public func PUSH_ALBUM(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2087]!, self._r[2087]!, [_1]) + return formatWithArgumentRanges(self._s[2088]!, self._r[2088]!, [_1]) } - public var Wallet_Send_NetworkErrorText: String { return self._s[2088]! } - public var Checkout_NewCard_SaveInfo: String { return self._s[2089]! } - public var Passport_Language_it: String { return self._s[2090]! } + public var Wallet_Send_NetworkErrorText: String { return self._s[2089]! } + public var Checkout_NewCard_SaveInfo: String { return self._s[2090]! } + public var Passport_Language_it: String { return self._s[2091]! } public func Channel_OwnershipTransfer_DescriptionInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2091]!, self._r[2091]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2092]!, self._r[2092]!, [_1, _2]) } - public var NotificationsSound_Pulse: String { return self._s[2092]! } - public var MessagePoll_NoVotes: String { return self._s[2096]! } - public var Message_Wallpaper: String { return self._s[2097]! } - public var Wallet_Created_Proceed: String { return self._s[2098]! } - public var Appearance_Other: String { return self._s[2099]! } - public var Passport_Identity_NativeNameHelp: String { return self._s[2101]! } - public var Group_PublicLink_Placeholder: String { return self._s[2104]! } - public var Appearance_ThemePreview_ChatList_2_Text: String { return self._s[2105]! } - public var VoiceOver_Recording_StopAndPreview: String { return self._s[2106]! } - public var ChatListFolder_NameBots: String { return self._s[2107]! } - public var Conversation_StopPollConfirmation: String { return self._s[2108]! } - public var UserInfo_DeleteContact: String { return self._s[2109]! } + public var NotificationsSound_Pulse: String { return self._s[2093]! } + public var MessagePoll_NoVotes: String { return self._s[2097]! } + public var Message_Wallpaper: String { return self._s[2098]! } + public var Wallet_Created_Proceed: String { return self._s[2099]! } + public var Appearance_Other: String { return self._s[2100]! } + public var Passport_Identity_NativeNameHelp: String { return self._s[2102]! } + public var Group_PublicLink_Placeholder: String { return self._s[2105]! } + public var Appearance_ThemePreview_ChatList_2_Text: String { return self._s[2106]! } + public var VoiceOver_Recording_StopAndPreview: String { return self._s[2107]! } + public var ChatListFolder_NameBots: String { return self._s[2108]! } + public var Conversation_StopPollConfirmation: String { return self._s[2109]! } + public var UserInfo_DeleteContact: String { return self._s[2110]! } public func Time_MonthOfYear_m11(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2110]!, self._r[2110]!, [_0]) + return formatWithArgumentRanges(self._s[2111]!, self._r[2111]!, [_0]) } - public var Wallpaper_Wallpaper: String { return self._s[2112]! } + public var Wallpaper_Wallpaper: String { return self._s[2113]! } public func PUSH_MESSAGE_NOTEXT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2113]!, self._r[2113]!, [_1]) + return formatWithArgumentRanges(self._s[2114]!, self._r[2114]!, [_1]) } - public var LoginPassword_ForgotPassword: String { return self._s[2114]! } - public var FeaturedStickerPacks_Title: String { return self._s[2115]! } - public var Paint_Pen: String { return self._s[2116]! } - public var Channel_AdminLogFilter_EventsInfo: String { return self._s[2117]! } - public var ChatListFolderSettings_Info: String { return self._s[2118]! } - public var FastTwoStepSetup_HintPlaceholder: String { return self._s[2119]! } - public var PhotoEditor_CurvesAll: String { return self._s[2121]! } - public var Wallet_Info_UnknownTransaction: String { return self._s[2122]! } + public var LoginPassword_ForgotPassword: String { return self._s[2115]! } + public var FeaturedStickerPacks_Title: String { return self._s[2116]! } + public var Paint_Pen: String { return self._s[2117]! } + public var Channel_AdminLogFilter_EventsInfo: String { return self._s[2118]! } + public var ChatListFolderSettings_Info: String { return self._s[2119]! } + public var FastTwoStepSetup_HintPlaceholder: String { return self._s[2120]! } + public var PhotoEditor_CurvesAll: String { return self._s[2122]! } + public var Wallet_Info_UnknownTransaction: String { return self._s[2123]! } public func Time_PreciseDate_m12(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2124]!, self._r[2124]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2125]!, self._r[2125]!, [_1, _2, _3]) } - public var Passport_Address_TypeRentalAgreement: String { return self._s[2126]! } - public var Message_ImageExpired: String { return self._s[2127]! } - public var Call_ConnectionErrorMessage: String { return self._s[2128]! } - public var SearchImages_NoImagesFound: String { return self._s[2130]! } - public var PeerInfo_PaneGifs: String { return self._s[2131]! } - public var Passport_DeletePersonalDetailsConfirmation: String { return self._s[2132]! } - public var EnterPasscode_RepeatNewPasscode: String { return self._s[2133]! } - public var PhotoEditor_VignetteTool: String { return self._s[2134]! } - public var Passport_Language_dz: String { return self._s[2135]! } - public var Notifications_ChannelNotificationsHelp: String { return self._s[2136]! } - public var Conversation_BlockUser: String { return self._s[2137]! } + public var Passport_Address_TypeRentalAgreement: String { return self._s[2127]! } + public var Message_ImageExpired: String { return self._s[2128]! } + public var Call_ConnectionErrorMessage: String { return self._s[2129]! } + public var SearchImages_NoImagesFound: String { return self._s[2131]! } + public var PeerInfo_PaneGifs: String { return self._s[2132]! } + public var Passport_DeletePersonalDetailsConfirmation: String { return self._s[2133]! } + public var EnterPasscode_RepeatNewPasscode: String { return self._s[2134]! } + public var PhotoEditor_VignetteTool: String { return self._s[2135]! } + public var Passport_Language_dz: String { return self._s[2136]! } + public var Notifications_ChannelNotificationsHelp: String { return self._s[2137]! } + public var Conversation_BlockUser: String { return self._s[2138]! } public func Wallet_Send_Balance(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2139]!, self._r[2139]!, [_0]) + return formatWithArgumentRanges(self._s[2140]!, self._r[2140]!, [_0]) } - public var GroupPermission_PermissionDisabledByDefault: String { return self._s[2140]! } - public var Group_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[2141]! } + public var GroupPermission_PermissionDisabledByDefault: String { return self._s[2141]! } + public var Group_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[2142]! } public func Time_MonthOfYear_m8(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2142]!, self._r[2142]!, [_0]) + return formatWithArgumentRanges(self._s[2143]!, self._r[2143]!, [_0]) } - public var KeyCommand_NewMessage: String { return self._s[2143]! } - public var EditTheme_Edit_Preview_IncomingReplyText: String { return self._s[2145]! } + public var KeyCommand_NewMessage: String { return self._s[2144]! } + public var EditTheme_Edit_Preview_IncomingReplyText: String { return self._s[2146]! } public func PUSH_CHAT_MESSAGE_GEO(_ _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 var ContactList_Context_StartSecretChat: String { return self._s[2148]! } - public var VoiceOver_Chat_File: String { return self._s[2149]! } - public var ChatList_EditFolder: String { return self._s[2151]! } - public var Appearance_BubbleCorners_Title: String { return self._s[2152]! } - public var PeerInfo_PaneAudio: String { return self._s[2153]! } - public var Wallet_SecureStorageReset_Title: String { return self._s[2154]! } - public var ChatListFolder_CategoryContacts: String { return self._s[2156]! } + public var ContactList_Context_StartSecretChat: String { return self._s[2149]! } + public var VoiceOver_Chat_File: String { return self._s[2150]! } + public var ChatList_EditFolder: String { return self._s[2152]! } + public var Appearance_BubbleCorners_Title: String { return self._s[2153]! } + public var PeerInfo_PaneAudio: String { return self._s[2154]! } + public var Wallet_SecureStorageReset_Title: String { return self._s[2155]! } + public var ChatListFolder_CategoryContacts: String { return self._s[2157]! } public func Login_InvalidPhoneEmailBody(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2157]!, self._r[2157]!, [_1, _2, _3, _4, _5]) + return formatWithArgumentRanges(self._s[2158]!, self._r[2158]!, [_1, _2, _3, _4, _5]) } - public var ChatList_PeerTypeChannel: String { return self._s[2158]! } - public var VoiceOver_Navigation_Search: String { return self._s[2159]! } - public var Settings_Search: String { return self._s[2160]! } - public var WallpaperSearch_ColorYellow: String { return self._s[2161]! } - public var Login_PhoneBannedError: String { return self._s[2162]! } - public var KeyCommand_JumpToNextChat: String { return self._s[2163]! } - public var Passport_Language_fa: String { return self._s[2164]! } - public var Settings_About: String { return self._s[2165]! } - public var Wallet_Configuration_Title: String { return self._s[2166]! } - public var AutoDownloadSettings_MaxFileSize: String { return self._s[2167]! } - public var Channel_AdminLog_InfoPanelChannelAlertText: String { return self._s[2168]! } - public var AutoDownloadSettings_DataUsageHigh: String { return self._s[2169]! } + public var ChatList_PeerTypeChannel: String { return self._s[2159]! } + public var VoiceOver_Navigation_Search: String { return self._s[2160]! } + public var Settings_Search: String { return self._s[2161]! } + public var WallpaperSearch_ColorYellow: String { return self._s[2162]! } + public var Login_PhoneBannedError: String { return self._s[2163]! } + public var KeyCommand_JumpToNextChat: String { return self._s[2164]! } + public var Passport_Language_fa: String { return self._s[2165]! } + public var Settings_About: String { return self._s[2166]! } + public var Wallet_Configuration_Title: String { return self._s[2167]! } + public var AutoDownloadSettings_MaxFileSize: String { return self._s[2168]! } + public var Channel_AdminLog_InfoPanelChannelAlertText: String { return self._s[2169]! } + public var AutoDownloadSettings_DataUsageHigh: String { return self._s[2170]! } public func PUSH_CHAT_MESSAGE_TEXT(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2170]!, self._r[2170]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2171]!, self._r[2171]!, [_1, _2, _3]) } - public var Common_OK: String { return self._s[2171]! } - public var Contacts_SortBy: String { return self._s[2172]! } - public var AutoNightTheme_PreferredTheme: String { return self._s[2173]! } + public var Common_OK: String { return self._s[2172]! } + public var Contacts_SortBy: String { return self._s[2173]! } + public var AutoNightTheme_PreferredTheme: String { return self._s[2174]! } public func AutoDownloadSettings_OnFor(_ _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 CallFeedback_IncludeLogs: String { return self._s[2178]! } + public var CallFeedback_IncludeLogs: String { return self._s[2179]! } public func External_OpenIn(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2179]!, self._r[2179]!, [_0]) + return formatWithArgumentRanges(self._s[2180]!, self._r[2180]!, [_0]) } - public var Passcode_AppLockedAlert: String { return self._s[2180]! } - public var TwoStepAuth_SetupPasswordTitle: String { return self._s[2181]! } - public var Wallet_Send_ErrorDecryptionFailed: String { return self._s[2182]! } - public var Channel_NotificationLoading: String { return self._s[2184]! } - public var Passport_Identity_DocumentNumber: String { return self._s[2185]! } - public var VoiceOver_Chat_PagePreview: String { return self._s[2186]! } - public var VoiceOver_Chat_OpenHint: String { return self._s[2187]! } - public var Weekday_ShortFriday: String { return self._s[2188]! } - public var Wallet_CreateInvoice_Title: String { return self._s[2189]! } - public var Conversation_TitleMute: String { return self._s[2190]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsSound: String { return self._s[2191]! } - public var ScheduledMessages_PollUnavailable: String { return self._s[2192]! } - public var DialogList_LanguageTooltip: String { return self._s[2193]! } - public var Channel_AdminLogFilter_EventsPinned: String { return self._s[2195]! } + public var Passcode_AppLockedAlert: String { return self._s[2181]! } + public var TwoStepAuth_SetupPasswordTitle: String { return self._s[2182]! } + public var Wallet_Send_ErrorDecryptionFailed: String { return self._s[2183]! } + public var Channel_NotificationLoading: String { return self._s[2185]! } + public var Passport_Identity_DocumentNumber: String { return self._s[2186]! } + public var VoiceOver_Chat_PagePreview: String { return self._s[2187]! } + public var VoiceOver_Chat_OpenHint: String { return self._s[2188]! } + public var Weekday_ShortFriday: String { return self._s[2189]! } + public var Wallet_CreateInvoice_Title: String { return self._s[2190]! } + public var Conversation_TitleMute: String { return self._s[2191]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsSound: String { return self._s[2192]! } + public var ScheduledMessages_PollUnavailable: String { return self._s[2193]! } + public var DialogList_LanguageTooltip: String { return self._s[2194]! } + public var Channel_AdminLogFilter_EventsPinned: String { return self._s[2196]! } public func DialogList_SingleUploadingVideoSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2196]!, self._r[2196]!, [_0]) + return formatWithArgumentRanges(self._s[2197]!, self._r[2197]!, [_0]) } - public var TwoStepAuth_SetupResendEmailCodeAlert: String { return self._s[2198]! } - public var Privacy_Calls_AlwaysAllow_Title: String { return self._s[2199]! } - public var Settings_EditVideo: String { return self._s[2200]! } - public var Stickers_FrequentlyUsed: String { return self._s[2201]! } - public var GroupPermission_Title: String { return self._s[2202]! } - public var AccessDenied_VideoMessageCamera: String { return self._s[2203]! } - public var Appearance_ThemeCarouselDay: String { return self._s[2204]! } + public var TwoStepAuth_SetupResendEmailCodeAlert: String { return self._s[2199]! } + public var Privacy_Calls_AlwaysAllow_Title: String { return self._s[2200]! } + public var Settings_EditVideo: String { return self._s[2201]! } + public var Stickers_FrequentlyUsed: String { return self._s[2202]! } + public var GroupPermission_Title: String { return self._s[2203]! } + public var AccessDenied_VideoMessageCamera: String { return self._s[2204]! } + public var Appearance_ThemeCarouselDay: String { return self._s[2205]! } public func PUSH_CHAT_MESSAGE_AUDIO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2205]!, self._r[2205]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2206]!, self._r[2206]!, [_1, _2]) } - public var Passport_Identity_DocumentNumberPlaceholder: String { return self._s[2206]! } - public var Tour_Title6: String { return self._s[2207]! } - public var EmptyGroupInfo_Title: String { return self._s[2208]! } + public var Passport_Identity_DocumentNumberPlaceholder: String { return self._s[2207]! } + public var Tour_Title6: String { return self._s[2208]! } + public var EmptyGroupInfo_Title: String { return self._s[2209]! } public func Channel_AdminLog_MessageToggleSignaturesOn(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2209]!, self._r[2209]!, [_0]) + return formatWithArgumentRanges(self._s[2210]!, self._r[2210]!, [_0]) } - public var Passport_Language_sk: String { return self._s[2210]! } - public var VoiceOver_Chat_YourAnonymousPoll: String { return self._s[2211]! } - public var Preview_SaveToCameraRoll: String { return self._s[2212]! } - public var LogoutOptions_SetPasscodeTitle: String { return self._s[2213]! } - public var Passport_Address_TypeUtilityBillUploadScan: String { return self._s[2214]! } - public var Conversation_ContextMenuMore: String { return self._s[2215]! } - public var Conversation_ForwardAuthorHiddenTooltip: String { return self._s[2216]! } - public var Channel_AdminLog_CanBeAnonymous: String { return self._s[2217]! } - public var CallFeedback_ReasonSilentLocal: String { return self._s[2219]! } - public var UserInfo_NotificationsDisable: String { return self._s[2220]! } + public var Passport_Language_sk: String { return self._s[2211]! } + public var VoiceOver_Chat_YourAnonymousPoll: String { return self._s[2212]! } + public var Preview_SaveToCameraRoll: String { return self._s[2213]! } + public var LogoutOptions_SetPasscodeTitle: String { return self._s[2214]! } + public var Passport_Address_TypeUtilityBillUploadScan: String { return self._s[2215]! } + public var Conversation_ContextMenuMore: String { return self._s[2216]! } + public var Conversation_ForwardAuthorHiddenTooltip: String { return self._s[2217]! } + public var Channel_AdminLog_CanBeAnonymous: String { return self._s[2218]! } + public var CallFeedback_ReasonSilentLocal: String { return self._s[2220]! } + public var UserInfo_NotificationsDisable: String { return self._s[2221]! } public func Channel_AdminLog_EmptyFilterQueryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2222]!, self._r[2222]!, [_0]) + return formatWithArgumentRanges(self._s[2223]!, self._r[2223]!, [_0]) } - public var SettingsSearch_Synonyms_EditProfile_Bio: String { return self._s[2223]! } + public var SettingsSearch_Synonyms_EditProfile_Bio: String { return self._s[2224]! } public func Date_ChatDateHeader(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2225]!, self._r[2225]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2226]!, self._r[2226]!, [_1, _2]) } - public var WallpaperSearch_ColorPrefix: String { return self._s[2226]! } + public var WallpaperSearch_ColorPrefix: String { return self._s[2227]! } public func Message_ForwardedPsa_covid(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2227]!, self._r[2227]!, [_0]) + return formatWithArgumentRanges(self._s[2228]!, self._r[2228]!, [_0]) } - public var Conversation_RestrictedMedia: String { return self._s[2229]! } - public var Group_MessageVideoUpdated: String { return self._s[2230]! } - public var NetworkUsageSettings_ResetStatsConfirmation: String { return self._s[2231]! } - public var GroupInfo_DeleteAndExit: String { return self._s[2232]! } - public var TwoFactorSetup_Email_Action: String { return self._s[2233]! } - public var Media_ShareThisVideo: String { return self._s[2235]! } - public var DialogList_Replies: String { return self._s[2236]! } + public var Conversation_RestrictedMedia: String { return self._s[2230]! } + public var Group_MessageVideoUpdated: String { return self._s[2231]! } + public var NetworkUsageSettings_ResetStatsConfirmation: String { return self._s[2232]! } + public var GroupInfo_DeleteAndExit: String { return self._s[2233]! } + public var TwoFactorSetup_Email_Action: String { return self._s[2234]! } + public var Media_ShareThisVideo: String { return self._s[2236]! } + public var DialogList_Replies: String { return self._s[2237]! } public func Conversation_Moderate_DeleteAllMessages(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2237]!, self._r[2237]!, [_0]) + return formatWithArgumentRanges(self._s[2238]!, self._r[2238]!, [_0]) } - public var CheckoutInfo_ShippingInfoAddress1: String { return self._s[2238]! } - public var Watch_Suggestion_OnMyWay: String { return self._s[2239]! } - public var CheckoutInfo_ShippingInfoAddress2: String { return self._s[2240]! } + public var CheckoutInfo_ShippingInfoAddress1: String { return self._s[2239]! } + public var Watch_Suggestion_OnMyWay: String { return self._s[2240]! } + public var CheckoutInfo_ShippingInfoAddress2: String { return self._s[2241]! } public func PUSH_PINNED_POLL(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2241]!, self._r[2241]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2242]!, self._r[2242]!, [_1, _2]) } public func GroupInfo_InvitationLinkAcceptChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2242]!, self._r[2242]!, [_0]) + return formatWithArgumentRanges(self._s[2243]!, self._r[2243]!, [_0]) } - public var Channel_EditAdmin_PermissinAddAdminOff: String { return self._s[2243]! } - public var Conversation_WalletRequiredSetup: String { return self._s[2244]! } - public var ChatAdmins_AllMembersAreAdminsOnHelp: String { return self._s[2245]! } - public var Channel_Members_InviteLink: String { return self._s[2246]! } - public var ChatList_Search_NoResultsFitlerMedia: String { return self._s[2247]! } - public var Conversation_TapAndHoldToRecord: String { return self._s[2248]! } - public var Wallet_Info_Receive: String { return self._s[2249]! } - public var WatchRemote_AlertText: String { return self._s[2250]! } + public var Channel_EditAdmin_PermissinAddAdminOff: String { return self._s[2244]! } + public var Conversation_WalletRequiredSetup: String { return self._s[2245]! } + public var ChatAdmins_AllMembersAreAdminsOnHelp: String { return self._s[2246]! } + public var Channel_Members_InviteLink: String { return self._s[2247]! } + public var ChatList_Search_NoResultsFitlerMedia: String { return self._s[2248]! } + public var Conversation_TapAndHoldToRecord: String { return self._s[2249]! } + public var Wallet_Info_Receive: String { return self._s[2250]! } + public var WatchRemote_AlertText: String { return self._s[2251]! } public func Channel_DiscussionGroup_PrivateChannelLink(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2251]!, self._r[2251]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2252]!, self._r[2252]!, [_1, _2]) } - public var Conversation_Pin: String { return self._s[2252]! } - public var InfoPlist_NSMicrophoneUsageDescription: String { return self._s[2253]! } - public var Stickers_RemoveFromFavorites: String { return self._s[2254]! } + public var Conversation_Pin: String { return self._s[2253]! } + public var InfoPlist_NSMicrophoneUsageDescription: String { return self._s[2254]! } + public var Stickers_RemoveFromFavorites: String { return self._s[2255]! } public func Notification_PinnedPollMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2255]!, self._r[2255]!, [_0]) + return formatWithArgumentRanges(self._s[2256]!, self._r[2256]!, [_0]) } - public var Appearance_AppIconFilled: String { return self._s[2256]! } - public var StickerPack_ErrorNotFound: String { return self._s[2257]! } + public var Appearance_AppIconFilled: String { return self._s[2257]! } + public var StickerPack_ErrorNotFound: String { return self._s[2258]! } public func Channel_AdminLog_MessageRestrictedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2258]!, self._r[2258]!, [_1]) + return formatWithArgumentRanges(self._s[2259]!, self._r[2259]!, [_1]) } - public var Passport_Identity_AddIdentityCard: String { return self._s[2259]! } + public var Passport_Identity_AddIdentityCard: String { return self._s[2260]! } public func PUSH_CHANNEL_MESSAGE_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2260]!, self._r[2260]!, [_1]) + return formatWithArgumentRanges(self._s[2261]!, self._r[2261]!, [_1]) } - public var Call_Camera: String { return self._s[2261]! } - public var GroupInfo_InviteLink_RevokeAlert_Text: String { return self._s[2262]! } - public var Group_Location_Info: String { return self._s[2263]! } - public var Watch_LastSeen_WithinAMonth: String { return self._s[2264]! } - public var UserInfo_NotificationsDefaultEnabled: String { return self._s[2265]! } + public var Call_Camera: String { return self._s[2262]! } + public var GroupInfo_InviteLink_RevokeAlert_Text: String { return self._s[2263]! } + public var Group_Location_Info: String { return self._s[2264]! } + public var Watch_LastSeen_WithinAMonth: String { return self._s[2265]! } + public var UserInfo_NotificationsDefaultEnabled: String { return self._s[2266]! } public func DialogList_PinLimitError(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2266]!, self._r[2266]!, [_0]) + return formatWithArgumentRanges(self._s[2267]!, self._r[2267]!, [_0]) } - public var Weekday_Yesterday: String { return self._s[2267]! } - public var TwoStepAuth_SetupPasswordEnterPasswordNew: String { return self._s[2268]! } - public var ArchivedPacksAlert_Title: String { return self._s[2269]! } - public var PeerInfo_PaneMembers: String { return self._s[2270]! } - public var PhotoEditor_SelectCoverFrame: String { return self._s[2271]! } + public var Weekday_Yesterday: String { return self._s[2268]! } + public var TwoStepAuth_SetupPasswordEnterPasswordNew: String { return self._s[2269]! } + public var ArchivedPacksAlert_Title: String { return self._s[2270]! } + public var PeerInfo_PaneMembers: String { return self._s[2271]! } + public var PhotoEditor_SelectCoverFrame: String { return self._s[2272]! } public func Location_ProximityAlertSetTextGroup(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2272]!, self._r[2272]!, [_0]) + return formatWithArgumentRanges(self._s[2273]!, self._r[2273]!, [_0]) } - public var ContactInfo_PhoneLabelMain: String { return self._s[2273]! } + public var ContactInfo_PhoneLabelMain: String { return self._s[2274]! } public func Time_PreciseDate_m7(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2274]!, self._r[2274]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2275]!, self._r[2275]!, [_1, _2, _3]) } - public var TwoFactorSetup_EmailVerification_ChangeAction: String { return self._s[2275]! } - public var Channel_DiscussionGroup: String { return self._s[2276]! } - public var EditTheme_Edit_Preview_IncomingReplyName: String { return self._s[2277]! } - public var Channel_EditAdmin_PermissionsHeader: String { return self._s[2279]! } - public var VoiceOver_MessageContextForward: String { return self._s[2280]! } - public var SocksProxySetup_TypeNone: String { return self._s[2281]! } - public var CreatePoll_MultipleChoiceQuizAlert: String { return self._s[2283]! } - public var ProfilePhoto_OpenInEditor: String { return self._s[2285]! } - public var WallpaperSearch_ColorPurple: String { return self._s[2286]! } - public var ChatListFolder_IncludeChatsTitle: String { return self._s[2287]! } - public var Group_Username_InvalidTooShort: String { return self._s[2288]! } - public var Location_ProximityNotification_DistanceM: String { return self._s[2289]! } + public var TwoFactorSetup_EmailVerification_ChangeAction: String { return self._s[2276]! } + public var Channel_DiscussionGroup: String { return self._s[2277]! } + public var EditTheme_Edit_Preview_IncomingReplyName: String { return self._s[2278]! } + public var Channel_EditAdmin_PermissionsHeader: String { return self._s[2280]! } + public var VoiceOver_MessageContextForward: String { return self._s[2281]! } + public var SocksProxySetup_TypeNone: String { return self._s[2282]! } + public var CreatePoll_MultipleChoiceQuizAlert: String { return self._s[2284]! } + public var ProfilePhoto_OpenInEditor: String { return self._s[2286]! } + public var WallpaperSearch_ColorPurple: String { return self._s[2287]! } + public var ChatListFolder_IncludeChatsTitle: String { return self._s[2288]! } + public var Group_Username_InvalidTooShort: String { return self._s[2289]! } + public var Location_ProximityNotification_DistanceM: String { return self._s[2290]! } public func Login_EmailPhoneBody(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2290]!, self._r[2290]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[2291]!, self._r[2291]!, [_0, _1, _2]) } - public var Passport_Language_tk: String { return self._s[2291]! } - public var ConvertToSupergroup_Title: String { return self._s[2292]! } - public var Channel_BanUser_PermissionEmbedLinks: String { return self._s[2293]! } - public var Cache_KeepMediaHelp: String { return self._s[2294]! } - public var Channel_Management_Title: String { return self._s[2295]! } + public var Passport_Language_tk: String { return self._s[2292]! } + public var ConvertToSupergroup_Title: String { return self._s[2293]! } + public var Channel_BanUser_PermissionEmbedLinks: String { return self._s[2294]! } + public var Cache_KeepMediaHelp: String { return self._s[2295]! } + public var Channel_Management_Title: String { return self._s[2296]! } public func PUSH_MESSAGE_PHOTO_SECRET(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2296]!, self._r[2296]!, [_1]) + return formatWithArgumentRanges(self._s[2297]!, self._r[2297]!, [_1]) } - public var Conversation_ForwardChats: String { return self._s[2297]! } - public var Passport_Language_bg: String { return self._s[2298]! } - public var SocksProxySetup_TypeSocks: String { return self._s[2299]! } - public var Permissions_PrivacyPolicy: String { return self._s[2300]! } - public var VoiceOver_Chat_YourMusic: String { return self._s[2301]! } - public var SettingsSearch_Synonyms_Notifications_ResetAllNotifications: String { return self._s[2302]! } - public var Conversation_EmptyGifPanelPlaceholder: String { return self._s[2303]! } - public var Conversation_ContextMenuOpenChannel: String { return self._s[2304]! } - public var Activity_UploadingVideo: String { return self._s[2305]! } - public var PrivacyPolicy_AgeVerificationAgree: String { return self._s[2307]! } - public var Wallet_Sending_Text: String { return self._s[2308]! } - public var SocksProxySetup_Credentials: String { return self._s[2310]! } - public var Preview_SaveGif: String { return self._s[2311]! } - public var Cache_Photos: String { return self._s[2312]! } - public var Conversation_ContextMenuCancelEditing: String { return self._s[2313]! } - public var Wallet_Intro_NotNow: String { return self._s[2314]! } - public var Contacts_FailedToSendInvitesMessage: String { return self._s[2315]! } - public var Passport_Language_lt: String { return self._s[2316]! } - public var Passport_DeleteDocument: String { return self._s[2317]! } - public var GroupInfo_SetGroupPhotoStop: String { return self._s[2318]! } + public var Conversation_ForwardChats: String { return self._s[2298]! } + public var Passport_Language_bg: String { return self._s[2299]! } + public var SocksProxySetup_TypeSocks: String { return self._s[2300]! } + public var Permissions_PrivacyPolicy: String { return self._s[2301]! } + public var VoiceOver_Chat_YourMusic: String { return self._s[2302]! } + public var SettingsSearch_Synonyms_Notifications_ResetAllNotifications: String { return self._s[2303]! } + public var Conversation_EmptyGifPanelPlaceholder: String { return self._s[2304]! } + public var Conversation_ContextMenuOpenChannel: String { return self._s[2305]! } + public var Activity_UploadingVideo: String { return self._s[2306]! } + public var PrivacyPolicy_AgeVerificationAgree: String { return self._s[2308]! } + public var Wallet_Sending_Text: String { return self._s[2309]! } + public var SocksProxySetup_Credentials: String { return self._s[2311]! } + public var Preview_SaveGif: String { return self._s[2312]! } + public var Cache_Photos: String { return self._s[2313]! } + public var Conversation_ContextMenuCancelEditing: String { return self._s[2314]! } + public var Wallet_Intro_NotNow: String { return self._s[2315]! } + public var Contacts_FailedToSendInvitesMessage: String { return self._s[2316]! } + public var Passport_Language_lt: String { return self._s[2317]! } + public var Passport_DeleteDocument: String { return self._s[2318]! } + public var GroupInfo_SetGroupPhotoStop: String { return self._s[2319]! } public func Location_ProximityNotification_NotifyLong(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2319]!, self._r[2319]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2320]!, self._r[2320]!, [_1, _2]) } - public var AccessDenied_VideoMessageMicrophone: String { return self._s[2320]! } + public var AccessDenied_VideoMessageMicrophone: String { return self._s[2321]! } public func PeopleNearby_VisibleUntil(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2321]!, self._r[2321]!, [_0]) + return formatWithArgumentRanges(self._s[2322]!, self._r[2322]!, [_0]) } - public var AccessDenied_VideoCallCamera: String { return self._s[2322]! } + public var AccessDenied_VideoCallCamera: String { return self._s[2323]! } public func Channel_AdminLog_MessageDeleted(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2323]!, self._r[2323]!, [_0]) + return formatWithArgumentRanges(self._s[2324]!, self._r[2324]!, [_0]) } - public var PhotoEditor_SharpenTool: String { return self._s[2324]! } + public var PhotoEditor_SharpenTool: String { return self._s[2325]! } public func PUSH_CHANNEL_MESSAGE_AUDIO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2325]!, self._r[2325]!, [_1]) + return formatWithArgumentRanges(self._s[2326]!, self._r[2326]!, [_1]) } - public var DialogList_Unpin: String { return self._s[2326]! } - public var Stickers_NoStickersFound: String { return self._s[2327]! } - public var UserInfo_AddContact: String { return self._s[2329]! } + public var DialogList_Unpin: String { return self._s[2327]! } + public var Stickers_NoStickersFound: String { return self._s[2328]! } + public var UserInfo_AddContact: String { return self._s[2330]! } public func AddContact_SharedContactExceptionInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2331]!, self._r[2331]!, [_0]) - } - public func Notification_PinnedLocationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2332]!, self._r[2332]!, [_0]) } - public var CallFeedback_VideoReasonDistorted: String { return self._s[2333]! } - public var Tour_Text2: String { return self._s[2334]! } + public func Notification_PinnedLocationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2333]!, self._r[2333]!, [_0]) + } + public var CallFeedback_VideoReasonDistorted: String { return self._s[2334]! } + public var Tour_Text2: String { return self._s[2335]! } public func Conversation_TitleCommentsFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2336]!, self._r[2336]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2337]!, self._r[2337]!, [_1, _2]) } - public var Wallet_SecureStorageChanged_CreateWallet: String { return self._s[2337]! } - public var Paint_Delete: String { return self._s[2339]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsVibrate: String { return self._s[2340]! } + public var Wallet_SecureStorageChanged_CreateWallet: String { return self._s[2338]! } + public var Paint_Delete: String { return self._s[2340]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsVibrate: String { return self._s[2341]! } public func PrivacySettings_LastSeenEverybodyMinus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2342]!, self._r[2342]!, [_0]) + return formatWithArgumentRanges(self._s[2343]!, self._r[2343]!, [_0]) } - public var Privacy_Calls_NeverAllow_Title: String { return self._s[2343]! } - public var Notification_CallOutgoingShort: String { return self._s[2344]! } - public var Checkout_PasswordEntry_Title: String { return self._s[2345]! } - public var Channel_AdminLogFilter_AdminsAll: String { return self._s[2346]! } - public var Notification_MessageLifetime1m: String { return self._s[2347]! } - public var Wallet_TransactionInfo_CommentHeader: String { return self._s[2349]! } - public var BlockedUsers_AddNew: String { return self._s[2350]! } - public var Wallet_Intro_CreateErrorText: String { return self._s[2351]! } - public var FastTwoStepSetup_EmailSection: String { return self._s[2352]! } - public var Settings_SaveEditedPhotos: String { return self._s[2353]! } - public var GroupInfo_GroupNamePlaceholder: String { return self._s[2354]! } - public var Channel_AboutItem: String { return self._s[2355]! } - public var GroupInfo_InviteLink_RevokeLink: String { return self._s[2356]! } - public var Privacy_Calls_P2PNever: String { return self._s[2358]! } - public var Wallet_Weekday_Yesterday: String { return self._s[2359]! } - public var Passport_Language_uk: String { return self._s[2360]! } - public var NetworkUsageSettings_Wifi: String { return self._s[2361]! } - public var Conversation_Moderate_Report: String { return self._s[2362]! } - public var Wallpaper_ResetWallpapersConfirmation: String { return self._s[2363]! } - public var VoiceOver_Chat_SeenByRecipients: String { return self._s[2364]! } - public var Permissions_SiriText_v0: String { return self._s[2365]! } - public var Theme_Colors_Background: String { return self._s[2366]! } - public var Notification_CallMissed: String { return self._s[2367]! } - public var Stats_ZoomOut: String { return self._s[2368]! } - public var Profile_AddToExisting: String { return self._s[2369]! } - public var Passport_FieldAddressUploadHelp: String { return self._s[2372]! } - public var Undo_DeletedChannel: String { return self._s[2373]! } + public var Privacy_Calls_NeverAllow_Title: String { return self._s[2344]! } + public var Notification_CallOutgoingShort: String { return self._s[2345]! } + public var Checkout_PasswordEntry_Title: String { return self._s[2346]! } + public var Channel_AdminLogFilter_AdminsAll: String { return self._s[2347]! } + public var Notification_MessageLifetime1m: String { return self._s[2348]! } + public var Wallet_TransactionInfo_CommentHeader: String { return self._s[2350]! } + public var BlockedUsers_AddNew: String { return self._s[2351]! } + public var Wallet_Intro_CreateErrorText: String { return self._s[2352]! } + public var FastTwoStepSetup_EmailSection: String { return self._s[2353]! } + public var Settings_SaveEditedPhotos: String { return self._s[2354]! } + public var GroupInfo_GroupNamePlaceholder: String { return self._s[2355]! } + public var Channel_AboutItem: String { return self._s[2356]! } + public var GroupInfo_InviteLink_RevokeLink: String { return self._s[2357]! } + public var Privacy_Calls_P2PNever: String { return self._s[2359]! } + public var Wallet_Weekday_Yesterday: String { return self._s[2360]! } + public var Passport_Language_uk: String { return self._s[2361]! } + public var NetworkUsageSettings_Wifi: String { return self._s[2362]! } + public var Conversation_Moderate_Report: String { return self._s[2363]! } + public var Wallpaper_ResetWallpapersConfirmation: String { return self._s[2364]! } + public var VoiceOver_Chat_SeenByRecipients: String { return self._s[2365]! } + public var Permissions_SiriText_v0: String { return self._s[2366]! } + public var Theme_Colors_Background: String { return self._s[2367]! } + public var Notification_CallMissed: String { return self._s[2368]! } + public var Stats_ZoomOut: String { return self._s[2369]! } + public var Profile_AddToExisting: String { return self._s[2370]! } + public var Passport_FieldAddressUploadHelp: String { return self._s[2373]! } + public var Undo_DeletedChannel: String { return self._s[2374]! } public func Channel_AdminLog_MessagePinned(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2374]!, self._r[2374]!, [_0]) + return formatWithArgumentRanges(self._s[2375]!, self._r[2375]!, [_0]) } - public var Login_ResetAccountProtected_TimerTitle: String { return self._s[2375]! } - public var Map_LiveLocationGroupDescription: String { return self._s[2376]! } - public var Passport_InfoFAQ_URL: String { return self._s[2377]! } - public var IntentsSettings_SuggestedChats: String { return self._s[2379]! } + public var Login_ResetAccountProtected_TimerTitle: String { return self._s[2376]! } + public var Map_LiveLocationGroupDescription: String { return self._s[2377]! } + public var Passport_InfoFAQ_URL: String { return self._s[2378]! } + public var IntentsSettings_SuggestedChats: String { return self._s[2380]! } public func PUSH_MESSAGE_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2380]!, self._r[2380]!, [_1]) + return formatWithArgumentRanges(self._s[2381]!, self._r[2381]!, [_1]) } - public var State_connecting: String { return self._s[2381]! } - public var Passport_Identity_Country: String { return self._s[2382]! } - public var Passport_PasswordDescription: String { return self._s[2383]! } - public var ChatList_PsaLabel_covid: String { return self._s[2384]! } + public var State_connecting: String { return self._s[2382]! } + public var Passport_Identity_Country: String { return self._s[2383]! } + public var Passport_PasswordDescription: String { return self._s[2384]! } + public var ChatList_PsaLabel_covid: String { return self._s[2385]! } public func PUSH_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2385]!, self._r[2385]!, [_1]) + return formatWithArgumentRanges(self._s[2386]!, self._r[2386]!, [_1]) } - public var Contacts_AddPeopleNearby: String { return self._s[2386]! } - public var OwnershipTransfer_SetupTwoStepAuth: String { return self._s[2387]! } - public var ClearCache_Description: String { return self._s[2388]! } - public var Localization_LanguageName: String { return self._s[2389]! } + public var Contacts_AddPeopleNearby: String { return self._s[2387]! } + public var OwnershipTransfer_SetupTwoStepAuth: String { return self._s[2388]! } + public var ClearCache_Description: String { return self._s[2389]! } + public var Localization_LanguageName: String { return self._s[2390]! } public func UserInfo_UnblockConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2390]!, self._r[2390]!, [_0]) + return formatWithArgumentRanges(self._s[2391]!, self._r[2391]!, [_0]) } - public var ChatList_TabIconFoldersTooltipEmptyFolders: String { return self._s[2391]! } - public var UserInfo_CreateNewContact: String { return self._s[2392]! } - public var Channel_Stickers_NotFound: String { return self._s[2393]! } - public var Watch_Message_Poll: String { return self._s[2394]! } - public var Privacy_Forwards_WhoCanForward: String { return self._s[2395]! } + public var ChatList_TabIconFoldersTooltipEmptyFolders: String { return self._s[2392]! } + public var UserInfo_CreateNewContact: String { return self._s[2393]! } + public var Channel_Stickers_NotFound: String { return self._s[2394]! } + public var Watch_Message_Poll: String { return self._s[2395]! } + public var Privacy_Forwards_WhoCanForward: String { return self._s[2396]! } public func Notification_Kicked(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2396]!, self._r[2396]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2397]!, self._r[2397]!, [_0, _1]) } - public var Login_InfoDeletePhoto: String { return self._s[2397]! } - public var Appearance_ThemePreview_ChatList_6_Name: String { return self._s[2398]! } - public var InstantPage_FeedbackButton: String { return self._s[2399]! } - public var Appearance_PreviewReplyText: String { return self._s[2400]! } - public var Passport_FieldPhoneHelp: String { return self._s[2401]! } - public var Group_ErrorAddTooMuchBots: String { return self._s[2402]! } - public var Media_SendingOptionsTooltip: String { return self._s[2403]! } - public var ScheduledMessages_ScheduledOnline: String { return self._s[2404]! } - public var Notifications_Badge: String { return self._s[2405]! } - public var VoiceOver_Chat_VideoMessage: String { return self._s[2406]! } - public var TwoStepAuth_RecoveryCodeExpired: String { return self._s[2407]! } - public var Wallet_Configuration_ApplyErrorTitle: String { return self._s[2408]! } + public var Login_InfoDeletePhoto: String { return self._s[2398]! } + public var Appearance_ThemePreview_ChatList_6_Name: String { return self._s[2399]! } + public var InstantPage_FeedbackButton: String { return self._s[2400]! } + public var Appearance_PreviewReplyText: String { return self._s[2401]! } + public var Passport_FieldPhoneHelp: String { return self._s[2402]! } + public var Group_ErrorAddTooMuchBots: String { return self._s[2403]! } + public var Media_SendingOptionsTooltip: String { return self._s[2404]! } + public var ScheduledMessages_ScheduledOnline: String { return self._s[2405]! } + public var Notifications_Badge: String { return self._s[2406]! } + public var VoiceOver_Chat_VideoMessage: String { return self._s[2407]! } + public var TwoStepAuth_RecoveryCodeExpired: String { return self._s[2408]! } + public var Wallet_Configuration_ApplyErrorTitle: String { return self._s[2409]! } public func Notification_PinnedPhotoMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2410]!, self._r[2410]!, [_0]) + return formatWithArgumentRanges(self._s[2411]!, self._r[2411]!, [_0]) } - public var Wallet_Info_Send: String { return self._s[2411]! } - public var Passport_InfoLearnMore: String { return self._s[2412]! } - public var EnterPasscode_EnterTitle: String { return self._s[2413]! } - public var Appearance_EditTheme: String { return self._s[2414]! } - public var EditTheme_Expand_BottomInfo: String { return self._s[2415]! } - public var Stats_FollowersTitle: String { return self._s[2416]! } - public var Passport_Identity_SurnamePlaceholder: String { return self._s[2417]! } - public var Channel_Subscribers_Title: String { return self._s[2418]! } - public var Group_ErrorSupergroupConversionNotPossible: String { return self._s[2419]! } + public var Wallet_Info_Send: String { return self._s[2412]! } + public var Passport_InfoLearnMore: String { return self._s[2413]! } + public var EnterPasscode_EnterTitle: String { return self._s[2414]! } + public var Appearance_EditTheme: String { return self._s[2415]! } + public var EditTheme_Expand_BottomInfo: String { return self._s[2416]! } + public var Stats_FollowersTitle: String { return self._s[2417]! } + public var Passport_Identity_SurnamePlaceholder: String { return self._s[2418]! } + public var Channel_Subscribers_Title: String { return self._s[2419]! } + public var Group_ErrorSupergroupConversionNotPossible: String { return self._s[2420]! } public func Wallet_Time_PreciseDate_m5(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2420]!, self._r[2420]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2421]!, self._r[2421]!, [_1, _2, _3]) } - public var EditTheme_ThemeTemplateAlertTitle: String { return self._s[2421]! } - public var Wallet_Intro_CreateWallet: String { return self._s[2422]! } - public var Conversation_AddToReadingList: String { return self._s[2423]! } - public var EditTheme_Create_Preview_IncomingText: String { return self._s[2424]! } + public var EditTheme_ThemeTemplateAlertTitle: String { return self._s[2422]! } + public var Wallet_Intro_CreateWallet: String { return self._s[2423]! } + public var Conversation_AddToReadingList: String { return self._s[2424]! } + public var EditTheme_Create_Preview_IncomingText: String { return self._s[2425]! } public func Notifications_ExceptionsChangeSound(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2425]!, self._r[2425]!, [_0]) + return formatWithArgumentRanges(self._s[2426]!, self._r[2426]!, [_0]) } - public var Group_AdminLog_EmptyText: String { return self._s[2426]! } - public var Passport_Identity_EditInternalPassport: String { return self._s[2427]! } - public var Wallet_Sending_Title: String { return self._s[2429]! } - public var Watch_Location_Current: String { return self._s[2430]! } - public var PrivacyPolicy_Title: String { return self._s[2431]! } - public var Privacy_GroupsAndChannels_CustomHelp: String { return self._s[2438]! } - public var Channel_TypeSetup_Title: String { return self._s[2441]! } - public var Appearance_PreviewReplyAuthor: String { return self._s[2442]! } - public var Passport_Language_ja: String { return self._s[2443]! } - public var ReportPeer_ReasonSpam: String { return self._s[2444]! } - public var Widget_GalleryDescription: String { return self._s[2445]! } - public var Privacy_PaymentsClearInfoHelp: String { return self._s[2446]! } - public var Conversation_EditingMessageMediaEditCurrentPhoto: String { return self._s[2448]! } - public var Channel_AdminLog_ChangeInfo: String { return self._s[2449]! } - public var ChatListFolder_NameNonContacts: String { return self._s[2450]! } - public var Call_Audio: String { return self._s[2451]! } - public var PhotoEditor_CurvesGreen: String { return self._s[2452]! } - public var Wallet_Updated_JustNow: String { return self._s[2453]! } - public var ChatList_Search_NoResultsFitlerFiles: String { return self._s[2454]! } - public var Settings_PrivacySettings: String { return self._s[2455]! } - public var Stats_Followers: String { return self._s[2456]! } - public var Notifications_AddExceptionTitle: String { return self._s[2457]! } - public var TwoFactorSetup_Password_Title: String { return self._s[2458]! } - public var ChannelMembers_WhoCanAddMembersAllHelp: String { return self._s[2459]! } - public var OldChannels_NoticeText: String { return self._s[2460]! } - public var Conversation_SavedMessages: String { return self._s[2461]! } + public var Group_AdminLog_EmptyText: String { return self._s[2427]! } + public var Passport_Identity_EditInternalPassport: String { return self._s[2428]! } + public var Wallet_Sending_Title: String { return self._s[2430]! } + public var Watch_Location_Current: String { return self._s[2431]! } + public var PrivacyPolicy_Title: String { return self._s[2432]! } + public var Privacy_GroupsAndChannels_CustomHelp: String { return self._s[2439]! } + public var Channel_TypeSetup_Title: String { return self._s[2442]! } + public var Appearance_PreviewReplyAuthor: String { return self._s[2443]! } + public var Passport_Language_ja: String { return self._s[2444]! } + public var ReportPeer_ReasonSpam: String { return self._s[2445]! } + public var Widget_GalleryDescription: String { return self._s[2446]! } + public var Privacy_PaymentsClearInfoHelp: String { return self._s[2447]! } + public var Conversation_EditingMessageMediaEditCurrentPhoto: String { return self._s[2449]! } + public var Channel_AdminLog_ChangeInfo: String { return self._s[2450]! } + public var ChatListFolder_NameNonContacts: String { return self._s[2451]! } + public var Call_Audio: String { return self._s[2452]! } + public var PhotoEditor_CurvesGreen: String { return self._s[2453]! } + public var Wallet_Updated_JustNow: String { return self._s[2454]! } + public var ChatList_Search_NoResultsFitlerFiles: String { return self._s[2455]! } + public var Settings_PrivacySettings: String { return self._s[2456]! } + public var Stats_Followers: String { return self._s[2457]! } + public var Notifications_AddExceptionTitle: String { return self._s[2458]! } + public var TwoFactorSetup_Password_Title: String { return self._s[2459]! } + public var ChannelMembers_WhoCanAddMembersAllHelp: String { return self._s[2460]! } + public var OldChannels_NoticeText: String { return self._s[2461]! } + public var Conversation_SavedMessages: String { return self._s[2462]! } public func Conversation_PeerNearbyTitle(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2463]!, self._r[2463]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2464]!, self._r[2464]!, [_1, _2]) } - public var Passport_Address_TypeResidentialAddress: String { return self._s[2464]! } + public var Passport_Address_TypeResidentialAddress: String { return self._s[2465]! } public func Wallet_Info_TransactionBlockchainFee(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2465]!, self._r[2465]!, [_0]) + return formatWithArgumentRanges(self._s[2466]!, self._r[2466]!, [_0]) } - public var Appearance_ThemeNightBlue: String { return self._s[2466]! } - public var Notification_ChannelInviterSelf: String { return self._s[2467]! } - public var Watch_UserInfo_Service: String { return self._s[2469]! } - public var ChatList_Context_Back: String { return self._s[2470]! } - public var Passport_Email_Title: String { return self._s[2471]! } - public var Wallet_Month_ShortDecember: String { return self._s[2472]! } - public var Stats_GroupTopAdmin_Promote: String { return self._s[2473]! } + public var Appearance_ThemeNightBlue: String { return self._s[2467]! } + public var Notification_ChannelInviterSelf: String { return self._s[2468]! } + public var Watch_UserInfo_Service: String { return self._s[2470]! } + public var ChatList_Context_Back: String { return self._s[2471]! } + public var Passport_Email_Title: String { return self._s[2472]! } + public var Wallet_Month_ShortDecember: String { return self._s[2473]! } + public var Stats_GroupTopAdmin_Promote: String { return self._s[2474]! } public func PUSH_PINNED_INVOICE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2474]!, self._r[2474]!, [_1]) + return formatWithArgumentRanges(self._s[2475]!, self._r[2475]!, [_1]) } - public var Conversation_UnsupportedMedia: String { return self._s[2475]! } - public var Passport_Address_OneOfTypePassportRegistration: String { return self._s[2476]! } - public var Privacy_TopPeersHelp: String { return self._s[2478]! } - public var Privacy_Forwards_AlwaysLink: String { return self._s[2479]! } - public var Notifications_Badge_CountUnreadMessages_InfoOn: String { return self._s[2480]! } - public var Permissions_NotificationsTitle_v0: String { return self._s[2481]! } + public var Conversation_UnsupportedMedia: String { return self._s[2476]! } + public var Passport_Address_OneOfTypePassportRegistration: String { return self._s[2477]! } + public var Privacy_TopPeersHelp: String { return self._s[2479]! } + public var Privacy_Forwards_AlwaysLink: String { return self._s[2480]! } + public var Notifications_Badge_CountUnreadMessages_InfoOn: String { return self._s[2481]! } + public var Permissions_NotificationsTitle_v0: String { return self._s[2482]! } public func Location_ProximityNotification_AlreadyClose(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2482]!, self._r[2482]!, [_0]) + return formatWithArgumentRanges(self._s[2483]!, self._r[2483]!, [_0]) } - public var Notification_PassportValueProofOfAddress: String { return self._s[2483]! } - public var Map_Map: String { return self._s[2484]! } - public var WallpaperSearch_ColorBlue: String { return self._s[2485]! } - public var Privacy_Calls_CustomShareHelp: String { return self._s[2486]! } - public var PhotoEditor_BlurToolRadial: String { return self._s[2487]! } - public var ChatList_Search_FilterMusic: String { return self._s[2488]! } - public var SettingsSearch_Synonyms_Data_AutoplayGifs: String { return self._s[2489]! } - public var Privacy_PaymentsClear_ShippingInfo: String { return self._s[2490]! } - public var Settings_LogoutConfirmationTitle: String { return self._s[2492]! } + public var Notification_PassportValueProofOfAddress: String { return self._s[2484]! } + public var Map_Map: String { return self._s[2485]! } + public var WallpaperSearch_ColorBlue: String { return self._s[2486]! } + public var Privacy_Calls_CustomShareHelp: String { return self._s[2487]! } + public var PhotoEditor_BlurToolRadial: String { return self._s[2488]! } + public var ChatList_Search_FilterMusic: String { return self._s[2489]! } + public var SettingsSearch_Synonyms_Data_AutoplayGifs: String { return self._s[2490]! } + public var Privacy_PaymentsClear_ShippingInfo: String { return self._s[2491]! } + public var Settings_LogoutConfirmationTitle: String { return self._s[2493]! } public func PUSH_CHANNEL_MESSAGE_VIDEOS(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2493]!, self._r[2493]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2494]!, self._r[2494]!, [_1, _2]) } public func Notification_ChangedGroupPhoto(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2494]!, self._r[2494]!, [_0]) + return formatWithArgumentRanges(self._s[2495]!, self._r[2495]!, [_0]) } - public var Channel_Username_RevokeExistingUsernamesInfo: String { return self._s[2495]! } - public var Group_Username_CreatePublicLinkHelp: String { return self._s[2496]! } - public var GroupInfo_Location: String { return self._s[2499]! } - public var Passport_Language_ka: String { return self._s[2500]! } + public var Channel_Username_RevokeExistingUsernamesInfo: String { return self._s[2496]! } + public var Group_Username_CreatePublicLinkHelp: String { return self._s[2497]! } + public var GroupInfo_Location: String { return self._s[2500]! } + public var Passport_Language_ka: String { return self._s[2501]! } public func TwoStepAuth_SetupPendingEmail(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2501]!, self._r[2501]!, [_0]) + return formatWithArgumentRanges(self._s[2502]!, self._r[2502]!, [_0]) } - public var Conversation_ContextMenuOpenChannelProfile: String { return self._s[2502]! } - public var ScheduledMessages_ClearAllConfirmation: String { return self._s[2505]! } - public var DialogList_SearchSectionRecent: String { return self._s[2506]! } - public var Passport_Address_OneOfTypeTemporaryRegistration: String { return self._s[2507]! } - public var Conversation_Timer_Send: String { return self._s[2508]! } - public var ChatState_Updating: String { return self._s[2510]! } - public var ChannelMembers_WhoCanAddMembers: String { return self._s[2511]! } - public var ChannelInfo_DeleteGroup: String { return self._s[2512]! } - public var TwoStepAuth_RecoveryFailed: String { return self._s[2513]! } - public var Channel_OwnershipTransfer_EnterPassword: String { return self._s[2514]! } - public var ChatListFolderSettings_AddRecommended: String { return self._s[2516]! } - public var ChatList_Search_NoResults: String { return self._s[2517]! } - public var ChangePhoneNumberCode_Called: String { return self._s[2518]! } - public var PeerInfo_GroupAboutItem: String { return self._s[2519]! } - public var Wallet_Info_YourBalance: String { return self._s[2521]! } + public var Conversation_ContextMenuOpenChannelProfile: String { return self._s[2503]! } + public var ScheduledMessages_ClearAllConfirmation: String { return self._s[2506]! } + public var DialogList_SearchSectionRecent: String { return self._s[2507]! } + public var Passport_Address_OneOfTypeTemporaryRegistration: String { return self._s[2508]! } + public var Conversation_Timer_Send: String { return self._s[2509]! } + public var ChatState_Updating: String { return self._s[2511]! } + public var ChannelMembers_WhoCanAddMembers: String { return self._s[2512]! } + public var ChannelInfo_DeleteGroup: String { return self._s[2513]! } + public var TwoStepAuth_RecoveryFailed: String { return self._s[2514]! } + public var Channel_OwnershipTransfer_EnterPassword: String { return self._s[2515]! } + public var ChatListFolderSettings_AddRecommended: String { return self._s[2517]! } + public var ChatList_Search_NoResults: String { return self._s[2518]! } + public var ChangePhoneNumberCode_Called: String { return self._s[2519]! } + public var PeerInfo_GroupAboutItem: String { return self._s[2520]! } + public var Wallet_Info_YourBalance: String { return self._s[2522]! } public func LiveLocationUpdated_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2522]!, self._r[2522]!, [_0]) + return formatWithArgumentRanges(self._s[2523]!, self._r[2523]!, [_0]) } - public var PrivacySettings_AuthSessions: String { return self._s[2523]! } - public var Passport_Address_Postcode: String { return self._s[2524]! } - public var VoiceOver_Chat_YourVideoMessage: String { return self._s[2525]! } - public var Passport_Address_Street2Placeholder: String { return self._s[2526]! } - public var Group_Location_Title: String { return self._s[2527]! } - public var SettingsSearch_Synonyms_Data_AutoDownloadReset: String { return self._s[2528]! } - public var PeopleNearby_UsersEmpty: String { return self._s[2529]! } - public var SettingsSearch_Synonyms_Data_Title: String { return self._s[2531]! } + public var PrivacySettings_AuthSessions: String { return self._s[2524]! } + public var Passport_Address_Postcode: String { return self._s[2525]! } + public var VoiceOver_Chat_YourVideoMessage: String { return self._s[2526]! } + public var Passport_Address_Street2Placeholder: String { return self._s[2527]! } + public var Group_Location_Title: String { return self._s[2528]! } + public var SettingsSearch_Synonyms_Data_AutoDownloadReset: String { return self._s[2529]! } + public var PeopleNearby_UsersEmpty: String { return self._s[2530]! } + public var SettingsSearch_Synonyms_Data_Title: String { return self._s[2532]! } public func Checkout_PasswordEntry_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2533]!, self._r[2533]!, [_0]) + return formatWithArgumentRanges(self._s[2534]!, self._r[2534]!, [_0]) } - public var Proxy_TooltipUnavailable: String { return self._s[2534]! } - public var Map_Search: String { return self._s[2535]! } - public var AutoDownloadSettings_TypeContacts: String { return self._s[2536]! } - public var Conversation_SearchByName_Prefix: String { return self._s[2537]! } + public var Proxy_TooltipUnavailable: String { return self._s[2535]! } + public var Map_Search: String { return self._s[2536]! } + public var AutoDownloadSettings_TypeContacts: String { return self._s[2537]! } + public var Conversation_SearchByName_Prefix: String { return self._s[2538]! } public func Channel_AdminLog_MessageToggleSignaturesOff(_ _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 TwoStepAuth_EmailAddSuccess: String { return self._s[2539]! } - public var ProfilePhoto_MainPhoto: String { return self._s[2540]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsSound: String { return self._s[2541]! } - public var SharedMedia_EmptyMusicText: String { return self._s[2542]! } - public var ChatSettings_AutoDownloadPhotos: String { return self._s[2543]! } - public var NetworkUsageSettings_BytesReceived: String { return self._s[2544]! } - public var Channel_AdminLog_EmptyText: String { return self._s[2545]! } - public var Channel_BanUser_PermissionSendMessages: String { return self._s[2546]! } - public var Undo_ChatDeletedForBothSides: String { return self._s[2547]! } - public var Notifications_GroupNotifications: String { return self._s[2548]! } - public var Wallet_Configuration_BlockchainNameChangedTitle: String { return self._s[2549]! } - public var Wallet_AccessDenied_Title: String { return self._s[2550]! } - public var AccessDenied_SaveMedia: String { return self._s[2551]! } - public var GroupInfo_LabelOwner: String { return self._s[2552]! } - public var Passport_Language_id: String { return self._s[2553]! } - public var ChatSettings_AutoDownloadTitle: String { return self._s[2554]! } - public var Conversation_UnpinMessageAlert: String { return self._s[2555]! } + public var TwoStepAuth_EmailAddSuccess: String { return self._s[2540]! } + public var ProfilePhoto_MainPhoto: String { return self._s[2541]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsSound: String { return self._s[2542]! } + public var SharedMedia_EmptyMusicText: String { return self._s[2543]! } + public var ChatSettings_AutoDownloadPhotos: String { return self._s[2544]! } + public var NetworkUsageSettings_BytesReceived: String { return self._s[2545]! } + public var Channel_AdminLog_EmptyText: String { return self._s[2546]! } + public var Channel_BanUser_PermissionSendMessages: String { return self._s[2547]! } + public var Undo_ChatDeletedForBothSides: String { return self._s[2548]! } + public var Notifications_GroupNotifications: String { return self._s[2549]! } + public var Wallet_Configuration_BlockchainNameChangedTitle: String { return self._s[2550]! } + public var Wallet_AccessDenied_Title: String { return self._s[2551]! } + public var AccessDenied_SaveMedia: String { return self._s[2552]! } + public var GroupInfo_LabelOwner: String { return self._s[2553]! } + public var Passport_Language_id: String { return self._s[2554]! } + public var ChatSettings_AutoDownloadTitle: String { return self._s[2555]! } + public var Conversation_UnpinMessageAlert: String { return self._s[2556]! } public func LiveLocationUpdated_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2556]!, self._r[2556]!, [_0]) - } - public func Call_RemoteVideoPaused(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2557]!, self._r[2557]!, [_0]) } - public var TwoFactorSetup_Done_Text: String { return self._s[2558]! } + public func Call_RemoteVideoPaused(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2558]!, self._r[2558]!, [_0]) + } + public var TwoFactorSetup_Done_Text: String { return self._s[2559]! } public func LastSeen_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2559]!, self._r[2559]!, [_0]) + return formatWithArgumentRanges(self._s[2560]!, self._r[2560]!, [_0]) } - public var Wallet_Words_Title: String { return self._s[2560]! } - public var NetworkUsageSettings_BytesSent: String { return self._s[2561]! } - public var OwnershipTransfer_Transfer: String { return self._s[2562]! } + public var Wallet_Words_Title: String { return self._s[2561]! } + public var NetworkUsageSettings_BytesSent: String { return self._s[2562]! } + public var OwnershipTransfer_Transfer: String { return self._s[2563]! } public func Notification_Exceptions_Sound(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2563]!, self._r[2563]!, [_0]) + return formatWithArgumentRanges(self._s[2564]!, self._r[2564]!, [_0]) } - public var Passport_Language_pt: String { return self._s[2564]! } - public var PrivacySettings_WebSessions: String { return self._s[2565]! } - public var PrivacyPolicy_DeclineDeleteNow: String { return self._s[2567]! } - public var TwoFactorSetup_Hint_Title: String { return self._s[2568]! } + public var Passport_Language_pt: String { return self._s[2565]! } + public var PrivacySettings_WebSessions: String { return self._s[2566]! } + public var PrivacyPolicy_DeclineDeleteNow: String { return self._s[2568]! } + public var TwoFactorSetup_Hint_Title: String { return self._s[2569]! } public func Notification_Joined(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2569]!, self._r[2569]!, [_0]) + return formatWithArgumentRanges(self._s[2570]!, self._r[2570]!, [_0]) } - public var Group_Username_RemoveExistingUsernamesInfo: String { return self._s[2570]! } - public var PrivacyLastSeenSettings_CustomShareSettings_Delete: String { return self._s[2571]! } - public var AutoNightTheme_Scheduled: String { return self._s[2572]! } - public var CreatePoll_ExplanationHeader: String { return self._s[2573]! } - public var Calls_TabTitle: String { return self._s[2574]! } - public var ChatList_UndoArchiveHiddenText: String { return self._s[2575]! } - public var Notification_VideoCallCanceled: String { return self._s[2576]! } - public var Login_CodeSentInternal: String { return self._s[2577]! } - public var SettingsSearch_Synonyms_Proxy_AddProxy: String { return self._s[2578]! } - public var Call_RecordingDisabledMessage: String { return self._s[2580]! } - public var AutoDownloadSettings_TypeChannels: String { return self._s[2582]! } - public var Wallet_Configuration_BlockchainNameChangedProceed: String { return self._s[2583]! } - public var Channel_Info_Stickers: String { return self._s[2584]! } - public var Passport_DeleteAddressConfirmation: String { return self._s[2585]! } + public var Group_Username_RemoveExistingUsernamesInfo: String { return self._s[2571]! } + public var PrivacyLastSeenSettings_CustomShareSettings_Delete: String { return self._s[2572]! } + public var AutoNightTheme_Scheduled: String { return self._s[2573]! } + public var CreatePoll_ExplanationHeader: String { return self._s[2574]! } + public var Calls_TabTitle: String { return self._s[2575]! } + public var ChatList_UndoArchiveHiddenText: String { return self._s[2576]! } + public var Notification_VideoCallCanceled: String { return self._s[2577]! } + public var Login_CodeSentInternal: String { return self._s[2578]! } + public var SettingsSearch_Synonyms_Proxy_AddProxy: String { return self._s[2579]! } + public var Call_RecordingDisabledMessage: String { return self._s[2581]! } + public var AutoDownloadSettings_TypeChannels: String { return self._s[2583]! } + public var Wallet_Configuration_BlockchainNameChangedProceed: String { return self._s[2584]! } + public var Channel_Info_Stickers: String { return self._s[2585]! } + public var Passport_DeleteAddressConfirmation: String { return self._s[2586]! } public func Conversation_PeerNearbyDistance(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2586]!, self._r[2586]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2587]!, self._r[2587]!, [_1, _2]) } - public var ChannelMembers_WhoCanAddMembers_Admins: String { return self._s[2587]! } + public var ChannelMembers_WhoCanAddMembers_Admins: String { return self._s[2588]! } public func Call_StatusOngoing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2588]!, self._r[2588]!, [_0]) + return formatWithArgumentRanges(self._s[2589]!, self._r[2589]!, [_0]) } - public var Passport_DiscardMessageTitle: String { return self._s[2589]! } - public var Localization_LanguageOther: String { return self._s[2590]! } - public var Conversation_EncryptionCanceled: String { return self._s[2591]! } - public var ChatSettings_AutomaticPhotoDownload: String { return self._s[2592]! } + public var Passport_DiscardMessageTitle: String { return self._s[2590]! } + public var Localization_LanguageOther: String { return self._s[2591]! } + public var Conversation_EncryptionCanceled: String { return self._s[2592]! } + public var ChatSettings_AutomaticPhotoDownload: String { return self._s[2593]! } public func Notification_SecretChatMessageScreenshot(_ _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 Target_InviteToGroupErrorAlreadyInvited: String { return self._s[2596]! } - public var SocksProxySetup_SavedProxies: String { return self._s[2597]! } + public var Target_InviteToGroupErrorAlreadyInvited: String { return self._s[2597]! } + public var SocksProxySetup_SavedProxies: String { return self._s[2598]! } public func ApplyLanguage_ChangeLanguageAlreadyActive(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2598]!, self._r[2598]!, [_1]) + return formatWithArgumentRanges(self._s[2599]!, self._r[2599]!, [_1]) } - public var Conversation_ScamWarning: String { return self._s[2599]! } - public var Channel_AdminLog_InfoPanelAlertTitle: String { return self._s[2600]! } - public var LocalGroup_Title: String { return self._s[2601]! } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsAlert: String { return self._s[2602]! } - public var SettingsSearch_Synonyms_Privacy_PasscodeAndFaceId: String { return self._s[2603]! } - public var Login_PhoneFloodError: String { return self._s[2604]! } - public var Username_InvalidTaken: String { return self._s[2606]! } - public var SocksProxySetup_AddProxy: String { return self._s[2608]! } - public var PrivacyLastSeenSettings_WhoCanSeeMyTimestamp: String { return self._s[2609]! } - public var MediaPicker_UngroupDescription: String { return self._s[2610]! } - public var Login_CodeExpired: String { return self._s[2611]! } - public var Localization_ChooseLanguage: String { return self._s[2612]! } - public var Checkout_NewCard_PostcodePlaceholder: String { return self._s[2613]! } + public var Conversation_ScamWarning: String { return self._s[2600]! } + public var Channel_AdminLog_InfoPanelAlertTitle: String { return self._s[2601]! } + public var LocalGroup_Title: String { return self._s[2602]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsAlert: String { return self._s[2603]! } + public var SettingsSearch_Synonyms_Privacy_PasscodeAndFaceId: String { return self._s[2604]! } + public var Login_PhoneFloodError: String { return self._s[2605]! } + public var Username_InvalidTaken: String { return self._s[2607]! } + public var SocksProxySetup_AddProxy: String { return self._s[2609]! } + public var PrivacyLastSeenSettings_WhoCanSeeMyTimestamp: String { return self._s[2610]! } + public var MediaPicker_UngroupDescription: String { return self._s[2611]! } + public var Login_CodeExpired: String { return self._s[2612]! } + public var Localization_ChooseLanguage: String { return self._s[2613]! } + public var Checkout_NewCard_PostcodePlaceholder: String { return self._s[2614]! } public func ChangePhone_ErrorOccupied(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2614]!, self._r[2614]!, [_0]) - } - public func Channel_DiscussionGroup_HeaderSet(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2615]!, self._r[2615]!, [_0]) } - public var ReportPeer_ReasonOther_Title: String { return self._s[2617]! } - public var Conversation_ScheduleMessage_Title: String { return self._s[2618]! } - public var PeerInfo_ButtonDiscuss: String { return self._s[2619]! } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedPublicGroups: String { return self._s[2620]! } - public var Call_StatusNoAnswer: String { return self._s[2621]! } - public var ScheduledMessages_DeleteMany: String { return self._s[2623]! } - public var Channel_DiscussionGroupInfo: String { return self._s[2624]! } - public var Conversation_UnarchiveDone: String { return self._s[2625]! } - public var LogoutOptions_AddAccountText: String { return self._s[2626]! } - public var Message_PinnedContactMessage: String { return self._s[2627]! } + public func Channel_DiscussionGroup_HeaderSet(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2616]!, self._r[2616]!, [_0]) + } + public var ReportPeer_ReasonOther_Title: String { return self._s[2618]! } + public var Conversation_ScheduleMessage_Title: String { return self._s[2619]! } + public var PeerInfo_ButtonDiscuss: String { return self._s[2620]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedPublicGroups: String { return self._s[2621]! } + public var Call_StatusNoAnswer: String { return self._s[2622]! } + public var ScheduledMessages_DeleteMany: String { return self._s[2624]! } + public var Channel_DiscussionGroupInfo: String { return self._s[2625]! } + public var Conversation_UnarchiveDone: String { return self._s[2626]! } + public var LogoutOptions_AddAccountText: String { return self._s[2627]! } + public var Message_PinnedContactMessage: String { return self._s[2628]! } public func FileSize_GB(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2629]!, self._r[2629]!, [_0]) + return formatWithArgumentRanges(self._s[2630]!, self._r[2630]!, [_0]) } - public var Stats_GroupLanguagesTitle: String { return self._s[2630]! } - public var Passport_FieldAddressHelp: String { return self._s[2631]! } + public var Stats_GroupLanguagesTitle: String { return self._s[2631]! } + public var Passport_FieldAddressHelp: String { return self._s[2632]! } public func Passport_FieldOneOf_Or(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2632]!, self._r[2632]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2633]!, self._r[2633]!, [_1, _2]) } - public var ChatSettings_OpenLinksIn: String { return self._s[2634]! } - public var TwoFactorSetup_Hint_SkipAction: String { return self._s[2635]! } - public var Message_Photo: String { return self._s[2636]! } - public var MediaPicker_AddCaption: String { return self._s[2638]! } - public var LogoutOptions_Title: String { return self._s[2639]! } + public var ChatSettings_OpenLinksIn: String { return self._s[2635]! } + public var TwoFactorSetup_Hint_SkipAction: String { return self._s[2636]! } + public var Message_Photo: String { return self._s[2637]! } + public var MediaPicker_AddCaption: String { return self._s[2639]! } + public var LogoutOptions_Title: String { return self._s[2640]! } public func PUSH_PINNED_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2640]!, self._r[2640]!, [_1]) + return formatWithArgumentRanges(self._s[2641]!, self._r[2641]!, [_1]) } - public var Conversation_StatusKickedFromGroup: String { return self._s[2641]! } - public var Channel_AdminLogFilter_AdminsTitle: String { return self._s[2642]! } - public var ChatList_DeleteSavedMessagesConfirmationTitle: String { return self._s[2643]! } - public var Channel_AdminLogFilter_Title: String { return self._s[2644]! } - public var Passport_Address_TypeRentalAgreementUploadScan: String { return self._s[2645]! } + public var Conversation_StatusKickedFromGroup: String { return self._s[2642]! } + public var Channel_AdminLogFilter_AdminsTitle: String { return self._s[2643]! } + public var ChatList_DeleteSavedMessagesConfirmationTitle: String { return self._s[2644]! } + public var Channel_AdminLogFilter_Title: String { return self._s[2645]! } + public var Passport_Address_TypeRentalAgreementUploadScan: String { return self._s[2646]! } public func Wallet_Info_TransactionDateHeader(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2646]!, self._r[2646]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2647]!, self._r[2647]!, [_1, _2]) } - public var Compose_GroupTokenListPlaceholder: String { return self._s[2647]! } - public var Wallet_Words_NotDoneResponse: String { return self._s[2648]! } - public var Notifications_MessageNotificationsExceptions: String { return self._s[2649]! } - public var ChannelIntro_Title: String { return self._s[2650]! } - public var Stats_Message_Views: String { return self._s[2651]! } - public var Stickers_Install: String { return self._s[2652]! } + public var Compose_GroupTokenListPlaceholder: String { return self._s[2648]! } + public var Wallet_Words_NotDoneResponse: String { return self._s[2649]! } + public var Notifications_MessageNotificationsExceptions: String { return self._s[2650]! } + public var ChannelIntro_Title: String { return self._s[2651]! } + public var Stats_Message_Views: String { return self._s[2652]! } + public var Stickers_Install: String { return self._s[2653]! } public func VoiceOver_Chat_FileFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2653]!, self._r[2653]!, [_0]) + return formatWithArgumentRanges(self._s[2654]!, self._r[2654]!, [_0]) } - public var EditTheme_Create_Preview_IncomingReplyText: String { return self._s[2654]! } - public var Conversation_SwipeToReplyHintTitle: String { return self._s[2656]! } - public var Settings_Username: String { return self._s[2659]! } - public var FastTwoStepSetup_Title: String { return self._s[2660]! } - public var Notifications_Badge_CountUnreadMessages_InfoOff: String { return self._s[2661]! } - public var SettingsSearch_Synonyms_Privacy_Title: String { return self._s[2662]! } - public var Passport_Identity_IssueDatePlaceholder: String { return self._s[2663]! } - public var CallFeedback_ReasonEcho: String { return self._s[2664]! } + public var EditTheme_Create_Preview_IncomingReplyText: String { return self._s[2655]! } + public var Conversation_SwipeToReplyHintTitle: String { return self._s[2657]! } + public var Settings_Username: String { return self._s[2660]! } + public var FastTwoStepSetup_Title: String { return self._s[2661]! } + public var Notifications_Badge_CountUnreadMessages_InfoOff: String { return self._s[2662]! } + public var SettingsSearch_Synonyms_Privacy_Title: String { return self._s[2663]! } + public var Passport_Identity_IssueDatePlaceholder: String { return self._s[2664]! } + public var CallFeedback_ReasonEcho: String { return self._s[2665]! } public func Time_MonthOfYear_m1(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2665]!, self._r[2665]!, [_0]) + return formatWithArgumentRanges(self._s[2666]!, self._r[2666]!, [_0]) } - public var Conversation_OpenBotLinkTitle: String { return self._s[2666]! } - public var SocksProxySetup_Title: String { return self._s[2667]! } - public var CallFeedback_Success: String { return self._s[2668]! } - public var WallpaperPreview_SwipeTopText: String { return self._s[2670]! } - public var InstantPage_AutoNightTheme: String { return self._s[2672]! } - public var Watch_Conversation_Reply: String { return self._s[2673]! } - public var Chat_PanelUnpinAllMessages: String { return self._s[2675]! } - public var WallpaperPreview_Pattern: String { return self._s[2676]! } - public var CheckoutInfo_ReceiverInfoEmail: String { return self._s[2677]! } - public var Wallet_Send_ErrorNotEnoughFundsTitle: String { return self._s[2678]! } + public var Conversation_OpenBotLinkTitle: String { return self._s[2667]! } + public var SocksProxySetup_Title: String { return self._s[2668]! } + public var CallFeedback_Success: String { return self._s[2669]! } + public var WallpaperPreview_SwipeTopText: String { return self._s[2671]! } + public var InstantPage_AutoNightTheme: String { return self._s[2673]! } + public var Watch_Conversation_Reply: String { return self._s[2674]! } + public var Chat_PanelUnpinAllMessages: String { return self._s[2676]! } + public var WallpaperPreview_Pattern: String { return self._s[2677]! } + public var CheckoutInfo_ReceiverInfoEmail: String { return self._s[2678]! } + public var Wallet_Send_ErrorNotEnoughFundsTitle: String { return self._s[2679]! } public func Conversation_DeleteMessagesFor(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2679]!, self._r[2679]!, [_0]) + return formatWithArgumentRanges(self._s[2680]!, self._r[2680]!, [_0]) } - public var AutoDownloadSettings_TypeGroupChats: String { return self._s[2680]! } - public var DialogList_SavedMessagesTooltip: String { return self._s[2682]! } - public var Update_Title: String { return self._s[2683]! } - public var Conversation_ShareMyPhoneNumber: String { return self._s[2684]! } + public var AutoDownloadSettings_TypeGroupChats: String { return self._s[2681]! } + public var DialogList_SavedMessagesTooltip: String { return self._s[2683]! } + public var Update_Title: String { return self._s[2684]! } + public var Conversation_ShareMyPhoneNumber: String { return self._s[2685]! } public func Wallet_WordCheck_Text(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2685]!, self._r[2685]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2686]!, self._r[2686]!, [_1, _2, _3]) } - public var Wallet_SecureStorageReset_BiometryTouchId: String { return self._s[2686]! } - public var WallpaperPreview_CropTopText: String { return self._s[2688]! } - public var Channel_EditMessageErrorGeneric: String { return self._s[2689]! } - public var AccessDenied_LocationAlwaysDenied: String { return self._s[2690]! } - public var ChatListFolder_DiscardCancel: String { return self._s[2691]! } - public var Message_PinnedPhotoMessage: String { return self._s[2692]! } - public var Appearance_ThemeDayClassic: String { return self._s[2693]! } - public var SocksProxySetup_ProxySocks5: String { return self._s[2694]! } - public var AccessDenied_Wallpapers: String { return self._s[2700]! } + public var Wallet_SecureStorageReset_BiometryTouchId: String { return self._s[2687]! } + public var WallpaperPreview_CropTopText: String { return self._s[2689]! } + public var Channel_EditMessageErrorGeneric: String { return self._s[2690]! } + public var AccessDenied_LocationAlwaysDenied: String { return self._s[2691]! } + public var ChatListFolder_DiscardCancel: String { return self._s[2692]! } + public var Message_PinnedPhotoMessage: String { return self._s[2693]! } + public var Appearance_ThemeDayClassic: String { return self._s[2694]! } + public var SocksProxySetup_ProxySocks5: String { return self._s[2695]! } + public var AccessDenied_Wallpapers: String { return self._s[2701]! } public func Channel_AdminLog_MessageChangedGroupAbout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2701]!, self._r[2701]!, [_0]) + return formatWithArgumentRanges(self._s[2702]!, self._r[2702]!, [_0]) } - public var Weekday_Sunday: String { return self._s[2702]! } - public var SettingsSearch_Synonyms_Privacy_GroupsAndChannels: String { return self._s[2704]! } - public var PeopleNearby_MakeVisibleDescription: String { return self._s[2705]! } - public var AccessDenied_LocationDisabled: String { return self._s[2706]! } - public var Tour_Text3: String { return self._s[2707]! } - public var AuthSessions_AddDevice_ScanTitle: String { return self._s[2708]! } + public var Weekday_Sunday: String { return self._s[2703]! } + public var SettingsSearch_Synonyms_Privacy_GroupsAndChannels: String { return self._s[2705]! } + public var PeopleNearby_MakeVisibleDescription: String { return self._s[2706]! } + public var AccessDenied_LocationDisabled: String { return self._s[2707]! } + public var Tour_Text3: String { return self._s[2708]! } + public var AuthSessions_AddDevice_ScanTitle: String { return self._s[2709]! } public func Time_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2709]!, self._r[2709]!, [_0]) + return formatWithArgumentRanges(self._s[2710]!, self._r[2710]!, [_0]) } - public var Privacy_SecretChatsLinkPreviewsHelp: String { return self._s[2710]! } - public var Conversation_ClearCache: String { return self._s[2711]! } - public var StickerPacksSettings_ArchivedMasks_Info: String { return self._s[2712]! } - public var ChatList_Tabs_AllChats: String { return self._s[2713]! } - public var DialogList_RecentTitlePeople: String { return self._s[2714]! } - public var Stickers_AddToFavorites: String { return self._s[2715]! } - public var ChatList_Context_RemoveFromFolder: String { return self._s[2716]! } - public var Settings_RemoveVideo: String { return self._s[2717]! } - public var PhotoEditor_CropAspectRatioSquare: String { return self._s[2718]! } - public var ConversationProfile_LeaveDeleteAndExit: String { return self._s[2719]! } - public var VoiceOver_Chat_YourFile: String { return self._s[2720]! } - public var SettingsSearch_Synonyms_Privacy_Forwards: String { return self._s[2721]! } - public var Group_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[2722]! } - public var Channel_AdminLog_AddMembers: String { return self._s[2723]! } - public var Map_SendThisLocation: String { return self._s[2725]! } - public var TwoStepAuth_EmailSkipAlert: String { return self._s[2727]! } - public var IntentsSettings_SuggestedChatsPrivateChats: String { return self._s[2728]! } - public var CloudStorage_Title: String { return self._s[2729]! } - public var TwoFactorSetup_Password_Action: String { return self._s[2730]! } - public var TwoStepAuth_ConfirmationText: String { return self._s[2731]! } - public var Passport_Address_EditTemporaryRegistration: String { return self._s[2733]! } - public var Undo_LeftGroup: String { return self._s[2734]! } - public var Conversation_StopLiveLocation: String { return self._s[2736]! } - public var NotificationSettings_ShowNotificationsFromAccountsSection: String { return self._s[2737]! } - public var Message_PinnedInvoice: String { return self._s[2738]! } - public var ApplyLanguage_LanguageNotSupportedError: String { return self._s[2739]! } + public var Privacy_SecretChatsLinkPreviewsHelp: String { return self._s[2711]! } + public var Conversation_ClearCache: String { return self._s[2712]! } + public var StickerPacksSettings_ArchivedMasks_Info: String { return self._s[2713]! } + public var ChatList_Tabs_AllChats: String { return self._s[2714]! } + public var DialogList_RecentTitlePeople: String { return self._s[2715]! } + public var Stickers_AddToFavorites: String { return self._s[2716]! } + public var ChatList_Context_RemoveFromFolder: String { return self._s[2717]! } + public var Settings_RemoveVideo: String { return self._s[2718]! } + public var PhotoEditor_CropAspectRatioSquare: String { return self._s[2719]! } + public var ConversationProfile_LeaveDeleteAndExit: String { return self._s[2720]! } + public var VoiceOver_Chat_YourFile: String { return self._s[2721]! } + public var SettingsSearch_Synonyms_Privacy_Forwards: String { return self._s[2722]! } + public var Group_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[2723]! } + public var Channel_AdminLog_AddMembers: String { return self._s[2724]! } + public var Map_SendThisLocation: String { return self._s[2726]! } + public var TwoStepAuth_EmailSkipAlert: String { return self._s[2728]! } + public var IntentsSettings_SuggestedChatsPrivateChats: String { return self._s[2729]! } + public var CloudStorage_Title: String { return self._s[2730]! } + public var TwoFactorSetup_Password_Action: String { return self._s[2731]! } + public var TwoStepAuth_ConfirmationText: String { return self._s[2732]! } + public var Passport_Address_EditTemporaryRegistration: String { return self._s[2734]! } + public var Undo_LeftGroup: String { return self._s[2735]! } + public var Conversation_StopLiveLocation: String { return self._s[2737]! } + public var NotificationSettings_ShowNotificationsFromAccountsSection: String { return self._s[2738]! } + public var Message_PinnedInvoice: String { return self._s[2739]! } + public var ApplyLanguage_LanguageNotSupportedError: String { return self._s[2740]! } public func PUSH_CHAT_MESSAGE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2740]!, self._r[2740]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2741]!, self._r[2741]!, [_1, _2]) } public func Notification_PinnedAudioMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2741]!, self._r[2741]!, [_0]) + return formatWithArgumentRanges(self._s[2742]!, self._r[2742]!, [_0]) } - public var Weekday_Tuesday: String { return self._s[2742]! } - public var ChangePhoneNumberCode_Code: String { return self._s[2743]! } - public var VoiceOver_Chat_YourMessage: String { return self._s[2744]! } - public var Calls_CallTabDescription: String { return self._s[2745]! } - public var SocksProxySetup_UseProxy: String { return self._s[2747]! } - public var SettingsSearch_Synonyms_Stickers_Title: String { return self._s[2748]! } - public var PasscodeSettings_AlphanumericCode: String { return self._s[2749]! } - public var VoiceOver_Chat_YourVideo: String { return self._s[2750]! } - public var ChannelMembers_WhoCanAddMembersAdminsHelp: String { return self._s[2752]! } - public var SettingsSearch_Synonyms_Privacy_DeleteAccountIfAwayFor: String { return self._s[2753]! } - public var Exceptions_AddToExceptions: String { return self._s[2754]! } - public var UserInfo_Title: String { return self._s[2755]! } - public var Passport_DeleteDocumentConfirmation: String { return self._s[2757]! } - public var ChatList_Unmute: String { return self._s[2759]! } - public var SettingsSearch_Synonyms_Privacy_Data_ContactsSync: String { return self._s[2760]! } - public var Stats_GroupTopPostersTitle: String { return self._s[2761]! } - public var Username_CheckingUsername: String { return self._s[2762]! } - public var WallpaperColors_SetCustomColor: String { return self._s[2763]! } - public var AuthSessions_AddedDeviceTerminate: String { return self._s[2767]! } - public var Location_ProximityAlertSetTitle: String { return self._s[2768]! } - public var Privacy_ProfilePhoto_CustomHelp: String { return self._s[2769]! } - public var Settings_ChangePhoneNumber: String { return self._s[2770]! } - public var PeerInfo_PaneLinks: String { return self._s[2771]! } - public var Appearance_ThemePreview_ChatList_1_Text: String { return self._s[2774]! } - public var Channel_EditAdmin_PermissionInviteSubscribers: String { return self._s[2776]! } - public var LogoutOptions_ChangePhoneNumberText: String { return self._s[2777]! } - public var VoiceOver_Media_PlaybackPause: String { return self._s[2778]! } - public var Wallet_RestoreFailed_Title: String { return self._s[2779]! } - public var Stats_FollowersBySourceTitle: String { return self._s[2781]! } + public var Weekday_Tuesday: String { return self._s[2743]! } + public var ChangePhoneNumberCode_Code: String { return self._s[2744]! } + public var VoiceOver_Chat_YourMessage: String { return self._s[2745]! } + public var Calls_CallTabDescription: String { return self._s[2746]! } + public var SocksProxySetup_UseProxy: String { return self._s[2748]! } + public var SettingsSearch_Synonyms_Stickers_Title: String { return self._s[2749]! } + public var PasscodeSettings_AlphanumericCode: String { return self._s[2750]! } + public var VoiceOver_Chat_YourVideo: String { return self._s[2751]! } + public var ChannelMembers_WhoCanAddMembersAdminsHelp: String { return self._s[2753]! } + public var SettingsSearch_Synonyms_Privacy_DeleteAccountIfAwayFor: String { return self._s[2754]! } + public var Exceptions_AddToExceptions: String { return self._s[2755]! } + public var UserInfo_Title: String { return self._s[2756]! } + public var Passport_DeleteDocumentConfirmation: String { return self._s[2758]! } + public var ChatList_Unmute: String { return self._s[2760]! } + public var SettingsSearch_Synonyms_Privacy_Data_ContactsSync: String { return self._s[2761]! } + public var Stats_GroupTopPostersTitle: String { return self._s[2762]! } + public var Username_CheckingUsername: String { return self._s[2763]! } + public var WallpaperColors_SetCustomColor: String { return self._s[2764]! } + public var AuthSessions_AddedDeviceTerminate: String { return self._s[2768]! } + public var Location_ProximityAlertSetTitle: String { return self._s[2769]! } + public var Privacy_ProfilePhoto_CustomHelp: String { return self._s[2770]! } + public var Settings_ChangePhoneNumber: String { return self._s[2771]! } + public var PeerInfo_PaneLinks: String { return self._s[2772]! } + public var Appearance_ThemePreview_ChatList_1_Text: String { return self._s[2775]! } + public var Channel_EditAdmin_PermissionInviteSubscribers: String { return self._s[2777]! } + public var LogoutOptions_ChangePhoneNumberText: String { return self._s[2778]! } + public var VoiceOver_Media_PlaybackPause: String { return self._s[2779]! } + public var Wallet_RestoreFailed_Title: String { return self._s[2780]! } + public var Stats_FollowersBySourceTitle: String { return self._s[2782]! } public func Conversation_ScheduleMessage_SendOn(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2782]!, self._r[2782]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2783]!, self._r[2783]!, [_0, _1]) } - public var Compose_NewEncryptedChatTitle: String { return self._s[2783]! } - public var Channel_CommentsGroup_Header: String { return self._s[2785]! } + public var Compose_NewEncryptedChatTitle: String { return self._s[2784]! } + public var Channel_CommentsGroup_Header: String { return self._s[2786]! } public func ShareFileTip_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2789]!, self._r[2789]!, [_0]) + return formatWithArgumentRanges(self._s[2790]!, self._r[2790]!, [_0]) } public func PUSH_MESSAGE_AUDIO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2790]!, self._r[2790]!, [_1]) + return formatWithArgumentRanges(self._s[2791]!, self._r[2791]!, [_1]) } - public var Group_Setup_BasicHistoryHiddenHelp: String { return self._s[2792]! } + public var Group_Setup_BasicHistoryHiddenHelp: String { return self._s[2793]! } public func TwoStepAuth_RecoveryEmailUnavailable(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2793]!, self._r[2793]!, [_0]) + return formatWithArgumentRanges(self._s[2794]!, self._r[2794]!, [_0]) } - public var Conversation_OpenBotLinkOpen: String { return self._s[2794]! } - public var VoiceOver_Chat_RecordModeVoiceMessage: String { return self._s[2795]! } - public var PrivacySettings_LastSeen: String { return self._s[2797]! } - public var SettingsSearch_Synonyms_Privacy_Passcode: String { return self._s[2798]! } - public var Theme_Colors_Proceed: String { return self._s[2799]! } - public var UserInfo_ScamBotWarning: String { return self._s[2800]! } - public var LogoutOptions_LogOut: String { return self._s[2802]! } - public var Conversation_SendMessage: String { return self._s[2803]! } - public var Passport_Address_Region: String { return self._s[2805]! } - public var MediaPicker_CameraRoll: String { return self._s[2807]! } + public var Conversation_OpenBotLinkOpen: String { return self._s[2795]! } + public var VoiceOver_Chat_RecordModeVoiceMessage: String { return self._s[2796]! } + public var PrivacySettings_LastSeen: String { return self._s[2798]! } + public var SettingsSearch_Synonyms_Privacy_Passcode: String { return self._s[2799]! } + public var Theme_Colors_Proceed: String { return self._s[2800]! } + public var UserInfo_ScamBotWarning: String { return self._s[2801]! } + public var LogoutOptions_LogOut: String { return self._s[2803]! } + public var Conversation_SendMessage: String { return self._s[2804]! } + public var Passport_Address_Region: String { return self._s[2806]! } + public var MediaPicker_CameraRoll: String { return self._s[2808]! } public func VoiceOver_Chat_ForwardedFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2809]!, self._r[2809]!, [_0]) + return formatWithArgumentRanges(self._s[2810]!, self._r[2810]!, [_0]) } - public var Call_ReportSend: String { return self._s[2811]! } - public var Month_ShortJune: String { return self._s[2812]! } - public var AutoDownloadSettings_GroupChats: String { return self._s[2813]! } + public var Call_ReportSend: String { return self._s[2812]! } + public var Month_ShortJune: String { return self._s[2813]! } + public var AutoDownloadSettings_GroupChats: String { return self._s[2814]! } public func Channel_AdminLog_CaptionEdited(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2816]!, self._r[2816]!, [_0]) + return formatWithArgumentRanges(self._s[2817]!, self._r[2817]!, [_0]) } - public var TwoStepAuth_DisableSuccess: String { return self._s[2817]! } - public var Cache_KeepMedia: String { return self._s[2818]! } + public var TwoStepAuth_DisableSuccess: String { return self._s[2818]! } + public var Cache_KeepMedia: String { return self._s[2819]! } public func Date_ChatDateHeaderYear(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2819]!, self._r[2819]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2820]!, self._r[2820]!, [_1, _2, _3]) } - public var Wallet_Alert_OK: String { return self._s[2820]! } - public var Appearance_LargeEmoji: String { return self._s[2821]! } + public var Wallet_Alert_OK: String { return self._s[2821]! } + public var Appearance_LargeEmoji: String { return self._s[2822]! } public func Notification_NewAuthDetected(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String, _ _6: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2822]!, self._r[2822]!, [_1, _2, _3, _4, _5, _6]) + return formatWithArgumentRanges(self._s[2823]!, self._r[2823]!, [_1, _2, _3, _4, _5, _6]) } - public var Chat_AttachmentMultipleForwardDisabled: String { return self._s[2823]! } - public var Wallet_Navigation_Close: String { return self._s[2824]! } - public var Call_CameraConfirmationText: String { return self._s[2825]! } + public var Chat_AttachmentMultipleForwardDisabled: String { return self._s[2824]! } + public var Wallet_Navigation_Close: String { return self._s[2825]! } + public var Call_CameraConfirmationText: String { return self._s[2826]! } public func AuthSessions_AppUnofficial(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2827]!, self._r[2827]!, [_0]) + return formatWithArgumentRanges(self._s[2828]!, self._r[2828]!, [_0]) } - public var VoiceOver_MessageContextReport: String { return self._s[2829]! } - public var ChatListFolder_ExcludeChatsTitle: String { return self._s[2830]! } - public var NotificationsSound_Tritone: String { return self._s[2832]! } - public var Wallet_Configuration_BlockchainIdHeader: String { return self._s[2833]! } - public var Notifications_InAppNotificationsPreview: String { return self._s[2836]! } - public var Stats_GroupTopAdmin_Actions: String { return self._s[2837]! } - public var PeerInfo_AddToContacts: String { return self._s[2838]! } - public var AccessDenied_Title: String { return self._s[2839]! } - public var Tour_Title1: String { return self._s[2840]! } - public var VoiceOver_AttachMedia: String { return self._s[2841]! } + public var VoiceOver_MessageContextReport: String { return self._s[2830]! } + public var ChatListFolder_ExcludeChatsTitle: String { return self._s[2831]! } + public var NotificationsSound_Tritone: String { return self._s[2833]! } + public var Wallet_Configuration_BlockchainIdHeader: String { return self._s[2834]! } + public var Notifications_InAppNotificationsPreview: String { return self._s[2837]! } + public var Stats_GroupTopAdmin_Actions: String { return self._s[2838]! } + public var PeerInfo_AddToContacts: String { return self._s[2839]! } + public var AccessDenied_Title: String { return self._s[2840]! } + public var Tour_Title1: String { return self._s[2841]! } + public var VoiceOver_AttachMedia: String { return self._s[2842]! } public func SharedMedia_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2843]!, self._r[2843]!, [_0]) + return formatWithArgumentRanges(self._s[2844]!, self._r[2844]!, [_0]) } - public var Chat_Gifs_SavedSectionHeader: String { return self._s[2844]! } - public var LogoutOptions_ChangePhoneNumberTitle: String { return self._s[2845]! } + public var Chat_Gifs_SavedSectionHeader: String { return self._s[2845]! } + public var LogoutOptions_ChangePhoneNumberTitle: String { return self._s[2846]! } public func Passport_Scans_ScanIndex(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2846]!, self._r[2846]!, [_0]) + return formatWithArgumentRanges(self._s[2847]!, self._r[2847]!, [_0]) } - public var Channel_AdminLog_MessagePreviousLink: String { return self._s[2847]! } - public var Wallet_Send_AddressText: String { return self._s[2848]! } - public var OldChannels_Title: String { return self._s[2849]! } - public var LoginPassword_FloodError: String { return self._s[2850]! } - public var Checkout_ErrorPaymentFailed: String { return self._s[2852]! } + public var Channel_AdminLog_MessagePreviousLink: String { return self._s[2848]! } + public var Wallet_Send_AddressText: String { return self._s[2849]! } + public var OldChannels_Title: String { return self._s[2850]! } + public var LoginPassword_FloodError: String { return self._s[2851]! } + public var Checkout_ErrorPaymentFailed: String { return self._s[2853]! } public func Time_MonthOfYear_m7(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2853]!, self._r[2853]!, [_0]) + return formatWithArgumentRanges(self._s[2854]!, self._r[2854]!, [_0]) } - public var VoiceOver_Media_PlaybackPlay: String { return self._s[2856]! } - public var Passport_CorrectErrors: String { return self._s[2858]! } + public var VoiceOver_Media_PlaybackPlay: String { return self._s[2857]! } + public var Passport_CorrectErrors: String { return self._s[2859]! } public func PUSH_CHAT_PHOTO_EDITED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2859]!, self._r[2859]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2860]!, self._r[2860]!, [_1, _2]) } - public var ChatListFolderSettings_Title: String { return self._s[2860]! } + public var ChatListFolderSettings_Title: String { return self._s[2861]! } public func AutoDownloadSettings_UpToFor(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2861]!, self._r[2861]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2862]!, self._r[2862]!, [_1, _2]) } - public var PhotoEditor_HighlightsTool: String { return self._s[2862]! } - public var Contacts_NotRegisteredSection: String { return self._s[2865]! } + public var PhotoEditor_HighlightsTool: String { return self._s[2863]! } + public var Contacts_NotRegisteredSection: String { return self._s[2866]! } public func PUSH_PINNED_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2866]!, self._r[2866]!, [_1]) + return formatWithArgumentRanges(self._s[2867]!, self._r[2867]!, [_1]) } - public var User_DeletedAccount: String { return self._s[2867]! } - public var Conversation_ViewContactDetails: String { return self._s[2868]! } - public var WebSearch_GIFs: String { return self._s[2869]! } - public var ChatList_DeleteSavedMessagesConfirmationAction: String { return self._s[2870]! } - public var Appearance_PreviewOutgoingText: String { return self._s[2871]! } - public var Calls_CallTabTitle: String { return self._s[2872]! } + public var User_DeletedAccount: String { return self._s[2868]! } + public var Conversation_ViewContactDetails: String { return self._s[2869]! } + public var WebSearch_GIFs: String { return self._s[2870]! } + public var ChatList_DeleteSavedMessagesConfirmationAction: String { return self._s[2871]! } + public var Appearance_PreviewOutgoingText: String { return self._s[2872]! } + public var Calls_CallTabTitle: String { return self._s[2873]! } public func LastSeen_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2873]!, self._r[2873]!, [_0]) + return formatWithArgumentRanges(self._s[2874]!, self._r[2874]!, [_0]) } - public var Channel_Status: String { return self._s[2874]! } - public var Conversation_SendMessageErrorGroupRestricted: String { return self._s[2876]! } - public var VoiceOver_Chat_OptionSelected: String { return self._s[2877]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsAlert: String { return self._s[2878]! } + public var Channel_Status: String { return self._s[2875]! } + public var Conversation_SendMessageErrorGroupRestricted: String { return self._s[2877]! } + public var VoiceOver_Chat_OptionSelected: String { return self._s[2878]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsAlert: String { return self._s[2879]! } public func ClearCache_Success(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2879]!, self._r[2879]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2880]!, self._r[2880]!, [_0, _1]) } - public var Passport_Identity_ExpiryDateNone: String { return self._s[2881]! } - public var Your_cards_expiration_month_is_invalid: String { return self._s[2883]! } - public var Month_ShortDecember: String { return self._s[2884]! } - public var Username_Help: String { return self._s[2885]! } - public var Login_InfoAvatarAdd: String { return self._s[2886]! } - public var Month_ShortMay: String { return self._s[2887]! } - public var DialogList_UnknownPinLimitError: String { return self._s[2888]! } - public var PasscodeSettings_AutoLock_IfAwayFor_5hours: String { return self._s[2889]! } - public var TwoStepAuth_EnabledSuccess: String { return self._s[2890]! } - public var Weekday_ShortSunday: String { return self._s[2891]! } - public var Channel_Username_InvalidTooShort: String { return self._s[2892]! } - public var AuthSessions_TerminateSession: String { return self._s[2893]! } - public var Passport_Identity_FilesTitle: String { return self._s[2894]! } + public var Passport_Identity_ExpiryDateNone: String { return self._s[2882]! } + public var Your_cards_expiration_month_is_invalid: String { return self._s[2884]! } + public var Month_ShortDecember: String { return self._s[2885]! } + public var Username_Help: String { return self._s[2886]! } + public var Login_InfoAvatarAdd: String { return self._s[2887]! } + public var Month_ShortMay: String { return self._s[2888]! } + public var DialogList_UnknownPinLimitError: String { return self._s[2889]! } + public var PasscodeSettings_AutoLock_IfAwayFor_5hours: String { return self._s[2890]! } + public var TwoStepAuth_EnabledSuccess: String { return self._s[2891]! } + public var Weekday_ShortSunday: String { return self._s[2892]! } + public var Channel_Username_InvalidTooShort: String { return self._s[2893]! } + public var AuthSessions_TerminateSession: String { return self._s[2894]! } + public var Passport_Identity_FilesTitle: String { return self._s[2895]! } public func Notification_PinnedRoundMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2895]!, self._r[2895]!, [_0]) + return formatWithArgumentRanges(self._s[2896]!, self._r[2896]!, [_0]) } - public var PeopleNearby_MakeVisible: String { return self._s[2897]! } + public var PeopleNearby_MakeVisible: String { return self._s[2898]! } public func Conversation_RestrictedMediaTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2898]!, self._r[2898]!, [_0]) + return formatWithArgumentRanges(self._s[2899]!, self._r[2899]!, [_0]) } public func Notification_MessageLifetimeChanged(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2899]!, self._r[2899]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2900]!, self._r[2900]!, [_1, _2]) } public func GroupInfo_AddParticipantConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2900]!, self._r[2900]!, [_0]) + return formatWithArgumentRanges(self._s[2901]!, self._r[2901]!, [_0]) } - public var PrivacyPolicy_DeclineDeclineAndDelete: String { return self._s[2901]! } - public var Conversation_ContextMenuForward: String { return self._s[2902]! } + public var PrivacyPolicy_DeclineDeclineAndDelete: String { return self._s[2902]! } + public var Conversation_ContextMenuForward: String { return self._s[2903]! } public func PUSH_CHAT_MESSAGE_QUIZ(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2904]!, self._r[2904]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2905]!, self._r[2905]!, [_1, _2, _3]) } - public var Notification_GroupInviterSelf: String { return self._s[2905]! } - public var Privacy_Forwards_NeverLink: String { return self._s[2906]! } - public var AuthSessions_CurrentSession: String { return self._s[2907]! } - public var Passport_Address_EditPassportRegistration: String { return self._s[2908]! } - public var ChannelInfo_DeleteChannelConfirmation: String { return self._s[2909]! } - public var ChatSearch_ResultsTooltip: String { return self._s[2911]! } - public var CheckoutInfo_Pay: String { return self._s[2912]! } + public var Notification_GroupInviterSelf: String { return self._s[2906]! } + public var Privacy_Forwards_NeverLink: String { return self._s[2907]! } + public var AuthSessions_CurrentSession: String { return self._s[2908]! } + public var Passport_Address_EditPassportRegistration: String { return self._s[2909]! } + public var ChannelInfo_DeleteChannelConfirmation: String { return self._s[2910]! } + public var ChatSearch_ResultsTooltip: String { return self._s[2912]! } + public var CheckoutInfo_Pay: String { return self._s[2913]! } public func Channel_AdminLog_MessageChangedChannelUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2914]!, self._r[2914]!, [_0]) + return formatWithArgumentRanges(self._s[2915]!, self._r[2915]!, [_0]) } - public var GroupInfo_AddParticipant: String { return self._s[2915]! } - public var GroupPermission_ApplyAlertAction: String { return self._s[2916]! } - public var ChatList_UndoArchiveText1: String { return self._s[2917]! } - public var Localization_LanguageCustom: String { return self._s[2918]! } - public var SettingsSearch_Synonyms_Passport: String { return self._s[2919]! } - public var Settings_UsernameEmpty: String { return self._s[2920]! } - public var Settings_FAQ_URL: String { return self._s[2921]! } + public var GroupInfo_AddParticipant: String { return self._s[2916]! } + public var GroupPermission_ApplyAlertAction: String { return self._s[2917]! } + public var ChatList_UndoArchiveText1: String { return self._s[2918]! } + public var Localization_LanguageCustom: String { return self._s[2919]! } + public var SettingsSearch_Synonyms_Passport: String { return self._s[2920]! } + public var Settings_UsernameEmpty: String { return self._s[2921]! } + public var Settings_FAQ_URL: String { return self._s[2922]! } public func Conversation_PinMessagesFor(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2922]!, self._r[2922]!, [_0]) + return formatWithArgumentRanges(self._s[2923]!, self._r[2923]!, [_0]) } - public var Common_Select: String { return self._s[2924]! } - public var Notification_MessageLifetimeRemovedOutgoing: String { return self._s[2925]! } - public var Notification_PassportValueAddress: String { return self._s[2926]! } - public var Conversation_MessageDialogDelete: String { return self._s[2927]! } - public var Map_OpenInYandexNavigator: String { return self._s[2929]! } - public var DialogList_SearchSectionDialogs: String { return self._s[2930]! } - public var AccessDenied_Contacts: String { return self._s[2931]! } - public var SettingsSearch_Synonyms_Privacy_Data_DeleteDrafts: String { return self._s[2933]! } - public var Passport_ScanPassportHelp: String { return self._s[2934]! } - public var Chat_PinnedListPreview_HidePinnedMessages: String { return self._s[2935]! } - public var ChatListFolder_NameChannels: String { return self._s[2936]! } - public var Appearance_ThemePreview_Chat_5_Text: String { return self._s[2937]! } + public var Common_Select: String { return self._s[2925]! } + public var Notification_MessageLifetimeRemovedOutgoing: String { return self._s[2926]! } + public var Notification_PassportValueAddress: String { return self._s[2927]! } + public var Conversation_MessageDialogDelete: String { return self._s[2928]! } + public var Map_OpenInYandexNavigator: String { return self._s[2930]! } + public var DialogList_SearchSectionDialogs: String { return self._s[2931]! } + public var AccessDenied_Contacts: String { return self._s[2932]! } + public var SettingsSearch_Synonyms_Privacy_Data_DeleteDrafts: String { return self._s[2934]! } + public var Passport_ScanPassportHelp: String { return self._s[2935]! } + public var Chat_PinnedListPreview_HidePinnedMessages: String { return self._s[2936]! } + public var ChatListFolder_NameChannels: String { return self._s[2937]! } + public var Appearance_ThemePreview_Chat_5_Text: String { return self._s[2938]! } public func Channel_OwnershipTransfer_TransferCompleted(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2938]!, self._r[2938]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2939]!, self._r[2939]!, [_1, _2]) } - public var Checkout_ErrorInvoiceAlreadyPaid: String { return self._s[2939]! } - public var Conversation_GifTooltip: String { return self._s[2940]! } - public var Passport_Identity_TypeDriversLicenseUploadScan: String { return self._s[2942]! } - public var AutoDownloadSettings_OffForAll: String { return self._s[2943]! } - public var Privacy_GroupsAndChannels_InviteToChannelMultipleError: String { return self._s[2944]! } - public var AutoDownloadSettings_PreloadVideo: String { return self._s[2945]! } - public var CreatePoll_Quiz: String { return self._s[2946]! } - public var TwoFactorSetup_Email_Placeholder: String { return self._s[2947]! } - public var Watch_Message_Invoice: String { return self._s[2948]! } - public var Settings_AddAnotherAccount_Help: String { return self._s[2949]! } - public var Watch_Message_Unsupported: String { return self._s[2950]! } + public var Checkout_ErrorInvoiceAlreadyPaid: String { return self._s[2940]! } + public var Conversation_GifTooltip: String { return self._s[2941]! } + public var Passport_Identity_TypeDriversLicenseUploadScan: String { return self._s[2943]! } + public var AutoDownloadSettings_OffForAll: String { return self._s[2944]! } + public var Privacy_GroupsAndChannels_InviteToChannelMultipleError: String { return self._s[2945]! } + public var AutoDownloadSettings_PreloadVideo: String { return self._s[2946]! } + public var CreatePoll_Quiz: String { return self._s[2947]! } + public var TwoFactorSetup_Email_Placeholder: String { return self._s[2948]! } + public var Watch_Message_Invoice: String { return self._s[2949]! } + public var Settings_AddAnotherAccount_Help: String { return self._s[2950]! } + public var Watch_Message_Unsupported: String { return self._s[2951]! } public func Call_CameraOff(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2952]!, self._r[2952]!, [_0]) + return formatWithArgumentRanges(self._s[2953]!, self._r[2953]!, [_0]) } - public var AuthSessions_TerminateOtherSessions: String { return self._s[2953]! } - public var CreatePoll_AllOptionsAdded: String { return self._s[2955]! } - public var TwoStepAuth_RecoveryEmailTitle: String { return self._s[2956]! } - public var Call_IncomingVoiceCall: String { return self._s[2957]! } + public var AuthSessions_TerminateOtherSessions: String { return self._s[2954]! } + public var CreatePoll_AllOptionsAdded: String { return self._s[2956]! } + public var TwoStepAuth_RecoveryEmailTitle: String { return self._s[2957]! } + public var Call_IncomingVoiceCall: String { return self._s[2958]! } public func Channel_AdminLog_MessageTransferedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2958]!, self._r[2958]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2959]!, self._r[2959]!, [_1, _2]) } - public var PrivacySettings_DeleteAccountHelp: String { return self._s[2959]! } - public var Passport_Address_TypePassportRegistrationUploadScan: String { return self._s[2960]! } - public var Group_EditAdmin_RankOwnerPlaceholder: String { return self._s[2961]! } - public var Group_ErrorAccessDenied: String { return self._s[2962]! } - public var PasscodeSettings_HelpTop: String { return self._s[2963]! } - public var Watch_ChatList_NoConversationsTitle: String { return self._s[2964]! } - public var AddContact_SharedContactException: String { return self._s[2965]! } - public var AccessDenied_MicrophoneRestricted: String { return self._s[2966]! } - public var Privacy_TopPeers: String { return self._s[2967]! } - public var Web_OpenExternal: String { return self._s[2968]! } - public var Group_ErrorSendRestrictedStickers: String { return self._s[2969]! } - public var Channel_Management_LabelAdministrator: String { return self._s[2970]! } + public var PrivacySettings_DeleteAccountHelp: String { return self._s[2960]! } + public var Passport_Address_TypePassportRegistrationUploadScan: String { return self._s[2961]! } + public var Group_EditAdmin_RankOwnerPlaceholder: String { return self._s[2962]! } + public var Group_ErrorAccessDenied: String { return self._s[2963]! } + public var PasscodeSettings_HelpTop: String { return self._s[2964]! } + public var Watch_ChatList_NoConversationsTitle: String { return self._s[2965]! } + public var AddContact_SharedContactException: String { return self._s[2966]! } + public var AccessDenied_MicrophoneRestricted: String { return self._s[2967]! } + public var Privacy_TopPeers: String { return self._s[2968]! } + public var Web_OpenExternal: String { return self._s[2969]! } + public var Group_ErrorSendRestrictedStickers: String { return self._s[2970]! } + public var Channel_Management_LabelAdministrator: String { return self._s[2971]! } public func ChangePhoneNumberCode_CallTimer(_ _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 Permissions_Skip: String { return self._s[2972]! } - public var Notifications_GroupNotificationsExceptions: String { return self._s[2973]! } - public var PeopleNearby_Title: String { return self._s[2974]! } - public var GroupInfo_SharedMediaNone: String { return self._s[2975]! } + public var Permissions_Skip: String { return self._s[2973]! } + public var Notifications_GroupNotificationsExceptions: String { return self._s[2974]! } + public var PeopleNearby_Title: String { return self._s[2975]! } + public var GroupInfo_SharedMediaNone: String { return self._s[2976]! } public func PUSH_MESSAGE_GEOLIVE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2977]!, self._r[2977]!, [_1]) + return formatWithArgumentRanges(self._s[2978]!, self._r[2978]!, [_1]) } - public var Profile_MessageLifetime1w: String { return self._s[2978]! } + public var Profile_MessageLifetime1w: String { return self._s[2979]! } public func Time_PreciseDate_m6(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2979]!, self._r[2979]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2980]!, self._r[2980]!, [_1, _2, _3]) } - public var WebBrowser_DefaultBrowser: String { return self._s[2980]! } - public var Conversation_PinOlderMessageAlertTitle: String { return self._s[2982]! } - public var EditTheme_Edit_BottomInfo: String { return self._s[2983]! } - public var Privacy_Forwards_Preview: String { return self._s[2984]! } - public var Settings_EditAccount: String { return self._s[2985]! } + public var WebBrowser_DefaultBrowser: String { return self._s[2981]! } + public var Conversation_PinOlderMessageAlertTitle: String { return self._s[2983]! } + public var EditTheme_Edit_BottomInfo: String { return self._s[2984]! } + public var Privacy_Forwards_Preview: String { return self._s[2985]! } + public var Settings_EditAccount: String { return self._s[2986]! } public func Conversation_RestrictedInlineTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2986]!, self._r[2986]!, [_0]) + return formatWithArgumentRanges(self._s[2987]!, self._r[2987]!, [_0]) } - public var TwoFactorSetup_Intro_Title: String { return self._s[2987]! } + public var TwoFactorSetup_Intro_Title: String { return self._s[2988]! } public func Channel_AdminLog_MessagePromotedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2989]!, self._r[2989]!, [_1]) + return formatWithArgumentRanges(self._s[2990]!, self._r[2990]!, [_1]) } - public var PeerInfo_ButtonVideoCall: String { return self._s[2990]! } + public var PeerInfo_ButtonVideoCall: String { return self._s[2991]! } public func DialogList_SingleUploadingPhotoSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2991]!, self._r[2991]!, [_0]) + return formatWithArgumentRanges(self._s[2992]!, self._r[2992]!, [_0]) } - public var Login_InfoHelp: String { return self._s[2992]! } - public var Notification_SecretChatMessageScreenshotSelf: String { return self._s[2993]! } - public var Profile_MessageLifetime1d: String { return self._s[2994]! } - public var Group_UpgradeConfirmation: String { return self._s[2995]! } + public var Login_InfoHelp: String { return self._s[2993]! } + public var Notification_SecretChatMessageScreenshotSelf: String { return self._s[2994]! } + public var Profile_MessageLifetime1d: String { return self._s[2995]! } + public var Group_UpgradeConfirmation: String { return self._s[2996]! } public func PUSH_PINNED_STICKER(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2996]!, self._r[2996]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2997]!, self._r[2997]!, [_1, _2]) } - public var Appearance_RemoveThemeColor: String { return self._s[2997]! } - public var Channel_AdminLog_TitleSelectedEvents: String { return self._s[2998]! } - public var Wallet_Configuration_BlockchainIdInfo: String { return self._s[2999]! } + public var Appearance_RemoveThemeColor: String { return self._s[2998]! } + public var Channel_AdminLog_TitleSelectedEvents: String { return self._s[2999]! } + public var Wallet_Configuration_BlockchainIdInfo: String { return self._s[3000]! } public func Call_AnsweringWithAccount(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3000]!, self._r[3000]!, [_0]) + return formatWithArgumentRanges(self._s[3001]!, self._r[3001]!, [_0]) } - public var UserInfo_BotSettings: String { return self._s[3001]! } + public var UserInfo_BotSettings: String { return self._s[3002]! } public func Notification_ChannelInviter(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3003]!, self._r[3003]!, [_0]) + return formatWithArgumentRanges(self._s[3004]!, self._r[3004]!, [_0]) } - public var Permissions_ContactsText_v0: String { return self._s[3004]! } - public var Conversation_PinMessagesForMe: String { return self._s[3005]! } - public var Conversation_DiscussionStarted: String { return self._s[3007]! } - public var SettingsSearch_Synonyms_Privacy_TwoStepAuth: String { return self._s[3008]! } - public var SharedMedia_SearchNoResults: String { return self._s[3010]! } + public var Permissions_ContactsText_v0: String { return self._s[3005]! } + public var Conversation_PinMessagesForMe: String { return self._s[3006]! } + public var Conversation_DiscussionStarted: String { return self._s[3008]! } + public var SettingsSearch_Synonyms_Privacy_TwoStepAuth: String { return self._s[3009]! } + public var SharedMedia_SearchNoResults: String { return self._s[3011]! } public func Login_EmailPhoneSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3012]!, self._r[3012]!, [_0]) + return formatWithArgumentRanges(self._s[3013]!, self._r[3013]!, [_0]) } public func Conversation_ShareMyPhoneNumber_StatusSuccess(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3014]!, self._r[3014]!, [_0]) + return formatWithArgumentRanges(self._s[3015]!, self._r[3015]!, [_0]) } - public var ReportPeer_ReasonOther_Placeholder: String { return self._s[3015]! } - public var ContactInfo_PhoneLabelHomeFax: String { return self._s[3016]! } - public var Call_AudioRouteHeadphones: String { return self._s[3017]! } + public var ReportPeer_ReasonOther_Placeholder: String { return self._s[3016]! } + public var ContactInfo_PhoneLabelHomeFax: String { return self._s[3017]! } + public var Call_AudioRouteHeadphones: String { return self._s[3018]! } public func PUSH_AUTH_UNKNOWN(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3018]!, self._r[3018]!, [_1]) + return formatWithArgumentRanges(self._s[3019]!, self._r[3019]!, [_1]) } - public var Passport_Identity_FilesView: String { return self._s[3019]! } - public var TwoStepAuth_SetupEmail: String { return self._s[3020]! } - public var Widget_ApplicationStartRequired: String { return self._s[3021]! } - public var PhotoEditor_Original: String { return self._s[3022]! } - public var Call_YourMicrophoneOff: String { return self._s[3023]! } - public var Permissions_ContactsAllow_v0: String { return self._s[3024]! } - public var Notification_Exceptions_PreviewAlwaysOn: String { return self._s[3025]! } - public var PrivacyPolicy_Decline: String { return self._s[3026]! } - public var SettingsSearch_Synonyms_ChatFolders: String { return self._s[3027]! } - public var TwoStepAuth_PasswordRemoveConfirmation: String { return self._s[3028]! } - public var ChatListFolder_IncludeSectionInfo: String { return self._s[3029]! } + public var Passport_Identity_FilesView: String { return self._s[3020]! } + public var TwoStepAuth_SetupEmail: String { return self._s[3021]! } + public var Widget_ApplicationStartRequired: String { return self._s[3022]! } + public var PhotoEditor_Original: String { return self._s[3023]! } + public var Call_YourMicrophoneOff: String { return self._s[3024]! } + public var Permissions_ContactsAllow_v0: String { return self._s[3025]! } + public var Notification_Exceptions_PreviewAlwaysOn: String { return self._s[3026]! } + public var PrivacyPolicy_Decline: String { return self._s[3027]! } + public var SettingsSearch_Synonyms_ChatFolders: String { return self._s[3028]! } + public var TwoStepAuth_PasswordRemoveConfirmation: String { return self._s[3029]! } + public var ChatListFolder_IncludeSectionInfo: String { return self._s[3030]! } public func Map_DirectionsDriveEta(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3030]!, self._r[3030]!, [_0]) + return formatWithArgumentRanges(self._s[3031]!, self._r[3031]!, [_0]) } - public var Passport_Identity_Name: String { return self._s[3031]! } - public var WallpaperPreview_PatternTitle: String { return self._s[3033]! } - public var VoiceOver_Chat_RecordModeVideoMessage: String { return self._s[3034]! } - public var WallpaperSearch_ColorOrange: String { return self._s[3036]! } - public var Appearance_ThemePreview_ChatList_5_Name: String { return self._s[3037]! } - public var GroupInfo_Permissions_SlowmodeInfo: String { return self._s[3038]! } - public var Your_cards_security_code_is_invalid: String { return self._s[3039]! } - public var IntentsSettings_ResetAll: String { return self._s[3040]! } - public var SettingsSearch_Synonyms_Calls_CallTab: String { return self._s[3042]! } - public var Group_EditAdmin_TransferOwnership: String { return self._s[3043]! } - public var Notification_Exceptions_Add: String { return self._s[3044]! } - public var Cache_Help: String { return self._s[3045]! } - public var Call_AudioRouteMute: String { return self._s[3046]! } - public var VoiceOver_Chat_YourVoiceMessage: String { return self._s[3047]! } - public var SocksProxySetup_ProxyEnabled: String { return self._s[3048]! } + public var Passport_Identity_Name: String { return self._s[3032]! } + public var WallpaperPreview_PatternTitle: String { return self._s[3034]! } + public var VoiceOver_Chat_RecordModeVideoMessage: String { return self._s[3035]! } + public var WallpaperSearch_ColorOrange: String { return self._s[3037]! } + public var Appearance_ThemePreview_ChatList_5_Name: String { return self._s[3038]! } + public var GroupInfo_Permissions_SlowmodeInfo: String { return self._s[3039]! } + public var Your_cards_security_code_is_invalid: String { return self._s[3040]! } + public var IntentsSettings_ResetAll: String { return self._s[3041]! } + public var SettingsSearch_Synonyms_Calls_CallTab: String { return self._s[3043]! } + public var Group_EditAdmin_TransferOwnership: String { return self._s[3044]! } + public var Notification_Exceptions_Add: String { return self._s[3045]! } + public var Cache_Help: String { return self._s[3046]! } + public var Call_AudioRouteMute: String { return self._s[3047]! } + public var VoiceOver_Chat_YourVoiceMessage: String { return self._s[3048]! } + public var SocksProxySetup_ProxyEnabled: String { return self._s[3049]! } public func ApplyLanguage_UnsufficientDataText(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3049]!, self._r[3049]!, [_1]) + return formatWithArgumentRanges(self._s[3050]!, self._r[3050]!, [_1]) } public func Call_CallInProgressMessage(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3050]!, self._r[3050]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3051]!, self._r[3051]!, [_1, _2]) } - public var AutoDownloadSettings_VideoMessagesTitle: String { return self._s[3051]! } - public var Channel_BanUser_PermissionAddMembers: String { return self._s[3052]! } - public var Contacts_MemberSearchSectionTitleGroup: String { return self._s[3053]! } + public var AutoDownloadSettings_VideoMessagesTitle: String { return self._s[3052]! } + public var Channel_BanUser_PermissionAddMembers: String { return self._s[3053]! } + public var Contacts_MemberSearchSectionTitleGroup: String { return self._s[3054]! } public func Wallet_Time_PreciseDate_m10(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3054]!, self._r[3054]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3055]!, self._r[3055]!, [_1, _2, _3]) } - public var TwoStepAuth_RecoveryCodeHelp: String { return self._s[3055]! } - public var ClearCache_StorageFree: String { return self._s[3056]! } + public var TwoStepAuth_RecoveryCodeHelp: String { return self._s[3056]! } + public var ClearCache_StorageFree: String { return self._s[3057]! } public func DialogList_SingleRecordingVideoMessageSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3057]!, self._r[3057]!, [_0]) + return formatWithArgumentRanges(self._s[3058]!, self._r[3058]!, [_0]) } - public var Privacy_Forwards_CustomHelp: String { return self._s[3058]! } - public var Group_ErrorAddTooMuchAdmins: String { return self._s[3060]! } - public var DialogList_Typing: String { return self._s[3061]! } + public var Privacy_Forwards_CustomHelp: String { return self._s[3059]! } + public var Group_ErrorAddTooMuchAdmins: String { return self._s[3061]! } + public var DialogList_Typing: String { return self._s[3062]! } public func Login_EmailCodeSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3062]!, self._r[3062]!, [_0]) + return formatWithArgumentRanges(self._s[3063]!, self._r[3063]!, [_0]) } - public var Target_SelectGroup: String { return self._s[3063]! } - public var AuthSessions_IncompleteAttempts: String { return self._s[3064]! } + public var Target_SelectGroup: String { return self._s[3064]! } + public var AuthSessions_IncompleteAttempts: String { return self._s[3065]! } public func Notification_ProximityReached(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3065]!, self._r[3065]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3066]!, self._r[3066]!, [_1, _2, _3]) } - public var Chat_PinnedListPreview_ShowAllMessages: String { return self._s[3066]! } - public var TwoStepAuth_EmailChangeSuccess: String { return self._s[3067]! } + public var Chat_PinnedListPreview_ShowAllMessages: String { return self._s[3067]! } + public var TwoStepAuth_EmailChangeSuccess: String { return self._s[3068]! } public func Settings_CheckPhoneNumberTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3068]!, self._r[3068]!, [_0]) + return formatWithArgumentRanges(self._s[3069]!, self._r[3069]!, [_0]) } - public var Channel_AdminLog_CanSendMessages: String { return self._s[3069]! } - public var TwoFactorSetup_EmailVerification_Title: String { return self._s[3070]! } - public var ChatSettings_TextSize: String { return self._s[3071]! } - public var Channel_AdminLogFilter_EventsEditedMessages: String { return self._s[3073]! } - public var Map_SendThisPlace: String { return self._s[3074]! } - public var Login_PhoneNumberAlreadyAuthorized: String { return self._s[3075]! } - public var ContactInfo_BirthdayLabel: String { return self._s[3076]! } - public var Call_ShareStats: String { return self._s[3077]! } - public var ChatList_UndoArchiveRevealedText: String { return self._s[3079]! } - public var Notifications_GroupNotificationsPreview: String { return self._s[3080]! } - public var Settings_Support: String { return self._s[3081]! } - public var GroupInfo_ChannelListNamePlaceholder: String { return self._s[3082]! } + public var Channel_AdminLog_CanSendMessages: String { return self._s[3070]! } + public var TwoFactorSetup_EmailVerification_Title: String { return self._s[3071]! } + public var ChatSettings_TextSize: String { return self._s[3072]! } + public var Channel_AdminLogFilter_EventsEditedMessages: String { return self._s[3074]! } + public var Map_SendThisPlace: String { return self._s[3075]! } + public var Conversation_TextCopied: String { return self._s[3076]! } + public var Login_PhoneNumberAlreadyAuthorized: String { return self._s[3077]! } + public var ContactInfo_BirthdayLabel: String { return self._s[3078]! } + public var Call_ShareStats: String { return self._s[3079]! } + public var ChatList_UndoArchiveRevealedText: String { return self._s[3081]! } + public var Notifications_GroupNotificationsPreview: String { return self._s[3082]! } + public var Settings_Support: String { return self._s[3083]! } + public var GroupInfo_ChannelListNamePlaceholder: String { return self._s[3084]! } public func EmptyGroupInfo_Line1(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3084]!, self._r[3084]!, [_0]) + return formatWithArgumentRanges(self._s[3086]!, self._r[3086]!, [_0]) } - public var Watch_Conversation_GroupInfo: String { return self._s[3085]! } - public var Tour_Text4: String { return self._s[3086]! } - public var PasscodeSettings_AutoLock: String { return self._s[3088]! } - public var Channel_BanList_BlockedTitle: String { return self._s[3089]! } - public var Bot_DescriptionTitle: String { return self._s[3090]! } - public var Map_LocationTitle: String { return self._s[3091]! } - public var ChatListFolder_ExcludeSectionInfo: String { return self._s[3092]! } + public var Watch_Conversation_GroupInfo: String { return self._s[3087]! } + public var Tour_Text4: String { return self._s[3088]! } + public var PasscodeSettings_AutoLock: String { return self._s[3090]! } + public var Channel_BanList_BlockedTitle: String { return self._s[3091]! } + public var Bot_DescriptionTitle: String { return self._s[3092]! } + public var Map_LocationTitle: String { return self._s[3093]! } + public var ChatListFolder_ExcludeSectionInfo: String { return self._s[3094]! } public func Notification_MessageLifetimeChangedOutgoing(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3093]!, self._r[3093]!, [_1]) + return formatWithArgumentRanges(self._s[3095]!, self._r[3095]!, [_1]) } - public var Login_EmailNotConfiguredError: String { return self._s[3094]! } - public var AutoDownloadSettings_LimitBySize: String { return self._s[3095]! } - public var PrivacySettings_LastSeenNobody: String { return self._s[3096]! } - public var Permissions_CellularDataText_v0: String { return self._s[3097]! } - public var Conversation_EncryptionProcessing: String { return self._s[3098]! } - public var GroupPermission_Delete: String { return self._s[3099]! } - public var Contacts_SortByName: String { return self._s[3100]! } - public var TwoStepAuth_RecoveryUnavailable: String { return self._s[3101]! } - public var Compose_ChannelTokenListPlaceholder: String { return self._s[3102]! } - public var Group_Management_AddModeratorHelp: String { return self._s[3104]! } - public var SettingsSearch_Synonyms_EditProfile_Logout: String { return self._s[3105]! } - public var Forward_ErrorPublicPollDisabledInChannels: String { return self._s[3106]! } + public var Login_EmailNotConfiguredError: String { return self._s[3096]! } + public var AutoDownloadSettings_LimitBySize: String { return self._s[3097]! } + public var PrivacySettings_LastSeenNobody: String { return self._s[3098]! } + public var Permissions_CellularDataText_v0: String { return self._s[3099]! } + public var Conversation_EncryptionProcessing: String { return self._s[3100]! } + public var GroupPermission_Delete: String { return self._s[3101]! } + public var Contacts_SortByName: String { return self._s[3102]! } + public var TwoStepAuth_RecoveryUnavailable: String { return self._s[3103]! } + public var Compose_ChannelTokenListPlaceholder: String { return self._s[3104]! } + public var Group_Management_AddModeratorHelp: String { return self._s[3106]! } + public var SettingsSearch_Synonyms_EditProfile_Logout: String { return self._s[3107]! } + public var Forward_ErrorPublicPollDisabledInChannels: String { return self._s[3108]! } public func Wallet_Time_PreciseDate_m7(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3108]!, self._r[3108]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3110]!, self._r[3110]!, [_1, _2, _3]) } - public var CallFeedback_IncludeLogsInfo: String { return self._s[3109]! } + public var CallFeedback_IncludeLogsInfo: String { return self._s[3111]! } public func PUSH_CHANNEL_MESSAGE_QUIZ(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3110]!, self._r[3110]!, [_1]) + return formatWithArgumentRanges(self._s[3112]!, self._r[3112]!, [_1]) } public func SecretVideo_NotViewedYet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3111]!, self._r[3111]!, [_0]) + return formatWithArgumentRanges(self._s[3113]!, self._r[3113]!, [_0]) } - public var ChatList_Context_Delete: String { return self._s[3112]! } - public var PrivacyPhoneNumberSettings_CustomDisabledHelp: String { return self._s[3113]! } - public var Conversation_Processing: String { return self._s[3114]! } - public var TwoStepAuth_EmailCodeExpired: String { return self._s[3115]! } - public var ChatSettings_Stickers: String { return self._s[3116]! } - public var AppleWatch_ReplyPresetsHelp: String { return self._s[3117]! } - public var Passport_Language_cs: String { return self._s[3118]! } - public var GroupInfo_InvitationLinkGroupFull: String { return self._s[3120]! } - public var Conversation_Contact: String { return self._s[3121]! } - public var Passport_Identity_ReverseSideHelp: String { return self._s[3122]! } - public var SocksProxySetup_PasteFromClipboard: String { return self._s[3123]! } - public var Wallet_VoiceOver_Editing_ClearText: String { return self._s[3124]! } - public var Theme_Unsupported: String { return self._s[3125]! } - public var Wallet_SecureStorageNotAvailable_Text: String { return self._s[3126]! } - public var Privacy_TopPeersWarning: String { return self._s[3127]! } + public var ChatList_Context_Delete: String { return self._s[3114]! } + public var PrivacyPhoneNumberSettings_CustomDisabledHelp: String { return self._s[3115]! } + public var Conversation_Processing: String { return self._s[3116]! } + public var TwoStepAuth_EmailCodeExpired: String { return self._s[3117]! } + public var ChatSettings_Stickers: String { return self._s[3118]! } + public var AppleWatch_ReplyPresetsHelp: String { return self._s[3119]! } + public var Passport_Language_cs: String { return self._s[3120]! } + public var GroupInfo_InvitationLinkGroupFull: String { return self._s[3122]! } + public var Conversation_Contact: String { return self._s[3123]! } + public var Passport_Identity_ReverseSideHelp: String { return self._s[3124]! } + public var SocksProxySetup_PasteFromClipboard: String { return self._s[3125]! } + public var Wallet_VoiceOver_Editing_ClearText: String { return self._s[3126]! } + public var Theme_Unsupported: String { return self._s[3127]! } + public var Wallet_SecureStorageNotAvailable_Text: String { return self._s[3128]! } + public var Privacy_TopPeersWarning: String { return self._s[3129]! } public func UserInfo_BlockConfirmationTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3129]!, self._r[3129]!, [_0]) + return formatWithArgumentRanges(self._s[3131]!, self._r[3131]!, [_0]) } - public var Conversation_SilentBroadcastTooltipOn: String { return self._s[3130]! } - public var TwoStepAuth_RemovePassword: String { return self._s[3131]! } - public var Settings_CheckPhoneNumberText: String { return self._s[3132]! } - public var PeopleNearby_Users: String { return self._s[3133]! } - public var Appearance_TextSize_UseSystem: String { return self._s[3134]! } - public var Settings_SetProfilePhoto: String { return self._s[3135]! } - public var Conversation_ContextMenuBan: String { return self._s[3136]! } - public var KeyCommand_ScrollUp: String { return self._s[3137]! } - public var Settings_ChatSettings: String { return self._s[3139]! } + public var Conversation_SilentBroadcastTooltipOn: String { return self._s[3132]! } + public var TwoStepAuth_RemovePassword: String { return self._s[3133]! } + public var Settings_CheckPhoneNumberText: String { return self._s[3134]! } + public var PeopleNearby_Users: String { return self._s[3135]! } + public var Appearance_TextSize_UseSystem: String { return self._s[3136]! } + public var Settings_SetProfilePhoto: String { return self._s[3137]! } + public var Conversation_ContextMenuBan: String { return self._s[3138]! } + public var KeyCommand_ScrollUp: String { return self._s[3139]! } + public var Settings_ChatSettings: String { return self._s[3141]! } public func PUSH_CHAT_MESSAGE_VIDEO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3140]!, self._r[3140]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3142]!, self._r[3142]!, [_1, _2]) } - public var Stats_GroupTopInvitersTitle: String { return self._s[3141]! } - public var Passport_Phone_EnterOtherNumber: String { return self._s[3142]! } - public var Passport_Identity_MiddleNamePlaceholder: String { return self._s[3144]! } - public var Passport_Address_OneOfTypeBankStatement: String { return self._s[3145]! } - public var Stats_GroupTopPoster_Promote: String { return self._s[3146]! } - public var Cache_Title: String { return self._s[3147]! } - public var Clipboard_SendPhoto: String { return self._s[3148]! } - public var Notifications_ExceptionsMessagePlaceholder: String { return self._s[3150]! } - public var TwoStepAuth_EnterPasswordForgot: String { return self._s[3151]! } - public var WatchRemote_AlertTitle: String { return self._s[3152]! } - public var Appearance_ReduceMotion: String { return self._s[3153]! } + public var Stats_GroupTopInvitersTitle: String { return self._s[3143]! } + public var Passport_Phone_EnterOtherNumber: String { return self._s[3144]! } + public var Passport_Identity_MiddleNamePlaceholder: String { return self._s[3146]! } + public var Passport_Address_OneOfTypeBankStatement: String { return self._s[3147]! } + public var Stats_GroupTopPoster_Promote: String { return self._s[3148]! } + public var Cache_Title: String { return self._s[3149]! } + public var Clipboard_SendPhoto: String { return self._s[3150]! } + public var Notifications_ExceptionsMessagePlaceholder: String { return self._s[3152]! } + public var TwoStepAuth_EnterPasswordForgot: String { return self._s[3153]! } + public var WatchRemote_AlertTitle: String { return self._s[3154]! } + public var Appearance_ReduceMotion: String { return self._s[3155]! } public func PUSH_CHAT_MESSAGE_ROUND(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3156]!, self._r[3156]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3158]!, self._r[3158]!, [_1, _2]) } - public var Notifications_PermissionsSuppressWarningText: String { return self._s[3157]! } - public var ChatList_UndoArchiveHiddenTitle: String { return self._s[3158]! } - public var Passport_Identity_TypePersonalDetails: String { return self._s[3159]! } - public var Wallet_TransactionInfo_CopyAddress: String { return self._s[3161]! } + public var Notifications_PermissionsSuppressWarningText: String { return self._s[3159]! } + public var ChatList_UndoArchiveHiddenTitle: String { return self._s[3160]! } + public var Passport_Identity_TypePersonalDetails: String { return self._s[3161]! } + public var Wallet_TransactionInfo_CopyAddress: String { return self._s[3163]! } public func Passport_Identity_UploadOneOfScan(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3162]!, self._r[3162]!, [_0]) - } - public var ChatListFolder_DiscardConfirmation: String { return self._s[3163]! } - public func Conversation_RestrictedStickersTimed(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3164]!, self._r[3164]!, [_0]) } - public var ChatState_WaitingForNetwork: String { return self._s[3165]! } - public var GroupInfo_Sound: String { return self._s[3166]! } - public var NotificationsSound_Telegraph: String { return self._s[3167]! } - public var NotificationsSound_Hello: String { return self._s[3168]! } - public var Passport_FieldIdentityDetailsHelp: String { return self._s[3169]! } - public var Wallet_Settings_BackupWallet: String { return self._s[3170]! } - public var Group_Members_AddMemberBotErrorNotAllowed: String { return self._s[3171]! } - public var Conversation_HoldForVideo: String { return self._s[3172]! } - public var Conversation_PinOlderMessageAlertText: String { return self._s[3173]! } - public var Wallet_Configuration_ApplyErrorTextURLInvalidData: String { return self._s[3174]! } - public var Wallet_RestoreFailed_EnterWords: String { return self._s[3175]! } - public var Appearance_ShareTheme: String { return self._s[3176]! } - public var TwoStepAuth_SetupHint: String { return self._s[3177]! } - public var Wallet_Created_Text: String { return self._s[3180]! } - public var Stats_GrowthTitle: String { return self._s[3181]! } - public var GroupInfo_InviteLink_ShareLink: String { return self._s[3182]! } - public var Conversation_DefaultRestrictedMedia: String { return self._s[3183]! } - public var Channel_EditAdmin_PermissionPostMessages: String { return self._s[3184]! } - public var GroupPermission_NoSendMessages: String { return self._s[3186]! } - public var Conversation_SetReminder_Title: String { return self._s[3187]! } - public var Privacy_Calls_CustomHelp: String { return self._s[3188]! } - public var CheckoutInfo_ErrorPostcodeInvalid: String { return self._s[3189]! } + public var ChatListFolder_DiscardConfirmation: String { return self._s[3165]! } + public func Conversation_RestrictedStickersTimed(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3166]!, self._r[3166]!, [_0]) + } + public var ChatState_WaitingForNetwork: String { return self._s[3167]! } + public var GroupInfo_Sound: String { return self._s[3168]! } + public var NotificationsSound_Telegraph: String { return self._s[3169]! } + public var NotificationsSound_Hello: String { return self._s[3170]! } + public var Passport_FieldIdentityDetailsHelp: String { return self._s[3171]! } + public var Wallet_Settings_BackupWallet: String { return self._s[3172]! } + public var Group_Members_AddMemberBotErrorNotAllowed: String { return self._s[3173]! } + public var Conversation_HoldForVideo: String { return self._s[3174]! } + public var Conversation_PinOlderMessageAlertText: String { return self._s[3175]! } + public var Wallet_Configuration_ApplyErrorTextURLInvalidData: String { return self._s[3176]! } + public var Wallet_RestoreFailed_EnterWords: String { return self._s[3177]! } + public var Appearance_ShareTheme: String { return self._s[3178]! } + public var TwoStepAuth_SetupHint: String { return self._s[3179]! } + public var Wallet_Created_Text: String { return self._s[3182]! } + public var Stats_GrowthTitle: String { return self._s[3183]! } + public var GroupInfo_InviteLink_ShareLink: String { return self._s[3184]! } + public var Conversation_DefaultRestrictedMedia: String { return self._s[3185]! } + public var Channel_EditAdmin_PermissionPostMessages: String { return self._s[3186]! } + public var GroupPermission_NoSendMessages: String { return self._s[3188]! } + public var Conversation_SetReminder_Title: String { return self._s[3189]! } + public var Privacy_Calls_CustomHelp: String { return self._s[3190]! } + public var CheckoutInfo_ErrorPostcodeInvalid: String { return self._s[3191]! } public func ClearCache_StorageTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3190]!, self._r[3190]!, [_0]) + return formatWithArgumentRanges(self._s[3192]!, self._r[3192]!, [_0]) } - public var Undo_SecretChatDeleted: String { return self._s[3192]! } - public var PhotoEditor_ContrastTool: String { return self._s[3193]! } - public var Privacy_Forwards: String { return self._s[3194]! } - public var AuthSessions_LoggedInWithTelegram: String { return self._s[3195]! } - public var KeyCommand_SendMessage: String { return self._s[3197]! } + public var Undo_SecretChatDeleted: String { return self._s[3194]! } + public var PhotoEditor_ContrastTool: String { return self._s[3195]! } + public var Privacy_Forwards: String { return self._s[3196]! } + public var AuthSessions_LoggedInWithTelegram: String { return self._s[3197]! } + public var KeyCommand_SendMessage: String { return self._s[3199]! } public func InstantPage_RelatedArticleAuthorAndDateTitle(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3198]!, self._r[3198]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3200]!, self._r[3200]!, [_1, _2]) } - public var GroupPermission_NoSendGifs: String { return self._s[3199]! } - public var Wallet_Month_ShortJune: String { return self._s[3200]! } - public var Notification_MessageLifetime2s: String { return self._s[3201]! } - public var Message_Theme: String { return self._s[3202]! } - public var Conversation_Dice_u1F3AF: String { return self._s[3205]! } + public var GroupPermission_NoSendGifs: String { return self._s[3201]! } + public var Wallet_Month_ShortJune: String { return self._s[3202]! } + public var Notification_MessageLifetime2s: String { return self._s[3203]! } + public var Message_Theme: String { return self._s[3204]! } + public var Conversation_Dice_u1F3AF: String { return self._s[3207]! } public func DialogList_SinglePlayingGameSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3206]!, self._r[3206]!, [_0]) + return formatWithArgumentRanges(self._s[3208]!, self._r[3208]!, [_0]) } - public var Group_UpgradeNoticeHeader: String { return self._s[3208]! } - public var PeerInfo_BioExpand: String { return self._s[3209]! } - public var Passport_DeletePersonalDetails: String { return self._s[3210]! } - public var Widget_NoUsers: String { return self._s[3211]! } - public var TwoStepAuth_AddHintTitle: String { return self._s[3212]! } - public var Login_TermsOfServiceDecline: String { return self._s[3213]! } - public var CreatePoll_QuizTip: String { return self._s[3215]! } - public var Watch_LastSeen_WithinAWeek: String { return self._s[3216]! } - public var MessagePoll_SubmitVote: String { return self._s[3218]! } - public var ChatSettings_AutoDownloadEnabled: String { return self._s[3219]! } - public var Passport_Address_EditRentalAgreement: String { return self._s[3220]! } - public var Conversation_SearchByName_Placeholder: String { return self._s[3221]! } - public var Conversation_UpdateTelegram: String { return self._s[3222]! } + public var Group_UpgradeNoticeHeader: String { return self._s[3210]! } + public var PeerInfo_BioExpand: String { return self._s[3211]! } + public var Passport_DeletePersonalDetails: String { return self._s[3212]! } + public var Widget_NoUsers: String { return self._s[3213]! } + public var TwoStepAuth_AddHintTitle: String { return self._s[3214]! } + public var Login_TermsOfServiceDecline: String { return self._s[3215]! } + public var CreatePoll_QuizTip: String { return self._s[3217]! } + public var Watch_LastSeen_WithinAWeek: String { return self._s[3218]! } + public var MessagePoll_SubmitVote: String { return self._s[3220]! } + public var ChatSettings_AutoDownloadEnabled: String { return self._s[3221]! } + public var Passport_Address_EditRentalAgreement: String { return self._s[3222]! } + public var Conversation_SearchByName_Placeholder: String { return self._s[3223]! } + public var Conversation_UpdateTelegram: String { return self._s[3224]! } public func FileSize_KB(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3223]!, self._r[3223]!, [_0]) + return formatWithArgumentRanges(self._s[3225]!, self._r[3225]!, [_0]) } - public var UserInfo_About_Placeholder: String { return self._s[3224]! } - public var CallSettings_Always: String { return self._s[3225]! } - public var ChannelInfo_ScamChannelWarning: String { return self._s[3226]! } - public var Login_TermsOfServiceHeader: String { return self._s[3227]! } - public var KeyCommand_ChatInfo: String { return self._s[3228]! } - public var MessagePoll_LabelPoll: String { return self._s[3229]! } - public var Paint_Clear: String { return self._s[3230]! } - public var PeerInfo_ButtonMute: String { return self._s[3231]! } - public var LastSeen_WithinAWeek: String { return self._s[3232]! } - public var Passport_Identity_FrontSide: String { return self._s[3233]! } - public var Stickers_GroupStickers: String { return self._s[3234]! } - public var ChangePhoneNumberNumber_NumberPlaceholder: String { return self._s[3235]! } + public var UserInfo_About_Placeholder: String { return self._s[3226]! } + public var CallSettings_Always: String { return self._s[3227]! } + public var ChannelInfo_ScamChannelWarning: String { return self._s[3228]! } + public var Login_TermsOfServiceHeader: String { return self._s[3229]! } + public var KeyCommand_ChatInfo: String { return self._s[3230]! } + public var MessagePoll_LabelPoll: String { return self._s[3231]! } + public var Paint_Clear: String { return self._s[3232]! } + public var PeerInfo_ButtonMute: String { return self._s[3233]! } + public var LastSeen_WithinAWeek: String { return self._s[3234]! } + public var Passport_Identity_FrontSide: String { return self._s[3235]! } + public var Stickers_GroupStickers: String { return self._s[3236]! } + public var ChangePhoneNumberNumber_NumberPlaceholder: String { return self._s[3237]! } public func Map_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3236]!, self._r[3236]!, [_0]) + return formatWithArgumentRanges(self._s[3238]!, self._r[3238]!, [_0]) } public func PUSH_MESSAGE_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3239]!, self._r[3239]!, [_1]) + return formatWithArgumentRanges(self._s[3241]!, self._r[3241]!, [_1]) } - public var SocksProxySetup_ProxyStatusConnected: String { return self._s[3240]! } - public var Chat_MultipleTextMessagesDisabled: String { return self._s[3241]! } + public var SocksProxySetup_ProxyStatusConnected: String { return self._s[3242]! } + public var Chat_MultipleTextMessagesDisabled: String { return self._s[3243]! } public func Notification_LeftChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3242]!, self._r[3242]!, [_0]) + return formatWithArgumentRanges(self._s[3244]!, self._r[3244]!, [_0]) } - public var Wallet_Send_AmountText: String { return self._s[3243]! } - public var WebSearch_SearchNoResults: String { return self._s[3245]! } - public var Channel_DiscussionGroup_Create: String { return self._s[3246]! } - public var Passport_Language_es: String { return self._s[3247]! } - public var EnterPasscode_EnterCurrentPasscode: String { return self._s[3248]! } - public var Wallet_Intro_Title: String { return self._s[3249]! } - public var Map_LiveLocationShowAll: String { return self._s[3250]! } - public var Cache_MaximumCacheSizeHelp: String { return self._s[3252]! } - public var Map_OpenInGoogleMaps: String { return self._s[3253]! } - public var CheckoutInfo_ErrorNameInvalid: String { return self._s[3255]! } - public var EditTheme_Create_BottomInfo: String { return self._s[3256]! } - public var PhotoEditor_BlurToolLinear: String { return self._s[3257]! } + public var Wallet_Send_AmountText: String { return self._s[3245]! } + public var WebSearch_SearchNoResults: String { return self._s[3247]! } + public var Channel_DiscussionGroup_Create: String { return self._s[3248]! } + public var Passport_Language_es: String { return self._s[3249]! } + public var EnterPasscode_EnterCurrentPasscode: String { return self._s[3250]! } + public var Wallet_Intro_Title: String { return self._s[3251]! } + public var Map_LiveLocationShowAll: String { return self._s[3252]! } + public var Cache_MaximumCacheSizeHelp: String { return self._s[3254]! } + public var Map_OpenInGoogleMaps: String { return self._s[3255]! } + public var CheckoutInfo_ErrorNameInvalid: String { return self._s[3257]! } + public var EditTheme_Create_BottomInfo: String { return self._s[3258]! } + public var PhotoEditor_BlurToolLinear: String { return self._s[3259]! } public func Channel_AdminLog_MessageEdited(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3258]!, self._r[3258]!, [_0]) + return formatWithArgumentRanges(self._s[3260]!, self._r[3260]!, [_0]) } - public var Passport_Phone_Delete: String { return self._s[3259]! } - public var Channel_Username_CreatePrivateLinkHelp: String { return self._s[3260]! } - public var PrivacySettings_PrivacyTitle: String { return self._s[3261]! } - public var CheckoutInfo_ReceiverInfoNamePlaceholder: String { return self._s[3262]! } + public var Passport_Phone_Delete: String { return self._s[3261]! } + public var Channel_Username_CreatePrivateLinkHelp: String { return self._s[3262]! } + public var PrivacySettings_PrivacyTitle: String { return self._s[3263]! } + public var CheckoutInfo_ReceiverInfoNamePlaceholder: String { return self._s[3264]! } public func EncryptionKey_Description(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3263]!, self._r[3263]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3265]!, self._r[3265]!, [_1, _2]) } - public var LogoutOptions_LogOutInfo: String { return self._s[3264]! } - public var Wallet_Month_GenAugust: String { return self._s[3265]! } - public var Cache_ByPeerHeader: String { return self._s[3266]! } - public var Username_InvalidCharacters: String { return self._s[3267]! } - public var Wallet_Qr_Title: String { return self._s[3269]! } - public var Checkout_ShippingAddress: String { return self._s[3270]! } + public var LogoutOptions_LogOutInfo: String { return self._s[3266]! } + public var Wallet_Month_GenAugust: String { return self._s[3267]! } + public var Cache_ByPeerHeader: String { return self._s[3268]! } + public var Username_InvalidCharacters: String { return self._s[3269]! } + public var Wallet_Qr_Title: String { return self._s[3271]! } + public var Checkout_ShippingAddress: String { return self._s[3272]! } public func PUSH_CHAT_MESSAGE_GAME_SCORE(_ _1: String, _ _2: String, _ _3: String, _ _4: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3271]!, self._r[3271]!, [_1, _2, _3, _4]) + return formatWithArgumentRanges(self._s[3273]!, self._r[3273]!, [_1, _2, _3, _4]) } - public var Conversation_AddContact: String { return self._s[3273]! } - public var Passport_Address_EditUtilityBill: String { return self._s[3274]! } - public var Message_Video: String { return self._s[3275]! } + public var Conversation_AddContact: String { return self._s[3275]! } + public var Passport_Address_EditUtilityBill: String { return self._s[3276]! } + public var Message_Video: String { return self._s[3277]! } public func Watch_Time_ShortYesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3276]!, self._r[3276]!, [_0]) + return formatWithArgumentRanges(self._s[3278]!, self._r[3278]!, [_0]) } public func Conversation_Megabytes(_ _0: Float) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3277]!, self._r[3277]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[3279]!, self._r[3279]!, ["\(_0)"]) } - public var Passport_Language_km: String { return self._s[3278]! } + public var Passport_Language_km: String { return self._s[3280]! } public func PUSH_MESSAGE_CHANNEL_MESSAGE_GAME_SCORE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3279]!, self._r[3279]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3281]!, self._r[3281]!, [_1, _2, _3]) } - public var EmptyGroupInfo_Line4: String { return self._s[3280]! } - public var Conversation_SendMessageErrorTooMuchScheduled: String { return self._s[3282]! } - public var Notification_CallCanceledShort: String { return self._s[3283]! } - public var PhotoEditor_FadeTool: String { return self._s[3284]! } - public var Group_PublicLink_Info: String { return self._s[3285]! } - public var Contacts_DeselectAll: String { return self._s[3286]! } - public var Conversation_Moderate_Delete: String { return self._s[3287]! } - public var TwoStepAuth_RecoveryCodeInvalid: String { return self._s[3288]! } - public var NotificationsSound_Note: String { return self._s[3291]! } + public var EmptyGroupInfo_Line4: String { return self._s[3282]! } + public var Conversation_SendMessageErrorTooMuchScheduled: String { return self._s[3284]! } + public var Notification_CallCanceledShort: String { return self._s[3285]! } + public var PhotoEditor_FadeTool: String { return self._s[3286]! } + public var Group_PublicLink_Info: String { return self._s[3287]! } + public var Contacts_DeselectAll: String { return self._s[3288]! } + public var Conversation_Moderate_Delete: String { return self._s[3289]! } + public var TwoStepAuth_RecoveryCodeInvalid: String { return self._s[3290]! } + public var NotificationsSound_Note: String { return self._s[3293]! } public func Message_PaymentSent(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3292]!, self._r[3292]!, [_0]) + return formatWithArgumentRanges(self._s[3294]!, self._r[3294]!, [_0]) } - public var Appearance_ThemePreview_ChatList_7_Text: String { return self._s[3293]! } - public var Channel_EditAdmin_PermissionInviteViaLink: String { return self._s[3294]! } - public var DialogList_SearchSectionGlobal: String { return self._s[3295]! } - public var AccessDenied_Settings: String { return self._s[3296]! } - public var Passport_Identity_TypeIdentityCardUploadScan: String { return self._s[3297]! } - public var AuthSessions_EmptyTitle: String { return self._s[3298]! } - public var TwoStepAuth_PasswordChangeSuccess: String { return self._s[3299]! } - public var GroupInfo_GroupType: String { return self._s[3300]! } - public var Calls_Missed: String { return self._s[3301]! } - public var UserInfo_GenericPhoneLabel: String { return self._s[3302]! } - public var Passport_Language_uz: String { return self._s[3303]! } - public var Conversation_StopQuizConfirmationTitle: String { return self._s[3304]! } - public var PhotoEditor_BlurToolPortrait: String { return self._s[3305]! } - public var Map_ChooseLocationTitle: String { return self._s[3306]! } - public var Checkout_EnterPassword: String { return self._s[3307]! } - public var GroupInfo_ConvertToSupergroup: String { return self._s[3308]! } - public var AutoNightTheme_UpdateLocation: String { return self._s[3309]! } - public var NetworkUsageSettings_Title: String { return self._s[3310]! } - public var Location_ProximityAlertCancelled: String { return self._s[3311]! } - public var SettingsSearch_Synonyms_ChatSettings_IntentsSettings: String { return self._s[3312]! } - public var Message_PinnedLiveLocationMessage: String { return self._s[3313]! } - public var Compose_NewChannel: String { return self._s[3314]! } - public var Privacy_PaymentsClearInfo: String { return self._s[3316]! } + public var Appearance_ThemePreview_ChatList_7_Text: String { return self._s[3295]! } + public var Channel_EditAdmin_PermissionInviteViaLink: String { return self._s[3296]! } + public var DialogList_SearchSectionGlobal: String { return self._s[3297]! } + public var AccessDenied_Settings: String { return self._s[3298]! } + public var Passport_Identity_TypeIdentityCardUploadScan: String { return self._s[3299]! } + public var AuthSessions_EmptyTitle: String { return self._s[3300]! } + public var TwoStepAuth_PasswordChangeSuccess: String { return self._s[3301]! } + public var GroupInfo_GroupType: String { return self._s[3302]! } + public var Calls_Missed: String { return self._s[3303]! } + public var UserInfo_GenericPhoneLabel: String { return self._s[3304]! } + public var Passport_Language_uz: String { return self._s[3305]! } + public var Conversation_StopQuizConfirmationTitle: String { return self._s[3306]! } + public var PhotoEditor_BlurToolPortrait: String { return self._s[3307]! } + public var Map_ChooseLocationTitle: String { return self._s[3308]! } + public var Checkout_EnterPassword: String { return self._s[3309]! } + public var GroupInfo_ConvertToSupergroup: String { return self._s[3310]! } + public var AutoNightTheme_UpdateLocation: String { return self._s[3311]! } + public var NetworkUsageSettings_Title: String { return self._s[3312]! } + public var Location_ProximityAlertCancelled: String { return self._s[3313]! } + public var SettingsSearch_Synonyms_ChatSettings_IntentsSettings: String { return self._s[3314]! } + public var Message_PinnedLiveLocationMessage: String { return self._s[3315]! } + public var Compose_NewChannel: String { return self._s[3316]! } + public var Privacy_PaymentsClearInfo: String { return self._s[3318]! } public func PUSH_MESSAGE_POLL(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3317]!, self._r[3317]!, [_1]) + return formatWithArgumentRanges(self._s[3319]!, self._r[3319]!, [_1]) } - public var Notification_Exceptions_AlwaysOn: String { return self._s[3318]! } - public var Privacy_GroupsAndChannels_WhoCanAddMe: String { return self._s[3319]! } - public var AutoNightTheme_AutomaticSection: String { return self._s[3322]! } - public var WallpaperSearch_ColorBrown: String { return self._s[3323]! } - public var Appearance_AppIconDefault: String { return self._s[3324]! } - public var Wallet_Month_GenJune: String { return self._s[3327]! } - public var StickerSettings_ContextInfo: String { return self._s[3328]! } - public var Channel_AddBotErrorNoRights: String { return self._s[3329]! } - public var Passport_FieldPhone: String { return self._s[3331]! } - public var Contacts_PermissionsTitle: String { return self._s[3332]! } - public var TwoFactorSetup_Email_SkipConfirmationSkip: String { return self._s[3333]! } + public var Notification_Exceptions_AlwaysOn: String { return self._s[3320]! } + public var Privacy_GroupsAndChannels_WhoCanAddMe: String { return self._s[3321]! } + public var AutoNightTheme_AutomaticSection: String { return self._s[3324]! } + public var WallpaperSearch_ColorBrown: String { return self._s[3325]! } + public var Appearance_AppIconDefault: String { return self._s[3326]! } + public var Wallet_Month_GenJune: String { return self._s[3329]! } + public var StickerSettings_ContextInfo: String { return self._s[3330]! } + public var Channel_AddBotErrorNoRights: String { return self._s[3331]! } + public var Passport_FieldPhone: String { return self._s[3333]! } + public var Contacts_PermissionsTitle: String { return self._s[3334]! } + public var TwoFactorSetup_Email_SkipConfirmationSkip: String { return self._s[3335]! } public func Notification_JoinedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3334]!, self._r[3334]!, [_0]) + return formatWithArgumentRanges(self._s[3336]!, self._r[3336]!, [_0]) } - public var Bot_Unblock: String { return self._s[3335]! } - public var PasscodeSettings_SimplePasscode: String { return self._s[3336]! } - public var Passport_PasswordHelp: String { return self._s[3337]! } - public var Watch_Conversation_UserInfo: String { return self._s[3338]! } + public var Bot_Unblock: String { return self._s[3337]! } + public var PasscodeSettings_SimplePasscode: String { return self._s[3338]! } + public var Passport_PasswordHelp: String { return self._s[3339]! } + public var Watch_Conversation_UserInfo: String { return self._s[3340]! } public func Channel_AdminLog_MessageChangedGroupGeoLocation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3342]!, self._r[3342]!, [_0]) + return formatWithArgumentRanges(self._s[3344]!, self._r[3344]!, [_0]) } - public var State_Connecting: String { return self._s[3344]! } - public var Passport_Address_TypeTemporaryRegistration: String { return self._s[3345]! } - public var TextFormat_AddLinkPlaceholder: String { return self._s[3346]! } - public var Conversation_Dice_u1F3B2: String { return self._s[3347]! } + public var State_Connecting: String { return self._s[3346]! } + public var Passport_Address_TypeTemporaryRegistration: String { return self._s[3347]! } + public var TextFormat_AddLinkPlaceholder: String { return self._s[3348]! } + public var Conversation_Dice_u1F3B2: String { return self._s[3349]! } public func Call_StatusBar(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3348]!, self._r[3348]!, [_0]) + return formatWithArgumentRanges(self._s[3350]!, self._r[3350]!, [_0]) } - public var Conversation_SendingOptionsTooltip: String { return self._s[3349]! } - public var ChatList_UndoArchiveTitle: String { return self._s[3350]! } - public var ChatList_EmptyChatListNewMessage: String { return self._s[3351]! } - public var WallpaperSearch_ColorGreen: String { return self._s[3353]! } - public var PhotoEditor_BlurToolOff: String { return self._s[3354]! } - public var SocksProxySetup_PortPlaceholder: String { return self._s[3355]! } - public var Weekday_Saturday: String { return self._s[3356]! } - public var DialogList_Unread: String { return self._s[3357]! } - public var Watch_LastSeen_ALongTimeAgo: String { return self._s[3358]! } - public var Stats_GroupPosters: String { return self._s[3359]! } + public var Conversation_SendingOptionsTooltip: String { return self._s[3351]! } + public var ChatList_UndoArchiveTitle: String { return self._s[3352]! } + public var ChatList_EmptyChatListNewMessage: String { return self._s[3353]! } + public var WallpaperSearch_ColorGreen: String { return self._s[3355]! } + public var PhotoEditor_BlurToolOff: String { return self._s[3356]! } + public var SocksProxySetup_PortPlaceholder: String { return self._s[3357]! } + public var Weekday_Saturday: String { return self._s[3358]! } + public var DialogList_Unread: String { return self._s[3359]! } + public var Watch_LastSeen_ALongTimeAgo: String { return self._s[3360]! } + public var Stats_GroupPosters: String { return self._s[3361]! } public func PUSH_ENCRYPTION_REQUEST(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3360]!, self._r[3360]!, [_1]) + return formatWithArgumentRanges(self._s[3362]!, self._r[3362]!, [_1]) } public func Target_ShareGameConfirmationGroup(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3363]!, self._r[3363]!, [_0]) + return formatWithArgumentRanges(self._s[3365]!, self._r[3365]!, [_0]) } - public var ReportPeer_ReasonChildAbuse: String { return self._s[3364]! } + public var ReportPeer_ReasonChildAbuse: String { return self._s[3366]! } public func Channel_AdminLog_MessageUnkickedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3365]!, self._r[3365]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3367]!, self._r[3367]!, [_1, _2]) } - public var InfoPlist_NSContactsUsageDescription: String { return self._s[3366]! } - public var AutoNightTheme_UseSunsetSunrise: String { return self._s[3368]! } - public var Channel_OwnershipTransfer_ChangeOwner: String { return self._s[3369]! } - public var Passport_Language_dv: String { return self._s[3370]! } - public var GroupPermission_AddSuccess: String { return self._s[3373]! } - public var Passport_Email_Help: String { return self._s[3374]! } - public var Call_ReportPlaceholder: String { return self._s[3375]! } - public var CreatePoll_AddOption: String { return self._s[3376]! } - public var MessagePoll_LabelAnonymousQuiz: String { return self._s[3377]! } - public var PeerInfo_ButtonLeave: String { return self._s[3378]! } - public var PhotoEditor_TiltShift: String { return self._s[3381]! } - public var SecretGif_Title: String { return self._s[3383]! } - public var PhotoEditor_QualityVeryLow: String { return self._s[3384]! } - public var SocksProxySetup_Connecting: String { return self._s[3385]! } - public var PrivacySettings_PasscodeAndFaceId: String { return self._s[3386]! } - public var ContactInfo_PhoneLabelWork: String { return self._s[3387]! } - public var Stats_GroupTopHoursTitle: String { return self._s[3388]! } - public var Compose_NewMessage: String { return self._s[3389]! } - public var NotificationsSound_Synth: String { return self._s[3390]! } - public var Conversation_FileOpenIn: String { return self._s[3391]! } - public var AutoDownloadSettings_WifiTitle: String { return self._s[3392]! } - public var UserInfo_SendMessage: String { return self._s[3393]! } - public var Checkout_PayWithFaceId: String { return self._s[3394]! } + public var InfoPlist_NSContactsUsageDescription: String { return self._s[3368]! } + public var AutoNightTheme_UseSunsetSunrise: String { return self._s[3370]! } + public var Channel_OwnershipTransfer_ChangeOwner: String { return self._s[3371]! } + public var Passport_Language_dv: String { return self._s[3372]! } + public var GroupPermission_AddSuccess: String { return self._s[3375]! } + public var Passport_Email_Help: String { return self._s[3376]! } + public var Call_ReportPlaceholder: String { return self._s[3377]! } + public var CreatePoll_AddOption: String { return self._s[3378]! } + public var MessagePoll_LabelAnonymousQuiz: String { return self._s[3379]! } + public var PeerInfo_ButtonLeave: String { return self._s[3380]! } + public var PhotoEditor_TiltShift: String { return self._s[3383]! } + public var SecretGif_Title: String { return self._s[3385]! } + public var PhotoEditor_QualityVeryLow: String { return self._s[3386]! } + public var SocksProxySetup_Connecting: String { return self._s[3387]! } + public var PrivacySettings_PasscodeAndFaceId: String { return self._s[3388]! } + public var ContactInfo_PhoneLabelWork: String { return self._s[3389]! } + public var Stats_GroupTopHoursTitle: String { return self._s[3390]! } + public var Compose_NewMessage: String { return self._s[3391]! } + public var NotificationsSound_Synth: String { return self._s[3392]! } + public var Conversation_FileOpenIn: String { return self._s[3393]! } + public var AutoDownloadSettings_WifiTitle: String { return self._s[3394]! } + public var UserInfo_SendMessage: String { return self._s[3395]! } + public var Checkout_PayWithFaceId: String { return self._s[3396]! } public func Map_LiveLocationShortHour(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3395]!, self._r[3395]!, [_0]) + return formatWithArgumentRanges(self._s[3397]!, self._r[3397]!, [_0]) } - public var TextFormat_Strikethrough: String { return self._s[3396]! } - public var SettingsSearch_Synonyms_Notifications_DisplayNamesOnLockScreen: String { return self._s[3397]! } - public var Conversation_ViewChannel: String { return self._s[3398]! } + public var TextFormat_Strikethrough: String { return self._s[3398]! } + public var SettingsSearch_Synonyms_Notifications_DisplayNamesOnLockScreen: String { return self._s[3399]! } + public var Conversation_ViewChannel: String { return self._s[3400]! } public func Message_ForwardedMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3399]!, self._r[3399]!, [_0]) + return formatWithArgumentRanges(self._s[3401]!, self._r[3401]!, [_0]) } - public var Channel_Stickers_Placeholder: String { return self._s[3400]! } - public var Channel_OwnershipTransfer_PasswordPlaceholder: String { return self._s[3401]! } - public var Camera_FlashAuto: String { return self._s[3402]! } - public var Conversation_EncryptedDescription1: String { return self._s[3403]! } - public var LocalGroup_Text: String { return self._s[3404]! } - public var SettingsSearch_Synonyms_Data_Storage_KeepMedia: String { return self._s[3405]! } - public var UserInfo_FirstNamePlaceholder: String { return self._s[3406]! } - public var Conversation_SendMessageErrorFlood: String { return self._s[3407]! } - public var Conversation_EncryptedDescription2: String { return self._s[3408]! } - public var Notification_GroupActivated: String { return self._s[3409]! } - public var LastSeen_Lately: String { return self._s[3410]! } - public var Conversation_EncryptedDescription3: String { return self._s[3411]! } - public var SettingsSearch_Synonyms_Privacy_ProfilePhoto: String { return self._s[3412]! } - public var Conversation_SwipeToReplyHintText: String { return self._s[3413]! } - public var Conversation_EncryptedDescription4: String { return self._s[3414]! } - public var SharedMedia_EmptyTitle: String { return self._s[3415]! } - public var Wallet_Configuration_Apply: String { return self._s[3416]! } - public var Appearance_CreateTheme: String { return self._s[3417]! } - public var Stats_SharesPerPost: String { return self._s[3418]! } - public var Contacts_TabTitle: String { return self._s[3419]! } - public var Weekday_ShortThursday: String { return self._s[3420]! } - public var MessageTimer_Forever: String { return self._s[3421]! } - public var ChatListFolder_CategoryArchived: String { return self._s[3422]! } - public var Channel_EditAdmin_PermissionDeleteMessages: String { return self._s[3423]! } - public var EditTheme_Create_TopInfo: String { return self._s[3425]! } - public var Month_GenDecember: String { return self._s[3426]! } - public var EnterPasscode_EnterPasscode: String { return self._s[3427]! } - public var SettingsSearch_Synonyms_Appearance_LargeEmoji: String { return self._s[3428]! } - public var PeopleNearby_CreateGroup: String { return self._s[3430]! } - public var Group_EditAdmin_PermissionChangeInfo: String { return self._s[3431]! } - public var Paint_ClearConfirm: String { return self._s[3432]! } - public var ChatList_ReadAll: String { return self._s[3433]! } - public var ChatSettings_IntentsSettings: String { return self._s[3434]! } - public var Passport_PassportInformation: String { return self._s[3436]! } - public var Login_CheckOtherSessionMessages: String { return self._s[3438]! } - public var Location_ProximityNotification_DistanceMI: String { return self._s[3441]! } - public var PhotoEditor_ExposureTool: String { return self._s[3442]! } - public var Group_Username_CreatePrivateLinkHelp: String { return self._s[3443]! } - public var SettingsSearch_Synonyms_Watch: String { return self._s[3444]! } - public var Stats_GroupTopPoster_History: String { return self._s[3445]! } - public var UserInfo_AddPhone: String { return self._s[3446]! } - public var Media_SendWithTimer: String { return self._s[3448]! } - public var SettingsSearch_Synonyms_Notifications_Title: String { return self._s[3449]! } - public var Channel_EditAdmin_PermissionEnabledByDefault: String { return self._s[3450]! } - public var PasscodeSettings_AutoLock_Disabled: String { return self._s[3451]! } - public var ChatList_Context_Unarchive: String { return self._s[3453]! } + public var Channel_Stickers_Placeholder: String { return self._s[3402]! } + public var Channel_OwnershipTransfer_PasswordPlaceholder: String { return self._s[3403]! } + public var Camera_FlashAuto: String { return self._s[3404]! } + public var Conversation_EncryptedDescription1: String { return self._s[3405]! } + public var LocalGroup_Text: String { return self._s[3406]! } + public var SettingsSearch_Synonyms_Data_Storage_KeepMedia: String { return self._s[3407]! } + public var UserInfo_FirstNamePlaceholder: String { return self._s[3408]! } + public var Conversation_SendMessageErrorFlood: String { return self._s[3409]! } + public var Conversation_EncryptedDescription2: String { return self._s[3410]! } + public var Notification_GroupActivated: String { return self._s[3411]! } + public var LastSeen_Lately: String { return self._s[3412]! } + public var Conversation_EncryptedDescription3: String { return self._s[3413]! } + public var SettingsSearch_Synonyms_Privacy_ProfilePhoto: String { return self._s[3414]! } + public var Conversation_SwipeToReplyHintText: String { return self._s[3415]! } + public var Conversation_EncryptedDescription4: String { return self._s[3416]! } + public var SharedMedia_EmptyTitle: String { return self._s[3417]! } + public var Wallet_Configuration_Apply: String { return self._s[3418]! } + public var Appearance_CreateTheme: String { return self._s[3419]! } + public var Stats_SharesPerPost: String { return self._s[3420]! } + public var Contacts_TabTitle: String { return self._s[3421]! } + public var Weekday_ShortThursday: String { return self._s[3422]! } + public var MessageTimer_Forever: String { return self._s[3423]! } + public var ChatListFolder_CategoryArchived: String { return self._s[3424]! } + public var Channel_EditAdmin_PermissionDeleteMessages: String { return self._s[3425]! } + public var EditTheme_Create_TopInfo: String { return self._s[3427]! } + public var Month_GenDecember: String { return self._s[3428]! } + public var EnterPasscode_EnterPasscode: String { return self._s[3429]! } + public var SettingsSearch_Synonyms_Appearance_LargeEmoji: String { return self._s[3430]! } + public var PeopleNearby_CreateGroup: String { return self._s[3432]! } + public var Group_EditAdmin_PermissionChangeInfo: String { return self._s[3433]! } + public var Paint_ClearConfirm: String { return self._s[3434]! } + public var ChatList_ReadAll: String { return self._s[3435]! } + public var ChatSettings_IntentsSettings: String { return self._s[3436]! } + public var Passport_PassportInformation: String { return self._s[3438]! } + public var Login_CheckOtherSessionMessages: String { return self._s[3440]! } + public var Location_ProximityNotification_DistanceMI: String { return self._s[3443]! } + public var PhotoEditor_ExposureTool: String { return self._s[3444]! } + public var Group_Username_CreatePrivateLinkHelp: String { return self._s[3445]! } + public var SettingsSearch_Synonyms_Watch: String { return self._s[3446]! } + public var Stats_GroupTopPoster_History: String { return self._s[3447]! } + public var UserInfo_AddPhone: String { return self._s[3448]! } + public var Media_SendWithTimer: String { return self._s[3450]! } + public var SettingsSearch_Synonyms_Notifications_Title: String { return self._s[3451]! } + public var Channel_EditAdmin_PermissionEnabledByDefault: String { return self._s[3452]! } + public var PasscodeSettings_AutoLock_Disabled: String { return self._s[3453]! } + public var ChatList_Context_Unarchive: String { return self._s[3455]! } public func DialogList_LiveLocationSharingTo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3454]!, self._r[3454]!, [_0]) + return formatWithArgumentRanges(self._s[3456]!, self._r[3456]!, [_0]) } - public var BlockedUsers_Title: String { return self._s[3456]! } - public var TwoStepAuth_EmailPlaceholder: String { return self._s[3457]! } - public var Media_ShareThisPhoto: String { return self._s[3458]! } - public var Notifications_DisplayNamesOnLockScreen: String { return self._s[3459]! } - public var Conversation_FilePhotoOrVideo: String { return self._s[3460]! } - public var Appearance_ThemePreview_Chat_2_ReplyName: String { return self._s[3464]! } + public var BlockedUsers_Title: String { return self._s[3458]! } + public var TwoStepAuth_EmailPlaceholder: String { return self._s[3459]! } + public var Media_ShareThisPhoto: String { return self._s[3460]! } + public var Notifications_DisplayNamesOnLockScreen: String { return self._s[3461]! } + public var Conversation_FilePhotoOrVideo: String { return self._s[3462]! } + public var Appearance_ThemePreview_Chat_2_ReplyName: String { return self._s[3466]! } public func PUSH_CHAT_MESSAGE_DOCS(_ _1: String, _ _2: String, _ _3: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3465]!, self._r[3465]!, [_1, _2, "\(_3)"]) + return formatWithArgumentRanges(self._s[3467]!, self._r[3467]!, [_1, _2, "\(_3)"]) } - public var CallFeedback_ReasonNoise: String { return self._s[3466]! } - public var WebBrowser_Title: String { return self._s[3468]! } + public var CallFeedback_ReasonNoise: String { return self._s[3468]! } + public var WebBrowser_Title: String { return self._s[3470]! } public func Checkout_SavePasswordTimeoutAndTouchId(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3469]!, self._r[3469]!, [_0]) + return formatWithArgumentRanges(self._s[3471]!, self._r[3471]!, [_0]) } - public var Notification_MessageLifetime5s: String { return self._s[3470]! } - public var Passport_Address_AddResidentialAddress: String { return self._s[3471]! } - public var Profile_MessageLifetime1m: String { return self._s[3472]! } - public var Stats_LoadingTitle: String { return self._s[3474]! } - public var Passport_ScanPassport: String { return self._s[3475]! } - public var Passport_Address_AddTemporaryRegistration: String { return self._s[3478]! } - public var Permissions_NotificationsAllow_v0: String { return self._s[3479]! } - public var Login_InvalidFirstNameError: String { return self._s[3480]! } - public var Undo_ChatCleared: String { return self._s[3482]! } + public var Notification_MessageLifetime5s: String { return self._s[3472]! } + public var Passport_Address_AddResidentialAddress: String { return self._s[3473]! } + public var Profile_MessageLifetime1m: String { return self._s[3474]! } + public var Stats_LoadingTitle: String { return self._s[3476]! } + public var Passport_ScanPassport: String { return self._s[3477]! } + public var Passport_Address_AddTemporaryRegistration: String { return self._s[3480]! } + public var Permissions_NotificationsAllow_v0: String { return self._s[3481]! } + public var Login_InvalidFirstNameError: String { return self._s[3482]! } + public var Undo_ChatCleared: String { return self._s[3484]! } public func ApplyLanguage_ChangeLanguageUnofficialText(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3484]!, self._r[3484]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3486]!, self._r[3486]!, [_1, _2]) } - public var Conversation_PinMessageAlertPin: String { return self._s[3485]! } + public var Conversation_PinMessageAlertPin: String { return self._s[3487]! } public func Login_PhoneBannedEmailBody(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3486]!, self._r[3486]!, [_1, _2, _3, _4, _5]) + return formatWithArgumentRanges(self._s[3488]!, self._r[3488]!, [_1, _2, _3, _4, _5]) } public func PUSH_MESSAGE_FWD(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3487]!, self._r[3487]!, [_1]) + return formatWithArgumentRanges(self._s[3489]!, self._r[3489]!, [_1]) } - public var Share_MultipleMessagesDisabled: String { return self._s[3488]! } - public var TwoStepAuth_EmailInvalid: String { return self._s[3489]! } - public var EnterPasscode_ChangeTitle: String { return self._s[3491]! } + public var Share_MultipleMessagesDisabled: String { return self._s[3490]! } + public var TwoStepAuth_EmailInvalid: String { return self._s[3491]! } + public var EnterPasscode_ChangeTitle: String { return self._s[3493]! } public func Wallet_Send_ConfirmationText(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3492]!, self._r[3492]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3494]!, self._r[3494]!, [_1, _2, _3]) } - public var CallSettings_RecentCalls: String { return self._s[3493]! } - public var GroupInfo_DeactivatedStatus: String { return self._s[3494]! } - public var AuthSessions_OtherSessions: String { return self._s[3495]! } - public var PrivacyLastSeenSettings_CustomHelp: String { return self._s[3496]! } - public var Tour_Text5: String { return self._s[3497]! } - public var Login_PadPhoneHelp: String { return self._s[3498]! } - public var Wallpaper_PhotoLibrary: String { return self._s[3500]! } - public var Conversation_ViewGroup: String { return self._s[3501]! } - public var PeopleNearby_MakeVisibleTitle: String { return self._s[3503]! } - public var VoiceOver_Chat_YourContact: String { return self._s[3504]! } - public var Watch_AuthRequired: String { return self._s[3505]! } - public var VoiceOver_Chat_ForwardedFromYou: String { return self._s[3506]! } - public var Conversation_ForwardContacts: String { return self._s[3507]! } - public var Conversation_InputTextPlaceholder: String { return self._s[3508]! } + public var CallSettings_RecentCalls: String { return self._s[3495]! } + public var GroupInfo_DeactivatedStatus: String { return self._s[3496]! } + public var AuthSessions_OtherSessions: String { return self._s[3497]! } + public var PrivacyLastSeenSettings_CustomHelp: String { return self._s[3498]! } + public var Tour_Text5: String { return self._s[3499]! } + public var Login_PadPhoneHelp: String { return self._s[3500]! } + public var Wallpaper_PhotoLibrary: String { return self._s[3502]! } + public var Conversation_ViewGroup: String { return self._s[3503]! } + public var PeopleNearby_MakeVisibleTitle: String { return self._s[3505]! } + public var VoiceOver_Chat_YourContact: String { return self._s[3506]! } + public var Watch_AuthRequired: String { return self._s[3507]! } + public var VoiceOver_Chat_ForwardedFromYou: String { return self._s[3508]! } + public var Conversation_ForwardContacts: String { return self._s[3509]! } + public var Conversation_InputTextPlaceholder: String { return self._s[3510]! } public func PUSH_CHANNEL_MESSAGE_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3509]!, self._r[3509]!, [_1]) + return formatWithArgumentRanges(self._s[3511]!, self._r[3511]!, [_1]) } public func Conversation_MessageViaUser(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3510]!, self._r[3510]!, [_0]) - } - public var Channel_Setup_TypePrivate: String { return self._s[3511]! } - public func Conversation_NoticeInvitedByInChannel(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3512]!, self._r[3512]!, [_0]) } - public var InfoPlist_NSSiriUsageDescription: String { return self._s[3513]! } - public var Wallet_ContextMenuCopy: String { return self._s[3514]! } - public var EmptyGroupInfo_Subtitle: String { return self._s[3515]! } - public var AutoDownloadSettings_Delimeter: String { return self._s[3516]! } - public var UserInfo_StartSecretChatStart: String { return self._s[3517]! } + public var Channel_Setup_TypePrivate: String { return self._s[3513]! } + public func Conversation_NoticeInvitedByInChannel(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3514]!, self._r[3514]!, [_0]) + } + public var InfoPlist_NSSiriUsageDescription: String { return self._s[3515]! } + public var Wallet_ContextMenuCopy: String { return self._s[3516]! } + public var EmptyGroupInfo_Subtitle: String { return self._s[3517]! } + public var AutoDownloadSettings_Delimeter: String { return self._s[3518]! } + public var UserInfo_StartSecretChatStart: String { return self._s[3519]! } public func GroupPermission_AddedInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3518]!, self._r[3518]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3520]!, self._r[3520]!, [_1, _2]) } public func Channel_AdminLog_MessageRestricted(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3519]!, self._r[3519]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[3521]!, self._r[3521]!, [_0, _1, _2]) } - public var PrivacySettings_AutoArchiveTitle: String { return self._s[3520]! } - public var GroupInfo_InviteLink_LinkSection: String { return self._s[3521]! } - public var FastTwoStepSetup_EmailPlaceholder: String { return self._s[3522]! } - public var Wallet_SecureStorageReset_BiometryFaceId: String { return self._s[3523]! } - public var StickerPacksSettings_ArchivedMasks: String { return self._s[3525]! } - public var NewContact_Title: String { return self._s[3528]! } - public var Appearance_ThemeCarouselTintedNight: String { return self._s[3529]! } - public var Notifications_PermissionsKeepDisabled: String { return self._s[3530]! } + public var PrivacySettings_AutoArchiveTitle: String { return self._s[3522]! } + public var GroupInfo_InviteLink_LinkSection: String { return self._s[3523]! } + public var FastTwoStepSetup_EmailPlaceholder: String { return self._s[3524]! } + public var Wallet_SecureStorageReset_BiometryFaceId: String { return self._s[3525]! } + public var StickerPacksSettings_ArchivedMasks: String { return self._s[3527]! } + public var NewContact_Title: String { return self._s[3530]! } + public var Appearance_ThemeCarouselTintedNight: String { return self._s[3531]! } + public var Notifications_PermissionsKeepDisabled: String { return self._s[3532]! } public func Time_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3531]!, self._r[3531]!, [_0]) + return formatWithArgumentRanges(self._s[3533]!, self._r[3533]!, [_0]) } public func AutoNightTheme_LocationHelp(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3532]!, self._r[3532]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3534]!, self._r[3534]!, [_0, _1]) } - public var Chat_SlowmodeTooltipPending: String { return self._s[3533]! } - public var Wallet_WordCheck_TryAgain: String { return self._s[3534]! } - public var CallFeedback_ReasonInterruption: String { return self._s[3536]! } - public var ContactInfo_PhoneLabelHome: String { return self._s[3537]! } - public var Passport_Identity_OneOfTypeDriversLicense: String { return self._s[3538]! } + public var Chat_SlowmodeTooltipPending: String { return self._s[3535]! } + public var Wallet_WordCheck_TryAgain: String { return self._s[3536]! } + public var CallFeedback_ReasonInterruption: String { return self._s[3538]! } + public var ContactInfo_PhoneLabelHome: String { return self._s[3539]! } + public var Passport_Identity_OneOfTypeDriversLicense: String { return self._s[3540]! } public func PUSH_MESSAGE_DOCS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3540]!, self._r[3540]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[3542]!, self._r[3542]!, [_1, "\(_2)"]) } - public var Conversation_MessageEditedLabel: String { return self._s[3541]! } - public var Wallet_Settings_DeleteWalletInfo: String { return self._s[3542]! } - public var SocksProxySetup_PasswordPlaceholder: String { return self._s[3543]! } - public var ChatList_Context_AddToContacts: String { return self._s[3544]! } - public var Passport_Language_is: String { return self._s[3545]! } - public var Notification_PassportValueProofOfIdentity: String { return self._s[3546]! } - public var Wallet_Month_ShortOctober: String { return self._s[3547]! } - public var PhotoEditor_CurvesBlue: String { return self._s[3548]! } + public var Conversation_MessageEditedLabel: String { return self._s[3543]! } + public var Wallet_Settings_DeleteWalletInfo: String { return self._s[3544]! } + public var SocksProxySetup_PasswordPlaceholder: String { return self._s[3545]! } + public var ChatList_Context_AddToContacts: String { return self._s[3546]! } + public var Passport_Language_is: String { return self._s[3547]! } + public var Notification_PassportValueProofOfIdentity: String { return self._s[3548]! } + public var Wallet_Month_ShortOctober: String { return self._s[3549]! } + public var PhotoEditor_CurvesBlue: String { return self._s[3550]! } public func FileSize_MB(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3549]!, self._r[3549]!, [_0]) + return formatWithArgumentRanges(self._s[3551]!, self._r[3551]!, [_0]) } - public var SocksProxySetup_Username: String { return self._s[3550]! } - public var Login_SmsRequestState3: String { return self._s[3551]! } - public var Message_PinnedVideoMessage: String { return self._s[3552]! } - public var SharedMedia_TitleLink: String { return self._s[3553]! } - public var Passport_FieldIdentity: String { return self._s[3554]! } - public var Wallet_Configuration_SourceInfo: String { return self._s[3555]! } + public var SocksProxySetup_Username: String { return self._s[3552]! } + public var Login_SmsRequestState3: String { return self._s[3553]! } + public var Message_PinnedVideoMessage: String { return self._s[3554]! } + public var SharedMedia_TitleLink: String { return self._s[3555]! } + public var Passport_FieldIdentity: String { return self._s[3556]! } + public var Wallet_Configuration_SourceInfo: String { return self._s[3557]! } public func Conversation_EncryptedPlaceholderTitleOutgoing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3559]!, self._r[3559]!, [_0]) + return formatWithArgumentRanges(self._s[3561]!, self._r[3561]!, [_0]) } - public var DialogList_ProxyConnectionIssuesTooltip: String { return self._s[3562]! } - public var ReportSpam_DeleteThisChat: String { return self._s[3563]! } - public var Checkout_NewCard_CardholderNamePlaceholder: String { return self._s[3564]! } - public var Passport_Identity_DateOfBirth: String { return self._s[3565]! } - public var Call_StatusIncoming: String { return self._s[3566]! } - public var Wallet_TransactionInfo_NoAddress: String { return self._s[3567]! } - public var ChatAdmins_AdminLabel: String { return self._s[3568]! } - public var Wallet_WordCheck_IncorrectHeader: String { return self._s[3569]! } + public var DialogList_ProxyConnectionIssuesTooltip: String { return self._s[3564]! } + public var ReportSpam_DeleteThisChat: String { return self._s[3565]! } + public var Checkout_NewCard_CardholderNamePlaceholder: String { return self._s[3566]! } + public var Passport_Identity_DateOfBirth: String { return self._s[3567]! } + public var Call_StatusIncoming: String { return self._s[3568]! } + public var Wallet_TransactionInfo_NoAddress: String { return self._s[3569]! } + public var ChatAdmins_AdminLabel: String { return self._s[3570]! } + public var Wallet_WordCheck_IncorrectHeader: String { return self._s[3571]! } public func Time_MonthOfYear_m10(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3571]!, self._r[3571]!, [_0]) + return formatWithArgumentRanges(self._s[3573]!, self._r[3573]!, [_0]) } - public var Message_PinnedAnimationMessage: String { return self._s[3572]! } - public var Conversation_ReportSpamAndLeave: String { return self._s[3573]! } - public var Preview_CopyAddress: String { return self._s[3574]! } - public var MediaPlayer_UnknownTrack: String { return self._s[3575]! } - public var Login_CancelSignUpConfirmation: String { return self._s[3576]! } - public var Map_OpenInYandexMaps: String { return self._s[3578]! } + public var Message_PinnedAnimationMessage: String { return self._s[3574]! } + public var Conversation_ReportSpamAndLeave: String { return self._s[3575]! } + public var Preview_CopyAddress: String { return self._s[3576]! } + public var MediaPlayer_UnknownTrack: String { return self._s[3577]! } + public var Login_CancelSignUpConfirmation: String { return self._s[3578]! } + public var Map_OpenInYandexMaps: String { return self._s[3580]! } public func Time_PreciseDate_m11(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3581]!, self._r[3581]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3583]!, self._r[3583]!, [_1, _2, _3]) } - public var GroupRemoved_Remove: String { return self._s[3582]! } - public var ChatListFolder_TitleCreate: String { return self._s[3583]! } + public var GroupRemoved_Remove: String { return self._s[3584]! } + public var ChatListFolder_TitleCreate: String { return self._s[3585]! } public func InstantPage_AuthorAndDateTitle(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3585]!, self._r[3585]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3587]!, self._r[3587]!, [_1, _2]) } - public var Watch_UserInfo_MuteTitle: String { return self._s[3586]! } - public var Group_UpgradeNoticeText2: String { return self._s[3588]! } - public var Stats_GroupGrowthTitle: String { return self._s[3589]! } - public var CreatePoll_CancelConfirmation: String { return self._s[3592]! } - public var Month_GenOctober: String { return self._s[3593]! } - public var Conversation_TitleCommentsEmpty: String { return self._s[3594]! } - public var Settings_Appearance: String { return self._s[3595]! } + public var Watch_UserInfo_MuteTitle: String { return self._s[3588]! } + public var Group_UpgradeNoticeText2: String { return self._s[3590]! } + public var Stats_GroupGrowthTitle: String { return self._s[3591]! } + public var CreatePoll_CancelConfirmation: String { return self._s[3594]! } + public var Month_GenOctober: String { return self._s[3595]! } + public var Conversation_TitleCommentsEmpty: String { return self._s[3596]! } + public var Settings_Appearance: String { return self._s[3597]! } public func Time_MonthOfYear_m6(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3596]!, self._r[3596]!, [_0]) + return formatWithArgumentRanges(self._s[3598]!, self._r[3598]!, [_0]) } - public var Wallet_Completed_Title: String { return self._s[3597]! } - public var UserInfo_AddToExisting: String { return self._s[3598]! } - public var Call_PhoneCallInProgressMessage: String { return self._s[3599]! } - public var Map_HomeAndWorkInfo: String { return self._s[3600]! } - public var Paint_Arrow: String { return self._s[3601]! } - public var CancelResetAccount_Title: String { return self._s[3602]! } - public var NotificationsSound_Circles: String { return self._s[3603]! } - public var Notifications_GroupNotificationsExceptionsHelp: String { return self._s[3604]! } - public var ChatState_Connecting: String { return self._s[3606]! } - public var Profile_MessageLifetime5s: String { return self._s[3607]! } + public var Wallet_Completed_Title: String { return self._s[3599]! } + public var UserInfo_AddToExisting: String { return self._s[3600]! } + public var Call_PhoneCallInProgressMessage: String { return self._s[3601]! } + public var Map_HomeAndWorkInfo: String { return self._s[3602]! } + public var Paint_Arrow: String { return self._s[3603]! } + public var CancelResetAccount_Title: String { return self._s[3604]! } + public var NotificationsSound_Circles: String { return self._s[3605]! } + public var Notifications_GroupNotificationsExceptionsHelp: String { return self._s[3606]! } + public var ChatState_Connecting: String { return self._s[3608]! } + public var Profile_MessageLifetime5s: String { return self._s[3609]! } public func DialogList_AwaitingEncryption(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3608]!, self._r[3608]!, [_0]) + return formatWithArgumentRanges(self._s[3610]!, self._r[3610]!, [_0]) } - public var PrivacyPolicy_AgeVerificationTitle: String { return self._s[3609]! } - public var Channel_Username_CreatePublicLinkHelp: String { return self._s[3610]! } - public var AutoNightTheme_ScheduledTo: String { return self._s[3611]! } - public var Conversation_DefaultRestrictedStickers: String { return self._s[3612]! } - public var TwoStepAuth_ConfirmationTitle: String { return self._s[3613]! } + public var PrivacyPolicy_AgeVerificationTitle: String { return self._s[3611]! } + public var Channel_Username_CreatePublicLinkHelp: String { return self._s[3612]! } + public var AutoNightTheme_ScheduledTo: String { return self._s[3613]! } + public var Conversation_DefaultRestrictedStickers: String { return self._s[3614]! } + public var TwoStepAuth_ConfirmationTitle: String { return self._s[3615]! } public func Chat_UnsendMyMessagesAlertTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3614]!, self._r[3614]!, [_0]) + return formatWithArgumentRanges(self._s[3616]!, self._r[3616]!, [_0]) } - public var Passport_Phone_Help: String { return self._s[3615]! } - public var Privacy_ContactsSync: String { return self._s[3616]! } - public var CheckoutInfo_ReceiverInfoPhone: String { return self._s[3617]! } - public var Channel_AdminLogFilter_EventsLeavingSubscribers: String { return self._s[3618]! } - public var Map_SendMyCurrentLocation: String { return self._s[3619]! } - public var Map_AddressOnMap: String { return self._s[3620]! } + public var Passport_Phone_Help: String { return self._s[3617]! } + public var Privacy_ContactsSync: String { return self._s[3618]! } + public var CheckoutInfo_ReceiverInfoPhone: String { return self._s[3619]! } + public var Channel_AdminLogFilter_EventsLeavingSubscribers: String { return self._s[3620]! } + public var Map_SendMyCurrentLocation: String { return self._s[3621]! } + public var Map_AddressOnMap: String { return self._s[3622]! } public func Wallet_Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3621]!, self._r[3621]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3623]!, self._r[3623]!, [_1, _2, _3]) } - public var DialogList_SearchLabel: String { return self._s[3623]! } - public var Notification_Exceptions_NewException_NotificationHeader: String { return self._s[3624]! } - public var ConversationProfile_UnknownAddMemberError: String { return self._s[3625]! } - public var ChatList_Search_ShowMore: String { return self._s[3626]! } - public var DialogList_EncryptionRejected: String { return self._s[3627]! } - public var Wallet_WordImport_Text: String { return self._s[3628]! } - public var DialogList_DeleteBotConfirmation: String { return self._s[3629]! } - public var Privacy_TopPeersDelete: String { return self._s[3630]! } - public var AttachmentMenu_SendAsFile: String { return self._s[3631]! } - public var ChatList_GenericPsaAlert: String { return self._s[3633]! } - public var SecretTimer_ImageDescription: String { return self._s[3635]! } + public var DialogList_SearchLabel: String { return self._s[3625]! } + public var Notification_Exceptions_NewException_NotificationHeader: String { return self._s[3626]! } + public var ConversationProfile_UnknownAddMemberError: String { return self._s[3627]! } + public var ChatList_Search_ShowMore: String { return self._s[3628]! } + public var DialogList_EncryptionRejected: String { return self._s[3629]! } + public var Wallet_WordImport_Text: String { return self._s[3630]! } + public var DialogList_DeleteBotConfirmation: String { return self._s[3631]! } + public var Privacy_TopPeersDelete: String { return self._s[3632]! } + public var AttachmentMenu_SendAsFile: String { return self._s[3633]! } + public var ChatList_GenericPsaAlert: String { return self._s[3635]! } + public var SecretTimer_ImageDescription: String { return self._s[3637]! } public func Conversation_SetReminder_RemindOn(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3636]!, self._r[3636]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3638]!, self._r[3638]!, [_0, _1]) } - public var ChatSettings_TextSizeUnits: String { return self._s[3637]! } - public var Notification_RenamedGroup: String { return self._s[3638]! } - public var Wallet_Info_RefreshErrorNetworkText: String { return self._s[3639]! } - public var Tour_Title2: String { return self._s[3640]! } - public var Settings_CopyUsername: String { return self._s[3641]! } - public var Compose_NewEncryptedChat: String { return self._s[3642]! } - public var Conversation_CloudStorageInfo_Title: String { return self._s[3643]! } - public var Month_ShortSeptember: String { return self._s[3644]! } - public var AutoDownloadSettings_OnForAll: String { return self._s[3645]! } - public var ChatList_DeleteForEveryoneConfirmationText: String { return self._s[3646]! } - public var Settings_Wallet: String { return self._s[3647]! } - public var Call_StatusConnecting: String { return self._s[3649]! } - public var Privacy_GroupsAndChannels_NeverAllow_Placeholder: String { return self._s[3650]! } - public var Map_ShareLiveLocationHelp: String { return self._s[3651]! } - public var Cache_Files: String { return self._s[3652]! } - public var Notifications_Reset: String { return self._s[3653]! } + public var ChatSettings_TextSizeUnits: String { return self._s[3639]! } + public var Notification_RenamedGroup: String { return self._s[3640]! } + public var Wallet_Info_RefreshErrorNetworkText: String { return self._s[3641]! } + public var Tour_Title2: String { return self._s[3642]! } + public var Settings_CopyUsername: String { return self._s[3643]! } + public var Compose_NewEncryptedChat: String { return self._s[3644]! } + public var Conversation_CloudStorageInfo_Title: String { return self._s[3645]! } + public var Month_ShortSeptember: String { return self._s[3646]! } + public var AutoDownloadSettings_OnForAll: String { return self._s[3647]! } + public var ChatList_DeleteForEveryoneConfirmationText: String { return self._s[3648]! } + public var Settings_Wallet: String { return self._s[3649]! } + public var Call_StatusConnecting: String { return self._s[3651]! } + public var Privacy_GroupsAndChannels_NeverAllow_Placeholder: String { return self._s[3652]! } + public var Map_ShareLiveLocationHelp: String { return self._s[3653]! } + public var Cache_Files: String { return self._s[3654]! } + public var Notifications_Reset: String { return self._s[3655]! } public func Settings_KeepPhoneNumber(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3654]!, self._r[3654]!, [_0]) + return formatWithArgumentRanges(self._s[3656]!, self._r[3656]!, [_0]) } - public var Privacy_GroupsAndChannels_AlwaysAllow_Title: String { return self._s[3655]! } + public var Privacy_GroupsAndChannels_AlwaysAllow_Title: String { return self._s[3657]! } public func Conversation_OpenBotLinkLogin(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3656]!, self._r[3656]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3658]!, self._r[3658]!, [_1, _2]) } - public var Notification_CallIncomingShort: String { return self._s[3657]! } - public var UserInfo_BotPrivacy: String { return self._s[3659]! } - public var Appearance_BubbleCorners_Apply: String { return self._s[3660]! } - public var WebSearch_RecentClearConfirmation: String { return self._s[3661]! } - public var Conversation_ContextMenuLookUp: String { return self._s[3662]! } - public var Calls_RatingTitle: String { return self._s[3663]! } - public var SecretImage_Title: String { return self._s[3664]! } - public var Weekday_Monday: String { return self._s[3665]! } + public var Notification_CallIncomingShort: String { return self._s[3659]! } + public var UserInfo_BotPrivacy: String { return self._s[3661]! } + public var Appearance_BubbleCorners_Apply: String { return self._s[3662]! } + public var WebSearch_RecentClearConfirmation: String { return self._s[3663]! } + public var Conversation_ContextMenuLookUp: String { return self._s[3664]! } + public var Calls_RatingTitle: String { return self._s[3665]! } + public var SecretImage_Title: String { return self._s[3666]! } + public var Weekday_Monday: String { return self._s[3667]! } public func Passport_PrivacyPolicy(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3667]!, self._r[3667]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3669]!, self._r[3669]!, [_1, _2]) } - public var KeyCommand_JumpToPreviousChat: String { return self._s[3668]! } + public var KeyCommand_JumpToPreviousChat: String { return self._s[3670]! } public func Wallet_Updated_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3669]!, self._r[3669]!, [_0]) + return formatWithArgumentRanges(self._s[3671]!, self._r[3671]!, [_0]) } public func DialogList_SearchSubtitleFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3670]!, self._r[3670]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3672]!, self._r[3672]!, [_1, _2]) } - public var Stats_GroupMembers: String { return self._s[3671]! } - public var Camera_Retake: String { return self._s[3672]! } - public var Conversation_SearchPlaceholder: String { return self._s[3674]! } + public var Stats_GroupMembers: String { return self._s[3673]! } + public var Camera_Retake: String { return self._s[3674]! } + public var Conversation_SearchPlaceholder: String { return self._s[3676]! } public func Passport_Identity_NativeNameGenericHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3675]!, self._r[3675]!, [_0]) + return formatWithArgumentRanges(self._s[3677]!, self._r[3677]!, [_0]) } - public var Channel_DiscussionGroup_Info: String { return self._s[3676]! } - public var SocksProxySetup_Hostname: String { return self._s[3677]! } - public var Wallet_Send_OwnAddressAlertProceed: String { return self._s[3678]! } - public var PrivacyLastSeenSettings_EmpryUsersPlaceholder: String { return self._s[3679]! } - public var Privacy_DeleteDrafts: String { return self._s[3680]! } + public var Channel_DiscussionGroup_Info: String { return self._s[3678]! } + public var SocksProxySetup_Hostname: String { return self._s[3679]! } + public var Wallet_Send_OwnAddressAlertProceed: String { return self._s[3680]! } + public var PrivacyLastSeenSettings_EmpryUsersPlaceholder: String { return self._s[3681]! } + public var Privacy_DeleteDrafts: String { return self._s[3682]! } public func Checkout_LiabilityAlert(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3681]!, self._r[3681]!, [_1, _1, _1, _2]) + return formatWithArgumentRanges(self._s[3683]!, self._r[3683]!, [_1, _1, _1, _2]) } - public var Wallet_RestoreFailed_Text: String { return self._s[3682]! } - public var Wallet_Settings_DeleteWallet: String { return self._s[3683]! } - public var Login_CancelPhoneVerification: String { return self._s[3684]! } - public var TwoStepAuth_ResetAccountHelp: String { return self._s[3686]! } + public var Wallet_RestoreFailed_Text: String { return self._s[3684]! } + public var Wallet_Settings_DeleteWallet: String { return self._s[3685]! } + public var Login_CancelPhoneVerification: String { return self._s[3686]! } + public var TwoStepAuth_ResetAccountHelp: String { return self._s[3688]! } public func SocksProxySetup_ProxyStatusPing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3687]!, self._r[3687]!, [_0]) + return formatWithArgumentRanges(self._s[3689]!, self._r[3689]!, [_0]) } - public var TwoStepAuth_EmailSent: String { return self._s[3688]! } - public var Cache_Indexing: String { return self._s[3689]! } - public var Notifications_ExceptionsNone: String { return self._s[3690]! } - public var MessagePoll_LabelQuiz: String { return self._s[3691]! } - public var Call_EncryptionKey_Title: String { return self._s[3692]! } - public var Common_Yes: String { return self._s[3693]! } - public var Channel_ErrorAddBlocked: String { return self._s[3694]! } - public var Month_GenJanuary: String { return self._s[3695]! } - public var Checkout_NewCard_Title: String { return self._s[3696]! } - public var Wallet_TransactionInfo_OtherFeeHeader: String { return self._s[3697]! } + public var TwoStepAuth_EmailSent: String { return self._s[3690]! } + public var Cache_Indexing: String { return self._s[3691]! } + public var Notifications_ExceptionsNone: String { return self._s[3692]! } + public var MessagePoll_LabelQuiz: String { return self._s[3693]! } + public var Call_EncryptionKey_Title: String { return self._s[3694]! } + public var Common_Yes: String { return self._s[3695]! } + public var Channel_ErrorAddBlocked: String { return self._s[3696]! } + public var Month_GenJanuary: String { return self._s[3697]! } + public var Checkout_NewCard_Title: String { return self._s[3698]! } + public var Wallet_TransactionInfo_OtherFeeHeader: String { return self._s[3699]! } public func TwoStepAuth_EnterPasswordHint(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3698]!, self._r[3698]!, [_0]) + return formatWithArgumentRanges(self._s[3700]!, self._r[3700]!, [_0]) } - public var PasscodeSettings_AutoLock_IfAwayFor_1hour: String { return self._s[3700]! } - public var Conversation_SendDice: String { return self._s[3701]! } - public var Conversation_InputTextPlaceholderReply: String { return self._s[3702]! } + public var PasscodeSettings_AutoLock_IfAwayFor_1hour: String { return self._s[3702]! } + public var Conversation_SendDice: String { return self._s[3703]! } + public var Conversation_InputTextPlaceholderReply: String { return self._s[3704]! } public func ChatSettings_AutoDownloadSettings_TypeVideo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3703]!, self._r[3703]!, [_0]) + return formatWithArgumentRanges(self._s[3705]!, self._r[3705]!, [_0]) } public func VoiceOver_Chat_VideoFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3704]!, self._r[3704]!, [_0]) + return formatWithArgumentRanges(self._s[3706]!, self._r[3706]!, [_0]) } - public var Weekday_Wednesday: String { return self._s[3705]! } - public var ReportPeer_ReasonOther_Send: String { return self._s[3706]! } - public var PasscodeSettings_EncryptDataHelp: String { return self._s[3707]! } - public var PrivacyLastSeenSettings_CustomShareSettingsHelp: String { return self._s[3708]! } - public var OldChannels_NoticeTitle: String { return self._s[3709]! } - public var TwoStepAuth_ChangeEmail: String { return self._s[3710]! } - public var PasscodeSettings_PasscodeOptions: String { return self._s[3711]! } - public var InfoPlist_NSPhotoLibraryUsageDescription: String { return self._s[3712]! } - public var Passport_Address_AddUtilityBill: String { return self._s[3713]! } + public var Weekday_Wednesday: String { return self._s[3707]! } + public var ReportPeer_ReasonOther_Send: String { return self._s[3708]! } + public var PasscodeSettings_EncryptDataHelp: String { return self._s[3709]! } + public var PrivacyLastSeenSettings_CustomShareSettingsHelp: String { return self._s[3710]! } + public var OldChannels_NoticeTitle: String { return self._s[3711]! } + public var TwoStepAuth_ChangeEmail: String { return self._s[3712]! } + public var PasscodeSettings_PasscodeOptions: String { return self._s[3713]! } + public var InfoPlist_NSPhotoLibraryUsageDescription: String { return self._s[3714]! } + public var Passport_Address_AddUtilityBill: String { return self._s[3715]! } public func Time_PreciseDate_m5(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3715]!, self._r[3715]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3717]!, self._r[3717]!, [_1, _2, _3]) } - public var TwoFactorSetup_EmailVerification_ResendAction: String { return self._s[3717]! } - public var Stats_GroupTopAdminsTitle: String { return self._s[3718]! } - public var Paint_Regular: String { return self._s[3719]! } - public var Message_Contact: String { return self._s[3720]! } - public var NetworkUsageSettings_MediaVideoDataSection: String { return self._s[3721]! } - public var VoiceOver_Chat_YourPhoto: String { return self._s[3722]! } - public var Notification_Mute1hMin: String { return self._s[3723]! } + public var TwoFactorSetup_EmailVerification_ResendAction: String { return self._s[3719]! } + public var Stats_GroupTopAdminsTitle: String { return self._s[3720]! } + public var Paint_Regular: String { return self._s[3721]! } + public var Message_Contact: String { return self._s[3722]! } + public var NetworkUsageSettings_MediaVideoDataSection: String { return self._s[3723]! } + public var VoiceOver_Chat_YourPhoto: String { return self._s[3724]! } + public var Notification_Mute1hMin: String { return self._s[3725]! } public func Login_BannedPhoneSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3724]!, self._r[3724]!, [_0]) + return formatWithArgumentRanges(self._s[3726]!, self._r[3726]!, [_0]) } - public var Profile_MessageLifetime1h: String { return self._s[3725]! } - public var TwoStepAuth_GenericHelp: String { return self._s[3726]! } - public var TextFormat_Monospace: String { return self._s[3727]! } - public var VoiceOver_Media_PlaybackRateChange: String { return self._s[3729]! } - public var Conversation_DeleteMessagesForMe: String { return self._s[3730]! } - public var ChatList_DeleteChat: String { return self._s[3731]! } - public var Channel_OwnershipTransfer_EnterPasswordText: String { return self._s[3734]! } + public var Profile_MessageLifetime1h: String { return self._s[3727]! } + public var TwoStepAuth_GenericHelp: String { return self._s[3728]! } + public var TextFormat_Monospace: String { return self._s[3729]! } + public var VoiceOver_Media_PlaybackRateChange: String { return self._s[3731]! } + public var Conversation_DeleteMessagesForMe: String { return self._s[3732]! } + public var ChatList_DeleteChat: String { return self._s[3733]! } + public var Channel_OwnershipTransfer_EnterPasswordText: String { return self._s[3736]! } public func Settings_ApplyProxyAlertCredentials(_ _1: String, _ _2: String, _ _3: String, _ _4: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3735]!, self._r[3735]!, [_1, _2, _3, _4]) + return formatWithArgumentRanges(self._s[3737]!, self._r[3737]!, [_1, _2, _3, _4]) } - public var Login_CancelPhoneVerificationStop: String { return self._s[3736]! } - public var Appearance_ThemePreview_ChatList_4_Name: String { return self._s[3737]! } - public var MediaPicker_MomentsDateRangeSameMonthYearFormat: String { return self._s[3738]! } - public var Wallet_Settings_Configuration: String { return self._s[3739]! } - public var Notifications_Badge_IncludeChannels: String { return self._s[3740]! } + public var Login_CancelPhoneVerificationStop: String { return self._s[3738]! } + public var Appearance_ThemePreview_ChatList_4_Name: String { return self._s[3739]! } + public var MediaPicker_MomentsDateRangeSameMonthYearFormat: String { return self._s[3740]! } + public var Wallet_Settings_Configuration: String { return self._s[3741]! } + public var Notifications_Badge_IncludeChannels: String { return self._s[3742]! } public func Channel_AdminLog_MessageToggleInvitesOn(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3741]!, self._r[3741]!, [_0]) + return formatWithArgumentRanges(self._s[3743]!, self._r[3743]!, [_0]) } - public var Wallet_Sent_ViewWallet: String { return self._s[3742]! } - public var StickerPack_ViewPack: String { return self._s[3745]! } - public var FastTwoStepSetup_PasswordConfirmationPlaceholder: String { return self._s[3747]! } - public var EditTheme_Expand_Preview_IncomingText: String { return self._s[3748]! } - public var Notifications_Title: String { return self._s[3749]! } - public var Wallet_WordImport_Continue: String { return self._s[3750]! } - public var GroupInfo_PublicLink: String { return self._s[3751]! } - public var Conversation_InputTextPlaceholderComment: String { return self._s[3752]! } - public var VoiceOver_DiscardPreparedContent: String { return self._s[3753]! } - public var Conversation_Moderate_Ban: String { return self._s[3757]! } + public var Wallet_Sent_ViewWallet: String { return self._s[3744]! } + public var StickerPack_ViewPack: String { return self._s[3747]! } + public var FastTwoStepSetup_PasswordConfirmationPlaceholder: String { return self._s[3749]! } + public var EditTheme_Expand_Preview_IncomingText: String { return self._s[3750]! } + public var Notifications_Title: String { return self._s[3751]! } + public var Wallet_WordImport_Continue: String { return self._s[3752]! } + public var GroupInfo_PublicLink: String { return self._s[3753]! } + public var Conversation_InputTextPlaceholderComment: String { return self._s[3754]! } + public var VoiceOver_DiscardPreparedContent: String { return self._s[3755]! } + public var Conversation_Moderate_Ban: String { return self._s[3759]! } public func Activity_RemindAboutGroup(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3758]!, self._r[3758]!, [_0]) + return formatWithArgumentRanges(self._s[3760]!, self._r[3760]!, [_0]) } - public var TextFormat_Underline: String { return self._s[3759]! } + public var TextFormat_Underline: String { return self._s[3761]! } public func DownloadingStatus(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3760]!, self._r[3760]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3762]!, self._r[3762]!, [_0, _1]) } public func PUSH_PINNED_ROUND(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3761]!, self._r[3761]!, [_1]) + return formatWithArgumentRanges(self._s[3763]!, self._r[3763]!, [_1]) } - public var PollResults_Collapse: String { return self._s[3763]! } - public var Contacts_GlobalSearch: String { return self._s[3764]! } + public var PollResults_Collapse: String { return self._s[3765]! } + public var Contacts_GlobalSearch: String { return self._s[3766]! } public func Conversation_EncryptionWaiting(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3765]!, self._r[3765]!, [_0]) + return formatWithArgumentRanges(self._s[3767]!, self._r[3767]!, [_0]) } - public var Channel_Management_LabelEditor: String { return self._s[3766]! } - public var SettingsSearch_Synonyms_Stickers_FeaturedPacks: String { return self._s[3768]! } - public var Conversation_Theme: String { return self._s[3769]! } + public var Channel_Management_LabelEditor: String { return self._s[3768]! } + public var SettingsSearch_Synonyms_Stickers_FeaturedPacks: String { return self._s[3770]! } + public var Conversation_Theme: String { return self._s[3771]! } public func PUSH_CHANNEL_MESSAGE_DOCS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3770]!, self._r[3770]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[3772]!, self._r[3772]!, [_1, "\(_2)"]) } - public var Conversation_LinkDialogSave: String { return self._s[3771]! } - public var EnterPasscode_TouchId: String { return self._s[3772]! } - public var Stats_MessageOverview: String { return self._s[3773]! } - public var Privacy_Calls_P2PAlways: String { return self._s[3775]! } - public var Message_Sticker: String { return self._s[3776]! } - public var Conversation_Mute: String { return self._s[3778]! } - public var ContactInfo_Title: String { return self._s[3779]! } + public var Conversation_LinkDialogSave: String { return self._s[3773]! } + public var EnterPasscode_TouchId: String { return self._s[3774]! } + public var Stats_MessageOverview: String { return self._s[3775]! } + public var Privacy_Calls_P2PAlways: String { return self._s[3777]! } + public var Message_Sticker: String { return self._s[3778]! } + public var Conversation_Mute: String { return self._s[3780]! } + public var ContactInfo_Title: String { return self._s[3781]! } public func PUSH_CHANNEL_MESSAGE_CONTACT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3780]!, self._r[3780]!, [_1]) + return formatWithArgumentRanges(self._s[3782]!, self._r[3782]!, [_1]) } - public var Channel_Setup_TypeHeader: String { return self._s[3781]! } - public var AuthSessions_LogOut: String { return self._s[3782]! } - public var Wallet_WordCheck_ViewWords: String { return self._s[3783]! } - public var ChatSettings_AutoDownloadReset: String { return self._s[3784]! } - public var ChatListFolderSettings_NewFolder: String { return self._s[3786]! } - public var Appearance_ThemePreview_ChatList_3_AuthorName: String { return self._s[3787]! } - public var CreatePoll_Title: String { return self._s[3788]! } - public var EditTheme_EditTitle: String { return self._s[3789]! } - public var ChatListFolderSettings_RecommendedFoldersSection: String { return self._s[3790]! } - public var TwoStepAuth_SetPassword: String { return self._s[3791]! } - public var Wallet_Words_Done: String { return self._s[3792]! } + public var Channel_Setup_TypeHeader: String { return self._s[3783]! } + public var AuthSessions_LogOut: String { return self._s[3784]! } + public var Wallet_WordCheck_ViewWords: String { return self._s[3785]! } + public var ChatSettings_AutoDownloadReset: String { return self._s[3786]! } + public var ChatListFolderSettings_NewFolder: String { return self._s[3788]! } + public var Appearance_ThemePreview_ChatList_3_AuthorName: String { return self._s[3789]! } + public var CreatePoll_Title: String { return self._s[3790]! } + public var EditTheme_EditTitle: String { return self._s[3791]! } + public var ChatListFolderSettings_RecommendedFoldersSection: String { return self._s[3792]! } + public var TwoStepAuth_SetPassword: String { return self._s[3793]! } + public var Wallet_Words_Done: String { return self._s[3794]! } public func Login_InvalidPhoneEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3793]!, self._r[3793]!, [_0]) + return formatWithArgumentRanges(self._s[3795]!, self._r[3795]!, [_0]) } - public var BlockedUsers_Info: String { return self._s[3794]! } - public var AuthSessions_Sessions: String { return self._s[3795]! } - public var Group_EditAdmin_RankTitle: String { return self._s[3796]! } + public var BlockedUsers_Info: String { return self._s[3796]! } + public var AuthSessions_Sessions: String { return self._s[3797]! } + public var Group_EditAdmin_RankTitle: String { return self._s[3798]! } public func Wallet_Time_PreciseDate_m11(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3797]!, self._r[3797]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3799]!, self._r[3799]!, [_1, _2, _3]) } - public var Common_ActionNotAllowedError: String { return self._s[3798]! } - public var WebPreview_GettingLinkInfo: String { return self._s[3799]! } - public var Appearance_AppIconFilledX: String { return self._s[3800]! } - public var Wallet_TransactionInfo_StorageFeeInfo: String { return self._s[3801]! } - public var Passport_Email_EmailPlaceholder: String { return self._s[3802]! } - public var FeaturedStickers_OtherSection: String { return self._s[3803]! } - public var EditTheme_Edit_Preview_OutgoingText: String { return self._s[3804]! } - public var Profile_Username: String { return self._s[3805]! } - public var Appearance_RemoveTheme: String { return self._s[3806]! } - public var TwoStepAuth_SetupPasswordConfirmPassword: String { return self._s[3807]! } - public var Message_PinnedStickerMessage: String { return self._s[3808]! } - public var AccessDenied_VideoMicrophone: String { return self._s[3809]! } - public var WallpaperPreview_CustomColorBottomText: String { return self._s[3810]! } - public var Passport_Address_RegionPlaceholder: String { return self._s[3811]! } - public var SettingsSearch_Synonyms_Data_Storage_Title: String { return self._s[3812]! } - public var TwoStepAuth_Title: String { return self._s[3813]! } - public var Checkout_WebConfirmation_Title: String { return self._s[3814]! } - public var AutoDownloadSettings_VoiceMessagesInfo: String { return self._s[3815]! } - public var ChatListFolder_CategoryGroups: String { return self._s[3817]! } - public var Stats_GroupTopInviter_Promote: String { return self._s[3818]! } - public var Month_GenJuly: String { return self._s[3819]! } - public var Passport_Identity_Gender: String { return self._s[3820]! } - public var Channel_DiscussionGroup_UnlinkGroup: String { return self._s[3821]! } - public var Notification_Exceptions_DeleteAll: String { return self._s[3822]! } + public var Common_ActionNotAllowedError: String { return self._s[3800]! } + public var WebPreview_GettingLinkInfo: String { return self._s[3801]! } + public var Appearance_AppIconFilledX: String { return self._s[3802]! } + public var Wallet_TransactionInfo_StorageFeeInfo: String { return self._s[3803]! } + public var Passport_Email_EmailPlaceholder: String { return self._s[3804]! } + public var FeaturedStickers_OtherSection: String { return self._s[3805]! } + public var EditTheme_Edit_Preview_OutgoingText: String { return self._s[3806]! } + public var Profile_Username: String { return self._s[3807]! } + public var Appearance_RemoveTheme: String { return self._s[3808]! } + public var TwoStepAuth_SetupPasswordConfirmPassword: String { return self._s[3809]! } + public var Message_PinnedStickerMessage: String { return self._s[3810]! } + public var AccessDenied_VideoMicrophone: String { return self._s[3811]! } + public var WallpaperPreview_CustomColorBottomText: String { return self._s[3812]! } + public var Passport_Address_RegionPlaceholder: String { return self._s[3813]! } + public var SettingsSearch_Synonyms_Data_Storage_Title: String { return self._s[3814]! } + public var TwoStepAuth_Title: String { return self._s[3815]! } + public var Checkout_WebConfirmation_Title: String { return self._s[3816]! } + public var AutoDownloadSettings_VoiceMessagesInfo: String { return self._s[3817]! } + public var ChatListFolder_CategoryGroups: String { return self._s[3819]! } + public var Stats_GroupTopInviter_Promote: String { return self._s[3820]! } + public var Month_GenJuly: String { return self._s[3821]! } + public var Passport_Identity_Gender: String { return self._s[3822]! } + public var Channel_DiscussionGroup_UnlinkGroup: String { return self._s[3823]! } + public var Notification_Exceptions_DeleteAll: String { return self._s[3824]! } public func Conversation_FileHowToText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3823]!, self._r[3823]!, [_0]) + return formatWithArgumentRanges(self._s[3825]!, self._r[3825]!, [_0]) } public func Channel_AdminLog_MessageAdmin(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3824]!, self._r[3824]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[3826]!, self._r[3826]!, [_0, _1, _2]) } - public var Login_CodeSentSms: String { return self._s[3825]! } + public var Login_CodeSentSms: String { return self._s[3827]! } public func VoiceOver_Chat_ReplyFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3827]!, self._r[3827]!, [_0]) + return formatWithArgumentRanges(self._s[3829]!, self._r[3829]!, [_0]) } - public var Login_CallRequestState2: String { return self._s[3828]! } - public var Channel_DiscussionGroup_Header: String { return self._s[3829]! } + public var Login_CallRequestState2: String { return self._s[3830]! } + public var Channel_DiscussionGroup_Header: String { return self._s[3831]! } public func Channel_AdminLog_MessageToggleInvitesOff(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3830]!, self._r[3830]!, [_0]) + return formatWithArgumentRanges(self._s[3832]!, self._r[3832]!, [_0]) } - public var Passport_Language_ms: String { return self._s[3831]! } - public var PeopleNearby_MakeInvisible: String { return self._s[3833]! } - public var ChatList_Search_FilterVoice: String { return self._s[3835]! } - public var Camera_TapAndHoldForVideo: String { return self._s[3837]! } - public var Permissions_NotificationsAllowInSettings_v0: String { return self._s[3838]! } + public var Passport_Language_ms: String { return self._s[3833]! } + public var PeopleNearby_MakeInvisible: String { return self._s[3835]! } + public var ChatList_Search_FilterVoice: String { return self._s[3837]! } + public var Camera_TapAndHoldForVideo: String { return self._s[3839]! } + public var Permissions_NotificationsAllowInSettings_v0: String { return self._s[3840]! } public func Notification_LeftChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3839]!, self._r[3839]!, [_0]) + return formatWithArgumentRanges(self._s[3841]!, self._r[3841]!, [_0]) } public func Wallet_Time_PreciseDate_m9(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3840]!, self._r[3840]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3842]!, self._r[3842]!, [_1, _2, _3]) } - public var Wallet_Info_TransactionTo: String { return self._s[3841]! } - public var Map_Locating: String { return self._s[3842]! } + public var Wallet_Info_TransactionTo: String { return self._s[3843]! } + public var Map_Locating: String { return self._s[3844]! } public func Checkout_SavePasswordTimeout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3844]!, self._r[3844]!, [_0]) + return formatWithArgumentRanges(self._s[3846]!, self._r[3846]!, [_0]) } - public var Passport_Identity_TypeInternalPassport: String { return self._s[3846]! } - public var Appearance_ThemePreview_Chat_4_Text: String { return self._s[3847]! } - public var SettingsSearch_Synonyms_EditProfile_Username: String { return self._s[3848]! } - public var Stickers_Installed: String { return self._s[3849]! } - public var Notifications_PermissionsAllowInSettings: String { return self._s[3850]! } - public var StickerPackActionInfo_RemovedTitle: String { return self._s[3851]! } - public var CallSettings_Never: String { return self._s[3853]! } - public var Wallet_AccessDenied_Camera: String { return self._s[3854]! } - public var Channel_Setup_TypePublicHelp: String { return self._s[3855]! } + public var Passport_Identity_TypeInternalPassport: String { return self._s[3848]! } + public var Appearance_ThemePreview_Chat_4_Text: String { return self._s[3849]! } + public var SettingsSearch_Synonyms_EditProfile_Username: String { return self._s[3850]! } + public var Stickers_Installed: String { return self._s[3851]! } + public var Notifications_PermissionsAllowInSettings: String { return self._s[3852]! } + public var StickerPackActionInfo_RemovedTitle: String { return self._s[3853]! } + public var CallSettings_Never: String { return self._s[3855]! } + public var Wallet_AccessDenied_Camera: String { return self._s[3856]! } + public var Channel_Setup_TypePublicHelp: String { return self._s[3857]! } public func ChatList_DeleteForEveryone(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3857]!, self._r[3857]!, [_0]) + return formatWithArgumentRanges(self._s[3859]!, self._r[3859]!, [_0]) } - public var Message_Game: String { return self._s[3858]! } - public var Call_Message: String { return self._s[3859]! } + public var Message_Game: String { return self._s[3860]! } + public var Call_Message: String { return self._s[3861]! } public func PUSH_CHANNEL_MESSAGE_VIDEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3860]!, self._r[3860]!, [_1]) + return formatWithArgumentRanges(self._s[3862]!, self._r[3862]!, [_1]) } - public var ChannelIntro_Text: String { return self._s[3861]! } - public var StickerPack_Send: String { return self._s[3862]! } - public var Share_AuthDescription: String { return self._s[3863]! } - public var PasscodeSettings_AutoLock_IfAwayFor_5minutes: String { return self._s[3864]! } - public var CallFeedback_WhatWentWrong: String { return self._s[3865]! } - public var Common_Create: String { return self._s[3868]! } - public var Passport_Language_hy: String { return self._s[3869]! } - public var CreatePoll_Explanation: String { return self._s[3870]! } - public var GroupPermission_AddMembersNotAvailable: String { return self._s[3871]! } - public var Undo_ChatClearedForBothSides: String { return self._s[3872]! } - public var DialogList_NoMessagesTitle: String { return self._s[3873]! } - public var GroupInfo_Title: String { return self._s[3875]! } - public var Channel_AdminLog_CanBanUsers: String { return self._s[3876]! } - public var PhoneNumberHelp_Help: String { return self._s[3877]! } - public var TwoStepAuth_AdditionalPassword: String { return self._s[3878]! } - public var Settings_Logout: String { return self._s[3879]! } - public var Privacy_PaymentsTitle: String { return self._s[3880]! } - public var StickerPacksSettings_StickerPacksSection: String { return self._s[3881]! } - public var Tour_Text6: String { return self._s[3882]! } - public var Channel_Username_Help: String { return self._s[3884]! } - public var Wallet_Info_RefreshErrorTitle: String { return self._s[3885]! } - public var VoiceOver_Chat_RecordModeVoiceMessageInfo: String { return self._s[3886]! } - public var AttachmentMenu_Poll: String { return self._s[3887]! } - public var EditTheme_Create_Preview_IncomingReplyName: String { return self._s[3888]! } - public var Conversation_ReportSpamChannelConfirmation: String { return self._s[3889]! } - public var Passport_DeletePassport: String { return self._s[3890]! } - public var Login_Code: String { return self._s[3891]! } - public var Notification_SecretChatScreenshot: String { return self._s[3892]! } - public var Login_CodeFloodError: String { return self._s[3893]! } + public var ChannelIntro_Text: String { return self._s[3863]! } + public var StickerPack_Send: String { return self._s[3864]! } + public var Share_AuthDescription: String { return self._s[3865]! } + public var PasscodeSettings_AutoLock_IfAwayFor_5minutes: String { return self._s[3866]! } + public var CallFeedback_WhatWentWrong: String { return self._s[3867]! } + public var Common_Create: String { return self._s[3870]! } + public var Passport_Language_hy: String { return self._s[3871]! } + public var CreatePoll_Explanation: String { return self._s[3872]! } + public var GroupPermission_AddMembersNotAvailable: String { return self._s[3873]! } + public var Undo_ChatClearedForBothSides: String { return self._s[3874]! } + public var DialogList_NoMessagesTitle: String { return self._s[3875]! } + public var GroupInfo_Title: String { return self._s[3877]! } + public var Channel_AdminLog_CanBanUsers: String { return self._s[3878]! } + public var PhoneNumberHelp_Help: String { return self._s[3879]! } + public var TwoStepAuth_AdditionalPassword: String { return self._s[3880]! } + public var Settings_Logout: String { return self._s[3881]! } + public var Privacy_PaymentsTitle: String { return self._s[3882]! } + public var StickerPacksSettings_StickerPacksSection: String { return self._s[3883]! } + public var Tour_Text6: String { return self._s[3884]! } + public var Channel_Username_Help: String { return self._s[3886]! } + public var Wallet_Info_RefreshErrorTitle: String { return self._s[3887]! } + public var VoiceOver_Chat_RecordModeVoiceMessageInfo: String { return self._s[3888]! } + public var AttachmentMenu_Poll: String { return self._s[3889]! } + public var EditTheme_Create_Preview_IncomingReplyName: String { return self._s[3890]! } + public var Conversation_ReportSpamChannelConfirmation: String { return self._s[3891]! } + public var Passport_DeletePassport: String { return self._s[3892]! } + public var Login_Code: String { return self._s[3893]! } + public var Notification_SecretChatScreenshot: String { return self._s[3894]! } + public var Login_CodeFloodError: String { return self._s[3895]! } public func Notification_PinnedAnimationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3894]!, self._r[3894]!, [_0]) + return formatWithArgumentRanges(self._s[3896]!, self._r[3896]!, [_0]) } public func Channel_Username_UsernameIsAvailable(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3895]!, self._r[3895]!, [_0]) + return formatWithArgumentRanges(self._s[3897]!, self._r[3897]!, [_0]) } - public var Watch_Stickers_Recents: String { return self._s[3896]! } - public var Generic_ErrorMoreInfo: String { return self._s[3897]! } + public var Watch_Stickers_Recents: String { return self._s[3898]! } + public var Generic_ErrorMoreInfo: String { return self._s[3899]! } public func Call_AccountIsLoggedOnCurrentDevice(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3898]!, self._r[3898]!, [_0]) + return formatWithArgumentRanges(self._s[3900]!, self._r[3900]!, [_0]) } - public var AutoDownloadSettings_DataUsage: String { return self._s[3899]! } - public var Conversation_ViewTheme: String { return self._s[3900]! } - public var Contacts_InviteSearchLabel: String { return self._s[3901]! } - public var Settings_CancelUpload: String { return self._s[3903]! } - public var Settings_AppLanguage_Unofficial: String { return self._s[3904]! } + public var AutoDownloadSettings_DataUsage: String { return self._s[3901]! } + public var Conversation_ViewTheme: String { return self._s[3902]! } + public var Contacts_InviteSearchLabel: String { return self._s[3903]! } + public var Settings_CancelUpload: String { return self._s[3905]! } + public var Settings_AppLanguage_Unofficial: String { return self._s[3906]! } public func ChatList_ClearChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3905]!, self._r[3905]!, [_0]) + return formatWithArgumentRanges(self._s[3907]!, self._r[3907]!, [_0]) } - public var ChatList_AddFolder: String { return self._s[3906]! } - public var Conversation_Location: String { return self._s[3908]! } - public var Appearance_BubbleCorners_AdjustAdjacent: String { return self._s[3909]! } - public var DialogList_AdLabel: String { return self._s[3910]! } + public var ChatList_AddFolder: String { return self._s[3908]! } + public var Conversation_Location: String { return self._s[3910]! } + public var Appearance_BubbleCorners_AdjustAdjacent: String { return self._s[3911]! } + public var DialogList_AdLabel: String { return self._s[3912]! } public func Time_TomorrowAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3912]!, self._r[3912]!, [_0]) + return formatWithArgumentRanges(self._s[3914]!, self._r[3914]!, [_0]) } - public var Message_InvoiceLabel: String { return self._s[3913]! } - public var Channel_TooMuchBots: String { return self._s[3914]! } + public var Message_InvoiceLabel: String { return self._s[3915]! } + public var Channel_TooMuchBots: String { return self._s[3916]! } public func Channel_AdminLog_MessageRemovedChannelUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3915]!, self._r[3915]!, [_0]) + return formatWithArgumentRanges(self._s[3917]!, self._r[3917]!, [_0]) } - public var Wallet_Month_ShortAugust: String { return self._s[3916]! } - public var Call_IncomingVideoCall: String { return self._s[3917]! } - public var Conversation_LiveLocation: String { return self._s[3918]! } - public var TwoStepAuth_SetupPasswordEnterPasswordChange: String { return self._s[3919]! } - public var Passport_Identity_EditPassport: String { return self._s[3920]! } - public var Permissions_CellularDataTitle_v0: String { return self._s[3922]! } - public var ChatList_Search_NoResultsFitlerVoice: String { return self._s[3923]! } - public var GroupInfo_Permissions_AddException: String { return self._s[3924]! } - public var Channel_AdminLog_CanInviteUsers: String { return self._s[3926]! } - public var Channel_MessageVideoUpdated: String { return self._s[3927]! } - public var GroupInfo_Permissions_EditingDisabled: String { return self._s[3928]! } - public var AccessDenied_Camera: String { return self._s[3931]! } + public var Wallet_Month_ShortAugust: String { return self._s[3918]! } + public var Call_IncomingVideoCall: String { return self._s[3919]! } + public var Conversation_LiveLocation: String { return self._s[3920]! } + public var TwoStepAuth_SetupPasswordEnterPasswordChange: String { return self._s[3921]! } + public var Passport_Identity_EditPassport: String { return self._s[3922]! } + public var Permissions_CellularDataTitle_v0: String { return self._s[3924]! } + public var ChatList_Search_NoResultsFitlerVoice: String { return self._s[3925]! } + public var GroupInfo_Permissions_AddException: String { return self._s[3926]! } + public var Channel_AdminLog_CanInviteUsers: String { return self._s[3928]! } + public var Channel_MessageVideoUpdated: String { return self._s[3929]! } + public var GroupInfo_Permissions_EditingDisabled: String { return self._s[3930]! } + public var AccessDenied_Camera: String { return self._s[3933]! } public func Target_InviteToGroupConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3932]!, self._r[3932]!, [_0]) + return formatWithArgumentRanges(self._s[3934]!, self._r[3934]!, [_0]) } - public var Theme_Context_ChangeColors: String { return self._s[3933]! } - public var PrivacySettings_TwoStepAuth: String { return self._s[3934]! } - public var Privacy_Forwards_PreviewMessageText: String { return self._s[3935]! } - public var Login_CodeExpiredError: String { return self._s[3936]! } - public var State_ConnectingToProxy: String { return self._s[3937]! } - public var TextFormat_Link: String { return self._s[3938]! } - public var Passport_Language_lv: String { return self._s[3939]! } - public var AccessDenied_VoiceMicrophone: String { return self._s[3940]! } - public var WallpaperPreview_SwipeBottomText: String { return self._s[3941]! } - public var ProfilePhoto_SetMainVideo: String { return self._s[3942]! } - public var AutoDownloadSettings_Cellular: String { return self._s[3944]! } - public var ChatSettings_AutoDownloadVoiceMessages: String { return self._s[3945]! } + public var Theme_Context_ChangeColors: String { return self._s[3935]! } + public var PrivacySettings_TwoStepAuth: String { return self._s[3936]! } + public var Privacy_Forwards_PreviewMessageText: String { return self._s[3937]! } + public var Login_CodeExpiredError: String { return self._s[3938]! } + public var State_ConnectingToProxy: String { return self._s[3939]! } + public var TextFormat_Link: String { return self._s[3940]! } + public var Passport_Language_lv: String { return self._s[3941]! } + public var AccessDenied_VoiceMicrophone: String { return self._s[3942]! } + public var WallpaperPreview_SwipeBottomText: String { return self._s[3943]! } + public var ProfilePhoto_SetMainVideo: String { return self._s[3944]! } + public var AutoDownloadSettings_Cellular: String { return self._s[3946]! } + public var ChatSettings_AutoDownloadVoiceMessages: String { return self._s[3947]! } public func Channel_AdminLog_MessageKickedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3946]!, self._r[3946]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3948]!, self._r[3948]!, [_1, _2]) } - public var ChatList_EmptyChatListFilterTitle: String { return self._s[3947]! } - public var Checkout_PayNone: String { return self._s[3948]! } - public var NotificationsSound_Complete: String { return self._s[3950]! } - public var TwoStepAuth_ConfirmEmailCodePlaceholder: String { return self._s[3951]! } - public var AuthSessions_DevicesTitle: String { return self._s[3952]! } + public var ChatList_EmptyChatListFilterTitle: String { return self._s[3949]! } + public var Checkout_PayNone: String { return self._s[3950]! } + public var NotificationsSound_Complete: String { return self._s[3952]! } + public var TwoStepAuth_ConfirmEmailCodePlaceholder: String { return self._s[3953]! } + public var AuthSessions_DevicesTitle: String { return self._s[3954]! } public func DialogList_MultipleTyping(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3953]!, self._r[3953]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3955]!, self._r[3955]!, [_0, _1]) } - public var Message_LiveLocation: String { return self._s[3954]! } - public var Watch_Suggestion_BRB: String { return self._s[3955]! } - public var Channel_BanUser_Title: String { return self._s[3956]! } - public var SettingsSearch_Synonyms_Privacy_Data_Title: String { return self._s[3957]! } - public var Conversation_Dice_u1F3C0: String { return self._s[3958]! } - public var Conversation_ClearSelfHistory: String { return self._s[3959]! } - public var ProfilePhoto_OpenGallery: String { return self._s[3960]! } - public var PrivacySettings_LastSeenTitle: String { return self._s[3961]! } - public var Weekday_Thursday: String { return self._s[3962]! } - public var BroadcastListInfo_AddRecipient: String { return self._s[3963]! } - public var Privacy_ProfilePhoto: String { return self._s[3965]! } - public var StickerPacksSettings_ArchivedPacks_Info: String { return self._s[3966]! } + public var Message_LiveLocation: String { return self._s[3956]! } + public var Watch_Suggestion_BRB: String { return self._s[3957]! } + public var Channel_BanUser_Title: String { return self._s[3958]! } + public var SettingsSearch_Synonyms_Privacy_Data_Title: String { return self._s[3959]! } + public var Conversation_Dice_u1F3C0: String { return self._s[3960]! } + public var Conversation_ClearSelfHistory: String { return self._s[3961]! } + public var ProfilePhoto_OpenGallery: String { return self._s[3962]! } + public var PrivacySettings_LastSeenTitle: String { return self._s[3963]! } + public var Weekday_Thursday: String { return self._s[3964]! } + public var BroadcastListInfo_AddRecipient: String { return self._s[3965]! } + public var Privacy_ProfilePhoto: String { return self._s[3967]! } + public var StickerPacksSettings_ArchivedPacks_Info: String { return self._s[3968]! } public func Channel_AdminLog_MessageChangedUnlinkedGroup(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3967]!, self._r[3967]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3969]!, self._r[3969]!, [_1, _2]) } - public var Message_Audio: String { return self._s[3968]! } - public var Conversation_Info: String { return self._s[3969]! } - public var Cache_Videos: String { return self._s[3970]! } - public var Appearance_ThemePreview_ChatList_6_Text: String { return self._s[3971]! } - public var Channel_ErrorAddTooMuch: String { return self._s[3972]! } + public var Message_Audio: String { return self._s[3970]! } + public var Conversation_Info: String { return self._s[3971]! } + public var Cache_Videos: String { return self._s[3972]! } + public var Appearance_ThemePreview_ChatList_6_Text: String { return self._s[3973]! } + public var Channel_ErrorAddTooMuch: String { return self._s[3974]! } public func ChatList_DeleteSecretChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3973]!, self._r[3973]!, [_0]) + return formatWithArgumentRanges(self._s[3975]!, self._r[3975]!, [_0]) } - public var ChannelMembers_ChannelAdminsTitle: String { return self._s[3975]! } - public var ScheduledMessages_Title: String { return self._s[3977]! } - public var ShareFileTip_Title: String { return self._s[3980]! } - public var Chat_Gifs_TrendingSectionHeader: String { return self._s[3981]! } - public var ChatList_RemoveFolderConfirmation: String { return self._s[3982]! } + public var ChannelMembers_ChannelAdminsTitle: String { return self._s[3977]! } + public var ScheduledMessages_Title: String { return self._s[3979]! } + public var ShareFileTip_Title: String { return self._s[3982]! } + public var Chat_Gifs_TrendingSectionHeader: String { return self._s[3983]! } + public var ChatList_RemoveFolderConfirmation: String { return self._s[3984]! } public func PUSH_CHAT_MESSAGE_GEOLIVE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3983]!, self._r[3983]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3985]!, self._r[3985]!, [_1, _2]) } - public var Conversation_ContextViewStats: String { return self._s[3985]! } - public var Channel_DiscussionGroup_SearchPlaceholder: String { return self._s[3986]! } - public var PasscodeSettings_Title: String { return self._s[3987]! } - public var Channel_AdminLog_SendPolls: String { return self._s[3988]! } - public var LastSeen_ALongTimeAgo: String { return self._s[3989]! } + public var Conversation_ContextViewStats: String { return self._s[3987]! } + public var Channel_DiscussionGroup_SearchPlaceholder: String { return self._s[3988]! } + public var PasscodeSettings_Title: String { return self._s[3989]! } + public var Channel_AdminLog_SendPolls: String { return self._s[3990]! } + public var LastSeen_ALongTimeAgo: String { return self._s[3991]! } public func PUSH_CHANNEL_MESSAGE_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3990]!, self._r[3990]!, [_1]) + return formatWithArgumentRanges(self._s[3992]!, self._r[3992]!, [_1]) } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChannels: String { return self._s[3991]! } - public var CallFeedback_VideoReasonLowQuality: String { return self._s[3992]! } - public var Conversation_PinnedPreviousMessage: String { return self._s[3993]! } - public var SocksProxySetup_AddProxyTitle: String { return self._s[3994]! } - public var Passport_Identity_AddInternalPassport: String { return self._s[3995]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChannels: String { return self._s[3993]! } + public var CallFeedback_VideoReasonLowQuality: String { return self._s[3994]! } + public var Conversation_PinnedPreviousMessage: String { return self._s[3995]! } + public var SocksProxySetup_AddProxyTitle: String { return self._s[3996]! } + public var Passport_Identity_AddInternalPassport: String { return self._s[3997]! } public func ChatList_RemovedFromFolderTooltip(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3996]!, self._r[3996]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3998]!, self._r[3998]!, [_1, _2]) } public func Conversation_SetReminder_RemindToday(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3997]!, self._r[3997]!, [_0]) + return formatWithArgumentRanges(self._s[3999]!, self._r[3999]!, [_0]) } - public var Passport_Identity_GenderFemale: String { return self._s[3998]! } - public var ConvertToSupergroup_HelpTitle: String { return self._s[4001]! } - public var Location_ProximityNotification_DistanceKM: String { return self._s[4002]! } - public var SharedMedia_TitleAll: String { return self._s[4003]! } - public var Settings_Context_Logout: String { return self._s[4004]! } - public var GroupInfo_SetGroupPhotoDelete: String { return self._s[4006]! } - public var Settings_About_Title: String { return self._s[4007]! } - public var StickerSettings_ContextHide: String { return self._s[4008]! } + public var Passport_Identity_GenderFemale: String { return self._s[4000]! } + public var ConvertToSupergroup_HelpTitle: String { return self._s[4003]! } + public var Location_ProximityNotification_DistanceKM: String { return self._s[4004]! } + public var SharedMedia_TitleAll: String { return self._s[4005]! } + public var Settings_Context_Logout: String { return self._s[4006]! } + public var GroupInfo_SetGroupPhotoDelete: String { return self._s[4008]! } + public var Settings_About_Title: String { return self._s[4009]! } + public var StickerSettings_ContextHide: String { return self._s[4010]! } public func AutoDownloadSettings_UpTo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4009]!, self._r[4009]!, [_0]) + return formatWithArgumentRanges(self._s[4011]!, self._r[4011]!, [_0]) } public func Conversation_LiveLocationYouAndOther(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4010]!, self._r[4010]!, [_0]) + return formatWithArgumentRanges(self._s[4012]!, self._r[4012]!, [_0]) } - public var Common_Cancel: String { return self._s[4012]! } - public var CallFeedback_Title: String { return self._s[4014]! } + public var Common_Cancel: String { return self._s[4014]! } + public var CallFeedback_Title: String { return self._s[4016]! } public func Notification_PinnedContactMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4015]!, self._r[4015]!, [_0]) + return formatWithArgumentRanges(self._s[4017]!, self._r[4017]!, [_0]) } - public var Activity_UploadingVideoMessage: String { return self._s[4016]! } - public var Wallet_TransactionInfo_OtherFeeInfo: String { return self._s[4017]! } - public var MediaPicker_Send: String { return self._s[4018]! } - public var PasscodeSettings_AutoLock_IfAwayFor_1minute: String { return self._s[4019]! } - public var Conversation_LiveLocationYou: String { return self._s[4020]! } - public var Notifications_ExceptionsUnmuted: String { return self._s[4021]! } + public var Activity_UploadingVideoMessage: String { return self._s[4018]! } + public var Wallet_TransactionInfo_OtherFeeInfo: String { return self._s[4019]! } + public var MediaPicker_Send: String { return self._s[4020]! } + public var PasscodeSettings_AutoLock_IfAwayFor_1minute: String { return self._s[4021]! } + public var Conversation_LiveLocationYou: String { return self._s[4022]! } + public var Notifications_ExceptionsUnmuted: String { return self._s[4023]! } public func Channel_AdminLog_MessageGroupPreHistoryHidden(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4022]!, self._r[4022]!, [_0]) + return formatWithArgumentRanges(self._s[4024]!, self._r[4024]!, [_0]) } public func PUSH_CHAT_ADD_YOU(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4023]!, self._r[4023]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4025]!, self._r[4025]!, [_1, _2]) } - public var Conversation_ViewBackground: String { return self._s[4024]! } - public var ChatSettings_PrivateChats: String { return self._s[4027]! } - public var Conversation_ErrorInaccessibleMessage: String { return self._s[4028]! } - public var Wallet_Receive_AmountInfo: String { return self._s[4029]! } - public var Appearance_ThemeNight: String { return self._s[4030]! } - public var Common_Search: String { return self._s[4031]! } - public var TwoStepAuth_ReEnterPasswordTitle: String { return self._s[4032]! } - public var ChangePhoneNumberNumber_Help: String { return self._s[4034]! } - public var Stickers_SuggestAdded: String { return self._s[4035]! } - public var Conversation_DiscardVoiceMessageDescription: String { return self._s[4038]! } - public var NetworkUsageSettings_Cellular: String { return self._s[4039]! } - public var CheckoutInfo_Title: String { return self._s[4040]! } - public var Conversation_ShareBotLocationConfirmationTitle: String { return self._s[4041]! } - public var Channel_BotDoesntSupportGroups: String { return self._s[4042]! } + public var Conversation_ViewBackground: String { return self._s[4026]! } + public var ChatSettings_PrivateChats: String { return self._s[4029]! } + public var Conversation_ErrorInaccessibleMessage: String { return self._s[4030]! } + public var Wallet_Receive_AmountInfo: String { return self._s[4031]! } + public var Appearance_ThemeNight: String { return self._s[4032]! } + public var Common_Search: String { return self._s[4033]! } + public var TwoStepAuth_ReEnterPasswordTitle: String { return self._s[4034]! } + public var ChangePhoneNumberNumber_Help: String { return self._s[4036]! } + public var Stickers_SuggestAdded: String { return self._s[4037]! } + public var Conversation_DiscardVoiceMessageDescription: String { return self._s[4040]! } + public var NetworkUsageSettings_Cellular: String { return self._s[4041]! } + public var CheckoutInfo_Title: String { return self._s[4042]! } + public var Conversation_ShareBotLocationConfirmationTitle: String { return self._s[4043]! } + public var Channel_BotDoesntSupportGroups: String { return self._s[4044]! } public func DialogList_SingleRecordingAudioSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4043]!, self._r[4043]!, [_0]) + return formatWithArgumentRanges(self._s[4045]!, self._r[4045]!, [_0]) } - public var MaskStickerSettings_Info: String { return self._s[4044]! } - public var GroupRemoved_DeleteUser: String { return self._s[4045]! } - public var Contacts_ShareTelegram: String { return self._s[4046]! } - public var Group_UpgradeNoticeText1: String { return self._s[4047]! } + public var MaskStickerSettings_Info: String { return self._s[4046]! } + public var GroupRemoved_DeleteUser: String { return self._s[4047]! } + public var Contacts_ShareTelegram: String { return self._s[4048]! } + public var Group_UpgradeNoticeText1: String { return self._s[4049]! } public func PUSH_PHONE_CALL_REQUEST(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4048]!, self._r[4048]!, [_1]) + return formatWithArgumentRanges(self._s[4050]!, self._r[4050]!, [_1]) } - public var PrivacyLastSeenSettings_Title: String { return self._s[4049]! } - public var SettingsSearch_Synonyms_Support: String { return self._s[4053]! } - public var PhotoEditor_TintTool: String { return self._s[4054]! } - public var Wallet_Receive_InvoiceUrlHeader: String { return self._s[4056]! } - public var GroupPermission_NoSendPolls: String { return self._s[4057]! } - public var NotificationsSound_None: String { return self._s[4058]! } + public var PrivacyLastSeenSettings_Title: String { return self._s[4051]! } + public var SettingsSearch_Synonyms_Support: String { return self._s[4055]! } + public var PhotoEditor_TintTool: String { return self._s[4056]! } + public var Wallet_Receive_InvoiceUrlHeader: String { return self._s[4058]! } + public var GroupPermission_NoSendPolls: String { return self._s[4059]! } + public var NotificationsSound_None: String { return self._s[4060]! } public func LOCAL_CHANNEL_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4059]!, self._r[4059]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[4061]!, self._r[4061]!, [_1, "\(_2)"]) } - public var CheckoutInfo_ShippingInfoCityPlaceholder: String { return self._s[4061]! } - public var ExplicitContent_AlertChannel: String { return self._s[4063]! } - public var Conversation_ClousStorageInfo_Description1: String { return self._s[4064]! } - public var Contacts_SortedByPresence: String { return self._s[4065]! } - public var WallpaperSearch_ColorGray: String { return self._s[4066]! } - public var Channel_AdminLogFilter_EventsNewSubscribers: String { return self._s[4067]! } - public var Conversation_ReportSpam: String { return self._s[4068]! } - public var ChatList_Search_NoResultsFilter: String { return self._s[4071]! } - public var WallpaperSearch_ColorBlack: String { return self._s[4072]! } - public var ArchivedChats_IntroTitle3: String { return self._s[4073]! } - public var Conversation_DefaultRestrictedText: String { return self._s[4074]! } - public var Settings_Devices: String { return self._s[4075]! } - public var Call_AudioRouteSpeaker: String { return self._s[4076]! } - public var GroupInfo_InviteLink_CopyLink: String { return self._s[4077]! } - public var Passport_Address_Country: String { return self._s[4079]! } - public var Cache_MaximumCacheSize: String { return self._s[4080]! } - public var Chat_PanelHidePinnedMessages: String { return self._s[4081]! } - public var Notifications_Badge_IncludePublicGroups: String { return self._s[4082]! } - public var Wallet_Receive_CreateInvoice: String { return self._s[4084]! } - public var ChatSettings_AutoDownloadUsingWiFi: String { return self._s[4085]! } - public var Login_TermsOfServiceLabel: String { return self._s[4086]! } - public var Calls_NoMissedCallsPlacehoder: String { return self._s[4087]! } - public var SocksProxySetup_RequiredCredentials: String { return self._s[4088]! } - public var VoiceOver_MessageContextOpenMessageMenu: String { return self._s[4089]! } - public var AutoNightTheme_ScheduledFrom: String { return self._s[4090]! } - public var ChatSettings_AutoDownloadDocuments: String { return self._s[4091]! } - public var ConvertToSupergroup_Note: String { return self._s[4093]! } - public var Settings_SetNewProfilePhotoOrVideo: String { return self._s[4094]! } - public var PrivacySettings_PasscodeAndTouchId: String { return self._s[4095]! } - public var Common_More: String { return self._s[4096]! } - public var ShareMenu_SelectChats: String { return self._s[4098]! } + public var CheckoutInfo_ShippingInfoCityPlaceholder: String { return self._s[4063]! } + public var ExplicitContent_AlertChannel: String { return self._s[4065]! } + public var Conversation_ClousStorageInfo_Description1: String { return self._s[4066]! } + public var Contacts_SortedByPresence: String { return self._s[4067]! } + public var WallpaperSearch_ColorGray: String { return self._s[4068]! } + public var Channel_AdminLogFilter_EventsNewSubscribers: String { return self._s[4069]! } + public var Conversation_ReportSpam: String { return self._s[4070]! } + public var ChatList_Search_NoResultsFilter: String { return self._s[4073]! } + public var WallpaperSearch_ColorBlack: String { return self._s[4074]! } + public var ArchivedChats_IntroTitle3: String { return self._s[4075]! } + public var Conversation_DefaultRestrictedText: String { return self._s[4076]! } + public var Settings_Devices: String { return self._s[4077]! } + public var Call_AudioRouteSpeaker: String { return self._s[4078]! } + public var GroupInfo_InviteLink_CopyLink: String { return self._s[4079]! } + public var Passport_Address_Country: String { return self._s[4081]! } + public var Cache_MaximumCacheSize: String { return self._s[4082]! } + public var Chat_PanelHidePinnedMessages: String { return self._s[4083]! } + public var Notifications_Badge_IncludePublicGroups: String { return self._s[4084]! } + public var Wallet_Receive_CreateInvoice: String { return self._s[4086]! } + public var ChatSettings_AutoDownloadUsingWiFi: String { return self._s[4087]! } + public var Login_TermsOfServiceLabel: String { return self._s[4088]! } + public var Calls_NoMissedCallsPlacehoder: String { return self._s[4089]! } + public var SocksProxySetup_RequiredCredentials: String { return self._s[4090]! } + public var VoiceOver_MessageContextOpenMessageMenu: String { return self._s[4091]! } + public var AutoNightTheme_ScheduledFrom: String { return self._s[4092]! } + public var ChatSettings_AutoDownloadDocuments: String { return self._s[4093]! } + public var ConvertToSupergroup_Note: String { return self._s[4095]! } + public var Settings_SetNewProfilePhotoOrVideo: String { return self._s[4096]! } + public var PrivacySettings_PasscodeAndTouchId: String { return self._s[4097]! } + public var Common_More: String { return self._s[4098]! } + public var ShareMenu_SelectChats: String { return self._s[4100]! } public func Conversation_ScheduleMessage_SendToday(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4100]!, self._r[4100]!, [_0]) + return formatWithArgumentRanges(self._s[4102]!, self._r[4102]!, [_0]) } public func Channel_AdminLog_MessageRemovedGroupStickerPack(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4101]!, self._r[4101]!, [_0]) + return formatWithArgumentRanges(self._s[4103]!, self._r[4103]!, [_0]) } - public var Contacts_PermissionsKeepDisabled: String { return self._s[4103]! } + public var Contacts_PermissionsKeepDisabled: String { return self._s[4105]! } public func Call_ParticipantVersionOutdatedError(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4104]!, self._r[4104]!, [_0]) + return formatWithArgumentRanges(self._s[4106]!, self._r[4106]!, [_0]) } - public var WatchRemote_AlertOpen: String { return self._s[4105]! } + public var WatchRemote_AlertOpen: String { return self._s[4107]! } public func PUSH_CHAT_ADD_MEMBER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4106]!, self._r[4106]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4108]!, self._r[4108]!, [_1, _2, _3]) } - public var Channel_Members_AddMembersHelp: String { return self._s[4107]! } - public var Shortcut_SwitchAccount: String { return self._s[4108]! } - public var Map_LiveLocationFor8Hours: String { return self._s[4109]! } + public var Channel_Members_AddMembersHelp: String { return self._s[4109]! } + public var Shortcut_SwitchAccount: String { return self._s[4110]! } + public var Map_LiveLocationFor8Hours: String { return self._s[4111]! } public func AutoNightTheme_AutomaticHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4110]!, self._r[4110]!, [_0]) + return formatWithArgumentRanges(self._s[4112]!, self._r[4112]!, [_0]) } - public var Compose_NewGroupTitle: String { return self._s[4111]! } - public var DialogList_You: String { return self._s[4112]! } - public var ReportPeer_ReasonViolence: String { return self._s[4113]! } + public var Compose_NewGroupTitle: String { return self._s[4113]! } + public var DialogList_You: String { return self._s[4114]! } + public var ReportPeer_ReasonViolence: String { return self._s[4115]! } public func PUSH_CHANNEL_MESSAGE_STICKER(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4114]!, self._r[4114]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4116]!, self._r[4116]!, [_1, _2]) } - public var KeyCommand_ScrollDown: String { return self._s[4118]! } - public var ChatSettings_DownloadInBackground: String { return self._s[4119]! } - public var Wallpaper_ResetWallpapers: String { return self._s[4120]! } - public var Channel_BanList_RestrictedTitle: String { return self._s[4121]! } - public var ArchivedChats_IntroText3: String { return self._s[4122]! } - public var HashtagSearch_AllChats: String { return self._s[4124]! } - public var Channel_Info_BlackList: String { return self._s[4126]! } - public var Contacts_SearchUsersAndGroupsLabel: String { return self._s[4127]! } - public var PrivacyPhoneNumberSettings_DiscoveryHeader: String { return self._s[4128]! } - public var Paint_Neon: String { return self._s[4130]! } - public var SettingsSearch_Synonyms_AppLanguage: String { return self._s[4131]! } - public var AutoDownloadSettings_AutoDownload: String { return self._s[4132]! } + public var KeyCommand_ScrollDown: String { return self._s[4120]! } + public var ChatSettings_DownloadInBackground: String { return self._s[4121]! } + public var Wallpaper_ResetWallpapers: String { return self._s[4122]! } + public var Channel_BanList_RestrictedTitle: String { return self._s[4123]! } + public var ArchivedChats_IntroText3: String { return self._s[4124]! } + public var HashtagSearch_AllChats: String { return self._s[4126]! } + public var Channel_Info_BlackList: String { return self._s[4128]! } + public var Contacts_SearchUsersAndGroupsLabel: String { return self._s[4129]! } + public var PrivacyPhoneNumberSettings_DiscoveryHeader: String { return self._s[4130]! } + public var Paint_Neon: String { return self._s[4132]! } + public var SettingsSearch_Synonyms_AppLanguage: String { return self._s[4133]! } + public var AutoDownloadSettings_AutoDownload: String { return self._s[4134]! } public func Notification_PinnedVideoMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4134]!, self._r[4134]!, [_0]) + return formatWithArgumentRanges(self._s[4136]!, self._r[4136]!, [_0]) } - public var Map_StopLiveLocation: String { return self._s[4135]! } - public var SettingsSearch_Synonyms_Data_SaveEditedPhotos: String { return self._s[4136]! } - public var Channel_Username_InvalidCharacters: String { return self._s[4137]! } - public var InstantPage_Reference: String { return self._s[4138]! } - public var ChatList_HideAction: String { return self._s[4140]! } - public var Conversation_FileICloudDrive: String { return self._s[4142]! } + public var Map_StopLiveLocation: String { return self._s[4137]! } + public var SettingsSearch_Synonyms_Data_SaveEditedPhotos: String { return self._s[4138]! } + public var Channel_Username_InvalidCharacters: String { return self._s[4139]! } + public var InstantPage_Reference: String { return self._s[4140]! } + public var ChatList_HideAction: String { return self._s[4142]! } + public var Conversation_FileICloudDrive: String { return self._s[4144]! } public func PUSH_PINNED_GEOLIVE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4143]!, self._r[4143]!, [_1]) + return formatWithArgumentRanges(self._s[4145]!, self._r[4145]!, [_1]) } - public var Passport_PasswordReset: String { return self._s[4145]! } - public var ChatList_Context_UnhideArchive: String { return self._s[4147]! } - public var ConvertToSupergroup_HelpText: String { return self._s[4148]! } - public var Calls_AddTab: String { return self._s[4149]! } - public var TwoStepAuth_ConfirmEmailResendCode: String { return self._s[4150]! } - public var SettingsSearch_Synonyms_Stickers_SuggestStickers: String { return self._s[4151]! } - public var Privacy_GroupsAndChannels: String { return self._s[4153]! } - public var AutoNightTheme_Disabled: String { return self._s[4154]! } - public var CreatePoll_MultipleChoice: String { return self._s[4155]! } + public var Passport_PasswordReset: String { return self._s[4147]! } + public var ChatList_Context_UnhideArchive: String { return self._s[4149]! } + public var ConvertToSupergroup_HelpText: String { return self._s[4150]! } + public var Calls_AddTab: String { return self._s[4151]! } + public var TwoStepAuth_ConfirmEmailResendCode: String { return self._s[4152]! } + public var SettingsSearch_Synonyms_Stickers_SuggestStickers: String { return self._s[4153]! } + public var Privacy_GroupsAndChannels: String { return self._s[4155]! } + public var AutoNightTheme_Disabled: String { return self._s[4156]! } + public var CreatePoll_MultipleChoice: String { return self._s[4157]! } public func PINNED_INVOICE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4156]!, self._r[4156]!, [_1]) + return formatWithArgumentRanges(self._s[4158]!, self._r[4158]!, [_1]) } - public var Watch_Bot_Restart: String { return self._s[4158]! } + public var Watch_Bot_Restart: String { return self._s[4160]! } public func Conversation_Kilobytes(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4159]!, self._r[4159]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[4161]!, self._r[4161]!, ["\(_0)"]) } - public var GroupInfo_ScamGroupWarning: String { return self._s[4160]! } - public var Conversation_EditingMessagePanelMedia: String { return self._s[4161]! } - public var Appearance_PreviewIncomingText: String { return self._s[4162]! } - public var Notifications_ChannelNotificationsExceptionsHelp: String { return self._s[4163]! } - public var ChatList_UndoArchiveRevealedTitle: String { return self._s[4165]! } - public var Stats_GroupOverview: String { return self._s[4167]! } - public var ScheduledMessages_EditTime: String { return self._s[4170]! } - public var Month_GenFebruary: String { return self._s[4171]! } - public var ChatList_AutoarchiveSuggestion_OpenSettings: String { return self._s[4172]! } - public var Stickers_ClearRecent: String { return self._s[4173]! } - public var TwoStepAuth_EnterPasswordPassword: String { return self._s[4174]! } - public var Stats_Message_PublicShares: String { return self._s[4175]! } + public var GroupInfo_ScamGroupWarning: String { return self._s[4162]! } + public var Conversation_EditingMessagePanelMedia: String { return self._s[4163]! } + public var Appearance_PreviewIncomingText: String { return self._s[4164]! } + public var Notifications_ChannelNotificationsExceptionsHelp: String { return self._s[4165]! } + public var ChatList_UndoArchiveRevealedTitle: String { return self._s[4167]! } + public var Stats_GroupOverview: String { return self._s[4169]! } + public var ScheduledMessages_EditTime: String { return self._s[4172]! } + public var Month_GenFebruary: String { return self._s[4173]! } + public var ChatList_AutoarchiveSuggestion_OpenSettings: String { return self._s[4174]! } + public var Stickers_ClearRecent: String { return self._s[4175]! } + public var TwoStepAuth_EnterPasswordPassword: String { return self._s[4176]! } + public var Stats_Message_PublicShares: String { return self._s[4177]! } public func Checkout_PayPrice(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4176]!, self._r[4176]!, [_0]) + return formatWithArgumentRanges(self._s[4178]!, self._r[4178]!, [_0]) } - public var Login_TermsOfServiceSignupDecline: String { return self._s[4177]! } - public var CheckoutInfo_ErrorCityInvalid: String { return self._s[4178]! } - public var VoiceOver_Chat_PlayHint: String { return self._s[4179]! } - public var ChatAdmins_AllMembersAreAdminsOffHelp: String { return self._s[4180]! } - public var CheckoutInfo_ShippingInfoTitle: String { return self._s[4182]! } - public var CreatePoll_Create: String { return self._s[4183]! } - public var ChatList_Search_FilterLinks: String { return self._s[4184]! } - public var Your_cards_number_is_invalid: String { return self._s[4185]! } - public var Month_ShortApril: String { return self._s[4186]! } - public var SocksProxySetup_UseForCalls: String { return self._s[4187]! } - public var Conversation_EditingCaptionPanelTitle: String { return self._s[4188]! } - public var SocksProxySetup_Status: String { return self._s[4189]! } - public var ChannelInfo_DeleteGroupConfirmation: String { return self._s[4190]! } - public var ChatListFolder_CategoryBots: String { return self._s[4191]! } - public var Passport_FieldIdentitySelfieHelp: String { return self._s[4193]! } - public var GroupInfo_BroadcastListNamePlaceholder: String { return self._s[4194]! } - public var Chat_PinnedListPreview_UnpinAllMessages: String { return self._s[4195]! } - public var Wallpaper_ResetWallpapersInfo: String { return self._s[4196]! } - public var Conversation_TitleUnmute: String { return self._s[4197]! } - public var Group_Setup_TypeHeader: String { return self._s[4198]! } - public var Stats_ViewsPerPost: String { return self._s[4199]! } - public var CheckoutInfo_ShippingInfoCountry: String { return self._s[4200]! } - public var Passport_Identity_TranslationHelp: String { return self._s[4201]! } + public var Login_TermsOfServiceSignupDecline: String { return self._s[4179]! } + public var CheckoutInfo_ErrorCityInvalid: String { return self._s[4180]! } + public var VoiceOver_Chat_PlayHint: String { return self._s[4181]! } + public var ChatAdmins_AllMembersAreAdminsOffHelp: String { return self._s[4182]! } + public var CheckoutInfo_ShippingInfoTitle: String { return self._s[4184]! } + public var CreatePoll_Create: String { return self._s[4185]! } + public var ChatList_Search_FilterLinks: String { return self._s[4186]! } + public var Your_cards_number_is_invalid: String { return self._s[4187]! } + public var Month_ShortApril: String { return self._s[4188]! } + public var SocksProxySetup_UseForCalls: String { return self._s[4189]! } + public var Conversation_EditingCaptionPanelTitle: String { return self._s[4190]! } + public var SocksProxySetup_Status: String { return self._s[4191]! } + public var ChannelInfo_DeleteGroupConfirmation: String { return self._s[4192]! } + public var ChatListFolder_CategoryBots: String { return self._s[4193]! } + public var Passport_FieldIdentitySelfieHelp: String { return self._s[4195]! } + public var GroupInfo_BroadcastListNamePlaceholder: String { return self._s[4196]! } + public var Chat_PinnedListPreview_UnpinAllMessages: String { return self._s[4197]! } + public var Wallpaper_ResetWallpapersInfo: String { return self._s[4198]! } + public var Conversation_TitleUnmute: String { return self._s[4199]! } + public var Group_Setup_TypeHeader: String { return self._s[4200]! } + public var Stats_ViewsPerPost: String { return self._s[4201]! } + public var CheckoutInfo_ShippingInfoCountry: String { return self._s[4202]! } + public var Passport_Identity_TranslationHelp: String { return self._s[4203]! } public func PUSH_CHANNEL_MESSAGE_FWD(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4202]!, self._r[4202]!, [_1]) + return formatWithArgumentRanges(self._s[4204]!, self._r[4204]!, [_1]) } - public var GroupInfo_Administrators_Title: String { return self._s[4203]! } + public var GroupInfo_Administrators_Title: String { return self._s[4205]! } public func Channel_AdminLog_MessageRankName(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4204]!, self._r[4204]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4206]!, self._r[4206]!, [_1, _2]) } public func PUSH_CHAT_MESSAGE_POLL(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4205]!, self._r[4205]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4207]!, self._r[4207]!, [_1, _2, _3]) } - public var Wallet_Receive_Title: String { return self._s[4206]! } - public var CheckoutInfo_ShippingInfoState: String { return self._s[4207]! } - public var Passport_Language_my: String { return self._s[4209]! } - public var PrivacyLastSeenSettings_AlwaysShareWith_Title: String { return self._s[4210]! } - public var Map_PlacesNearby: String { return self._s[4211]! } - public var Channel_About_Help: String { return self._s[4212]! } - public var LogoutOptions_AddAccountTitle: String { return self._s[4213]! } - public var ChatSettings_AutomaticAudioDownload: String { return self._s[4214]! } - public var Channel_Username_Title: String { return self._s[4215]! } - public var Activity_RecordingVideoMessage: String { return self._s[4216]! } + public var Wallet_Receive_Title: String { return self._s[4208]! } + public var CheckoutInfo_ShippingInfoState: String { return self._s[4209]! } + public var Passport_Language_my: String { return self._s[4211]! } + public var PrivacyLastSeenSettings_AlwaysShareWith_Title: String { return self._s[4212]! } + public var Map_PlacesNearby: String { return self._s[4213]! } + public var Channel_About_Help: String { return self._s[4214]! } + public var LogoutOptions_AddAccountTitle: String { return self._s[4215]! } + public var ChatSettings_AutomaticAudioDownload: String { return self._s[4216]! } + public var Channel_Username_Title: String { return self._s[4217]! } + public var Activity_RecordingVideoMessage: String { return self._s[4218]! } public func StickerPackActionInfo_RemovedText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4217]!, self._r[4217]!, [_0]) + return formatWithArgumentRanges(self._s[4219]!, self._r[4219]!, [_0]) } - public var CheckoutInfo_ShippingInfoCity: String { return self._s[4218]! } - public var Passport_DiscardMessageDescription: String { return self._s[4219]! } - public var Conversation_LinkDialogOpen: String { return self._s[4220]! } - public var ChatList_Context_HideArchive: String { return self._s[4221]! } + public var CheckoutInfo_ShippingInfoCity: String { return self._s[4220]! } + public var Passport_DiscardMessageDescription: String { return self._s[4221]! } + public var Conversation_LinkDialogOpen: String { return self._s[4222]! } + public var ChatList_Context_HideArchive: String { return self._s[4223]! } public func Message_AuthorPinnedGame(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4222]!, self._r[4222]!, [_0]) + return formatWithArgumentRanges(self._s[4224]!, self._r[4224]!, [_0]) } - public var Privacy_GroupsAndChannels_CustomShareHelp: String { return self._s[4223]! } - public var Conversation_Admin: String { return self._s[4224]! } - public var DialogList_TabTitle: String { return self._s[4225]! } + public var Privacy_GroupsAndChannels_CustomShareHelp: String { return self._s[4225]! } + public var Conversation_Admin: String { return self._s[4226]! } + public var DialogList_TabTitle: String { return self._s[4227]! } public func PUSH_CHAT_ALBUM(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4226]!, self._r[4226]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4228]!, self._r[4228]!, [_1, _2]) } - public var Notifications_PermissionsUnreachableText: String { return self._s[4227]! } - public var Passport_Identity_GenderMale: String { return self._s[4229]! } - public var SettingsSearch_Synonyms_Privacy_BlockedUsers: String { return self._s[4231]! } - public var PhoneNumberHelp_Alert: String { return self._s[4232]! } - public var EnterPasscode_EnterNewPasscodeChange: String { return self._s[4233]! } - public var Notifications_InAppNotifications: String { return self._s[4234]! } + public var Notifications_PermissionsUnreachableText: String { return self._s[4229]! } + public var Passport_Identity_GenderMale: String { return self._s[4231]! } + public var SettingsSearch_Synonyms_Privacy_BlockedUsers: String { return self._s[4233]! } + public var PhoneNumberHelp_Alert: String { return self._s[4234]! } + public var EnterPasscode_EnterNewPasscodeChange: String { return self._s[4235]! } + public var Notifications_InAppNotifications: String { return self._s[4236]! } public func Update_AppVersion(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4235]!, self._r[4235]!, [_0]) + return formatWithArgumentRanges(self._s[4237]!, self._r[4237]!, [_0]) } - public var Notification_VideoCallOutgoing: String { return self._s[4236]! } - public var Login_InvalidCodeError: String { return self._s[4237]! } - public var Conversation_PrivateChannelTimeLimitedAlertJoin: String { return self._s[4238]! } + public var Notification_VideoCallOutgoing: String { return self._s[4238]! } + public var Login_InvalidCodeError: String { return self._s[4239]! } + public var Conversation_PrivateChannelTimeLimitedAlertJoin: String { return self._s[4240]! } public func LastSeen_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4239]!, self._r[4239]!, [_0]) + return formatWithArgumentRanges(self._s[4241]!, self._r[4241]!, [_0]) } - public var Conversation_InputTextCaptionPlaceholder: String { return self._s[4241]! } - public var ReportPeer_Report: String { return self._s[4242]! } - public var Camera_FlashOff: String { return self._s[4245]! } - public var Conversation_InputTextBroadcastPlaceholder: String { return self._s[4248]! } - public var PrivacyPolicy_DeclineTitle: String { return self._s[4251]! } - public var SettingsSearch_Synonyms_Privacy_PasscodeAndTouchId: String { return self._s[4252]! } - public var Passport_FieldEmail: String { return self._s[4253]! } + public var Conversation_InputTextCaptionPlaceholder: String { return self._s[4243]! } + public var ReportPeer_Report: String { return self._s[4244]! } + public var Camera_FlashOff: String { return self._s[4247]! } + public var Conversation_InputTextBroadcastPlaceholder: String { return self._s[4250]! } + public var PrivacyPolicy_DeclineTitle: String { return self._s[4253]! } + public var SettingsSearch_Synonyms_Privacy_PasscodeAndTouchId: String { return self._s[4254]! } + public var Passport_FieldEmail: String { return self._s[4255]! } public func Channel_AdminLog_MessageKickedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4254]!, self._r[4254]!, [_1]) + return formatWithArgumentRanges(self._s[4256]!, self._r[4256]!, [_1]) } - public var Notifications_ExceptionsResetToDefaults: String { return self._s[4255]! } - public var PeerInfo_PaneVoiceAndVideo: String { return self._s[4256]! } - public var Group_OwnershipTransfer_Title: String { return self._s[4257]! } - public var Conversation_DefaultRestrictedInline: String { return self._s[4258]! } - public var Login_PhoneNumberHelp: String { return self._s[4260]! } - public var Channel_AdminLogFilter_EventsNewMembers: String { return self._s[4261]! } - public var Conversation_PinnedQuiz: String { return self._s[4262]! } - public var CreateGroup_SoftUserLimitAlert: String { return self._s[4263]! } - public var Login_PhoneNumberAlreadyAuthorizedSwitch: String { return self._s[4264]! } - public var Group_MessagePhotoUpdated: String { return self._s[4265]! } - public var LoginPassword_PasswordPlaceholder: String { return self._s[4266]! } - public var Passport_Identity_Translations: String { return self._s[4268]! } - public var ChatAdmins_AllMembersAreAdmins: String { return self._s[4269]! } - public var ChannelInfo_DeleteChannel: String { return self._s[4271]! } - public var PasscodeSettings_HelpBottom: String { return self._s[4272]! } - public var Channel_Members_AddMembers: String { return self._s[4273]! } - public var AutoDownloadSettings_LastDelimeter: String { return self._s[4274]! } - public var Notification_Exceptions_DeleteAllConfirmation: String { return self._s[4276]! } - public var Conversation_HoldForAudio: String { return self._s[4277]! } - public var Watch_LastSeen_Lately: String { return self._s[4279]! } - public var ChatList_Context_MarkAsRead: String { return self._s[4280]! } - public var Conversation_PinnedMessage: String { return self._s[4281]! } - public var SettingsSearch_Synonyms_Appearance_ColorTheme: String { return self._s[4282]! } - public var Passport_UpdateRequiredError: String { return self._s[4284]! } - public var PrivacySettings_Passcode: String { return self._s[4285]! } + public var Notifications_ExceptionsResetToDefaults: String { return self._s[4257]! } + public var PeerInfo_PaneVoiceAndVideo: String { return self._s[4258]! } + public var Group_OwnershipTransfer_Title: String { return self._s[4259]! } + public var Conversation_DefaultRestrictedInline: String { return self._s[4260]! } + public var Login_PhoneNumberHelp: String { return self._s[4262]! } + public var Channel_AdminLogFilter_EventsNewMembers: String { return self._s[4263]! } + public var Conversation_PinnedQuiz: String { return self._s[4264]! } + public var CreateGroup_SoftUserLimitAlert: String { return self._s[4265]! } + public var Login_PhoneNumberAlreadyAuthorizedSwitch: String { return self._s[4266]! } + public var Group_MessagePhotoUpdated: String { return self._s[4267]! } + public var LoginPassword_PasswordPlaceholder: String { return self._s[4268]! } + public var Passport_Identity_Translations: String { return self._s[4270]! } + public var ChatAdmins_AllMembersAreAdmins: String { return self._s[4271]! } + public var ChannelInfo_DeleteChannel: String { return self._s[4273]! } + public var PasscodeSettings_HelpBottom: String { return self._s[4274]! } + public var Channel_Members_AddMembers: String { return self._s[4275]! } + public var AutoDownloadSettings_LastDelimeter: String { return self._s[4276]! } + public var Notification_Exceptions_DeleteAllConfirmation: String { return self._s[4278]! } + public var Conversation_HoldForAudio: String { return self._s[4279]! } + public var Watch_LastSeen_Lately: String { return self._s[4281]! } + public var ChatList_Context_MarkAsRead: String { return self._s[4282]! } + public var Conversation_PinnedMessage: String { return self._s[4283]! } + public var SettingsSearch_Synonyms_Appearance_ColorTheme: String { return self._s[4284]! } + public var Passport_UpdateRequiredError: String { return self._s[4286]! } + public var PrivacySettings_Passcode: String { return self._s[4287]! } public func Call_EmojiDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4286]!, self._r[4286]!, [_0]) + return formatWithArgumentRanges(self._s[4288]!, self._r[4288]!, [_0]) } - public var AutoNightTheme_NotAvailable: String { return self._s[4287]! } - public var Conversation_PressVolumeButtonForSound: String { return self._s[4288]! } - public var LoginPassword_InvalidPasswordError: String { return self._s[4289]! } - public var ChatListFolder_IncludedSectionHeader: String { return self._s[4290]! } - public var Channel_SignMessages_Help: String { return self._s[4291]! } - public var ChatList_DeleteForEveryoneConfirmationTitle: String { return self._s[4292]! } - public var Conversation_TitleNoComments: String { return self._s[4293]! } - public var MediaPicker_LivePhotoDescription: String { return self._s[4294]! } - public var GroupInfo_Permissions: String { return self._s[4295]! } - public var GroupPermission_NoSendLinks: String { return self._s[4298]! } - public var Passport_Identity_ResidenceCountry: String { return self._s[4299]! } - public var Appearance_ThemeCarouselNightBlue: String { return self._s[4301]! } - public var ChatList_ArchiveAction: String { return self._s[4302]! } + public var AutoNightTheme_NotAvailable: String { return self._s[4289]! } + public var Conversation_PressVolumeButtonForSound: String { return self._s[4290]! } + public var LoginPassword_InvalidPasswordError: String { return self._s[4291]! } + public var ChatListFolder_IncludedSectionHeader: String { return self._s[4292]! } + public var Channel_SignMessages_Help: String { return self._s[4293]! } + public var ChatList_DeleteForEveryoneConfirmationTitle: String { return self._s[4294]! } + public var Conversation_TitleNoComments: String { return self._s[4295]! } + public var MediaPicker_LivePhotoDescription: String { return self._s[4296]! } + public var GroupInfo_Permissions: String { return self._s[4297]! } + public var GroupPermission_NoSendLinks: String { return self._s[4300]! } + public var Passport_Identity_ResidenceCountry: String { return self._s[4301]! } + public var Appearance_ThemeCarouselNightBlue: String { return self._s[4303]! } + public var ChatList_ArchiveAction: String { return self._s[4304]! } public func Channel_AdminLog_DisabledSlowmode(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4303]!, self._r[4303]!, [_0]) + return formatWithArgumentRanges(self._s[4305]!, self._r[4305]!, [_0]) } - public var GroupInfo_GroupHistory: String { return self._s[4304]! } + public var GroupInfo_GroupHistory: String { return self._s[4306]! } public func Channel_Management_ErrorNotMember(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4306]!, self._r[4306]!, [_0]) + return formatWithArgumentRanges(self._s[4308]!, self._r[4308]!, [_0]) } - public var Privacy_Forwards_LinkIfAllowed: String { return self._s[4308]! } - public var Channel_Info_Banned: String { return self._s[4309]! } - public var Paint_RecentStickers: String { return self._s[4310]! } - public var VoiceOver_MessageContextSend: String { return self._s[4311]! } - public var Group_ErrorNotMutualContact: String { return self._s[4312]! } - public var ReportPeer_ReasonOther: String { return self._s[4314]! } - public var Channel_BanUser_PermissionChangeGroupInfo: String { return self._s[4315]! } - public var SocksProxySetup_ShareQRCodeInfo: String { return self._s[4317]! } - public var KeyCommand_Find: String { return self._s[4318]! } + public var Privacy_Forwards_LinkIfAllowed: String { return self._s[4310]! } + public var Channel_Info_Banned: String { return self._s[4311]! } + public var Paint_RecentStickers: String { return self._s[4312]! } + public var VoiceOver_MessageContextSend: String { return self._s[4313]! } + public var Group_ErrorNotMutualContact: String { return self._s[4314]! } + public var ReportPeer_ReasonOther: String { return self._s[4316]! } + public var Channel_BanUser_PermissionChangeGroupInfo: String { return self._s[4317]! } + public var SocksProxySetup_ShareQRCodeInfo: String { return self._s[4319]! } + public var KeyCommand_Find: String { return self._s[4320]! } public func Channel_MessageTitleUpdated(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4319]!, self._r[4319]!, [_0]) + return formatWithArgumentRanges(self._s[4321]!, self._r[4321]!, [_0]) } - public var ChatList_Context_Unmute: String { return self._s[4320]! } - public var Chat_SlowmodeAttachmentLimitReached: String { return self._s[4321]! } - public var Stickers_GroupStickersHelp: String { return self._s[4322]! } - public var Wallet_Configuration_BlockchainIdPlaceholder: String { return self._s[4323]! } - public var Checkout_Title: String { return self._s[4324]! } - public var Activity_RecordingAudio: String { return self._s[4325]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsPreview: String { return self._s[4326]! } - public var BlockedUsers_BlockTitle: String { return self._s[4327]! } - public var Wallet_Month_ShortFebruary: String { return self._s[4329]! } - public var Calls_All: String { return self._s[4330]! } - public var DialogList_SavedMessagesHelp: String { return self._s[4332]! } - public var Settings_FAQ_Button: String { return self._s[4333]! } - public var Conversation_Dice_u1F3B0: String { return self._s[4335]! } + public var ChatList_Context_Unmute: String { return self._s[4322]! } + public var Chat_SlowmodeAttachmentLimitReached: String { return self._s[4323]! } + public var Stickers_GroupStickersHelp: String { return self._s[4324]! } + public var Wallet_Configuration_BlockchainIdPlaceholder: String { return self._s[4325]! } + public var Checkout_Title: String { return self._s[4326]! } + public var Activity_RecordingAudio: String { return self._s[4327]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsPreview: String { return self._s[4328]! } + public var BlockedUsers_BlockTitle: String { return self._s[4329]! } + public var Wallet_Month_ShortFebruary: String { return self._s[4331]! } + public var Calls_All: String { return self._s[4332]! } + public var DialogList_SavedMessagesHelp: String { return self._s[4334]! } + public var Settings_FAQ_Button: String { return self._s[4335]! } + public var Conversation_Dice_u1F3B0: String { return self._s[4337]! } public func Time_MonthOfYear_m5(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4336]!, self._r[4336]!, [_0]) + return formatWithArgumentRanges(self._s[4338]!, self._r[4338]!, [_0]) } - public var Conversation_ReportGroupLocation: String { return self._s[4337]! } - public var Passport_Scans_Upload: String { return self._s[4338]! } - public var Channel_EditAdmin_PermissionPinMessages: String { return self._s[4340]! } - public var ChatList_UnarchiveAction: String { return self._s[4341]! } - public var Stats_GroupTopInviter_History: String { return self._s[4342]! } - public var GroupInfo_Permissions_Title: String { return self._s[4343]! } - public var Passport_Language_el: String { return self._s[4344]! } + public var Conversation_ReportGroupLocation: String { return self._s[4339]! } + public var Passport_Scans_Upload: String { return self._s[4340]! } + public var Channel_EditAdmin_PermissionPinMessages: String { return self._s[4342]! } + public var ChatList_UnarchiveAction: String { return self._s[4343]! } + public var Stats_GroupTopInviter_History: String { return self._s[4344]! } + public var GroupInfo_Permissions_Title: String { return self._s[4345]! } + public var Passport_Language_el: String { return self._s[4346]! } public func Wallet_Time_PreciseDate_m4(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4345]!, self._r[4345]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4347]!, self._r[4347]!, [_1, _2, _3]) } - public var Channel_DiscussionMessageUnavailable: String { return self._s[4346]! } - public var GroupInfo_ActionPromote: String { return self._s[4347]! } - public var Group_OwnershipTransfer_ErrorLocatedGroupsTooMuch: String { return self._s[4348]! } + public var Channel_DiscussionMessageUnavailable: String { return self._s[4348]! } + public var GroupInfo_ActionPromote: String { return self._s[4349]! } + public var Group_OwnershipTransfer_ErrorLocatedGroupsTooMuch: String { return self._s[4350]! } public func TwoStepAuth_PendingEmailHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4349]!, self._r[4349]!, [_0]) + return formatWithArgumentRanges(self._s[4351]!, self._r[4351]!, [_0]) } - public var VoiceOver_Chat_Reply: String { return self._s[4350]! } - public var Month_GenMay: String { return self._s[4351]! } - public var DialogList_DeleteBotConversationConfirmation: String { return self._s[4352]! } - public var Chat_PsaTooltip_covid: String { return self._s[4353]! } - public var Watch_Suggestion_CantTalk: String { return self._s[4354]! } - public var Privacy_GroupsAndChannels_NeverAllow_Title: String { return self._s[4355]! } - public var AppUpgrade_Running: String { return self._s[4356]! } - public var PasscodeSettings_UnlockWithFaceId: String { return self._s[4359]! } - public var Notification_Exceptions_PreviewAlwaysOff: String { return self._s[4360]! } - public var SharedMedia_EmptyText: String { return self._s[4361]! } - public var Passport_Address_EditResidentialAddress: String { return self._s[4362]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsAlert: String { return self._s[4363]! } - public var Message_PinnedGame: String { return self._s[4364]! } - public var KeyCommand_SearchInChat: String { return self._s[4365]! } - public var Appearance_ThemeCarouselNewNight: String { return self._s[4366]! } - public var ChatList_Search_FilterMedia: String { return self._s[4367]! } - public var Message_PinnedAudioMessage: String { return self._s[4368]! } - public var ChannelInfo_ConfirmLeave: String { return self._s[4369]! } + public var VoiceOver_Chat_Reply: String { return self._s[4352]! } + public var Month_GenMay: String { return self._s[4353]! } + public var DialogList_DeleteBotConversationConfirmation: String { return self._s[4354]! } + public var Chat_PsaTooltip_covid: String { return self._s[4355]! } + public var Watch_Suggestion_CantTalk: String { return self._s[4356]! } + public var Privacy_GroupsAndChannels_NeverAllow_Title: String { return self._s[4357]! } + public var AppUpgrade_Running: String { return self._s[4358]! } + public var PasscodeSettings_UnlockWithFaceId: String { return self._s[4361]! } + public var Notification_Exceptions_PreviewAlwaysOff: String { return self._s[4362]! } + public var SharedMedia_EmptyText: String { return self._s[4363]! } + public var Passport_Address_EditResidentialAddress: String { return self._s[4364]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsAlert: String { return self._s[4365]! } + public var Message_PinnedGame: String { return self._s[4366]! } + public var KeyCommand_SearchInChat: String { return self._s[4367]! } + public var Appearance_ThemeCarouselNewNight: String { return self._s[4368]! } + public var ChatList_Search_FilterMedia: String { return self._s[4369]! } + public var Message_PinnedAudioMessage: String { return self._s[4370]! } + public var ChannelInfo_ConfirmLeave: String { return self._s[4371]! } public func Channel_AdminLog_MessagePromotedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4370]!, self._r[4370]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4372]!, self._r[4372]!, [_1, _2]) } - public var SocksProxySetup_ProxyStatusUnavailable: String { return self._s[4371]! } + public var SocksProxySetup_ProxyStatusUnavailable: String { return self._s[4373]! } public func Passport_Email_CodeHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4372]!, self._r[4372]!, [_0]) - } - public var Wallet_Receive_AddressCopied: String { return self._s[4373]! } - public func Message_PinnedTextMessage(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[4374]!, self._r[4374]!, [_0]) } - public var Settings_AddAccount: String { return self._s[4375]! } - public var Channel_AdminLog_CanDeleteMessages: String { return self._s[4376]! } - public var Conversation_DiscardVoiceMessageTitle: String { return self._s[4377]! } - public var Channel_JoinChannel: String { return self._s[4378]! } - public var Watch_UserInfo_Unblock: String { return self._s[4379]! } - public var PhoneLabel_Title: String { return self._s[4380]! } - public var Group_Setup_HistoryHiddenHelp: String { return self._s[4382]! } - public var Privacy_ProfilePhoto_AlwaysShareWith_Title: String { return self._s[4383]! } + public var Wallet_Receive_AddressCopied: String { return self._s[4375]! } + public func Message_PinnedTextMessage(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[4376]!, self._r[4376]!, [_0]) + } + public var Settings_AddAccount: String { return self._s[4377]! } + public var Channel_AdminLog_CanDeleteMessages: String { return self._s[4378]! } + public var Conversation_DiscardVoiceMessageTitle: String { return self._s[4379]! } + public var Channel_JoinChannel: String { return self._s[4380]! } + public var Watch_UserInfo_Unblock: String { return self._s[4381]! } + public var PhoneLabel_Title: String { return self._s[4382]! } + public var Group_Setup_HistoryHiddenHelp: String { return self._s[4384]! } + public var Privacy_ProfilePhoto_AlwaysShareWith_Title: String { return self._s[4385]! } public func Login_PhoneGenericEmailBody(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String, _ _6: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4384]!, self._r[4384]!, [_1, _2, _3, _4, _5, _6]) + return formatWithArgumentRanges(self._s[4386]!, self._r[4386]!, [_1, _2, _3, _4, _5, _6]) } - public var Wallet_Month_GenOctober: String { return self._s[4385]! } - public var Channel_AddBotErrorHaveRights: String { return self._s[4386]! } - public var ChatList_TabIconFoldersTooltipNonEmptyFolders: String { return self._s[4387]! } - public var DialogList_EncryptionProcessing: String { return self._s[4388]! } - public var ChatList_Search_FilterChats: String { return self._s[4389]! } - public var WatchRemote_NotificationText: String { return self._s[4390]! } - public var EditTheme_ChangeColors: String { return self._s[4391]! } - public var GroupRemoved_ViewUserInfo: String { return self._s[4392]! } - public var Wallet_TransactionInfo_RecipientHeader: String { return self._s[4393]! } - public var CallSettings_OnMobile: String { return self._s[4395]! } - public var Month_ShortFebruary: String { return self._s[4397]! } - public var VoiceOver_MessageContextReply: String { return self._s[4398]! } + public var Wallet_Month_GenOctober: String { return self._s[4387]! } + public var Channel_AddBotErrorHaveRights: String { return self._s[4388]! } + public var ChatList_TabIconFoldersTooltipNonEmptyFolders: String { return self._s[4389]! } + public var DialogList_EncryptionProcessing: String { return self._s[4390]! } + public var ChatList_Search_FilterChats: String { return self._s[4391]! } + public var WatchRemote_NotificationText: String { return self._s[4392]! } + public var EditTheme_ChangeColors: String { return self._s[4393]! } + public var GroupRemoved_ViewUserInfo: String { return self._s[4394]! } + public var Wallet_TransactionInfo_RecipientHeader: String { return self._s[4395]! } + public var CallSettings_OnMobile: String { return self._s[4397]! } + public var Month_ShortFebruary: String { return self._s[4399]! } + public var VoiceOver_MessageContextReply: String { return self._s[4400]! } public func PUSH_VIDEO_CALL_REQUEST(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4399]!, self._r[4399]!, [_1]) + return formatWithArgumentRanges(self._s[4401]!, self._r[4401]!, [_1]) } - public var Group_Location_ChangeLocation: String { return self._s[4400]! } - public var Passport_Address_TypeBankStatementUploadScan: String { return self._s[4401]! } - public var Wallet_Send_EncryptComment: String { return self._s[4402]! } - public var VoiceOver_Media_PlaybackStop: String { return self._s[4403]! } - public var SettingsSearch_Synonyms_Data_SaveIncomingPhotos: String { return self._s[4404]! } + public var Group_Location_ChangeLocation: String { return self._s[4402]! } + public var Passport_Address_TypeBankStatementUploadScan: String { return self._s[4403]! } + public var Wallet_Send_EncryptComment: String { return self._s[4404]! } + public var VoiceOver_Media_PlaybackStop: String { return self._s[4405]! } + public var SettingsSearch_Synonyms_Data_SaveIncomingPhotos: String { return self._s[4406]! } public func Channel_AdminLog_MessageRestrictedUntil(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4406]!, self._r[4406]!, [_0]) + return formatWithArgumentRanges(self._s[4408]!, self._r[4408]!, [_0]) } - public var PhotoEditor_WarmthTool: String { return self._s[4407]! } - public var Login_InfoAvatarPhoto: String { return self._s[4408]! } - public var Notification_Exceptions_NewException_MessagePreviewHeader: String { return self._s[4409]! } - public var Permissions_CellularDataAllowInSettings_v0: String { return self._s[4410]! } - public var Map_PlacesInThisArea: String { return self._s[4411]! } - public var VoiceOver_Chat_ContactEmail: String { return self._s[4412]! } - public var Notifications_InAppNotificationsSounds: String { return self._s[4413]! } + public var PhotoEditor_WarmthTool: String { return self._s[4409]! } + public var Login_InfoAvatarPhoto: String { return self._s[4410]! } + public var Notification_Exceptions_NewException_MessagePreviewHeader: String { return self._s[4411]! } + public var Permissions_CellularDataAllowInSettings_v0: String { return self._s[4412]! } + public var Map_PlacesInThisArea: String { return self._s[4413]! } + public var VoiceOver_Chat_ContactEmail: String { return self._s[4414]! } + public var Notifications_InAppNotificationsSounds: String { return self._s[4415]! } public func PUSH_PINNED_NOTEXT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4414]!, self._r[4414]!, [_1]) + return formatWithArgumentRanges(self._s[4416]!, self._r[4416]!, [_1]) } - public var ShareMenu_Send: String { return self._s[4415]! } - public var Username_InvalidStartsWithNumber: String { return self._s[4416]! } - public var Appearance_AppIconClassicX: String { return self._s[4417]! } + public var ShareMenu_Send: String { return self._s[4417]! } + public var Username_InvalidStartsWithNumber: String { return self._s[4418]! } + public var Appearance_AppIconClassicX: String { return self._s[4419]! } public func PUSH_CHANNEL_MESSAGE_ROUND(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4418]!, self._r[4418]!, [_1]) + return formatWithArgumentRanges(self._s[4420]!, self._r[4420]!, [_1]) } - public var Conversation_StopPoll: String { return self._s[4419]! } - public var InfoPlist_NSLocationAlwaysUsageDescription: String { return self._s[4421]! } - public var Passport_Identity_EditIdentityCard: String { return self._s[4422]! } - public var Appearance_ThemePreview_ChatList_3_Name: String { return self._s[4423]! } - public var Wallet_WordCheck_Title: String { return self._s[4424]! } - public var Conversation_Timer_Title: String { return self._s[4425]! } - public var Common_Next: String { return self._s[4426]! } - public var Notification_Exceptions_NewException: String { return self._s[4427]! } + public var Conversation_StopPoll: String { return self._s[4421]! } + public var InfoPlist_NSLocationAlwaysUsageDescription: String { return self._s[4423]! } + public var Passport_Identity_EditIdentityCard: String { return self._s[4424]! } + public var Appearance_ThemePreview_ChatList_3_Name: String { return self._s[4425]! } + public var Wallet_WordCheck_Title: String { return self._s[4426]! } + public var Conversation_Timer_Title: String { return self._s[4427]! } + public var Common_Next: String { return self._s[4428]! } + public var Notification_Exceptions_NewException: String { return self._s[4429]! } public func Generic_OpenHiddenLinkAlert(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4428]!, self._r[4428]!, [_0]) + return formatWithArgumentRanges(self._s[4430]!, self._r[4430]!, [_0]) } - public var AccessDenied_CallMicrophone: String { return self._s[4429]! } - public var SettingsSearch_Synonyms_Data_AutoDownloadUsingCellular: String { return self._s[4430]! } - public var ChangePhoneNumberCode_Help: String { return self._s[4431]! } - public var Passport_Identity_OneOfTypeIdentityCard: String { return self._s[4432]! } - public var Channel_AdminLogFilter_EventsLeaving: String { return self._s[4433]! } - public var BlockedUsers_LeavePrefix: String { return self._s[4434]! } + public var AccessDenied_CallMicrophone: String { return self._s[4431]! } + public var SettingsSearch_Synonyms_Data_AutoDownloadUsingCellular: String { return self._s[4432]! } + public var ChangePhoneNumberCode_Help: String { return self._s[4433]! } + public var Passport_Identity_OneOfTypeIdentityCard: String { return self._s[4434]! } + public var Channel_AdminLogFilter_EventsLeaving: String { return self._s[4435]! } + public var BlockedUsers_LeavePrefix: String { return self._s[4436]! } public func Passport_RequestHeader(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4435]!, self._r[4435]!, [_0]) + return formatWithArgumentRanges(self._s[4437]!, self._r[4437]!, [_0]) } - public var Group_About_Help: String { return self._s[4436]! } - public var TwoStepAuth_ChangePasswordDescription: String { return self._s[4437]! } - public var Tour_Title3: String { return self._s[4438]! } - public var Watch_Conversation_Unblock: String { return self._s[4439]! } - public var Watch_UserInfo_Block: String { return self._s[4440]! } - public var Notifications_ChannelNotificationsAlert: String { return self._s[4441]! } - public var TwoFactorSetup_Hint_Action: String { return self._s[4442]! } - public var IntentsSettings_SuggestedChatsInfo: String { return self._s[4443]! } - public var Wallet_Alert_Cancel: String { return self._s[4444]! } - public var TextFormat_AddLinkTitle: String { return self._s[4445]! } - public var GroupInfo_InviteLink_RevokeAlert_Revoke: String { return self._s[4446]! } - public var TwoStepAuth_EnterPasswordTitle: String { return self._s[4447]! } - public var FastTwoStepSetup_PasswordSection: String { return self._s[4448]! } - public var Compose_ChannelMembers: String { return self._s[4449]! } - public var Conversation_ForwardTitle: String { return self._s[4450]! } + public var Group_About_Help: String { return self._s[4438]! } + public var TwoStepAuth_ChangePasswordDescription: String { return self._s[4439]! } + public var Tour_Title3: String { return self._s[4440]! } + public var Watch_Conversation_Unblock: String { return self._s[4441]! } + public var Watch_UserInfo_Block: String { return self._s[4442]! } + public var Notifications_ChannelNotificationsAlert: String { return self._s[4443]! } + public var TwoFactorSetup_Hint_Action: String { return self._s[4444]! } + public var IntentsSettings_SuggestedChatsInfo: String { return self._s[4445]! } + public var Wallet_Alert_Cancel: String { return self._s[4446]! } + public var TextFormat_AddLinkTitle: String { return self._s[4447]! } + public var GroupInfo_InviteLink_RevokeAlert_Revoke: String { return self._s[4448]! } + public var TwoStepAuth_EnterPasswordTitle: String { return self._s[4449]! } + public var FastTwoStepSetup_PasswordSection: String { return self._s[4450]! } + public var Compose_ChannelMembers: String { return self._s[4451]! } + public var Conversation_ForwardTitle: String { return self._s[4452]! } public func Wallet_Updated_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4451]!, self._r[4451]!, [_0]) + return formatWithArgumentRanges(self._s[4453]!, self._r[4453]!, [_0]) } - public var Conversation_PinnedPoll: String { return self._s[4453]! } + public var Conversation_PinnedPoll: String { return self._s[4455]! } public func VoiceOver_Chat_AnonymousPollFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4454]!, self._r[4454]!, [_0]) + return formatWithArgumentRanges(self._s[4456]!, self._r[4456]!, [_0]) } - public var SettingsSearch_Synonyms_EditProfile_AddAccount: String { return self._s[4455]! } - public var Conversation_ContextMenuStickerPackAdd: String { return self._s[4456]! } - public var Stats_Overview: String { return self._s[4457]! } - public var Map_HomeAndWorkTitle: String { return self._s[4458]! } - public var Wallet_Intro_Terms: String { return self._s[4459]! } + public var SettingsSearch_Synonyms_EditProfile_AddAccount: String { return self._s[4457]! } + public var Conversation_ContextMenuStickerPackAdd: String { return self._s[4458]! } + public var Stats_Overview: String { return self._s[4459]! } + public var Map_HomeAndWorkTitle: String { return self._s[4460]! } + public var Wallet_Intro_Terms: String { return self._s[4461]! } public func Time_PreciseDate_m4(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4460]!, self._r[4460]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4462]!, self._r[4462]!, [_1, _2, _3]) } - public var Passport_Address_CityPlaceholder: String { return self._s[4461]! } - public var InfoPlist_NSLocationAlwaysAndWhenInUseUsageDescription: String { return self._s[4462]! } - public var Privacy_PhoneNumber: String { return self._s[4463]! } - public var ChatList_Search_FilterFiles: String { return self._s[4464]! } - public var ChatList_DeleteForEveryoneConfirmationAction: String { return self._s[4465]! } - public var ChannelIntro_CreateChannel: String { return self._s[4466]! } - public var Conversation_InputTextAnonymousPlaceholder: String { return self._s[4467]! } + public var Passport_Address_CityPlaceholder: String { return self._s[4463]! } + public var InfoPlist_NSLocationAlwaysAndWhenInUseUsageDescription: String { return self._s[4464]! } + public var Privacy_PhoneNumber: String { return self._s[4465]! } + public var ChatList_Search_FilterFiles: String { return self._s[4466]! } + public var ChatList_DeleteForEveryoneConfirmationAction: String { return self._s[4467]! } + public var ChannelIntro_CreateChannel: String { return self._s[4468]! } + public var Conversation_InputTextAnonymousPlaceholder: String { return self._s[4469]! } public func Login_EmailCodeBody(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4468]!, self._r[4468]!, [_0]) + return formatWithArgumentRanges(self._s[4470]!, self._r[4470]!, [_0]) } - public var Weekday_ShortMonday: String { return self._s[4469]! } - public var Passport_Language_ar: String { return self._s[4471]! } - public var SettingsSearch_Synonyms_EditProfile_Title: String { return self._s[4472]! } - public var TwoFactorSetup_Done_Title: String { return self._s[4473]! } - public var Calls_RatingFeedback: String { return self._s[4474]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsPreview: String { return self._s[4475]! } - public var AutoDownloadSettings_ResetSettings: String { return self._s[4478]! } - public var Watch_Compose_Send: String { return self._s[4479]! } - public var PasscodeSettings_ChangePasscode: String { return self._s[4480]! } - public var WebSearch_RecentSectionClear: String { return self._s[4481]! } + public var Weekday_ShortMonday: String { return self._s[4471]! } + public var Passport_Language_ar: String { return self._s[4473]! } + public var SettingsSearch_Synonyms_EditProfile_Title: String { return self._s[4474]! } + public var TwoFactorSetup_Done_Title: String { return self._s[4475]! } + public var Calls_RatingFeedback: String { return self._s[4476]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsPreview: String { return self._s[4477]! } + public var AutoDownloadSettings_ResetSettings: String { return self._s[4480]! } + public var Watch_Compose_Send: String { return self._s[4481]! } + public var PasscodeSettings_ChangePasscode: String { return self._s[4482]! } + public var WebSearch_RecentSectionClear: String { return self._s[4483]! } public func Contacts_AccessDeniedHelpPortrait(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4482]!, self._r[4482]!, [_0]) + return formatWithArgumentRanges(self._s[4484]!, self._r[4484]!, [_0]) } - public var WallpaperSearch_ColorTeal: String { return self._s[4483]! } - public var Wallpaper_SetCustomBackgroundInfo: String { return self._s[4484]! } - public var Permissions_ContactsTitle_v0: String { return self._s[4485]! } - public var Checkout_PasswordEntry_Pay: String { return self._s[4487]! } - public var Settings_SavedMessages: String { return self._s[4488]! } - public var TwoStepAuth_ReEnterPasswordDescription: String { return self._s[4489]! } - public var Month_ShortMarch: String { return self._s[4490]! } - public var Message_Location: String { return self._s[4491]! } + public var WallpaperSearch_ColorTeal: String { return self._s[4485]! } + public var Wallpaper_SetCustomBackgroundInfo: String { return self._s[4486]! } + public var Permissions_ContactsTitle_v0: String { return self._s[4487]! } + public var Checkout_PasswordEntry_Pay: String { return self._s[4489]! } + public var Settings_SavedMessages: String { return self._s[4490]! } + public var TwoStepAuth_ReEnterPasswordDescription: String { return self._s[4491]! } + public var Month_ShortMarch: String { return self._s[4492]! } + public var Message_Location: String { return self._s[4493]! } public func PUSH_MESSAGE_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4492]!, self._r[4492]!, [_1]) + return formatWithArgumentRanges(self._s[4494]!, self._r[4494]!, [_1]) } public func Notification_CallTimeFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4493]!, self._r[4493]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4495]!, self._r[4495]!, [_1, _2]) } - public var VoiceOver_Chat_VoiceMessage: String { return self._s[4495]! } + public var VoiceOver_Chat_VoiceMessage: String { return self._s[4497]! } public func Channel_AdminLog_MessageChangedUnlinkedChannel(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4496]!, self._r[4496]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4498]!, self._r[4498]!, [_1, _2]) } - public var GroupPermission_NoSendMedia: String { return self._s[4497]! } - public var Conversation_ClousStorageInfo_Description2: String { return self._s[4498]! } - public var SharedMedia_CategoryDocs: String { return self._s[4499]! } - public var Appearance_RemoveThemeConfirmation: String { return self._s[4500]! } - public var Paint_Framed: String { return self._s[4501]! } - public var Channel_EditAdmin_PermissionAddAdmins: String { return self._s[4502]! } - public var Passport_Identity_DoesNotExpire: String { return self._s[4503]! } - public var Channel_SignMessages: String { return self._s[4504]! } - public var Contacts_AccessDeniedHelpON: String { return self._s[4505]! } - public var Conversation_ContextMenuStickerPackInfo: String { return self._s[4506]! } + public var GroupPermission_NoSendMedia: String { return self._s[4499]! } + public var Conversation_ClousStorageInfo_Description2: String { return self._s[4500]! } + public var SharedMedia_CategoryDocs: String { return self._s[4501]! } + public var Appearance_RemoveThemeConfirmation: String { return self._s[4502]! } + public var Paint_Framed: String { return self._s[4503]! } + public var Channel_EditAdmin_PermissionAddAdmins: String { return self._s[4504]! } + public var Passport_Identity_DoesNotExpire: String { return self._s[4505]! } + public var Channel_SignMessages: String { return self._s[4506]! } + public var Contacts_AccessDeniedHelpON: String { return self._s[4507]! } + public var Conversation_ContextMenuStickerPackInfo: String { return self._s[4508]! } public func PUSH_CHAT_LEFT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4507]!, self._r[4507]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4509]!, self._r[4509]!, [_1, _2]) } - public var GroupInfo_UpgradeButton: String { return self._s[4508]! } - public var Channel_EditAdmin_PermissionInviteMembers: String { return self._s[4509]! } - public var AutoDownloadSettings_Files: String { return self._s[4510]! } + public var GroupInfo_UpgradeButton: String { return self._s[4510]! } + public var Channel_EditAdmin_PermissionInviteMembers: String { return self._s[4511]! } + public var AutoDownloadSettings_Files: String { return self._s[4512]! } public func Notification_ChangedGroupName(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4511]!, self._r[4511]!, [_0, _1]) + return formatWithArgumentRanges(self._s[4513]!, self._r[4513]!, [_0, _1]) } - public var Login_SendCodeViaSms: String { return self._s[4513]! } - public var Update_UpdateApp: String { return self._s[4514]! } - public var Channel_Setup_TypePublic: String { return self._s[4515]! } - public var Watch_Compose_CreateMessage: String { return self._s[4516]! } + public var Login_SendCodeViaSms: String { return self._s[4515]! } + public var Update_UpdateApp: String { return self._s[4516]! } + public var Channel_Setup_TypePublic: String { return self._s[4517]! } + public var Watch_Compose_CreateMessage: String { return self._s[4518]! } public func PUSH_CHAT_MESSAGE_VIDEOS(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4517]!, self._r[4517]!, [_1, _2, _3]) - } - public var StickerPacksSettings_ManagingHelp: String { return self._s[4518]! } - public func Wallet_Time_PreciseDate_m12(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[4519]!, self._r[4519]!, [_1, _2, _3]) } - public var VoiceOver_Chat_Video: String { return self._s[4520]! } - public var Forward_ChannelReadOnly: String { return self._s[4521]! } - public var StickerPack_HideStickers: String { return self._s[4522]! } - public var ChatListFolder_NameContacts: String { return self._s[4523]! } - public var Profile_BotInfo: String { return self._s[4524]! } - public var Document_TargetConfirmationFormat: String { return self._s[4525]! } - public var GroupInfo_InviteByLink: String { return self._s[4526]! } - public var Channel_AdminLog_BanSendStickersAndGifs: String { return self._s[4527]! } - public var Watch_Stickers_RecentPlaceholder: String { return self._s[4528]! } - public var Broadcast_AdminLog_EmptyText: String { return self._s[4529]! } - public var Passport_NotLoggedInMessage: String { return self._s[4530]! } - public var Conversation_StopQuizConfirmation: String { return self._s[4531]! } - public var Checkout_PaymentMethod: String { return self._s[4532]! } - public var ChatList_ArchivedChatsTitle: String { return self._s[4536]! } - public var TwoStepAuth_SetupPasswordConfirmFailed: String { return self._s[4537]! } - public var VoiceOver_Chat_RecordPreviewVoiceMessage: String { return self._s[4538]! } - public var PrivacyLastSeenSettings_GroupsAndChannelsHelp: String { return self._s[4539]! } - public var SettingsSearch_Synonyms_Privacy_Data_ContactsReset: String { return self._s[4540]! } - public var Camera_Title: String { return self._s[4541]! } - public var Map_Directions: String { return self._s[4542]! } - public var Wallet_Intro_ImportExisting: String { return self._s[4543]! } - public var Stats_MessagePublicForwardsTitle: String { return self._s[4544]! } - public var Privacy_ProfilePhoto_WhoCanSeeMyPhoto: String { return self._s[4546]! } - public var Profile_EncryptionKey: String { return self._s[4547]! } + public var StickerPacksSettings_ManagingHelp: String { return self._s[4520]! } + public func Wallet_Time_PreciseDate_m12(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[4521]!, self._r[4521]!, [_1, _2, _3]) + } + public var VoiceOver_Chat_Video: String { return self._s[4522]! } + public var Forward_ChannelReadOnly: String { return self._s[4523]! } + public var StickerPack_HideStickers: String { return self._s[4524]! } + public var ChatListFolder_NameContacts: String { return self._s[4525]! } + public var Profile_BotInfo: String { return self._s[4526]! } + public var Document_TargetConfirmationFormat: String { return self._s[4527]! } + public var GroupInfo_InviteByLink: String { return self._s[4528]! } + public var Channel_AdminLog_BanSendStickersAndGifs: String { return self._s[4529]! } + public var Watch_Stickers_RecentPlaceholder: String { return self._s[4530]! } + public var Broadcast_AdminLog_EmptyText: String { return self._s[4531]! } + public var Passport_NotLoggedInMessage: String { return self._s[4532]! } + public var Conversation_StopQuizConfirmation: String { return self._s[4533]! } + public var Checkout_PaymentMethod: String { return self._s[4534]! } + public var ChatList_ArchivedChatsTitle: String { return self._s[4538]! } + public var TwoStepAuth_SetupPasswordConfirmFailed: String { return self._s[4539]! } + public var VoiceOver_Chat_RecordPreviewVoiceMessage: String { return self._s[4540]! } + public var PrivacyLastSeenSettings_GroupsAndChannelsHelp: String { return self._s[4541]! } + public var SettingsSearch_Synonyms_Privacy_Data_ContactsReset: String { return self._s[4542]! } + public var Camera_Title: String { return self._s[4543]! } + public var Map_Directions: String { return self._s[4544]! } + public var Wallet_Intro_ImportExisting: String { return self._s[4545]! } + public var Stats_MessagePublicForwardsTitle: String { return self._s[4546]! } + public var Privacy_ProfilePhoto_WhoCanSeeMyPhoto: String { return self._s[4548]! } + public var Profile_EncryptionKey: String { return self._s[4549]! } public func LOCAL_CHAT_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4548]!, self._r[4548]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[4550]!, self._r[4550]!, [_1, "\(_2)"]) } public func Compatibility_SecretMediaVersionTooLow(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4549]!, self._r[4549]!, [_0, _1]) + return formatWithArgumentRanges(self._s[4551]!, self._r[4551]!, [_0, _1]) } - public var Passport_Identity_TypePassport: String { return self._s[4550]! } - public var CreatePoll_QuizOptionsHeader: String { return self._s[4552]! } - public var Common_No: String { return self._s[4553]! } - public var Conversation_SendMessage_ScheduleMessage: String { return self._s[4554]! } - public var SettingsSearch_Synonyms_Privacy_LastSeen: String { return self._s[4555]! } - public var Settings_AboutEmpty: String { return self._s[4556]! } - public var TwoStepAuth_FloodError: String { return self._s[4558]! } - public var SettingsSearch_Synonyms_Appearance_TextSize: String { return self._s[4559]! } + public var Passport_Identity_TypePassport: String { return self._s[4552]! } + public var CreatePoll_QuizOptionsHeader: String { return self._s[4554]! } + public var Common_No: String { return self._s[4555]! } + public var Conversation_SendMessage_ScheduleMessage: String { return self._s[4556]! } + public var SettingsSearch_Synonyms_Privacy_LastSeen: String { return self._s[4557]! } + public var Settings_AboutEmpty: String { return self._s[4558]! } + public var TwoStepAuth_FloodError: String { return self._s[4560]! } + public var SettingsSearch_Synonyms_Appearance_TextSize: String { return self._s[4561]! } public func Channel_AdminLog_MessageUnkickedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4561]!, self._r[4561]!, [_1]) + return formatWithArgumentRanges(self._s[4563]!, self._r[4563]!, [_1]) } - public var Conversation_Edit: String { return self._s[4564]! } - public var CheckoutInfo_SaveInfo: String { return self._s[4565]! } - public var VoiceOver_Chat_AnonymousPoll: String { return self._s[4566]! } - public var Call_CameraTooltip: String { return self._s[4568]! } - public var InstantPage_FeedbackButtonShort: String { return self._s[4569]! } - public var Contacts_InviteToTelegram: String { return self._s[4570]! } - public var Wallet_WordImport_CanNotRemember: String { return self._s[4571]! } - public var Notifications_ResetAllNotifications: String { return self._s[4572]! } - public var Calls_NewCall: String { return self._s[4573]! } - public var VoiceOver_Chat_Music: String { return self._s[4576]! } - public var Channel_Members_AddAdminErrorNotAMember: String { return self._s[4577]! } - public var Channel_Edit_AboutItem: String { return self._s[4578]! } - public var Message_VideoExpired: String { return self._s[4579]! } - public var Passport_Address_TypeTemporaryRegistrationUploadScan: String { return self._s[4580]! } + public var Conversation_Edit: String { return self._s[4566]! } + public var CheckoutInfo_SaveInfo: String { return self._s[4567]! } + public var VoiceOver_Chat_AnonymousPoll: String { return self._s[4568]! } + public var Call_CameraTooltip: String { return self._s[4570]! } + public var InstantPage_FeedbackButtonShort: String { return self._s[4571]! } + public var Contacts_InviteToTelegram: String { return self._s[4572]! } + public var Wallet_WordImport_CanNotRemember: String { return self._s[4573]! } + public var Notifications_ResetAllNotifications: String { return self._s[4574]! } + public var Calls_NewCall: String { return self._s[4575]! } + public var VoiceOver_Chat_Music: String { return self._s[4578]! } + public var Channel_Members_AddAdminErrorNotAMember: String { return self._s[4579]! } + public var Channel_Edit_AboutItem: String { return self._s[4580]! } + public var Message_VideoExpired: String { return self._s[4581]! } + public var Passport_Address_TypeTemporaryRegistrationUploadScan: String { return self._s[4582]! } public func PUSH_CHAT_RETURNED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4581]!, self._r[4581]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4583]!, self._r[4583]!, [_1, _2]) } - public var NotificationsSound_Input: String { return self._s[4583]! } - public var Notifications_ClassicTones: String { return self._s[4584]! } - public var Conversation_StatusTyping: String { return self._s[4585]! } - public var Checkout_ErrorProviderAccountInvalid: String { return self._s[4586]! } - public var ChatSettings_AutoDownloadSettings_Delimeter: String { return self._s[4587]! } - public var Wallet_Month_ShortSeptember: String { return self._s[4588]! } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChats: String { return self._s[4589]! } - public var Conversation_MessageLeaveComment: String { return self._s[4590]! } - public var UserInfo_TapToCall: String { return self._s[4591]! } - public var EnterPasscode_EnterNewPasscodeNew: String { return self._s[4592]! } - public var Conversation_ClearAll: String { return self._s[4594]! } - public var UserInfo_NotificationsDefault: String { return self._s[4595]! } - public var Wallet_Send_OwnAddressAlertText: String { return self._s[4596]! } - public var Location_ProximityGroupTip: String { return self._s[4597]! } - public var Map_ChooseAPlace: String { return self._s[4598]! } + public var NotificationsSound_Input: String { return self._s[4585]! } + public var Notifications_ClassicTones: String { return self._s[4586]! } + public var Conversation_StatusTyping: String { return self._s[4587]! } + public var Checkout_ErrorProviderAccountInvalid: String { return self._s[4588]! } + public var ChatSettings_AutoDownloadSettings_Delimeter: String { return self._s[4589]! } + public var Wallet_Month_ShortSeptember: String { return self._s[4590]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChats: String { return self._s[4591]! } + public var Conversation_MessageLeaveComment: String { return self._s[4592]! } + public var UserInfo_TapToCall: String { return self._s[4593]! } + public var EnterPasscode_EnterNewPasscodeNew: String { return self._s[4594]! } + public var Conversation_ClearAll: String { return self._s[4596]! } + public var UserInfo_NotificationsDefault: String { return self._s[4597]! } + public var Wallet_Send_OwnAddressAlertText: String { return self._s[4598]! } + public var Location_ProximityGroupTip: String { return self._s[4599]! } + public var Map_ChooseAPlace: String { return self._s[4600]! } public func Wallet_Receive_ShareInvoiceUrlInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4599]!, self._r[4599]!, [_0]) + return formatWithArgumentRanges(self._s[4601]!, self._r[4601]!, [_0]) } - public var GroupInfo_AddParticipantTitle: String { return self._s[4600]! } - public var ChatList_PeerTypeNonContact: String { return self._s[4601]! } - public var Conversation_SlideToCancel: String { return self._s[4602]! } - public var Month_ShortJuly: String { return self._s[4603]! } - public var SocksProxySetup_ProxyType: String { return self._s[4604]! } + public var GroupInfo_AddParticipantTitle: String { return self._s[4602]! } + public var ChatList_PeerTypeNonContact: String { return self._s[4603]! } + public var Conversation_SlideToCancel: String { return self._s[4604]! } + public var Month_ShortJuly: String { return self._s[4605]! } + public var SocksProxySetup_ProxyType: String { return self._s[4606]! } public func ChatList_DeleteChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4605]!, self._r[4605]!, [_0]) + return formatWithArgumentRanges(self._s[4607]!, self._r[4607]!, [_0]) } - public var ChatList_EditFolders: String { return self._s[4606]! } - public var TwoStepAuth_SetPasswordHelp: String { return self._s[4607]! } - public var Wallet_Send_ConfirmationConfirm: String { return self._s[4609]! } - public var Wallet_Created_ExportErrorTitle: String { return self._s[4610]! } + public var ChatList_EditFolders: String { return self._s[4608]! } + public var TwoStepAuth_SetPasswordHelp: String { return self._s[4609]! } + public var Wallet_Send_ConfirmationConfirm: String { return self._s[4611]! } + public var Wallet_Created_ExportErrorTitle: String { return self._s[4612]! } public func GroupPermission_ApplyAlertText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4611]!, self._r[4611]!, [_0]) - } - public var Permissions_PeopleNearbyTitle_v0: String { return self._s[4612]! } - public var ScheduledMessages_RemindersTitle: String { return self._s[4613]! } - public var Your_cards_expiration_year_is_invalid: String { return self._s[4614]! } - public var Wallet_Info_TransactionPendingHeader: String { return self._s[4616]! } - public var UserInfo_ShareMyContactInfo: String { return self._s[4617]! } - public var Passport_DeleteAddress: String { return self._s[4619]! } - public var Passport_DeletePassportConfirmation: String { return self._s[4620]! } - public var Passport_Identity_ReverseSide: String { return self._s[4621]! } - public var CheckoutInfo_ErrorEmailInvalid: String { return self._s[4622]! } - public var Login_InfoLastNamePlaceholder: String { return self._s[4623]! } - public var Passport_FieldAddress: String { return self._s[4624]! } - public var SettingsSearch_Synonyms_Calls_Title: String { return self._s[4625]! } - public var Passport_Identity_ResidenceCountryPlaceholder: String { return self._s[4627]! } - public var Map_Home: String { return self._s[4629]! } - public var PollResults_Title: String { return self._s[4630]! } - public var ArchivedChats_IntroText2: String { return self._s[4632]! } - public var PasscodeSettings_SimplePasscodeHelp: String { return self._s[4633]! } - public var VoiceOver_Chat_ContactPhoneNumber: String { return self._s[4634]! } - public var CallFeedback_ReasonSilentRemote: String { return self._s[4636]! } - public var Passport_Identity_AddPersonalDetails: String { return self._s[4638]! } - public var Group_Info_AdminLog: String { return self._s[4640]! } - public var ChatSettings_AutoPlayTitle: String { return self._s[4641]! } - public var Appearance_Animations: String { return self._s[4642]! } - public var Appearance_TextSizeSetting: String { return self._s[4643]! } - public func Stats_GroupTopPosterChars(_ 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 Chat_MessagesUnpinned(_ 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_Search_Messages(_ 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 ForwardedStickers(_ 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 ForwardedPhotos(_ 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 ChatList_SelectedChats(_ 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 Conversation_TitleReplies(_ 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 MessageTimer_ShortWeeks(_ 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 ChatList_DeletedChats(_ 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_GameScoreSelfExtended(_ 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 LastSeen_HoursAgo(_ 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 ForwardedLocations(_ 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 SharedMedia_DeleteItemsConfirmation(_ 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 MessagePoll_VotedCount(_ 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 PUSH_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[14 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func Conversation_ContextViewReplies(_ 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 ChatList_MessagePhotos(_ 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_PollOptionCount(_ 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) + return formatWithArgumentRanges(self._s[4613]!, self._r[4613]!, [_0]) } + public var Permissions_PeopleNearbyTitle_v0: String { return self._s[4614]! } + public var ScheduledMessages_RemindersTitle: String { return self._s[4615]! } + public var Your_cards_expiration_year_is_invalid: String { return self._s[4616]! } + public var Wallet_Info_TransactionPendingHeader: String { return self._s[4618]! } + public var UserInfo_ShareMyContactInfo: String { return self._s[4619]! } + public var Passport_DeleteAddress: String { return self._s[4621]! } + public var Passport_DeletePassportConfirmation: String { return self._s[4622]! } + public var Passport_Identity_ReverseSide: String { return self._s[4623]! } + public var CheckoutInfo_ErrorEmailInvalid: String { return self._s[4624]! } + public var Login_InfoLastNamePlaceholder: String { return self._s[4625]! } + public var Passport_FieldAddress: String { return self._s[4626]! } + public var SettingsSearch_Synonyms_Calls_Title: String { return self._s[4627]! } + public var Passport_Identity_ResidenceCountryPlaceholder: String { return self._s[4629]! } + public var Map_Home: String { return self._s[4631]! } + public var PollResults_Title: String { return self._s[4632]! } + public var ArchivedChats_IntroText2: String { return self._s[4634]! } + public var PasscodeSettings_SimplePasscodeHelp: String { return self._s[4635]! } + public var VoiceOver_Chat_ContactPhoneNumber: String { return self._s[4636]! } + public var CallFeedback_ReasonSilentRemote: String { return self._s[4638]! } + public var Passport_Identity_AddPersonalDetails: String { return self._s[4640]! } + public var Group_Info_AdminLog: String { return self._s[4642]! } + public var ChatSettings_AutoPlayTitle: String { return self._s[4643]! } + public var Appearance_Animations: String { return self._s[4644]! } + public var Appearance_TextSizeSetting: String { return self._s[4645]! } public func PUSH_CHANNEL_MESSAGE_ROUNDS(_ 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 AttachmentMenu_SendGif(_ 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 Contacts_ImportersCount(_ 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 Watch_LastSeen_MinutesAgo(_ 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 ChatList_MessageFiles(_ 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 Stats_GroupTopAdminKicks(_ 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 MessagePoll_QuizCount(_ 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 Call_Seconds(_ 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 StickerPack_StickerCount(_ 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 ChatListFilter_ShowMoreChats(_ 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 MessageTimer_Days(_ 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 Stats_GroupTopPosterMessages(_ 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_ShortDays(_ 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 Map_ETAMinutes(_ 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 MessageTimer_Weeks(_ 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_MESSAGE_FWDS(_ 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 Conversation_StatusMembers(_ 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 MuteExpires_Days(_ 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 ForwardedAuthorsOthers(_ selector: Int32, _ _0: String, _ _1: String) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[37 * 6 + Int(form.rawValue)]!, _0, _1) - } - public func PUSH_CHANNEL_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[38 * 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[39 * 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[40 * 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[41 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_DOCS(_ 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 ServiceMessage_GameScoreSelfSimple(_ 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 PasscodeSettings_FailedAttempts(_ 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 ForwardedPolls(_ 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 ForwardedVideoMessages(_ 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 Call_ShortMinutes(_ 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 Watch_UserInfo_Mute(_ 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_ContactPhoneNumberCount(_ 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 ChatList_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 SharedMedia_File(_ 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 VoiceOver_Chat_ContactEmailCount(_ 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 Stats_GroupShowMoreTopAdmins(_ 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 UserCount(_ 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 ServiceMessage_GameScoreSimple(_ 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 Notification_GameScoreSimple(_ 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 Notifications_ExceptionMuteExpires_Days(_ 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 PUSH_CHANNEL_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[58 * 6 + Int(form.rawValue)]!, _1, _2) - } - 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[59 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func ForwardedFiles(_ 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 MuteFor_Hours(_ 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 Chat_DeleteMessagesConfirmation(_ 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_CHANNEL_MESSAGES(_ 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 Wallet_Updated_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 ForwardedMessages(_ 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 Contacts_InviteContacts(_ 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 Media_ShareItem(_ 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 Media_ShareVideo(_ 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 Notification_GameScoreSelfSimple(_ 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 Stats_GroupShowMoreTopPosters(_ 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 StickerPack_RemoveMaskCount(_ 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_PollVotes(_ 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 ServiceMessage_GameScoreSelfExtended(_ 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 Stats_MessageForwards(_ 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 PrivacyLastSeenSettings_AddUsers(_ 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 ForwardedContacts(_ 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 InstantPage_Views(_ 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 MessageTimer_ShortSeconds(_ 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_ROUNDS(_ 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 Conversation_TitleComments(_ 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 LiveLocation_MenuChatsCount(_ 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 StickerPack_AddStickerCount(_ 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_CHAT_MESSAGES(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[84 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func ForwardedVideos(_ 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 AttachmentMenu_SendItem(_ 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 Conversation_LiveLocationMembersCount(_ 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 MuteExpires_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 Conversation_SelectedMessages(_ 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 Passport_Scans(_ 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 MessageTimer_Years(_ 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 ServiceMessage_GameScoreExtended(_ 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 Chat_TitlePinnedMessages(_ 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 Theme_UsersCount(_ 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 MessageTimer_Seconds(_ 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 Call_Minutes(_ 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 Notifications_Exceptions(_ 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 PUSH_CHAT_MESSAGE_DOCS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[98 * 6 + Int(form.rawValue)]!, _2, _1, _3) + return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, _1, _2) } public func Stats_GroupTopAdminDeletions(_ 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) + return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue) } - public func LiveLocationUpdated_MinutesAgo(_ 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[100 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[2 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_CHAT_MESSAGE_PHOTOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + public func Stats_GroupTopPosterChars(_ 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 Stats_GroupShowMoreTopInviters(_ 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 Media_ShareVideo(_ 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 Stats_GroupTopInviterInvites(_ 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_CHAT_MESSAGE_ROUNDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[101 * 6 + Int(form.rawValue)]!, _2, _1, _3) + return String(format: self._ps[7 * 6 + Int(form.rawValue)]!, _2, _1, _3) } - public func GroupInfo_ParticipantCount(_ 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[102 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[8 * 6 + Int(form.rawValue)]!, stringValue) } - public func Conversation_ContextMenuSelectAll(_ value: Int32) -> String { + public func MessageTimer_Days(_ 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[9 * 6 + Int(form.rawValue)]!, stringValue) } - public func ChatList_MessageMusic(_ value: Int32) -> String { + 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[104 * 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[105 * 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[106 * 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[107 * 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[108 * 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[109 * 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[110 * 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[111 * 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[112 * 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[113 * 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[114 * 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[115 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ChatList_MessageVideos(_ 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 PUSH_CHAT_MESSAGE_VIDEOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[117 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - 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[118 * 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[119 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[10 * 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[120 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[11 * 6 + Int(form.rawValue)]!, stringValue) } - public func QuickSend_Photos(_ value: Int32) -> String { + public func PUSH_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[12 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func StickerPack_AddStickerCount(_ 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[13 * 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[14 * 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[15 * 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[16 * 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[17 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Stats_GroupShowMoreTopAdmins(_ 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 LiveLocation_MenuChatsCount(_ 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 ChatList_Search_Messages(_ 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 MuteExpires_Hours(_ 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 Map_ETAHours(_ 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[22 * 6 + Int(form.rawValue)]!, stringValue) + } + public func InstantPage_Views(_ 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 ChatList_DeleteConfirmation(_ 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 Notifications_ExceptionMuteExpires_Hours(_ 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 Conversation_ContextViewReplies(_ 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 SharedMedia_File(_ 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 MessageTimer_Minutes(_ 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 MuteFor_Hours(_ 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 Contacts_InviteContacts(_ 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 Notifications_ExceptionMuteExpires_Days(_ 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 ForwardedAuthorsOthers(_ selector: Int32, _ _0: String, _ _1: String) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[32 * 6 + Int(form.rawValue)]!, _0, _1) + } + 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[33 * 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[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[35 * 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[36 * 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[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 VoiceOver_Chat_PollVotes(_ 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 Chat_DeleteMessagesConfirmation(_ 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 Forward_ConfirmMultipleFiles(_ 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 Notification_GameScoreExtended(_ 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 MuteExpires_Days(_ 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 Chat_MessagesUnpinned(_ 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 ForwardedVideoMessages(_ 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_Years(_ 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_ShortHours(_ 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 Chat_TitlePinnedMessages(_ 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 ForwardedLocations(_ 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 VoiceOver_Chat_ContactEmailCount(_ 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 ChatList_MessageFiles(_ 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 SharedMedia_Video(_ 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 PUSH_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[54 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func MessageTimer_ShortDays(_ 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 Conversation_StatusOnline(_ 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 Conversation_SelectedMessages(_ 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 Stats_GroupTopPosterMessages(_ 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 SharedMedia_Link(_ 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 MessageTimer_ShortMinutes(_ 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_UserInfo_Mute(_ 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 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 MuteFor_Days(_ 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 CreatePoll_AddMoreOptions(_ 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_Weeks(_ 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 MessageTimer_Seconds(_ 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 MessageTimer_ShortSeconds(_ 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 StickerPack_AddMaskCount(_ 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_Months(_ 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 ForwardedPolls(_ 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 PollResults_ShowMore(_ 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 PasscodeSettings_FailedAttempts(_ 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_CHAT_MESSAGE_DOCS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[73 * 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[74 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_DOCS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[75 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func MessageTimer_ShortWeeks(_ 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 ChatListFilter_ShowMoreChats(_ 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_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 ChatList_DeletedChats(_ 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_PHOTOS(_ 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 ChatList_MessageMusic(_ 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 InviteText_ContactsCountText(_ 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 Call_Minutes(_ 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_CHANNEL_MESSAGE_PHOTOS(_ 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 Conversation_StatusSubscribers(_ 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_MESSAGES(_ 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 AttachmentMenu_SendItem(_ 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 PUSH_CHAT_MESSAGE_VIDEOS(_ 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 OldChannels_Leave(_ 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 GroupInfo_ParticipantCount(_ 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 ForwardedFiles(_ 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 Media_ShareItem(_ 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 Wallpaper_DeleteConfirmation(_ 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_InactiveMonth(_ 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_GroupFormat(_ 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 PUSH_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[98 * 6 + Int(form.rawValue)]!, _1, _2) + } + 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[99 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func AttachmentMenu_SendVideo(_ 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 LastSeen_MinutesAgo(_ 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 ForwardedVideos(_ 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 SharedMedia_DeleteItemsConfirmation(_ 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 PrivacyLastSeenSettings_AddUsers(_ 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 Notification_GameScoreSelfSimple(_ 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 MessagePoll_QuizCount(_ 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 Wallet_Updated_MinutesAgo(_ 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 Watch_LastSeen_HoursAgo(_ 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 Passport_Scans(_ 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 Wallet_Updated_HoursAgo(_ 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 Conversation_TitleReplies(_ 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 Media_SharePhoto(_ 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 Notification_GameScoreSelfExtended(_ 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_ImportersCount(_ 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 ServiceMessage_GameScoreSimple(_ 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 LiveLocationUpdated_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 Stats_GroupTopAdminBans(_ 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[118 * 6 + Int(form.rawValue)]!, stringValue) } - public func Invitation_Members(_ value: Int32) -> String { + public func OldChannels_InactiveYear(_ 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[119 * 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[120 * 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[121 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_TitleComments(_ 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 Notification_GameScoreSimple(_ 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_VIDEOS(_ 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 Conversation_MessageViewComments(_ 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 MessageTimer_Minutes(_ value: Int32) -> String { + public func AttachmentMenu_SendGif(_ 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 func LastSeen_MinutesAgo(_ value: Int32) -> String { + public func Call_ShortMinutes(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[127 * 6 + Int(form.rawValue)]!, stringValue) } - public func Stats_MessageViews(_ 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[128 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessageTimer_ShortHours(_ value: Int32) -> String { + public func ForwardedMessages(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[129 * 6 + Int(form.rawValue)]!, stringValue) } - public func Stats_GroupTopInviterInvites(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[130 * 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[131 * 6 + Int(form.rawValue)]!, stringValue) + public func PUSH_CHANNEL_MESSAGE_DOCS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[130 * 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[131 * 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[132 * 6 + Int(form.rawValue)]!, stringValue) } - public func Notification_GameScoreExtended(_ value: Int32) -> String { + public func ChatList_MessagePhotos(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[133 * 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[134 * 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[134 * 6 + Int(form.rawValue)]!, _2, _1, _3) } - public func ForwardedAudios(_ value: Int32) -> String { + public func Conversation_StatusMembers(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[135 * 6 + Int(form.rawValue)]!, stringValue) } - public func Wallpaper_DeleteConfirmation(_ value: Int32) -> String { + public func OldChannels_InactiveWeek(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[136 * 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[137 * 6 + Int(form.rawValue)]!, _1, _2) + public func Stats_GroupShowMoreTopPosters(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[137 * 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[138 * 6 + Int(form.rawValue)]!, _1, _2) + public func Stats_MessageViews(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[138 * 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[139 * 6 + Int(form.rawValue)]!, _2, _1, _3) + public func ForwardedContacts(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[139 * 6 + Int(form.rawValue)]!, stringValue) } - public func Stats_GroupShowMoreTopInviters(_ value: Int32) -> String { + public func Stats_GroupTopAdminKicks(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[140 * 6 + Int(form.rawValue)]!, stringValue) } - public func Conversation_StatusSubscribers(_ 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[141 * 6 + Int(form.rawValue)]!, stringValue) } - public func OldChannels_GroupFormat(_ value: Int32) -> String { + public func Stats_MessageForwards(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[142 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessageTimer_Months(_ 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[143 * 6 + Int(form.rawValue)]!, stringValue) } - public func InviteText_ContactsCountText(_ value: Int32) -> String { + public func ForwardedStickers(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[144 * 6 + Int(form.rawValue)]!, stringValue) } - public func Conversation_StatusOnline(_ value: Int32) -> String { + public func ChatList_MessageVideos(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[145 * 6 + Int(form.rawValue)]!, stringValue) } - public func ForwardedGifs(_ 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[146 * 6 + Int(form.rawValue)]!, stringValue) } - public func Watch_LastSeen_HoursAgo(_ 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[147 * 6 + Int(form.rawValue)]!, stringValue) } - public func Media_SharePhoto(_ value: Int32) -> String { + public func Conversation_ContextMenuSelectAll(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[148 * 6 + Int(form.rawValue)]!, stringValue) } - public func OldChannels_InactiveWeek(_ value: Int32) -> String { + public func MessagePoll_VotedCount(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[149 * 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[150 * 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[150 * 6 + Int(form.rawValue)]!, _1, _2) } - public func AttachmentMenu_SendPhoto(_ 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[151 * 6 + Int(form.rawValue)]!, stringValue) } - public func StickerPack_RemoveStickerCount(_ 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[152 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_MESSAGE_DOCS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[153 * 6 + Int(form.rawValue)]!, _1, _2) + public func StickerPack_RemoveMaskCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[153 * 6 + Int(form.rawValue)]!, stringValue) } - public func Notifications_ExceptionMuteExpires_Hours(_ value: Int32) -> String { + 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[154 * 6 + Int(form.rawValue)]!, stringValue) diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Caption.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Caption.imageset/Contents.json new file mode 100644 index 0000000000..ebb7714e79 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Caption.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "ic_menu_font1.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Caption.imageset/ic_menu_font1.pdf b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Caption.imageset/ic_menu_font1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3df88ff7e298b9efbe7490582acc9c03b3f627fc GIT binary patch literal 4027 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 literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Images.xcassets/Media Gallery/Contents.json b/submodules/TelegramUI/Images.xcassets/Media Gallery/Contents.json index 38f0c81fc2..6e965652df 100644 --- a/submodules/TelegramUI/Images.xcassets/Media Gallery/Contents.json +++ b/submodules/TelegramUI/Images.xcassets/Media Gallery/Contents.json @@ -1,9 +1,9 @@ { "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 }, "properties" : { "provides-namespace" : true } -} \ No newline at end of file +} diff --git a/submodules/TelegramUI/Images.xcassets/Media Gallery/Draw.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Media Gallery/Draw.imageset/Contents.json new file mode 100644 index 0000000000..0402056ad7 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Media Gallery/Draw.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "ic_editor_brush1.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Media Gallery/Draw.imageset/ic_editor_brush1.pdf b/submodules/TelegramUI/Images.xcassets/Media Gallery/Draw.imageset/ic_editor_brush1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..cafe10024af9dec0109399f7f259f394ce0a80f3 GIT binary patch literal 4155 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%0A=kgmWP|yzUhtiK5)9; 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

Xdw$sTvZ4Ugz*S_Hg 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 SbVZZ^0000SEg6= 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 A^Z)<= diff --git a/submodules/TelegramUI/Sources/ChatBotInfoItem.swift b/submodules/TelegramUI/Sources/ChatBotInfoItem.swift index 7743358b27..e97d668d82 100644 --- a/submodules/TelegramUI/Sources/ChatBotInfoItem.swift +++ b/submodules/TelegramUI/Sources/ChatBotInfoItem.swift @@ -119,7 +119,7 @@ final class ChatBotInfoItemNode: ListViewItemNode { break case .ignore: return .fail - case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults: + case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy: return .waitForSingleTap } } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 8ba77a354d..3d973b4930 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -615,6 +615,47 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G storedState = MediaPlaybackStoredState(timestamp: timestamp, playbackRate: .x1) } let _ = updateMediaPlaybackStoredStateInteractively(postbox: strongSelf.context.account.postbox, messageId: messageId, state: storedState).start() + }, editMedia: { [weak self] messageId in + guard let strongSelf = self else { + return + } + + let _ = (strongSelf.context.account.postbox.transaction { transaction -> Message? in + return transaction.getMessage(messageId) + } |> deliverOnMainQueue).start(next: { [weak self] message in + guard let strongSelf = self, let message = message else { + return + } + + var mediaReference: AnyMediaReference? + for m in message.media { + if let image = m as? TelegramMediaImage { + mediaReference = AnyMediaReference.standalone(media: image) + } + } + + if let mediaReference = mediaReference, let peer = message.peers[message.id.peerId] { + legacyMediaEditor(context: strongSelf.context, peer: peer, media: mediaReference, initialCaption: message.text, presentStickers: { [weak self] completion in + if let strongSelf = self { + let controller = DrawingStickersScreen(context: strongSelf.context, selectSticker: { fileReference, node, rect in + completion(fileReference.media, fileReference.media.isAnimatedSticker, node.view, rect) + return true + }) + strongSelf.present(controller, in: .window(.root)) + return controller + } else { + return nil + } + }, sendMessagesWithSignals: { [weak self] signals, _, _ in + if let strongSelf = self { + strongSelf.interfaceInteraction?.setupEditMessage(messageId, { _ in }) + strongSelf.editMessageMediaWithLegacySignals(signals!) + } + }, present: { [weak self] c, a in + self?.present(c, in: .window(.root), with: a) + }) + } + }) }))) }, openPeer: { [weak self] id, navigation, fromMessage in self?.openPeer(peerId: id, navigation: navigation, fromMessage: fromMessage) @@ -643,7 +684,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G break } } - let _ = combineLatest(queue: .mainQueue(), contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState: strongSelf.presentationInterfaceState, context: strongSelf.context, messages: updatedMessages, controllerInteraction: strongSelf.controllerInteraction, selectAll: selectAll, interfaceInteraction: strongSelf.interfaceInteraction), loadedStickerPack(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, reference: .animatedEmoji, forceActualized: false), ApplicationSpecificNotice.getChatTextSelectionTips(accountManager: strongSelf.context.sharedContext.accountManager) + let _ = combineLatest(queue: .mainQueue(), contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState: strongSelf.presentationInterfaceState, context: strongSelf.context, messages: updatedMessages, controllerInteraction: strongSelf.controllerInteraction, selectAll: selectAll, interfaceInteraction: strongSelf.interfaceInteraction), loadedStickerPack(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, reference: .animatedEmoji, forceActualized: false), ApplicationSpecificNotice.getChatTextSelectionTips(accountManager: strongSelf.context.sharedContext.accountManager) ).start(next: { actions, animatedEmojiStickers, chatTextSelectionTips in guard let strongSelf = self, !actions.isEmpty else { return @@ -2275,6 +2316,65 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } strongSelf.push(messageStatsController(context: context, messageId: id, cachedPeerData: cachedPeerData)) }) + }, editMessageMedia: { [weak self] messageId, draw in + guard let strongSelf = self else { + return + } + + strongSelf.chatDisplayNode.dismissInput() + + if draw { + let _ = (strongSelf.context.account.postbox.transaction { transaction -> Message? in + return transaction.getMessage(messageId) + } |> deliverOnMainQueue).start(next: { [weak self] message in + guard let strongSelf = self, let message = message else { + return + } + + var mediaReference: AnyMediaReference? + for m in message.media { + if let image = m as? TelegramMediaImage { + mediaReference = AnyMediaReference.standalone(media: image) + } + } + + if let mediaReference = mediaReference, let peer = message.peers[message.id.peerId] { + legacyMediaEditor(context: strongSelf.context, peer: peer, media: mediaReference, initialCaption: message.text, presentStickers: { [weak self] completion in + if let strongSelf = self { + let controller = DrawingStickersScreen(context: strongSelf.context, selectSticker: { fileReference, node, rect in + completion(fileReference.media, fileReference.media.isAnimatedSticker, node.view, rect) + return true + }) + strongSelf.present(controller, in: .window(.root)) + return controller + } else { + return nil + } + }, sendMessagesWithSignals: { [weak self] signals, _, _ in + if let strongSelf = self { + strongSelf.interfaceInteraction?.setupEditMessage(messageId, { _ in }) + strongSelf.editMessageMediaWithLegacySignals(signals!) + } + }, present: { [weak self] c, a in + self?.present(c, in: .window(.root), with: a) + }) + } + }) + } else { + strongSelf.presentMediaPicker(fileMode: false, editingMedia: true, completion: { signals, _, _ in + self?.interfaceInteraction?.setupEditMessage(messageId, { _ in }) + self?.editMessageMediaWithLegacySignals(signals) + }) + } + }, copyText: { [weak self] text in + if let strongSelf = self { + storeMessageTextInPasteboard(text, entities: nil) + + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.Conversation_TextCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in + return true + }), in: .current) + } }, requestMessageUpdate: { [weak self] id in if let strongSelf = self { strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(id) @@ -4326,7 +4426,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G break } } - var inputTextMaxLength: Int32? + var inputTextMaxLength: Int32 = 4096 for media in message.media { if media is TelegramMediaImage || media is TelegramMediaFile { inputTextMaxLength = strongSelf.context.currentLimitsConfiguration.with { $0 }.maxMediaCaptionLength diff --git a/submodules/TelegramUI/Sources/ChatControllerInteraction.swift b/submodules/TelegramUI/Sources/ChatControllerInteraction.swift index d6b1b7ea43..ed9093bba4 100644 --- a/submodules/TelegramUI/Sources/ChatControllerInteraction.swift +++ b/submodules/TelegramUI/Sources/ChatControllerInteraction.swift @@ -116,6 +116,8 @@ public final class ChatControllerInteraction { let openMessageReplies: (MessageId, Bool, Bool) -> Void let openReplyThreadOriginalMessage: (Message) -> Void let openMessageStats: (MessageId) -> Void + let editMessageMedia: (MessageId, Bool) -> Void + let copyText: (String) -> Void let requestMessageUpdate: (MessageId) -> Void let cancelInteractiveKeyboardGestures: () -> Void @@ -203,6 +205,8 @@ public final class ChatControllerInteraction { openMessageReplies: @escaping (MessageId, Bool, Bool) -> Void, openReplyThreadOriginalMessage: @escaping (Message) -> Void, openMessageStats: @escaping (MessageId) -> Void, + editMessageMedia: @escaping (MessageId, Bool) -> Void, + copyText: @escaping (String) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, @@ -277,6 +281,8 @@ public final class ChatControllerInteraction { self.openMessageReplies = openMessageReplies self.openReplyThreadOriginalMessage = openReplyThreadOriginalMessage self.openMessageStats = openMessageStats + self.editMessageMedia = editMessageMedia + self.copyText = copyText self.requestMessageUpdate = requestMessageUpdate self.cancelInteractiveKeyboardGestures = cancelInteractiveKeyboardGestures @@ -328,6 +334,8 @@ public final class ChatControllerInteraction { }, openMessageReplies: { _, _, _ in }, openReplyThreadOriginalMessage: { _ in }, openMessageStats: { _ in + }, editMessageMedia: { _, _ in + }, copyText: { _ in }, requestMessageUpdate: { _ in }, cancelInteractiveKeyboardGestures: { }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index 2eafbe9ccd..2c75544895 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -493,7 +493,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { self.inputPanelBackgroundSeparatorNode.backgroundColor = self.chatPresentationInterfaceState.theme.chat.inputPanel.panelSeparatorColor self.inputPanelBackgroundSeparatorNode.isLayerBacked = true - self.navigateButtons = ChatHistoryNavigationButtons(theme: self.chatPresentationInterfaceState.theme) + self.navigateButtons = ChatHistoryNavigationButtons(theme: self.chatPresentationInterfaceState.theme, dateTimeFormat: self.chatPresentationInterfaceState.dateTimeFormat) self.navigateButtons.accessibilityElementsHidden = true self.navigationBarBackroundNode = ASDisplayNode() @@ -1919,7 +1919,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { let updateInputTextState = self.chatPresentationInterfaceState.interfaceState.effectiveInputState != chatPresentationInterfaceState.interfaceState.effectiveInputState self.chatPresentationInterfaceState = chatPresentationInterfaceState - self.navigateButtons.updateTheme(theme: chatPresentationInterfaceState.theme) + self.navigateButtons.update(theme: chatPresentationInterfaceState.theme, dateTimeFormat: chatPresentationInterfaceState.dateTimeFormat) if themeUpdated { if case let .color(color) = self.chatPresentationInterfaceState.chatWallpaper, UIColor(rgb: color).isEqual(self.chatPresentationInterfaceState.theme.chat.inputPanel.panelBackgroundColorNoWallpaper) { diff --git a/submodules/TelegramUI/Sources/ChatHistoryNavigationButtons.swift b/submodules/TelegramUI/Sources/ChatHistoryNavigationButtons.swift index 90103f08e3..0cbd2d86a5 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryNavigationButtons.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryNavigationButtons.swift @@ -6,6 +6,7 @@ import TelegramPresentationData final class ChatHistoryNavigationButtons: ASDisplayNode { private var theme: PresentationTheme + private var dateTimeFormat: PresentationDateTimeFormat private let mentionsButton: ChatHistoryNavigationButtonNode private let mentionsButtonTapNode: ASDisplayNode @@ -31,7 +32,7 @@ final class ChatHistoryNavigationButtons: ASDisplayNode { var unreadCount: Int32 = 0 { didSet { if self.unreadCount != 0 { - self.downButton.badge = "\(self.unreadCount)" + self.downButton.badge = compactNumericCountString(Int(self.unreadCount), decimalSeparator: self.dateTimeFormat.decimalSeparator) } else { self.downButton.badge = "" } @@ -41,7 +42,7 @@ final class ChatHistoryNavigationButtons: ASDisplayNode { var mentionCount: Int32 = 0 { didSet { if self.mentionCount != 0 { - self.mentionsButton.badge = "\(self.mentionCount)" + self.mentionsButton.badge = compactNumericCountString(Int(self.mentionCount), decimalSeparator: self.dateTimeFormat.decimalSeparator) } else { self.mentionsButton.badge = "" } @@ -52,8 +53,9 @@ final class ChatHistoryNavigationButtons: ASDisplayNode { } } - init(theme: PresentationTheme) { + init(theme: PresentationTheme, dateTimeFormat: PresentationDateTimeFormat) { self.theme = theme + self.dateTimeFormat = dateTimeFormat self.mentionsButton = ChatHistoryNavigationButtonNode(theme: theme, type: .mentions) self.mentionsButton.alpha = 0.0 @@ -81,9 +83,10 @@ final class ChatHistoryNavigationButtons: ASDisplayNode { self.mentionsButtonTapNode.view.addGestureRecognizer(tapRecognizer) } - func updateTheme(theme: PresentationTheme) { - if self.theme !== theme { + func update(theme: PresentationTheme, dateTimeFormat: PresentationDateTimeFormat) { + if self.theme !== theme || self.dateTimeFormat != dateTimeFormat { self.theme = theme + self.dateTimeFormat = dateTimeFormat self.mentionsButton.updateTheme(theme: theme) self.downButton.updateTheme(theme: theme) diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift index 7a7c16a30a..3755ac4861 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift @@ -276,7 +276,7 @@ func updatedChatEditInterfaceMessageState(state: ChatPresentationInterfaceState, return updated } -func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState: ChatPresentationInterfaceState, context: AccountContext, messages: [Message], controllerInteraction: ChatControllerInteraction?, selectAll: Bool, interfaceInteraction: ChatPanelInterfaceInteraction?) -> Signal<[ContextMenuItem], NoError> { +func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState: ChatPresentationInterfaceState, context: AccountContext, messages: [Message], controllerInteraction: ChatControllerInteraction?, selectAll: Bool, interfaceInteraction: ChatPanelInterfaceInteraction?) -> Signal<[ContextMenuItem], NoError> { guard let interfaceInteraction = interfaceInteraction, let controllerInteraction = controllerInteraction else { return .single([]) } @@ -643,6 +643,17 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState: } if data.canEdit && !isPinnedMessages { + var mediaReference: AnyMediaReference? + for media in message.media { + if let image = media as? TelegramMediaImage, let _ = largestImageRepresentation(image.representations) { + mediaReference = ImageMediaReference.standalone(media: image).abstract + break + } else if let file = media as? TelegramMediaFile { + mediaReference = FileMediaReference.standalone(media: file).abstract + break + } + } + actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_MessageDialogEdit, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.actionSheet.primaryTextColor) }, action: { _, f in @@ -763,7 +774,7 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState: let presentationData = context.sharedContext.currentPresentationData.with { $0 } var warnAboutPrivate = false - if case let .peer = chatPresentationInterfaceState.chatLocation { + if case .peer = chatPresentationInterfaceState.chatLocation { if channel.addressName == nil { warnAboutPrivate = true } diff --git a/submodules/TelegramUI/Sources/ChatMediaInputNode.swift b/submodules/TelegramUI/Sources/ChatMediaInputNode.swift index 00601fe12a..1a3247afc9 100644 --- a/submodules/TelegramUI/Sources/ChatMediaInputNode.swift +++ b/submodules/TelegramUI/Sources/ChatMediaInputNode.swift @@ -146,19 +146,7 @@ func preparedChatMediaInputGridEntryTransition(account: Account, view: ItemColle firstIndexInSectionOffset = Int(index.itemIndex.index) } } - - if case .initial = update { - switch toEntries[0].index { - case .search: - if toEntries.count > 1 { - //scrollToItem = GridNodeScrollToItem(index: 1, position: .top, transition: .immediate, directionHint: .up, adjustForSection: true) - } - break - default: - break - } - } - + let opaqueState = ChatMediaInputStickerPaneOpaqueState(hasLower: view.lower != nil) return ChatMediaInputGridTransition(deletions: deletions, insertions: insertions, updates: updates, updateFirstIndexInSectionOffset: firstIndexInSectionOffset, stationaryItems: stationaryItems, scrollToItem: scrollToItem, updateOpaqueState: opaqueState, animated: animated) diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 9b895fd2d8..6465a70e05 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -190,7 +190,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { self.containerNode = ContextControllerSourceNode() self.imageNode = TransformImageNode() self.dateAndStatusNode = ChatMessageDateAndStatusNode() - + super.init(layerBacked: false) self.containerNode.shouldBegin = { [weak self] location in @@ -1117,7 +1117,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { switch recognizer.state { case .ended: if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation { - if let action = self.gestureRecognized(gesture: gesture, location: location, recognizer: nil) { + if let action = self.gestureRecognized(gesture: gesture, location: location, recognizer: recognizer) { if case .doubleTap = gesture { self.containerNode.cancelGesture() } @@ -1224,7 +1224,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { item.controllerInteraction.displayDiceTooltip(dice) }) } else if let _ = self.emojiFile { - if let animationNode = self.animationNode as? AnimatedStickerNode { + if let animationNode = self.animationNode as? AnimatedStickerNode, let _ = recognizer { var startTime: Signal var shouldPlay = false if !animationNode.isPlaying { @@ -1248,86 +1248,63 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } if let text = self.item?.message.text, let firstScalar = text.unicodeScalars.first { - if beatingHearts.contains(firstScalar.value) || firstScalar.value == peach { + return .optionalAction({ if shouldPlay { - animationNode.play() - } - return .optionalAction({ - let _ = startTime.start(next: { [weak self] time in + let _ = (appConfiguration + |> deliverOnMainQueue).start(next: { [weak self, weak animationNode] appConfiguration in guard let strongSelf = self else { return } - - var haptic: EmojiHaptic - if let current = strongSelf.haptic { - haptic = current - } else { - if beatingHearts.contains(firstScalar.value) { - haptic = HeartbeatHaptic() - } else { - haptic = PeachHaptic() - } - haptic.enabled = true - strongSelf.haptic = haptic - } - if !haptic.active { - haptic.start(time: time) - } - }) - }) - } else { - return .optionalAction({ - if shouldPlay { - let _ = (appConfiguration - |> deliverOnMainQueue).start(next: { [weak self, weak animationNode] appConfiguration in - guard let strongSelf = self else { - return - } - let emojiSounds = AnimatedEmojiSoundsConfiguration.with(appConfiguration: appConfiguration, account: item.context.account) - for (emoji, file) in emojiSounds.sounds { - if emoji.unicodeScalars.first == firstScalar { - let mediaManager = item.context.sharedContext.mediaManager - let mediaPlayer = MediaPlayer(audioSessionManager: mediaManager.audioSession, postbox: item.context.account.postbox, resourceReference: .standalone(resource: file.resource), streamable: .none, video: false, preferSoftwareDecoding: false, enableSound: true, fetchAutomatically: true, ambient: true) - mediaPlayer.togglePlayPause() - mediaPlayer.actionAtEnd = .action({ [weak self] in - self?.mediaPlayer = nil - }) - strongSelf.mediaPlayer = mediaPlayer - - strongSelf.mediaStatusDisposable.set((mediaPlayer.status - |> deliverOnMainQueue).start(next: { [weak self, weak animationNode] status in - if let strongSelf = self { - if firstScalar.value == coffin { - var haptic: EmojiHaptic - if let current = strongSelf.haptic { - haptic = current - } else { + let emojiSounds = AnimatedEmojiSoundsConfiguration.with(appConfiguration: appConfiguration, account: item.context.account) + for (emoji, file) in emojiSounds.sounds { + if emoji.strippedEmoji == text.strippedEmoji { + let mediaManager = item.context.sharedContext.mediaManager + let mediaPlayer = MediaPlayer(audioSessionManager: mediaManager.audioSession, postbox: item.context.account.postbox, resourceReference: .standalone(resource: file.resource), streamable: .none, video: false, preferSoftwareDecoding: false, enableSound: true, fetchAutomatically: true, ambient: true) + mediaPlayer.togglePlayPause() + mediaPlayer.actionAtEnd = .action({ [weak self] in + self?.mediaPlayer = nil + }) + strongSelf.mediaPlayer = mediaPlayer + + strongSelf.mediaStatusDisposable.set((mediaPlayer.status + |> deliverOnMainQueue).start(next: { [weak self, weak animationNode] status in + if let strongSelf = self { + if firstScalar.value == coffin || firstScalar.value == peach { + var haptic: EmojiHaptic + if let current = strongSelf.haptic { + haptic = current + } else { + if beatingHearts.contains(firstScalar.value) { + haptic = HeartbeatHaptic() + } else if firstScalar.value == coffin { haptic = CoffinHaptic() - haptic.enabled = true - strongSelf.haptic = haptic - } - if !haptic.active { - haptic.start(time: 0.0) + } else { + haptic = PeachHaptic() } + haptic.enabled = true + strongSelf.haptic = haptic } - - switch status.status { - case .playing: - animationNode?.play() - strongSelf.mediaStatusDisposable.set(nil) - default: - break + if !haptic.active { + haptic.start(time: 0.0) } } - })) - return - } + + switch status.status { + case .playing: + animationNode?.play() + strongSelf.mediaStatusDisposable.set(nil) + default: + break + } + } + })) + return } - animationNode?.play() - }) - } - }) - } + } + animationNode?.play() + }) + } + }) } } } diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleContentNode.swift index 3aaefaea07..323e2a7b45 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleContentNode.swift @@ -97,6 +97,7 @@ enum ChatMessageBubbleContentTapAction { case bankCard(String) case ignore case openPollResults(Data) + case copy(String) } final class ChatMessageBubbleContentItem { diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index effd6a8f2d..9df3dbb7ff 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -643,7 +643,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode break case .ignore: return .fail - case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults: + case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip, .openPollResults, .copy: return .waitForSingleTap } } @@ -3122,6 +3122,12 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode item.controllerInteraction.openMessagePollResults(item.message.id, option) }) } + case let .copy(text): + if let item = self.item { + return .optionalAction({ + item.controllerInteraction.copyText(text) + }) + } } } return nil @@ -3198,6 +3204,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode break case .openPollResults: break + case .copy: + break } } if let tapMessage = tapMessage { diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift index 2dca499f43..e894620c02 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift @@ -940,6 +940,8 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode { self.streamingStatusNode = streamingStatusNode streamingStatusNode.frame = streamingCacheStatusFrame self.addSubnode(streamingStatusNode) + } else if let streamingStatusNode = self.streamingStatusNode { + streamingStatusNode.backgroundNodeColor = backgroundNodeColor } if let statusNode = self.statusNode { diff --git a/submodules/TelegramUI/Sources/ChatMessageItem.swift b/submodules/TelegramUI/Sources/ChatMessageItem.swift index b704489ea5..546e288117 100644 --- a/submodules/TelegramUI/Sources/ChatMessageItem.swift +++ b/submodules/TelegramUI/Sources/ChatMessageItem.swift @@ -349,7 +349,7 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible { loop: for media in self.message.media { if let telegramFile = media as? TelegramMediaFile { - if telegramFile.isAnimatedSticker, (self.message.id.peerId.namespace == Namespaces.Peer.SecretChat || !telegramFile.previewRepresentations.isEmpty), let size = telegramFile.size, size > 0 && size <= 128 * 1024 { + if telegramFile.isAnimatedSticker, let size = telegramFile.size, size > 0 && size <= 128 * 1024 { if self.message.id.peerId.namespace == Namespaces.Peer.SecretChat { if telegramFile.fileId.namespace == Namespaces.Media.CloudFile { var isValidated = false diff --git a/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift b/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift index e5aa07c7fa..a5d3a5e03b 100644 --- a/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift +++ b/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift @@ -248,6 +248,24 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { title = nil messageText = rawText } + case .video: + let rawText = presentationData.strings.PUSH_CHANNEL_MESSAGE_VIDEOS(Int32(item.messages.count), peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder), Int32(item.messages.count)) + if let index = rawText.firstIndex(of: "|") { + title = String(rawText[rawText.startIndex ..< index]) + messageText = String(rawText[rawText.index(after: index)...]) + } else { + title = nil + messageText = rawText + } + case .file: + let rawText = presentationData.strings.PUSH_CHANNEL_MESSAGE_DOCS(Int32(item.messages.count), peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder), Int32(item.messages.count)) + if let index = rawText.firstIndex(of: "|") { + title = String(rawText[rawText.startIndex ..< index]) + messageText = String(rawText[rawText.index(after: index)...]) + } else { + title = nil + messageText = rawText + } default: let rawText = presentationData.strings.PUSH_CHANNEL_MESSAGES(Int32(item.messages.count), peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder), Int32(item.messages.count)) if let index = rawText.firstIndex(of: "|") { @@ -272,6 +290,24 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { title = nil messageText = rawText } + case .video: + let rawText = presentationData.strings.PUSH_CHAT_MESSAGE_VIDEOS(Int32(item.messages.count), author.compactDisplayTitle, peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder), Int32(item.messages.count)) + if let index = rawText.firstIndex(of: "|") { + title = String(rawText[rawText.startIndex ..< index]) + messageText = String(rawText[rawText.index(after: index)...]) + } else { + title = nil + messageText = rawText + } + case .file: + let rawText = presentationData.strings.PUSH_CHAT_MESSAGE_DOCS(Int32(item.messages.count), author.compactDisplayTitle, peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder), Int32(item.messages.count)) + if let index = rawText.firstIndex(of: "|") { + title = String(rawText[rawText.startIndex ..< index]) + messageText = String(rawText[rawText.index(after: index)...]) + } else { + title = nil + messageText = rawText + } default: let rawText = presentationData.strings.PUSH_CHAT_MESSAGES(Int32(item.messages.count), author.compactDisplayTitle, peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder), Int32(item.messages.count)) if let index = rawText.firstIndex(of: "|") { @@ -293,6 +329,24 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { title = nil messageText = rawText } + case .video: + let rawText = presentationData.strings.PUSH_MESSAGE_VIDEOS(Int32(item.messages.count), peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder), Int32(item.messages.count)) + if let index = rawText.firstIndex(of: "|") { + title = String(rawText[rawText.startIndex ..< index]) + messageText = String(rawText[rawText.index(after: index)...]) + } else { + title = nil + messageText = rawText + } + case .file: + let rawText = presentationData.strings.PUSH_MESSAGE_DOCS(Int32(item.messages.count), peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder), Int32(item.messages.count)) + if let index = rawText.firstIndex(of: "|") { + title = String(rawText[rawText.startIndex ..< index]) + messageText = String(rawText[rawText.index(after: index)...]) + } else { + title = nil + messageText = rawText + } default: let rawText = presentationData.strings.PUSH_MESSAGES(Int32(item.messages.count), peer.displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder), Int32(item.messages.count)) if let index = rawText.firstIndex(of: "|") { diff --git a/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift index 91dc7b9678..f54ab56e51 100644 --- a/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift @@ -450,6 +450,8 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { return .timecode(timecode.time, timecode.text) } else if let bankCard = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.BankCard)] as? String { return .bankCard(bankCard) + } else if let pre = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Pre)] as? String { + return .copy(pre) } else { return .none } diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift index eae9201b4a..54c2bcb967 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift @@ -455,6 +455,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { }, openMessageReplies: { _, _, _ in }, openReplyThreadOriginalMessage: { _ in }, openMessageStats: { _ in + }, editMessageMedia: { _, _ in + }, copyText: { _ in }, requestMessageUpdate: { _ in }, cancelInteractiveKeyboardGestures: { }, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, diff --git a/submodules/TelegramUI/Sources/ChatTextInputActionButtonsNode.swift b/submodules/TelegramUI/Sources/ChatTextInputActionButtonsNode.swift index 514f8698d2..ac26274088 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputActionButtonsNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputActionButtonsNode.swift @@ -31,8 +31,6 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode { self.micButton = ChatTextInputMediaRecordingButton(theme: theme, strings: strings, presentController: presentController) self.sendButton = HighlightTrackingButtonNode(pointerStyle: .lift) - //self.sendButton.adjustsImageWhenHighlighted = false - //self.sendButton.adjustsImageWhenDisabled = false self.expandMediaInputButton = HighlightableButtonNode(pointerStyle: .default) diff --git a/submodules/TelegramUI/Sources/DrawingStickersScreen.swift b/submodules/TelegramUI/Sources/DrawingStickersScreen.swift index 110bdf9431..cb4eca5ec0 100644 --- a/submodules/TelegramUI/Sources/DrawingStickersScreen.swift +++ b/submodules/TelegramUI/Sources/DrawingStickersScreen.swift @@ -148,6 +148,8 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode { }, openMessageReplies: { _, _, _ in }, openReplyThreadOriginalMessage: { _ in }, openMessageStats: { _ in + }, editMessageMedia: { _, _ in + }, copyText: { _ in }, requestMessageUpdate: { _ in }, cancelInteractiveKeyboardGestures: { }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, diff --git a/submodules/TelegramUI/Sources/OpenChatMessage.swift b/submodules/TelegramUI/Sources/OpenChatMessage.swift index 99d23e3b4b..47ce3c94ec 100644 --- a/submodules/TelegramUI/Sources/OpenChatMessage.swift +++ b/submodules/TelegramUI/Sources/OpenChatMessage.swift @@ -114,7 +114,15 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool { let controller = ShareController(context: params.context, subject: .media(.standalone(media: file)), immediateExternalShare: true) params.present(controller, nil) } else if let rootController = params.navigationController?.view.window?.rootViewController { - presentDocumentPreviewController(rootController: rootController, theme: presentationData.theme, strings: presentationData.strings, postbox: params.context.account.postbox, file: file) + let proceed = { + presentDocumentPreviewController(rootController: rootController, theme: presentationData.theme, strings: presentationData.strings, postbox: params.context.account.postbox, file: file) + } + if file.mimeType.contains("image/svg") { + let presentationData = params.context.sharedContext.currentPresentationData.with { $0 } + params.present(textAlertController(context: params.context, title: nil, text: presentationData.strings.OpenFile_PotentiallyDangerousContentAlert, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.OpenFile_Proceed, action: { proceed() })] ), nil) + } else { + proceed() + } } return true case let .audio(file): @@ -217,9 +225,7 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool { let path = params.context.account.postbox.mediaBox.completedResourcePath(media.resource) var previewTheme: PresentationTheme? if let path = path, let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe) { - let startTime = CACurrentMediaTime() previewTheme = makePresentationTheme(data: data) - print("time \(CACurrentMediaTime() - startTime)") } guard let theme = previewTheme else { @@ -306,6 +312,8 @@ func openChatTheme(context: AccountContext, message: Message, pushController: @e } else { displayUnsupportedAlert() } + } else { + displayUnsupportedAlert() } } else { displayUnsupportedAlert() diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift index 4bd124d7bf..e392578bfd 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift @@ -138,6 +138,8 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu }, openMessageReplies: { _, _, _ in }, openReplyThreadOriginalMessage: { _ in }, openMessageStats: { _ in + }, editMessageMedia: { _, _ in + }, copyText: { _ in }, requestMessageUpdate: { _ in }, cancelInteractiveKeyboardGestures: { }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false)) diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index a536be47e3..066cc3e6b6 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -1969,6 +1969,8 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD }, openMessageReplies: { _, _, _ in }, openReplyThreadOriginalMessage: { _ in }, openMessageStats: { _ in + }, editMessageMedia: { _, _ in + }, copyText: { _ in }, requestMessageUpdate: { _ in }, cancelInteractiveKeyboardGestures: { }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, @@ -3648,19 +3650,27 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } let context = self.context let presentationData = self.presentationData - let mapMedia = TelegramMediaMap(latitude: location.latitude, longitude: location.longitude, heading: nil, accuracyRadius: nil, geoPlace: nil, venue: MapVenue(title: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), address: location.address, provider: nil, id: nil, type: nil), liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil) - let locationController = legacyLocationController(message: nil, mapMedia: mapMedia, context: context, openPeer: { _ in }, sendLiveLocation: { _, _ in }, stopLiveLocation: {}, openUrl: { url in + let map = TelegramMediaMap(latitude: location.latitude, longitude: location.longitude, heading: nil, accuracyRadius: nil, geoPlace: nil, venue: MapVenue(title: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), address: location.address, provider: nil, id: nil, type: nil), liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil) + + let controllerParams = LocationViewParams(sendLiveLocation: { _ in + }, stopLiveLocation: { _ in + }, openUrl: { url in context.sharedContext.applicationBindings.openUrl(url) - }) - self.controller?.push(locationController) + }, openPeer: { _ in + }, showAll: false) + + let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer, text: "", attributes: [], media: [map], peers: SimpleDictionary(), associatedMessages: SimpleDictionary(), associatedMessageIds: []) + + let controller = LocationViewController(context: context, subject: message, params: controllerParams) + self.controller?.push(controller) } 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 + + let controller = LocationPickerController(context: self.context, mode: .pick, completion: { [weak self] location, address in guard let strongSelf = self else { return } @@ -3668,12 +3678,12 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD if let address = address { addressSignal = .single(address) } else { - addressSignal = reverseGeocodeLocation(latitude: coordinate.latitude, longitude: coordinate.longitude) + addressSignal = reverseGeocodeLocation(latitude: location.latitude, longitude: location.longitude) |> map { placemark in if let placemark = placemark { return placemark.fullAddress } else { - return "\(coordinate.latitude), \(coordinate.longitude)" + return "\(location.latitude), \(location.longitude)" } } } @@ -3681,12 +3691,11 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD 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) + return updateChannelGeoLocation(postbox: context.account.postbox, network: context.account.network, channelId: peer.id, coordinate: (location.latitude, location.longitude), address: address) } |> deliverOnMainQueue).start() - }, sendLiveLocation: { _, _ in }, theme: presentationData.theme, customLocationPicker: true, presentationCompleted: { }) - self.controller?.push(locationController) + self.controller?.push(controller) } private func openPeerInfo(peer: Peer, isMember: Bool) { diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index e8be1acdc0..c309999b54 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -1238,6 +1238,8 @@ public final class SharedAccountContextImpl: SharedAccountContext { }, openMessageReplies: { _, _, _ in }, openReplyThreadOriginalMessage: { _ in }, openMessageStats: { _ in + }, editMessageMedia: { _, _ in + }, copyText: { _ in }, requestMessageUpdate: { _ in }, cancelInteractiveKeyboardGestures: { }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, diff --git a/submodules/TelegramUI/Sources/StickerShimmerEffectNode.swift b/submodules/TelegramUI/Sources/StickerShimmerEffectNode.swift new file mode 100644 index 0000000000..7e35bfc1ce --- /dev/null +++ b/submodules/TelegramUI/Sources/StickerShimmerEffectNode.swift @@ -0,0 +1,605 @@ +import Foundation +import AsyncDisplayKit +import Display +import Postbox +import TelegramPresentationData +import GZip + +private final class ShimmerEffectForegroundNode: ASDisplayNode { + private var currentBackgroundColor: UIColor? + private var currentForegroundColor: UIColor? + private let imageNodeContainer: ASDisplayNode + private let imageNode: ASImageNode + + private var absoluteLocation: (CGRect, CGSize)? + private var isCurrentlyInHierarchy = false + private var shouldBeAnimating = false + + override init() { + self.imageNodeContainer = ASDisplayNode() + self.imageNodeContainer.isLayerBacked = true + + self.imageNode = ASImageNode() + self.imageNode.isLayerBacked = true + self.imageNode.displaysAsynchronously = false + self.imageNode.displayWithoutProcessing = true + self.imageNode.contentMode = .scaleToFill + + super.init() + + self.isLayerBacked = true + self.clipsToBounds = true + + self.imageNodeContainer.addSubnode(self.imageNode) + self.addSubnode(self.imageNodeContainer) + } + + override func didEnterHierarchy() { + super.didEnterHierarchy() + + self.isCurrentlyInHierarchy = true + self.updateAnimation() + } + + override func didExitHierarchy() { + super.didExitHierarchy() + + self.isCurrentlyInHierarchy = false + self.updateAnimation() + } + + func update(backgroundColor: UIColor, foregroundColor: UIColor) { + if let currentBackgroundColor = self.currentBackgroundColor, currentBackgroundColor.isEqual(backgroundColor), let currentForegroundColor = self.currentForegroundColor, currentForegroundColor.isEqual(foregroundColor) { + return + } + self.currentBackgroundColor = backgroundColor + self.currentForegroundColor = foregroundColor + + let image = generateImage(CGSize(width: 320.0, height: 16.0), opaque: false, scale: 1.0, rotatedContext: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + context.setFillColor(backgroundColor.cgColor) + context.fill(CGRect(origin: CGPoint(), size: size)) + + context.clip(to: CGRect(origin: CGPoint(), size: size)) + + let transparentColor = foregroundColor.withAlphaComponent(0.0).cgColor + let peakColor = foregroundColor.cgColor + + var locations: [CGFloat] = [0.0, 0.5, 1.0] + let colors: [CGColor] = [transparentColor, peakColor, transparentColor] + + 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: CGGradientDrawingOptions()) + }) + self.imageNode.image = image + } + + func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) { + if let absoluteLocation = self.absoluteLocation, absoluteLocation.0 == rect && absoluteLocation.1 == containerSize { + return + } + let sizeUpdated = self.absoluteLocation?.1 != containerSize + let frameUpdated = self.absoluteLocation?.0 != rect + self.absoluteLocation = (rect, containerSize) + + if sizeUpdated { + if self.shouldBeAnimating { + self.imageNode.layer.removeAnimation(forKey: "shimmer") + self.addImageAnimation() + } else { + self.updateAnimation() + } + } + + if frameUpdated { + self.imageNodeContainer.frame = CGRect(origin: CGPoint(x: -rect.minX, y: -rect.minY), size: containerSize) + } + } + + private func updateAnimation() { + let shouldBeAnimating = self.isCurrentlyInHierarchy && self.absoluteLocation != nil + if shouldBeAnimating != self.shouldBeAnimating { + self.shouldBeAnimating = shouldBeAnimating + if shouldBeAnimating { + self.addImageAnimation() + } else { + self.imageNode.layer.removeAnimation(forKey: "shimmer") + } + } + } + + private func addImageAnimation() { + guard let containerSize = self.absoluteLocation?.1 else { + return + } + let gradientHeight: CGFloat = 320.0 + self.imageNode.frame = CGRect(origin: CGPoint(x: -gradientHeight, y: 0.0), size: CGSize(width: gradientHeight, height: containerSize.height)) + let animation = self.imageNode.layer.makeAnimation(from: 0.0 as NSNumber, to: (containerSize.width + gradientHeight) as NSNumber, keyPath: "position.x", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: 1.3 * 1.0, delay: 0.0, mediaTimingFunction: nil, removeOnCompletion: true, additive: true) + animation.repeatCount = Float.infinity + animation.beginTime = 1.0 + self.imageNode.layer.add(animation, forKey: "shimmer") + } +} + +class StickerShimmerEffectNode: ASDisplayNode { + private let backgroundNode: ASDisplayNode + private let effectNode: ShimmerEffectForegroundNode + private let foregroundNode: ASImageNode + + private var maskView: UIImageView? + + private var currentData: Data? + private var currentBackgroundColor: UIColor? + private var currentForegroundColor: UIColor? + private var currentShimmeringColor: UIColor? + private var currentSize = CGSize() + + override init() { + self.backgroundNode = ASDisplayNode() + self.effectNode = ShimmerEffectForegroundNode() + self.foregroundNode = ASImageNode() + + super.init() + + self.addSubnode(self.backgroundNode) + self.addSubnode(self.effectNode) + self.addSubnode(self.foregroundNode) + } + + public func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) { + self.effectNode.updateAbsoluteRect(rect, within: containerSize) + } + + public func update(backgroundColor: UIColor?, foregroundColor: UIColor, shimmeringColor: UIColor, data: Data?, size: CGSize) { + if self.currentData == data, let currentBackgroundColor = self.currentBackgroundColor, currentBackgroundColor.isEqual(backgroundColor), let currentForegroundColor = self.currentForegroundColor, currentForegroundColor.isEqual(foregroundColor), let currentShimmeringColor = self.currentShimmeringColor, currentShimmeringColor.isEqual(shimmeringColor), self.currentSize == size { + return + } + + self.currentBackgroundColor = backgroundColor + self.currentForegroundColor = foregroundColor + self.currentShimmeringColor = shimmeringColor + self.currentData = data + self.currentSize = size + + self.backgroundNode.backgroundColor = foregroundColor + + self.effectNode.update(backgroundColor: backgroundColor == nil ? .clear : foregroundColor, foregroundColor: shimmeringColor) + + let image = generateImage(size, rotatedContext: { size, context in + if let backgroundColor = backgroundColor { + context.setFillColor(backgroundColor.cgColor) + context.setBlendMode(.copy) + context.fill(CGRect(origin: CGPoint(), size: size)) + + context.setFillColor(UIColor.clear.cgColor) + } else { + context.clear(CGRect(origin: CGPoint(), size: size)) + + context.setFillColor(UIColor.black.cgColor) + } + + if let data = data, let unpackedData = TGGUnzipData(data, 5 * 1024 * 1024), let path = String(data: unpackedData, encoding: .utf8) { + let reader = PathDataReader(input: path) + let segments = reader.read() + + var currentX: Double = 0.0 + var currentY: Double = 0.0 + + let mul: Double = Double(size.width) / 512.0 + + for segment in segments { + switch segment.type { + case .M, .m: + let x = segment.data[0] + let y = segment.data[1] + + if segment.isAbsolute() { + currentX = x + currentY = y + } else { + currentX += x + currentY += y + } + + context.move(to: CGPoint(x: currentX * mul, y: currentY * mul)) + case .L, .l: + let x = segment.data[0] + let y = segment.data[1] + + let effectiveX: Double + let effectiveY: Double + if segment.isAbsolute() { + effectiveX = x + effectiveY = y + } else { + effectiveX = currentX + x + effectiveY = currentY + y + } + + currentX = effectiveX + currentY = effectiveY + + context.addLine(to: CGPoint(x: effectiveX * mul, y: effectiveY * mul)) + case .C, .c: + let x1 = segment.data[0] + let y1 = segment.data[1] + let x2 = segment.data[2] + let y2 = segment.data[3] + let x = segment.data[4] + let y = segment.data[5] + + let effectiveX1: Double + let effectiveY1: Double + let effectiveX2: Double + let effectiveY2: Double + let effectiveX: Double + let effectiveY: Double + + if segment.isAbsolute() { + effectiveX1 = x1 + effectiveY1 = y1 + effectiveX2 = x2 + effectiveY2 = y2 + effectiveX = x + effectiveY = y + } else { + effectiveX1 = currentX + x1 + effectiveY1 = currentY + y1 + effectiveX2 = currentX + x2 + effectiveY2 = currentY + y2 + effectiveX = currentX + x + effectiveY = currentY + y + } + + currentX = effectiveX + currentY = effectiveY + + context.addCurve(to: CGPoint(x: effectiveX * mul, y: effectiveY * mul), control1: CGPoint(x: effectiveX1 * mul, y: effectiveY1 * mul), control2: CGPoint(x: effectiveX2 * mul, y: effectiveY2 * mul)) + case .z: + context.fillPath() + default: + break + } + } + } else { + let path = UIBezierPath(roundedRect: CGRect(origin: CGPoint(), size: size), byRoundingCorners: [.topLeft, .topRight, .bottomLeft, .bottomRight], cornerRadii: CGSize(width: 10.0, height: 10.0)) + UIGraphicsPushContext(context) + path.fill() + UIGraphicsPopContext() + } + }) + + if backgroundColor == nil { + self.foregroundNode.image = nil + + let maskView: UIImageView + if let current = self.maskView { + maskView = current + } else { + maskView = UIImageView() + maskView.frame = CGRect(origin: CGPoint(), size: size) + self.maskView = maskView + self.view.mask = maskView + } + + } else { + self.foregroundNode.image = image + + if let _ = self.maskView { + self.view.mask = nil + self.maskView = nil + } + } + + self.maskView?.image = image + + self.backgroundNode.frame = CGRect(origin: CGPoint(), size: size) + self.foregroundNode.frame = CGRect(origin: CGPoint(), size: size) + self.effectNode.frame = CGRect(origin: CGPoint(), size: size) + } +} + +open class PathSegment: Equatable { + public enum SegmentType { + case M + case L + case C + case Q + case A + case z + case H + case V + case S + case T + case m + case l + case c + case q + case a + case h + case v + case s + case t + case E + case e + } + + public let type: SegmentType + public let data: [Double] + + public init(type: PathSegment.SegmentType = .M, data: [Double] = []) { + self.type = type + self.data = data + } + + open func isAbsolute() -> Bool { + switch type { + case .M, .L, .H, .V, .C, .S, .Q, .T, .A, .E: + return true + default: + return false + } + } + + public static func == (lhs: PathSegment, rhs: PathSegment) -> Bool { + return lhs.type == rhs.type && lhs.data == rhs.data + } +} + +private class PathDataReader { + private let input: String + private var current: UnicodeScalar? + private var previous: UnicodeScalar? + private var iterator: String.UnicodeScalarView.Iterator + + private static let spaces: Set = Set("\n\r\t ,".unicodeScalars) + + init(input: String) { + self.input = input + self.iterator = input.unicodeScalars.makeIterator() + } + + public func read() -> [PathSegment] { + readNext() + var segments = [PathSegment]() + while let array = readSegments() { + segments.append(contentsOf: array) + } + return segments + } + + private func readSegments() -> [PathSegment]? { + if let type = readSegmentType() { + let argCount = getArgCount(segment: type) + if argCount == 0 { + return [PathSegment(type: type)] + } + var result = [PathSegment]() + let data: [Double] + if type == .a || type == .A { + data = readDataOfASegment() + } else { + data = readData() + } + var index = 0 + var isFirstSegment = true + while index < data.count { + let end = index + argCount + if end > data.count { + break + } + var currentType = type + if type == .M && !isFirstSegment { + currentType = .L + } + if type == .m && !isFirstSegment { + currentType = .l + } + result.append(PathSegment(type: currentType, data: Array(data[index.. [Double] { + var data = [Double]() + while true { + skipSpaces() + if let value = readNum() { + data.append(value) + } else { + return data + } + } + } + + private func readDataOfASegment() -> [Double] { + let argCount = getArgCount(segment: .A) + var data: [Double] = [] + var index = 0 + while true { + skipSpaces() + let value: Double? + let indexMod = index % argCount + if indexMod == 3 || indexMod == 4 { + value = readFlag() + } else { + value = readNum() + } + guard let doubleValue = value else { + return data + } + data.append(doubleValue) + index += 1 + } + return data + } + + private func skipSpaces() { + var currentCharacter = current + while let character = currentCharacter, Self.spaces.contains(character) { + currentCharacter = readNext() + } + } + + private func readFlag() -> Double? { + guard let ch = current else { + return .none + } + readNext() + switch ch { + case "0": + return 0 + case "1": + return 1 + default: + return .none + } + } + + fileprivate func readNum() -> Double? { + guard let ch = current else { + return .none + } + + guard ch >= "0" && ch <= "9" || ch == "." || ch == "-" else { + return .none + } + + var chars = [ch] + var hasDot = ch == "." + while let ch = readDigit(&hasDot) { + chars.append(ch) + } + + var buf = "" + buf.unicodeScalars.append(contentsOf: chars) + guard let value = Double(buf) else { + return .none + } + return value + } + + fileprivate func readDigit(_ hasDot: inout Bool) -> UnicodeScalar? { + if let ch = readNext() { + if (ch >= "0" && ch <= "9") || ch == "e" || (previous == "e" && ch == "-") { + return ch + } else if ch == "." && !hasDot { + hasDot = true + return ch + } + } + return nil + } + + fileprivate func isNum(ch: UnicodeScalar, hasDot: inout Bool) -> Bool { + switch ch { + case "0"..."9": + return true + case ".": + if hasDot { + return false + } + hasDot = true + default: + return true + } + return false + } + + @discardableResult + private func readNext() -> UnicodeScalar? { + previous = current + current = iterator.next() + return current + } + + private func isAcceptableSeparator(_ ch: UnicodeScalar?) -> Bool { + if let ch = ch { + return "\n\r\t ,".contains(String(ch)) + } + return false + } + + private func readSegmentType() -> PathSegment.SegmentType? { + while true { + if let type = getPathSegmentType() { + readNext() + return type + } + if readNext() == nil { + return nil + } + } + } + + fileprivate func getPathSegmentType() -> PathSegment.SegmentType? { + if let ch = current { + switch ch { + case "M": + return .M + case "m": + return .m + case "L": + return .L + case "l": + return .l + case "C": + return .C + case "c": + return .c + case "Q": + return .Q + case "q": + return .q + case "A": + return .A + case "a": + return .a + case "z", "Z": + return .z + case "H": + return .H + case "h": + return .h + case "V": + return .V + case "v": + return .v + case "S": + return .S + case "s": + return .s + case "T": + return .T + case "t": + return .t + default: + break + } + } + return nil + } + + fileprivate func getArgCount(segment: PathSegment.SegmentType) -> Int { + switch segment { + case .H, .h, .V, .v: + return 1 + case .M, .m, .L, .l, .T, .t: + return 2 + case .S, .s, .Q, .q: + return 4 + case .C, .c: + return 6 + case .A, .a: + return 7 + default: + return 0 + } + } +} diff --git a/submodules/TextFormat/Sources/StringWithAppliedEntities.swift b/submodules/TextFormat/Sources/StringWithAppliedEntities.swift index e3cad1726e..78dc7c3abd 100644 --- a/submodules/TextFormat/Sources/StringWithAppliedEntities.swift +++ b/submodules/TextFormat/Sources/StringWithAppliedEntities.swift @@ -160,15 +160,17 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti if case .Mention = entities[i + 1].type { let nextRange = NSRange(location: entities[i + 1].range.lowerBound, length: entities[i + 1].range.upperBound - entities[i + 1].range.lowerBound) if nextRange.location == range.location + range.length + 1 && nsString!.character(at: range.location + range.length) == 43 { - let peerName: String = nsString!.substring(with: NSRange(location: nextRange.location + 1, length: nextRange.length - 1)) - skipEntity = true - let combinedRange = NSRange(location: range.location, length: nextRange.location + nextRange.length - range.location) - string.addAttribute(NSAttributedString.Key.foregroundColor, value: linkColor, range: combinedRange) - if linkColor.isEqual(baseColor) { - string.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue as NSNumber, range: combinedRange) + if nextRange.length > 0 { + let peerName: String = nsString!.substring(with: NSRange(location: nextRange.location + 1, length: nextRange.length - 1)) + + let combinedRange = NSRange(location: range.location, length: nextRange.location + nextRange.length - range.location) + string.addAttribute(NSAttributedString.Key.foregroundColor, value: linkColor, range: combinedRange) + if linkColor.isEqual(baseColor) { + string.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue as NSNumber, range: combinedRange) + } + string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Hashtag), value: TelegramHashtag(peerName: peerName, hashtag: hashtag), range: combinedRange) } - string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Hashtag), value: TelegramHashtag(peerName: peerName, hashtag: hashtag), range: combinedRange) } } } @@ -190,6 +192,10 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.BotCommand), value: nsString!.substring(with: range), range: range) case .Code, .Pre: string.addAttribute(NSAttributedString.Key.font, value: fixedFont, range: range) + if nsString == nil { + nsString = text as NSString + } + string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Pre), value: nsString!.substring(with: range), range: range) case .BlockQuote: if let fontAttribute = fontAttributes[range] { fontAttributes[range] = fontAttribute.union(.blockQuote) diff --git a/submodules/TextFormat/Sources/TelegramAttributes.swift b/submodules/TextFormat/Sources/TelegramAttributes.swift index ab276a41e3..7ce2749909 100644 --- a/submodules/TextFormat/Sources/TelegramAttributes.swift +++ b/submodules/TextFormat/Sources/TelegramAttributes.swift @@ -40,4 +40,5 @@ public struct TelegramTextAttributes { public static let BankCard = "TelegramBankCard" public static let Timecode = "TelegramTimecode" public static let BlockQuote = "TelegramBlockQuote" + public static let Pre = "TelegramPre" } diff --git a/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift b/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift index 6674aed6f0..8fbe7afcdc 100644 --- a/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift +++ b/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift @@ -142,7 +142,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { self.textNode.attributedText = attributedText self.textNode.maximumNumberOfLines = 2 displayUndo = false - self.originalRemainingSeconds = 5 + self.originalRemainingSeconds = 3 case let .info(text): self.iconNode = nil self.iconCheckNode = nil diff --git a/submodules/WebSearchUI/Sources/WebSearchGalleryController.swift b/submodules/WebSearchUI/Sources/WebSearchGalleryController.swift index d5941381e7..87245d1f08 100644 --- a/submodules/WebSearchUI/Sources/WebSearchGalleryController.swift +++ b/submodules/WebSearchUI/Sources/WebSearchGalleryController.swift @@ -222,12 +222,13 @@ class WebSearchGalleryController: ViewController { if let strongSelf = self { strongSelf.present(controller, in: .window(.root), with: arguments, blockInteraction: true) } - }, dismissController: { [weak self] in - self?.dismiss(forceAway: true) - }, replaceRootController: { [weak self] controller, ready in - if let strongSelf = self { - strongSelf.replaceRootController(controller, ready) - } + }, dismissController: { [weak self] in + self?.dismiss(forceAway: true) + }, replaceRootController: { [weak self] controller, ready in + if let strongSelf = self { + strongSelf.replaceRootController(controller, ready) + } + }, editMedia: { _ in }) self.displayNode = GalleryControllerNode(controllerInteraction: controllerInteraction) self.displayNodeDidLoad() diff --git a/submodules/rlottie/BUILD b/submodules/rlottie/BUILD index a0a038abbb..0d2b59b685 100644 --- a/submodules/rlottie/BUILD +++ b/submodules/rlottie/BUILD @@ -24,6 +24,7 @@ objc_library( copts = [ "-Dpixman_region_selfcheck(x)=1", "-DLOTTIE_DISABLE_ARM_NEON=1", + "-DLOTTIE_THREAD_SAFE=1", "-DLOTTIE_IMAGE_MODULE_DISABLED=1", "-I{}".format(package_name()), "-I{}/rlottie/inc".format(package_name()),