From 702d37ce69fca77e78072ad408e9d29dfd2d2be8 Mon Sep 17 00:00:00 2001 From: xaxtix Date: Tue, 15 Aug 2023 02:42:46 +0400 Subject: [PATCH] update to 10.0.1 (3793) --- TMessagesProj/build.gradle | 2 +- .../config/debug/AndroidManifest.xml | 1 + .../config/debug/AndroidManifest_SDK23.xml | 1 + .../config/release/AndroidManifest.xml | 1 + .../config/release/AndroidManifest_SDK23.xml | 1 + .../release/AndroidManifest_standalone.xml | 1 + TMessagesProj/jni/gifvideo.cpp | 2 +- .../jni/tgnet/ConnectionsManager.cpp | 2 +- .../org_telegram_messenger_voip_Instance.cpp | 2 +- TMessagesProj/src/main/AndroidManifest.xml | 4 + .../google/android/exoplayer2/util/Util.java | 31 +- .../telegram/messenger/AndroidUtilities.java | 67 +- .../org/telegram/messenger/BuildVars.java | 4 +- .../ChatMessagesMetadataController.java | 4 +- .../messenger/ContactsController.java | 13 +- .../messenger/DatabaseMigrationHelper.java | 7 + .../org/telegram/messenger/DispatchQueue.java | 9 + .../telegram/messenger/FilePathDatabase.java | 13 +- .../messenger/FileStreamLoadOperation.java | 3 + .../messenger/FilesMigrationService.java | 17 +- .../messenger/GoogleMapsProvider.java | 10 + .../org/telegram/messenger/IMapsProvider.java | 2 + .../org/telegram/messenger/ImageReceiver.java | 8 + .../org/telegram/messenger/LinkifyPort.java | 21 +- .../messenger/LocationController.java | 182 ++- .../telegram/messenger/MediaController.java | 145 ++- .../messenger/MediaDataController.java | 19 +- .../org/telegram/messenger/MessageObject.java | 28 +- .../messenger/MessagesController.java | 232 +++- .../telegram/messenger/MessagesStorage.java | 5 +- .../messenger/NotificationCenter.java | 3 + .../messenger/PushListenerController.java | 2 +- .../org/telegram/messenger/SharedConfig.java | 19 + .../messenger/TranslateController.java | 251 ++++ .../telegram/messenger/VideoEditedInfo.java | 42 + .../telegram/messenger/browser/Browser.java | 4 +- .../messenger/video/TextureRenderer.java | 89 +- .../telegram/tgnet/ConnectionsManager.java | 4 + .../main/java/org/telegram/tgnet/TLRPC.java | 669 +++++++++- .../org/telegram/ui/ActionBar/ActionBar.java | 4 +- .../ui/ActionBar/ActionBarLayout.java | 2 +- .../telegram/ui/ActionBar/ActionBarMenu.java | 5 +- .../ui/ActionBar/ActionBarMenuItem.java | 12 + .../ui/ActionBar/ActionBarMenuSubItem.java | 4 + .../telegram/ui/ActionBar/BaseFragment.java | 3 + .../telegram/ui/ActionBar/BottomSheet.java | 10 + .../ui/ActionBar/FloatingToolbar.java | 213 +++- .../telegram/ui/ActionBar/SimpleTextView.java | 4 +- .../java/org/telegram/ui/ActionBar/Theme.java | 14 + .../telegram/ui/ActionBar/ThemeColors.java | 13 + .../org/telegram/ui/ActionIntroActivity.java | 2 +- .../ui/Adapters/BaseLocationAdapter.java | 216 +++- .../telegram/ui/Adapters/DialogsAdapter.java | 28 +- .../ui/Adapters/LocationActivityAdapter.java | 245 +++- .../LocationActivitySearchAdapter.java | 110 +- .../java/org/telegram/ui/ArticleViewer.java | 1 + .../telegram/ui/BasePermissionsActivity.java | 5 +- .../org/telegram/ui/CacheControlActivity.java | 2 +- .../org/telegram/ui/CameraScanActivity.java | 12 +- .../telegram/ui/Cells/ChatMessageCell.java | 28 +- .../telegram/ui/Cells/ContextLinkCell.java | 47 +- .../org/telegram/ui/Cells/DialogCell.java | 25 +- .../telegram/ui/Cells/DrawerActionCell.java | 19 +- .../org/telegram/ui/Cells/LocationCell.java | 106 +- .../ui/Cells/LocationDirectionCell.java | 2 +- .../ui/Cells/ReactedUserHolderView.java | 93 +- .../telegram/ui/Cells/SendLocationCell.java | 2 +- .../ui/Cells/SharingLiveLocationCell.java | 123 +- .../ui/Cells/TextSelectionHelper.java | 46 +- .../java/org/telegram/ui/ChatActivity.java | 45 +- .../org/telegram/ui/ChatUsersActivity.java | 1 + .../telegram/ui/Components/AlertsCreator.java | 7 + .../ui/Components/AnimatedFileDrawable.java | 5 +- .../ui/Components/AnimatedTextView.java | 4 + .../BottomSheetWithRecyclerListView.java | 2 +- .../org/telegram/ui/Components/Bulletin.java | 97 +- .../ui/Components/BulletinFactory.java | 26 + .../telegram/ui/Components/ButtonBounce.java | 30 +- .../telegram/ui/Components/CacheChart.java | 4 +- .../ui/Components/ChatActivityEnterView.java | 230 ++-- .../ui/Components/ChatAttachAlert.java | 138 +- .../ChatAttachAlertLocationLayout.java | 234 +++- .../ChatAttachAlertPhotoLayout.java | 36 +- .../ui/Components/ColoredImageSpan.java | 50 +- .../ui/Components/CombinedDrawable.java | 6 +- .../ui/Components/EditTextBoldCursor.java | 156 ++- .../ui/Components/EmojiTabsStrip.java | 27 +- .../FillLastLinearLayoutManager.java | 21 +- .../ui/Components/FlickerLoadingView.java | 2 +- .../telegram/ui/Components/GradientTools.java | 19 +- .../telegram/ui/Components/ImageUpdater.java | 12 +- .../ui/Components/InstantCameraView.java | 7 +- .../telegram/ui/Components/ItemOptions.java | 78 +- .../ui/Components/LoadingDrawable.java | 1 + .../ui/Components/MapPlaceholderDrawable.java | 6 +- .../telegram/ui/Components/MediaActivity.java | 23 +- .../ui/Components/MentionsContainerView.java | 76 +- .../MessageContainsEmojiButton.java | 28 +- .../ui/Components/Paint/PaintTypeface.java | 3 +- .../Paint/Views/EditTextOutline.java | 20 +- .../Paint/Views/EntitiesContainerView.java | 9 +- .../ui/Components/Paint/Views/EntityView.java | 604 ++++++--- .../Paint/Views/LPhotoPaintView.java | 39 +- .../Paint/Views/LocationMarker.java | 336 +++++ .../Components/Paint/Views/LocationView.java | 288 +++++ .../ui/Components/Paint/Views/PhotoView.java | 49 +- .../Components/Paint/Views/StickerView.java | 11 + .../Components/Paint/Views/TextPaintView.java | 37 +- .../ui/Components/PhotoPaintView.java | 7 +- .../Components/Premium/BaseListPageView.java | 62 + .../Premium/DoubleLimitsPageView.java | 47 +- .../Premium/DoubledLimitsBottomSheet.java | 30 +- .../Components/Premium/LimitPreviewView.java | 207 +-- .../Premium/LimitReachedBottomSheet.java | 56 +- .../Premium/PremiumAppIconsPreviewView.java | 7 +- .../Components/Premium/PremiumButtonView.java | 10 +- .../Premium/PremiumFeatureBottomSheet.java | 180 ++- .../Components/Premium/PremiumGradient.java | 17 +- .../Components/Premium/StarParticlesView.java | 21 +- .../Components/Premium/StoriesPageView.java | 265 ++++ .../Premium/VideoScreenPreview.java | 6 +- .../telegram/ui/Components/ProxyDrawable.java | 4 +- .../Reactions/AnimatedEmojiEffect.java | 4 +- .../Reactions/CustomEmojiReactionsWindow.java | 53 +- .../Components/ReactionsContainerLayout.java | 73 +- .../Components/ReplaceableIconDrawable.java | 9 +- .../telegram/ui/Components/SearchField.java | 19 +- .../ui/Components/SharedMediaLayout.java | 12 +- .../ui/Components/StickerEmptyView.java | 77 +- .../ui/Components/TextViewSwitcher.java | 8 +- .../ui/Components/ViewPagerFixed.java | 2 +- .../ui/Components/WallpaperUpdater.java | 16 +- .../spoilers/SpoilersClickDetector.java | 11 + .../org/telegram/ui/ContentPreviewViewer.java | 24 +- .../java/org/telegram/ui/DialogsActivity.java | 209 +-- .../org/telegram/ui/DownloadProgressIcon.java | 27 +- .../org/telegram/ui/FilterCreateActivity.java | 10 +- .../java/org/telegram/ui/LaunchActivity.java | 105 +- .../org/telegram/ui/LocationActivity.java | 165 ++- .../java/org/telegram/ui/LoginActivity.java | 24 +- .../ui/NotificationPermissionDialog.java | 320 +++++ .../org/telegram/ui/PaymentFormActivity.java | 4 +- .../org/telegram/ui/PeopleNearbyActivity.java | 2 +- .../java/org/telegram/ui/PhotoViewer.java | 476 +++++-- .../org/telegram/ui/PremiumFeatureCell.java | 11 +- .../telegram/ui/PremiumPreviewFragment.java | 97 +- .../java/org/telegram/ui/ProfileActivity.java | 63 +- .../telegram/ui/RecyclerListViewScroller.java | 9 +- .../ui/SelectAnimatedEmojiDialog.java | 16 +- .../org/telegram/ui/StickersActivity.java | 6 +- .../ui/Stories/DarkThemeResourceProvider.java | 12 +- .../ui/Stories/DialogStoriesCell.java | 239 +++- .../telegram/ui/Stories/PeerStoriesView.java | 973 ++++++++++++-- .../ui/Stories/SelfStoriesPreviewView.java | 106 +- .../ui/Stories/SelfStoryViewsPage.java | 1120 +++++++++++++++-- .../ui/Stories/SelfStoryViewsView.java | 185 ++- .../telegram/ui/Stories/StealthModeAlert.java | 250 ++++ .../ui/Stories/StoriesController.java | 542 +++++++- .../ui/Stories/StoriesLikeButton.java | 165 +++ .../ui/Stories/StoriesListPlaceProvider.java | 45 +- .../telegram/ui/Stories/StoriesStorage.java | 100 +- .../telegram/ui/Stories/StoriesUtilities.java | 473 ++++--- .../telegram/ui/Stories/StoriesViewPager.java | 75 +- .../telegram/ui/Stories/StoryCaptionView.java | 826 +++++++----- .../ui/Stories/StoryContainsEmojiButton.java | 6 +- .../ui/Stories/StoryCustomParamsHelper.java | 96 ++ .../ui/Stories/StoryMediaAreasView.java | 429 +++++++ .../ui/Stories/StoryPrivacyButton.java | 2 +- .../org/telegram/ui/Stories/StoryViewer.java | 282 ++++- .../ui/Stories/StoryViewsUsersAlert.java | 266 ---- .../recorder/ButtonWithCounterView.java | 18 +- .../recorder/CaptionContainerView.java | 80 +- .../ui/Stories/recorder/DownloadButton.java | 5 +- .../ui/Stories/recorder/DraftsController.java | 147 ++- .../ui/Stories/recorder/DualCameraView.java | 6 + .../ui/Stories/recorder/EmojiBottomSheet.java | 681 +++++++++- .../ui/Stories/recorder/GalleryListView.java | 467 ++++++- .../ui/Stories/recorder/HintView2.java | 167 ++- .../ui/Stories/recorder/PaintView.java | 428 ++++++- .../ui/Stories/recorder/PlayPauseButton.java | 61 + .../recorder/PreviewHighlightView.java | 10 +- .../ui/Stories/recorder/PreviewView.java | 17 +- .../ui/Stories/recorder/StoryEntry.java | 41 +- .../recorder/StoryPrivacyBottomSheet.java | 538 ++++++-- .../ui/Stories/recorder/StoryRecorder.java | 527 ++++++-- .../org/telegram/ui/ThemePreviewActivity.java | 2 +- .../ui/TwoStepVerificationSetupActivity.java | 10 + .../main/res/drawable-hdpi/large_stealth.png | Bin 0 -> 2033 bytes .../src/main/res/drawable-hdpi/media_like.png | Bin 0 -> 1406 bytes .../res/drawable-hdpi/media_like_active.png | Bin 0 -> 716 bytes .../main/res/drawable-hdpi/media_share.png | Bin 1233 -> 1372 bytes .../res/drawable-hdpi/media_views_liked.png | Bin 0 -> 662 bytes .../res/drawable-hdpi/menu_unsave_story.png | Bin 0 -> 1065 bytes .../drawable-hdpi/menu_views_reactions.png | Bin 0 -> 922 bytes .../drawable-hdpi/menu_views_reactions2.png | Bin 0 -> 708 bytes .../drawable-hdpi/menu_views_reactions3.png | Bin 0 -> 814 bytes .../res/drawable-hdpi/menu_views_recent.png | Bin 0 -> 882 bytes .../res/drawable-hdpi/menu_views_recent2.png | Bin 0 -> 705 bytes .../res/drawable-hdpi/menu_views_recent3.png | Bin 0 -> 741 bytes .../main/res/drawable-hdpi/mini_forwarded.png | Bin 0 -> 431 bytes .../res/drawable-hdpi/mini_like_filled.png | Bin 0 -> 454 bytes .../res/drawable-hdpi/mini_views_likes.png | Bin 0 -> 510 bytes .../res/drawable-hdpi/msg_customize_s.png | Bin 0 -> 585 bytes .../res/drawable-hdpi/msg_gallery_locked1.png | Bin 0 -> 798 bytes .../res/drawable-hdpi/msg_gallery_locked2.png | Bin 0 -> 404 bytes .../res/drawable-hdpi/msg_limit_stories.png | Bin 0 -> 976 bytes .../res/drawable-hdpi/msg_members_list2.png | Bin 0 -> 1005 bytes .../main/res/drawable-hdpi/msg_message_s.png | Bin 0 -> 975 bytes .../res/drawable-hdpi/msg_stealth_25min.png | Bin 0 -> 1337 bytes .../res/drawable-hdpi/msg_stealth_5min.png | Bin 0 -> 1182 bytes .../res/drawable-hdpi/msg_stealth_locked.png | Bin 0 -> 920 bytes .../res/drawable-hdpi/msg_stories_caption.png | Bin 0 -> 443 bytes .../res/drawable-hdpi/msg_stories_link.png | Bin 0 -> 931 bytes .../res/drawable-hdpi/msg_stories_myhide.png | Bin 0 -> 1131 bytes .../res/drawable-hdpi/msg_stories_order.png | Bin 0 -> 1370 bytes .../res/drawable-hdpi/msg_stories_save.png | Bin 0 -> 945 bytes .../res/drawable-hdpi/msg_stories_stealth.png | Bin 0 -> 1068 bytes .../drawable-hdpi/msg_stories_stealth2.png | Bin 0 -> 1114 bytes .../msg_stories_stealth_locked.png | Bin 0 -> 917 bytes .../res/drawable-hdpi/msg_stories_timer.png | Bin 0 -> 920 bytes .../res/drawable-hdpi/msg_stories_views.png | Bin 0 -> 807 bytes .../main/res/drawable-mdpi/large_stealth.png | Bin 0 -> 1309 bytes .../src/main/res/drawable-mdpi/media_like.png | Bin 0 -> 922 bytes .../res/drawable-mdpi/media_like_active.png | Bin 0 -> 533 bytes .../main/res/drawable-mdpi/media_share.png | Bin 855 -> 888 bytes .../res/drawable-mdpi/media_views_liked.png | Bin 0 -> 486 bytes .../res/drawable-mdpi/menu_unsave_story.png | Bin 0 -> 752 bytes .../drawable-mdpi/menu_views_reactions.png | Bin 0 -> 603 bytes .../drawable-mdpi/menu_views_reactions2.png | Bin 0 -> 488 bytes .../drawable-mdpi/menu_views_reactions3.png | Bin 0 -> 572 bytes .../res/drawable-mdpi/menu_views_recent.png | Bin 0 -> 567 bytes .../res/drawable-mdpi/menu_views_recent2.png | Bin 0 -> 501 bytes .../res/drawable-mdpi/menu_views_recent3.png | Bin 0 -> 495 bytes .../main/res/drawable-mdpi/mini_forwarded.png | Bin 0 -> 335 bytes .../res/drawable-mdpi/mini_like_filled.png | Bin 0 -> 335 bytes .../res/drawable-mdpi/mini_views_likes.png | Bin 0 -> 374 bytes .../res/drawable-mdpi/msg_customize_s.png | Bin 0 -> 468 bytes .../res/drawable-mdpi/msg_gallery_locked1.png | Bin 0 -> 572 bytes .../res/drawable-mdpi/msg_gallery_locked2.png | Bin 0 -> 326 bytes .../res/drawable-mdpi/msg_limit_stories.png | Bin 0 -> 637 bytes .../res/drawable-mdpi/msg_members_list2.png | Bin 0 -> 661 bytes .../main/res/drawable-mdpi/msg_message_s.png | Bin 0 -> 670 bytes .../res/drawable-mdpi/msg_stealth_25min.png | Bin 0 -> 829 bytes .../res/drawable-mdpi/msg_stealth_5min.png | Bin 0 -> 752 bytes .../res/drawable-mdpi/msg_stealth_locked.png | Bin 0 -> 624 bytes .../res/drawable-mdpi/msg_stories_caption.png | Bin 0 -> 366 bytes .../res/drawable-mdpi/msg_stories_link.png | Bin 0 -> 631 bytes .../res/drawable-mdpi/msg_stories_myhide.png | Bin 0 -> 770 bytes .../res/drawable-mdpi/msg_stories_order.png | Bin 0 -> 892 bytes .../res/drawable-mdpi/msg_stories_save.png | Bin 0 -> 659 bytes .../res/drawable-mdpi/msg_stories_stealth.png | Bin 0 -> 732 bytes .../drawable-mdpi/msg_stories_stealth2.png | Bin 0 -> 704 bytes .../msg_stories_stealth_locked.png | Bin 0 -> 628 bytes .../res/drawable-mdpi/msg_stories_timer.png | Bin 0 -> 689 bytes .../res/drawable-mdpi/msg_stories_views.png | Bin 0 -> 533 bytes .../main/res/drawable-xhdpi/large_stealth.png | Bin 0 -> 2820 bytes .../main/res/drawable-xhdpi/media_like.png | Bin 0 -> 1936 bytes .../res/drawable-xhdpi/media_like_active.png | Bin 0 -> 913 bytes .../main/res/drawable-xhdpi/media_share.png | Bin 1804 -> 1930 bytes .../res/drawable-xhdpi/media_views_liked.png | Bin 0 -> 883 bytes .../res/drawable-xhdpi/menu_unsave_story.png | Bin 0 -> 1469 bytes .../drawable-xhdpi/menu_views_reactions.png | Bin 0 -> 1250 bytes .../drawable-xhdpi/menu_views_reactions2.png | Bin 0 -> 924 bytes .../drawable-xhdpi/menu_views_reactions3.png | Bin 0 -> 1095 bytes .../res/drawable-xhdpi/menu_views_recent.png | Bin 0 -> 1382 bytes .../res/drawable-xhdpi/menu_views_recent2.png | Bin 0 -> 1034 bytes .../res/drawable-xhdpi/menu_views_recent3.png | Bin 0 -> 1135 bytes .../res/drawable-xhdpi/mini_forwarded.png | Bin 0 -> 589 bytes .../res/drawable-xhdpi/mini_like_filled.png | Bin 0 -> 556 bytes .../res/drawable-xhdpi/mini_views_likes.png | Bin 0 -> 634 bytes .../res/drawable-xhdpi/msg_customize_s.png | Bin 0 -> 787 bytes .../drawable-xhdpi/msg_gallery_locked1.png | Bin 0 -> 1026 bytes .../drawable-xhdpi/msg_gallery_locked2.png | Bin 0 -> 492 bytes .../res/drawable-xhdpi/msg_limit_stories.png | Bin 0 -> 1305 bytes .../res/drawable-xhdpi/msg_members_list2.png | Bin 0 -> 1396 bytes .../main/res/drawable-xhdpi/msg_message_s.png | Bin 0 -> 1259 bytes .../res/drawable-xhdpi/msg_stealth_25min.png | Bin 0 -> 1746 bytes .../res/drawable-xhdpi/msg_stealth_5min.png | Bin 0 -> 1579 bytes .../res/drawable-xhdpi/msg_stealth_locked.png | Bin 0 -> 1258 bytes .../drawable-xhdpi/msg_stories_caption.png | Bin 0 -> 592 bytes .../res/drawable-xhdpi/msg_stories_link.png | Bin 0 -> 1177 bytes .../res/drawable-xhdpi/msg_stories_myhide.png | Bin 0 -> 1489 bytes .../res/drawable-xhdpi/msg_stories_order.png | Bin 0 -> 1876 bytes .../res/drawable-xhdpi/msg_stories_save.png | Bin 0 -> 1258 bytes .../drawable-xhdpi/msg_stories_stealth.png | Bin 0 -> 1515 bytes .../drawable-xhdpi/msg_stories_stealth2.png | Bin 0 -> 1455 bytes .../msg_stories_stealth_locked.png | Bin 0 -> 1203 bytes .../res/drawable-xhdpi/msg_stories_timer.png | Bin 0 -> 1389 bytes .../res/drawable-xhdpi/msg_stories_views.png | Bin 0 -> 1388 bytes .../res/drawable-xxhdpi/large_stealth.png | Bin 0 -> 4377 bytes .../main/res/drawable-xxhdpi/media_like.png | Bin 0 -> 3178 bytes .../res/drawable-xxhdpi/media_like_active.png | Bin 0 -> 1420 bytes .../main/res/drawable-xxhdpi/media_share.png | Bin 2772 -> 2860 bytes .../res/drawable-xxhdpi/media_views_liked.png | Bin 0 -> 1271 bytes .../res/drawable-xxhdpi/menu_unsave_story.png | Bin 0 -> 2140 bytes .../drawable-xxhdpi/menu_views_reactions.png | Bin 0 -> 1888 bytes .../drawable-xxhdpi/menu_views_reactions2.png | Bin 0 -> 1354 bytes .../drawable-xxhdpi/menu_views_reactions3.png | Bin 0 -> 1607 bytes .../res/drawable-xxhdpi/menu_views_recent.png | Bin 0 -> 1745 bytes .../drawable-xxhdpi/menu_views_recent2.png | Bin 0 -> 1378 bytes .../drawable-xxhdpi/menu_views_recent3.png | Bin 0 -> 1459 bytes .../res/drawable-xxhdpi/mini_forwarded.png | Bin 0 -> 831 bytes .../res/drawable-xxhdpi/mini_like_filled.png | Bin 0 -> 809 bytes .../res/drawable-xxhdpi/mini_views_likes.png | Bin 0 -> 976 bytes .../res/drawable-xxhdpi/msg_customize_s.png | Bin 0 -> 941 bytes .../drawable-xxhdpi/msg_gallery_locked1.png | Bin 0 -> 1464 bytes .../drawable-xxhdpi/msg_gallery_locked2.png | Bin 0 -> 587 bytes .../res/drawable-xxhdpi/msg_limit_stories.png | Bin 0 -> 1932 bytes .../res/drawable-xxhdpi/msg_members_list2.png | Bin 0 -> 1793 bytes .../res/drawable-xxhdpi/msg_message_s.png | Bin 0 -> 1898 bytes .../res/drawable-xxhdpi/msg_stealth_25min.png | Bin 0 -> 2695 bytes .../res/drawable-xxhdpi/msg_stealth_5min.png | Bin 0 -> 2338 bytes .../drawable-xxhdpi/msg_stealth_locked.png | Bin 0 -> 1778 bytes .../drawable-xxhdpi/msg_stories_caption.png | Bin 0 -> 686 bytes .../res/drawable-xxhdpi/msg_stories_link.png | Bin 0 -> 1766 bytes .../drawable-xxhdpi/msg_stories_myhide.png | Bin 0 -> 2220 bytes .../res/drawable-xxhdpi/msg_stories_order.png | Bin 0 -> 2880 bytes .../res/drawable-xxhdpi/msg_stories_save.png | Bin 0 -> 1825 bytes .../drawable-xxhdpi/msg_stories_stealth.png | Bin 0 -> 2196 bytes .../drawable-xxhdpi/msg_stories_stealth2.png | Bin 0 -> 2214 bytes .../msg_stories_stealth_locked.png | Bin 0 -> 1761 bytes .../res/drawable-xxhdpi/msg_stories_timer.png | Bin 0 -> 1861 bytes .../res/drawable-xxhdpi/msg_stories_views.png | Bin 0 -> 1631 bytes .../src/main/res/drawable/map_pin3.xml | 19 + .../src/main/res/raw/mapstyle_dark.json | 186 +++ TMessagesProj/src/main/res/values/strings.xml | 120 +- TMessagesProj_App/build.gradle | 2 +- TMessagesProj_AppHockeyApp/build.gradle | 2 +- TMessagesProj_AppHuawei/build.gradle | 2 +- .../messenger/HuaweiMapsProvider.java | 10 + 330 files changed, 15335 insertions(+), 3257 deletions(-) create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LocationMarker.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LocationView.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/BaseListPageView.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StoriesPageView.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/NotificationPermissionDialog.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Stories/StealthModeAlert.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesLikeButton.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCustomParamsHelper.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryMediaAreasView.java delete mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewsUsersAlert.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PlayPauseButton.java create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/large_stealth.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/media_like.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/media_like_active.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/media_views_liked.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/menu_unsave_story.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/menu_views_reactions.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/menu_views_reactions2.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/menu_views_reactions3.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/menu_views_recent.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/menu_views_recent2.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/menu_views_recent3.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/mini_forwarded.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/mini_like_filled.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/mini_views_likes.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_customize_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_gallery_locked1.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_gallery_locked2.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_limit_stories.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_members_list2.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_message_s.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_stealth_25min.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_stealth_5min.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_stealth_locked.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_stories_caption.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_stories_link.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_stories_myhide.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_stories_order.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_stories_save.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_stories_stealth.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_stories_stealth2.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_stories_stealth_locked.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_stories_timer.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/msg_stories_views.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/large_stealth.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/media_like.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/media_like_active.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/media_views_liked.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/menu_unsave_story.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/menu_views_reactions.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/menu_views_reactions2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/menu_views_reactions3.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/menu_views_recent.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/menu_views_recent2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/menu_views_recent3.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/mini_forwarded.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/mini_like_filled.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/mini_views_likes.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_customize_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_gallery_locked1.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_gallery_locked2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_limit_stories.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_members_list2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_message_s.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_stealth_25min.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_stealth_5min.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_stealth_locked.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_stories_caption.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_stories_link.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_stories_myhide.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_stories_order.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_stories_save.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_stories_stealth.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_stories_stealth2.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_stories_stealth_locked.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_stories_timer.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/msg_stories_views.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/large_stealth.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/media_like.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/media_like_active.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/media_views_liked.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/menu_unsave_story.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/menu_views_reactions.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/menu_views_reactions2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/menu_views_reactions3.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/menu_views_recent.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/menu_views_recent2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/menu_views_recent3.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/mini_forwarded.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/mini_like_filled.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/mini_views_likes.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_customize_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_gallery_locked1.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_gallery_locked2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_limit_stories.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_members_list2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_message_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_stealth_25min.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_stealth_5min.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_stealth_locked.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_caption.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_link.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_myhide.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_order.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_save.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_stealth.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_stealth2.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_stealth_locked.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_timer.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_views.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/large_stealth.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/media_like.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/media_like_active.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/media_views_liked.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/menu_unsave_story.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/menu_views_reactions.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/menu_views_reactions2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/menu_views_reactions3.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/menu_views_recent.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/menu_views_recent2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/menu_views_recent3.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/mini_forwarded.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/mini_like_filled.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/mini_views_likes.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_customize_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_gallery_locked1.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_gallery_locked2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_limit_stories.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_members_list2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_message_s.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_stealth_25min.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_stealth_5min.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_stealth_locked.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_stories_caption.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_stories_link.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_stories_myhide.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_stories_order.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_stories_save.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_stories_stealth.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_stories_stealth2.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_stories_stealth_locked.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_stories_timer.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/msg_stories_views.png create mode 100644 TMessagesProj/src/main/res/drawable/map_pin3.xml create mode 100644 TMessagesProj/src/main/res/raw/mapstyle_dark.json diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index bd6343f3b14..e03a85d6605 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -82,7 +82,7 @@ android { defaultConfig { minSdkVersion 19 - targetSdkVersion 31 + targetSdkVersion 33 versionName "8.9.0" vectorDrawables.generatedDensities = ['mdpi', 'hdpi', 'xhdpi', 'xxhdpi'] diff --git a/TMessagesProj/config/debug/AndroidManifest.xml b/TMessagesProj/config/debug/AndroidManifest.xml index b7f49c6f5da..7d6dc8b3c62 100644 --- a/TMessagesProj/config/debug/AndroidManifest.xml +++ b/TMessagesProj/config/debug/AndroidManifest.xml @@ -13,6 +13,7 @@ + diff --git a/TMessagesProj/config/debug/AndroidManifest_SDK23.xml b/TMessagesProj/config/debug/AndroidManifest_SDK23.xml index f6464b533e0..5c958dc8b49 100644 --- a/TMessagesProj/config/debug/AndroidManifest_SDK23.xml +++ b/TMessagesProj/config/debug/AndroidManifest_SDK23.xml @@ -13,6 +13,7 @@ + diff --git a/TMessagesProj/config/release/AndroidManifest.xml b/TMessagesProj/config/release/AndroidManifest.xml index 457658f4af7..a6281473ad6 100644 --- a/TMessagesProj/config/release/AndroidManifest.xml +++ b/TMessagesProj/config/release/AndroidManifest.xml @@ -13,6 +13,7 @@ + diff --git a/TMessagesProj/config/release/AndroidManifest_SDK23.xml b/TMessagesProj/config/release/AndroidManifest_SDK23.xml index f52960f1e59..9cab3db1cd4 100644 --- a/TMessagesProj/config/release/AndroidManifest_SDK23.xml +++ b/TMessagesProj/config/release/AndroidManifest_SDK23.xml @@ -13,6 +13,7 @@ + diff --git a/TMessagesProj/config/release/AndroidManifest_standalone.xml b/TMessagesProj/config/release/AndroidManifest_standalone.xml index 66638636e6c..344cba957cc 100644 --- a/TMessagesProj/config/release/AndroidManifest_standalone.xml +++ b/TMessagesProj/config/release/AndroidManifest_standalone.xml @@ -13,6 +13,7 @@ + diff --git a/TMessagesProj/jni/gifvideo.cpp b/TMessagesProj/jni/gifvideo.cpp index b5a460b4952..68ef0738e80 100644 --- a/TMessagesProj/jni/gifvideo.cpp +++ b/TMessagesProj/jni/gifvideo.cpp @@ -122,7 +122,7 @@ typedef struct VideoInfo { } else { attached = false; } - DEBUG_DELREF("gifvideocpp stream"); + DEBUG_DELREF("gifvideo.cpp stream"); jniEnv->DeleteGlobalRef(stream); if (attached) { javaVm->DetachCurrentThread(); diff --git a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp index dff83fdbfa0..e6716b5b09a 100644 --- a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp +++ b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp @@ -3057,7 +3057,7 @@ void ConnectionsManager::updateDcSettings(uint32_t dcNum, bool workaround, bool if ((!workaround && !updatingDcSettings) || (workaround && !updatingDcSettingsWorkaround)) { return; } - if (!workaround && updatingDcSettingsAgain) { + if (!workaround && updatingDcSettingsAgain && updatingDcSettingsAgainDcNum == dcNum) { updatingDcSettingsAgain = false; for (auto & datacenter : datacenters) { datacenter.second->resetInitVersion(); diff --git a/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp b/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp index b2bb47369e3..11b9cf935e8 100644 --- a/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp +++ b/TMessagesProj/jni/voip/org_telegram_messenger_voip_Instance.cpp @@ -924,7 +924,7 @@ JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_onStreamP return; } auto context = (AndroidContext *) instance->_platformContext.get(); - std::shared_ptr task; + std::shared_ptr task = nullptr; auto q = (VideoChannelDescription::Quality) quality; if (videoChannel != 0) { for (auto videoTaskIter = context->videoStreamTasks.begin(); videoTaskIter != context->videoStreamTasks.end(); videoTaskIter++) { diff --git a/TMessagesProj/src/main/AndroidManifest.xml b/TMessagesProj/src/main/AndroidManifest.xml index 755fed8aa6a..12ff1899e31 100644 --- a/TMessagesProj/src/main/AndroidManifest.xml +++ b/TMessagesProj/src/main/AndroidManifest.xml @@ -30,6 +30,9 @@ + + + @@ -53,6 +56,7 @@ + diff --git a/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/Util.java b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/Util.java index ed042272a24..89242e5e953 100644 --- a/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/Util.java +++ b/TMessagesProj/src/main/java/com/google/android/exoplayer2/util/Util.java @@ -97,6 +97,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayDeque; +import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; @@ -2844,13 +2845,31 @@ private static HashMap createIsoLanguageReplacementMap() { @RequiresApi(api = Build.VERSION_CODES.M) private static boolean requestExternalStoragePermission(Activity activity) { - if (activity.checkSelfPermission(permission.READ_EXTERNAL_STORAGE) - != PackageManager.PERMISSION_GRANTED) { - activity.requestPermissions( - new String[] {permission.READ_EXTERNAL_STORAGE}, /* requestCode= */ 0); - return true; + if (Build.VERSION.SDK_INT >= 33) { + ArrayList permissions = new ArrayList<>(); + if (activity.checkSelfPermission(permission.READ_MEDIA_VIDEO) != PackageManager.PERMISSION_GRANTED) { + permissions.add(permission.READ_MEDIA_VIDEO); + } + if (activity.checkSelfPermission(permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) { + permissions.add(permission.READ_MEDIA_IMAGES); + } + if (activity.checkSelfPermission(permission.READ_MEDIA_AUDIO) != PackageManager.PERMISSION_GRANTED) { + permissions.add(permission.READ_MEDIA_AUDIO); + } + if (!permissions.isEmpty()) { + activity.requestPermissions(permissions.toArray(new String[0]), /* requestCode= */ 0); + return true; + } + return false; + } else { + if (activity.checkSelfPermission(permission.READ_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + activity.requestPermissions( + new String[]{permission.READ_EXTERNAL_STORAGE}, /* requestCode= */ 0); + return true; + } + return false; } - return false; } @RequiresApi(api = Build.VERSION_CODES.N) diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java index 2a9849f9122..c7f31914a94 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -8,6 +8,7 @@ package org.telegram.messenger; +import android.Manifest; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -112,6 +113,7 @@ import androidx.core.content.FileProvider; import androidx.core.graphics.ColorUtils; import androidx.core.math.MathUtils; +import androidx.core.widget.NestedScrollView; import androidx.dynamicanimation.animation.DynamicAnimation; import androidx.dynamicanimation.animation.SpringAnimation; import androidx.dynamicanimation.animation.SpringForce; @@ -157,6 +159,8 @@ import org.telegram.ui.Components.URLSpanReplacement; import org.telegram.ui.Components.UndoView; import org.telegram.ui.LaunchActivity; +import org.telegram.ui.Stories.PeerStoriesView; +import org.telegram.ui.Stories.StoryMediaAreasView; import org.telegram.ui.ThemePreviewActivity; import org.telegram.ui.WallpapersListActivity; @@ -454,6 +458,10 @@ public static CharSequence replaceSingleTag(String str, Runnable runnable) { } public static SpannableStringBuilder replaceSingleTag(String str, int colorKey, int type, Runnable runnable) { + return replaceSingleTag(str, colorKey, type, runnable, null); + } + + public static SpannableStringBuilder replaceSingleTag(String str, int colorKey, int type, Runnable runnable, Theme.ResourcesProvider resourcesProvider) { int startIndex = str.indexOf("**"); int endIndex = str.indexOf("**", startIndex + 1); str = str.replace("**", ""); @@ -473,7 +481,7 @@ public void updateDrawState(@NonNull TextPaint ds) { super.updateDrawState(ds); ds.setUnderlineText(false); if (colorKey >= 0) { - ds.setColor(Theme.getColor(colorKey)); + ds.setColor(Theme.getColor(colorKey, resourcesProvider)); } } @@ -490,7 +498,7 @@ public void onClick(@NonNull View view) { public void updateDrawState(TextPaint textPaint) { textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); int wasAlpha = textPaint.getAlpha(); - textPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText)); + textPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText, resourcesProvider)); textPaint.setAlpha(wasAlpha); } }, index, index + len, 0); @@ -573,18 +581,25 @@ public static void recycleBitmap(Bitmap image) { } public static boolean findClickableView(ViewGroup container, float x, float y) { + return findClickableView(container, x, y, null); + } + + public static boolean findClickableView(ViewGroup container, float x, float y, View onlyThisView) { if (container == null) { return false; } for (int i = 0; i < container.getChildCount(); i++) { View child = container.getChildAt(i); - if (child.getVisibility() != View.VISIBLE) { + if (child.getVisibility() != View.VISIBLE || child instanceof PeerStoriesView && child != onlyThisView) { + continue; + } + if (child instanceof StoryMediaAreasView.AreaView && !((StoryMediaAreasView) container).hasSelected() && (x < dp(60) || x > container.getWidth() - dp(60))) { continue; } child.getHitRect(AndroidUtilities.rectTmp2); if (AndroidUtilities.rectTmp2.contains((int) x, (int) y) && child.isClickable()) { return true; - } else if (child instanceof ViewGroup && findClickableView((ViewGroup) child, x - child.getX(), y - child.getY())) { + } else if (child instanceof ViewGroup && findClickableView((ViewGroup) child, x - child.getX(), y - child.getY(), onlyThisView)) { return true; } } @@ -721,6 +736,36 @@ public static void getBitmapFromSurface(SurfaceView surfaceView, Bitmap surfaceB } } + public static float[] getCoordinateInParent(ViewGroup parentView, View view) { + float x = 0, y = 0; + View child = view; + float yOffset = 0; + float xOffset = 0; + if (child != null && parentView != null) { + while (child != parentView) { + if (child == null) { + xOffset = 0; + yOffset = 0; + break; + } + yOffset += child.getY(); + xOffset += child.getX(); + if (child instanceof NestedScrollView) { + yOffset -= child.getScrollY(); + xOffset -= child.getScrollX(); + } + if (child.getParent() instanceof View) { + child = (View) child.getParent(); + } else { + xOffset = 0; + yOffset = 0; + break; + } + } + } + return new float[] {xOffset, yOffset}; + } + private static class LinkSpec { String url; int start; @@ -2982,7 +3027,17 @@ public static void addMediaToGallery(File file) { } private static File getAlbumDir(boolean secretChat) { - if (secretChat || !BuildVars.NO_SCOPED_STORAGE || (Build.VERSION.SDK_INT >= 23 && ApplicationLoader.applicationContext.checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) { + if ( + secretChat || + !BuildVars.NO_SCOPED_STORAGE || + ( + Build.VERSION.SDK_INT >= 33 && + ApplicationLoader.applicationContext.checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED + ) || ( + Build.VERSION.SDK_INT >= 23 && Build.VERSION.SDK_INT <= 33 && + ApplicationLoader.applicationContext.checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED + ) + ) { return FileLoader.getDirectory(FileLoader.MEDIA_DIR_IMAGE); } File storageDir = null; @@ -5197,7 +5252,7 @@ public static String getHostAuthority(Uri uri) { } public static boolean intersect1d(int x1, int x2, int y1, int y2) { - return Math.max(x1, x2) >= Math.min(y1, y2) && Math.max(y1, y2) >= Math.min(x1, x2); + return Math.max(x1, x2) > Math.min(y1, y2) && Math.max(y1, y2) > Math.min(x1, x2); } public static String getSysInfoString(String path) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java index 6c9ff9cf548..5eaa3d40b22 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java @@ -24,8 +24,8 @@ public class BuildVars { public static boolean USE_CLOUD_STRINGS = true; public static boolean CHECK_UPDATES = true; public static boolean NO_SCOPED_STORAGE = Build.VERSION.SDK_INT <= 29; - public static int BUILD_VERSION = 3721; - public static String BUILD_VERSION_STRING = "9.7.6"; + public static int BUILD_VERSION = 3793; + public static String BUILD_VERSION_STRING = "10.0.1"; public static int APP_ID = 4; public static String APP_HASH = "014b35b6184100b085b0d0572f9b5103"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatMessagesMetadataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatMessagesMetadataController.java index e847d92229c..fc73ae225d6 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatMessagesMetadataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatMessagesMetadataController.java @@ -177,11 +177,11 @@ public void loadExtendedMediaForMessages(long dialogId, ArrayList public void onFragmentDestroy() { for (int i = 0; i < reactionsRequests.size(); i++) { - chatActivity.getConnectionsManager().cancelRequest(reactionsRequests.remove(i), false); + chatActivity.getConnectionsManager().cancelRequest(reactionsRequests.get(i), false); } reactionsRequests.clear(); for (int i = 0; i < extendedMediaRequests.size(); i++) { - chatActivity.getConnectionsManager().cancelRequest(extendedMediaRequests.remove(i), false); + chatActivity.getConnectionsManager().cancelRequest(extendedMediaRequests.get(i), false); } extendedMediaRequests.clear(); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java index 3bfda0b4cb2..f3588267241 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java @@ -2878,6 +2878,11 @@ public static String formatName(String firstName, String lastName, int maxLength if (firstName != null) { firstName = firstName.trim(); } + if (firstName != null && lastName == null && maxLength > 0 && firstName.contains(" ") ) { + int i = firstName.indexOf(" "); + lastName = firstName.substring(i + 1); + firstName = firstName.substring(0, i); + } if (lastName != null) { lastName = lastName.trim(); } @@ -2885,7 +2890,7 @@ public static String formatName(String firstName, String lastName, int maxLength if (LocaleController.nameDisplayOrder == 1) { if (firstName != null && firstName.length() > 0) { if (maxLength > 0 && firstName.length() > maxLength + 2) { - return firstName.substring(0, maxLength); + return firstName.substring(0, maxLength) + "…"; } result.append(firstName); if (lastName != null && lastName.length() > 0) { @@ -2898,14 +2903,14 @@ public static String formatName(String firstName, String lastName, int maxLength } } else if (lastName != null && lastName.length() > 0) { if (maxLength > 0 && lastName.length() > maxLength + 2) { - return lastName.substring(0, maxLength); + return lastName.substring(0, maxLength) + "…"; } result.append(lastName); } } else { if (lastName != null && lastName.length() > 0) { if (maxLength > 0 && lastName.length() > maxLength + 2) { - return lastName.substring(0, maxLength); + return lastName.substring(0, maxLength) + "…"; } result.append(lastName); if (firstName != null && firstName.length() > 0) { @@ -2918,7 +2923,7 @@ public static String formatName(String firstName, String lastName, int maxLength } } else if (firstName != null && firstName.length() > 0) { if (maxLength > 0 && firstName.length() > maxLength + 2) { - return firstName.substring(0, maxLength); + return firstName.substring(0, maxLength) + "…"; } result.append(firstName); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java index 5058d08f310..885a008a500 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java @@ -1326,6 +1326,13 @@ public static int migrate(MessagesStorage messagesStorage, int version) throws E version = 127; } + if (version == 127) { + database.executeFast("ALTER TABLE stories ADD COLUMN custom_params BLOB default NULL").stepThis().dispose(); + + database.executeFast("PRAGMA user_version = 128").stepThis().dispose(); + version = 128; + } + return version; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DispatchQueue.java b/TMessagesProj/src/main/java/org/telegram/messenger/DispatchQueue.java index f118c0e9248..a08da5ab1e4 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DispatchQueue.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DispatchQueue.java @@ -84,6 +84,15 @@ public boolean postRunnable(Runnable runnable) { return postRunnable(runnable, 0); } + public boolean postToFrontRunnable(Runnable runnable) { + try { + syncLatch.await(); + } catch (Exception e) { + FileLog.e(e, false); + } + return handler.postAtFrontOfQueue(runnable); + } + public boolean postRunnable(Runnable runnable, long delay) { try { syncLatch.await(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FilePathDatabase.java b/TMessagesProj/src/main/java/org/telegram/messenger/FilePathDatabase.java index c09f367f1ac..e5b7f4b11f3 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FilePathDatabase.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FilePathDatabase.java @@ -280,18 +280,22 @@ public void checkMediaExistance(ArrayList messageObjects) { CountDownLatch syncLatch = new CountDownLatch(1); long time = System.currentTimeMillis(); - postRunnable(() -> { + long[] threadTime = new long[1]; + postToFrontRunnable(() -> { + long threadTimeLocal = System.currentTimeMillis(); ensureDatabaseCreated(); try { for (int i = 0; i < arrayListFinal.size(); i++) { MessageObject messageObject = arrayListFinal.get(i); messageObject.checkMediaExistance(false); } + threadTime[0] = System.currentTimeMillis() - threadTimeLocal; } catch (Throwable e) { FileLog.e(e); } finally { syncLatch.countDown(); } + }); try { @@ -300,7 +304,7 @@ public void checkMediaExistance(ArrayList messageObjects) { FileLog.e(e); } - FileLog.d("checkMediaExistance size=" + messageObjects.size() + " time=" + (System.currentTimeMillis() - time)); + FileLog.d("checkMediaExistance size=" + messageObjects.size() + " time=" + (System.currentTimeMillis() - time) + " thread_time=" + threadTime[0]); if (BuildVars.DEBUG_VERSION) { if (Thread.currentThread() == Looper.getMainLooper().getThread()) { @@ -465,6 +469,11 @@ private void postRunnable(Runnable runnable) { dispatchQueue.postRunnable(runnable); } + private void postToFrontRunnable(Runnable runnable) { + ensureQueueExist(); + dispatchQueue.postToFrontRunnable(runnable); + } + private void ensureQueueExist() { if (dispatchQueue == null) { synchronized (this) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileStreamLoadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileStreamLoadOperation.java index 18f019fc4a9..f62f59fd2d0 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileStreamLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileStreamLoadOperation.java @@ -146,6 +146,9 @@ public int read(byte[] buffer, int offset, int readLength) throws IOException { } File currentFileFast = loadOperation.getCurrentFileFast(); if (file == null || !Objects.equals(currentFile, currentFileFast)) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("check stream file " + currentFileFast); + } if (file != null) { try { file.close(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FilesMigrationService.java b/TMessagesProj/src/main/java/org/telegram/messenger/FilesMigrationService.java index b814b97c6fe..4ee9d221327 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FilesMigrationService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FilesMigrationService.java @@ -284,12 +284,25 @@ public FilesMigrationBottomSheet(BaseFragment fragment) { public void migrateOldFolder() { Activity activity = fragment.getParentActivity(); boolean canWrite = activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED; - boolean canRead = activity.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED; + boolean canRead = ( + Build.VERSION.SDK_INT >= 33 && ( + activity.checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED && + activity.checkSelfPermission(Manifest.permission.READ_MEDIA_VIDEO) == PackageManager.PERMISSION_GRANTED && + activity.checkSelfPermission(Manifest.permission.READ_MEDIA_AUDIO) == PackageManager.PERMISSION_GRANTED + ) || + Build.VERSION.SDK_INT < 33 && activity.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED + ); if (!canRead || !canWrite) { ArrayList permissions = new ArrayList<>(); if (!canRead) { - permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE); + if (Build.VERSION.SDK_INT >= 33) { + permissions.add(Manifest.permission.READ_MEDIA_IMAGES); + permissions.add(Manifest.permission.READ_MEDIA_VIDEO); + permissions.add(Manifest.permission.READ_MEDIA_AUDIO); + } else { + permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE); + } } if (!canWrite) { permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/GoogleMapsProvider.java b/TMessagesProj/src/main/java/org/telegram/messenger/GoogleMapsProvider.java index 648a6a21a09..5f483178087 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/GoogleMapsProvider.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/GoogleMapsProvider.java @@ -120,6 +120,11 @@ public float getMaxZoomLevel() { return googleMap.getMaxZoomLevel(); } + @Override + public float getMinZoomLevel() { + return googleMap.getMinZoomLevel(); + } + @SuppressLint("MissingPermission") @Override public void setMyLocationEnabled(boolean enabled) { @@ -151,6 +156,11 @@ public void setOnCameraMoveStartedListener(OnCameraMoveStartedListener onCameraM }); } + @Override + public void setOnCameraIdleListener(Runnable callback) { + googleMap.setOnCameraIdleListener(callback::run); + } + @Override public CameraPosition getCameraPosition() { com.google.android.gms.maps.model.CameraPosition pos = googleMap.getCameraPosition(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/IMapsProvider.java b/TMessagesProj/src/main/java/org/telegram/messenger/IMapsProvider.java index 0034510b03b..75db0a089d5 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/IMapsProvider.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/IMapsProvider.java @@ -37,8 +37,10 @@ interface IMap { void animateCamera(ICameraUpdate update, int duration, ICancelableCallback callback); void moveCamera(ICameraUpdate update); float getMaxZoomLevel(); + float getMinZoomLevel(); void setMyLocationEnabled(boolean enabled); IUISettings getUiSettings(); + void setOnCameraIdleListener(Runnable callback); void setOnCameraMoveStartedListener(OnCameraMoveStartedListener onCameraMoveStartedListener); CameraPosition getCameraPosition(); void setOnMapLoadedCallback(Runnable callback); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java index 9b48fddca03..23ac4df39d6 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java @@ -31,6 +31,8 @@ import androidx.annotation.Keep; +import com.google.android.exoplayer2.util.Log; + import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.Components.AnimatedFileDrawable; @@ -76,6 +78,12 @@ public Drawable getMediaDrawable() { return currentMediaDrawable; } + public void updateStaticDrawableThump(Bitmap bitmap) { + staticThumbShader = null; + roundPaint.setShader(null); + setStaticDrawable(new BitmapDrawable(bitmap)); + } + public interface ImageReceiverDelegate { void didSetImage(ImageReceiver imageReceiver, boolean set, boolean thumb, boolean memCache); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LinkifyPort.java b/TMessagesProj/src/main/java/org/telegram/messenger/LinkifyPort.java index a2e3bf1572d..1e361830cdf 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LinkifyPort.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LinkifyPort.java @@ -139,6 +139,25 @@ public class LinkifyPort { "\uDB00\uDC00-\uDB3F\uDFFD" + "\uDB44\uDC00-\uDB7F\uDFFD" + "&&[^\u00A0[\u2000-\u200A]\u2028\u2029\u202F\u3000]]"; + private static final String UCS_CHAR_FIXED = "[" + + "\u00A0-\uD7FF" + + "\uF900-\uFDCF" + + "\uFDF0-\uFFEF" + + // "\uD800\uDC00-\uD83F\uDFFD" + + "\uD840\uDC00-\uD87F\uDFFD" + + "\uD880\uDC00-\uD8BF\uDFFD" + + "\uD8C0\uDC00-\uD8FF\uDFFD" + + "\uD900\uDC00-\uD93F\uDFFD" + + "\uD940\uDC00-\uD97F\uDFFD" + + "\uD980\uDC00-\uD9BF\uDFFD" + + "\uD9C0\uDC00-\uD9FF\uDFFD" + + "\uDA00\uDC00-\uDA3F\uDFFD" + + "\uDA40\uDC00-\uDA7F\uDFFD" + + "\uDA80\uDC00-\uDABF\uDFFD" + + "\uDAC0\uDC00-\uDAFF\uDFFD" + + "\uDB00\uDC00-\uDB3F\uDFFD" + + "\uDB44\uDC00-\uDB7F\uDFFD" + + "&&[^\u00A0[\u2000-\u200A]\u2028\u2029\u202F\u3000]]"; private static final String IP_ADDRESS_STRING = "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]" + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]" @@ -146,7 +165,7 @@ public class LinkifyPort { + "|[1-9][0-9]|[0-9]))"; private static final String TLD_CHAR = "a-zA-Z" + UCS_CHAR; private static final String PUNYCODE_TLD = "xn\\-\\-[\\w\\-]{0,58}\\w"; - private static final String LABEL_CHAR = "a-zA-Z0-9" + UCS_CHAR; + private static final String LABEL_CHAR = "a-zA-Z0-9" + UCS_CHAR_FIXED; private static final String IRI_LABEL = "[" + LABEL_CHAR + "](?:[" + LABEL_CHAR + "_\\-]{0,61}[" + LABEL_CHAR + "]){0,1}"; private static String STRICT_TLD = "(?:" + IANA_TOP_LEVEL_DOMAINS + "|" + PUNYCODE_TLD + ")"; private static final String STRICT_HOST_NAME = "(?:(?:" + IRI_LABEL + "\\.)+" + STRICT_TLD + ")"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocationController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocationController.java index 894b11e055e..eee5cd401c6 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocationController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocationController.java @@ -20,6 +20,7 @@ import android.os.Bundle; import android.os.SystemClock; import android.text.TextUtils; +import android.util.Log; import android.util.SparseIntArray; import androidx.collection.LongSparseArray; @@ -997,7 +998,7 @@ public static int getLocationsCount() { } public interface LocationFetchCallback { - void onLocationAddressAvailable(String address, String displayAddress, Location location); + void onLocationAddressAvailable(String address, String displayAddress, TLRPC.TL_messageMediaVenue city, TLRPC.TL_messageMediaVenue street, Location location); } private static HashMap callbacks = new HashMap<>(); @@ -1011,15 +1012,24 @@ public static void fetchLocationAddress(Location location, LocationFetchCallback callbacks.remove(callback); } if (location == null) { - callback.onLocationAddressAvailable(null, null, null); + callback.onLocationAddressAvailable(null, null, null, null, null); return; } + Locale locale; + try { + locale = LocaleController.getInstance().getCurrentLocale(); + } catch (Exception ignore) { + locale = LocaleController.getInstance().getSystemDefaultLocale(); + } + final Locale finalLocale = locale; Utilities.globalQueue.postRunnable(fetchLocationRunnable = () -> { - String name; - String displayName; + String name, displayName, city, street, countryCode = null; + boolean onlyCountry = true; + TLRPC.TL_messageMediaVenue cityLocation = null; + TLRPC.TL_messageMediaVenue streetLocation = null; try { - Geocoder gcd = new Geocoder(ApplicationLoader.applicationContext, LocaleController.getInstance().getSystemDefaultLocale()); + Geocoder gcd = new Geocoder(ApplicationLoader.applicationContext, finalLocale); List
addresses = gcd.getFromLocation(location.getLatitude(), location.getLongitude(), 1); if (addresses.size() > 0) { Address address = addresses.get(0); @@ -1028,6 +1038,74 @@ public static void fetchLocationAddress(Location location, LocationFetchCallback StringBuilder nameBuilder = new StringBuilder(); StringBuilder displayNameBuilder = new StringBuilder(); + StringBuilder cityBuilder = new StringBuilder(); + StringBuilder streetBuilder = new StringBuilder(); + + String locality = null; + String feature = null; +// String addressLine = null; +// try { +// addressLine = address.getAddressLine(0); +// } catch (Exception ignore) {} +// if (addressLine != null) { +// String postalCode = address.getPostalCode(); +// if (postalCode != null) { +// addressLine = addressLine.replace(" " + postalCode, ""); +// addressLine = addressLine.replace(postalCode, ""); +// } +// String[] parts = addressLine.split(", "); +// if (parts.length > 2) { +// String _country = parts[parts.length - 1].replace(",", "").trim(); +// String _city = parts[parts.length - 2].replace(",", "").trim(); +//// if (_city.length() > 3) { +//// locality = _city; +//// } +//// feature = parts[0].replace(",", "").trim(); +// } +// } + if (TextUtils.isEmpty(locality)) { + locality = address.getLocality(); + } + if (TextUtils.isEmpty(locality)) { + locality = address.getSubAdminArea(); + } + if (TextUtils.isEmpty(locality)) { + locality = address.getAdminArea(); + } + +// if (TextUtils.isEmpty(feature) && !TextUtils.equals(address.getFeatureName(), locality) && !TextUtils.equals(address.getFeatureName(), address.getCountryName())) { +// feature = address.getFeatureName(); +// } + if (TextUtils.isEmpty(feature) && !TextUtils.equals(address.getThoroughfare(), locality) && !TextUtils.equals(address.getThoroughfare(), address.getCountryName())) { + feature = address.getThoroughfare(); + } + if (TextUtils.isEmpty(feature) && !TextUtils.equals(address.getSubLocality(), locality) && !TextUtils.equals(address.getSubLocality(), address.getCountryName())) { + feature = address.getSubLocality(); + } + if (TextUtils.isEmpty(feature) && !TextUtils.equals(address.getLocality(), locality) && !TextUtils.equals(address.getLocality(), address.getCountryName())) { + feature = address.getLocality(); + } + if (!TextUtils.isEmpty(feature) && !TextUtils.equals(feature, locality) && !TextUtils.equals(feature, address.getCountryName())) { + if (streetBuilder.length() > 0) { + streetBuilder.append(", "); + } + streetBuilder.append(feature); + } else { + streetBuilder = null; + } + if (!TextUtils.isEmpty(locality)) { + if (cityBuilder.length() > 0) { + cityBuilder.append(", "); + } + cityBuilder.append(locality); + onlyCountry = false; + if (streetBuilder != null) { + if (streetBuilder.length() > 0) { + streetBuilder.append(", "); + } + streetBuilder.append(locality); + } + } arg = address.getSubThoroughfare(); if (!TextUtils.isEmpty(arg)) { @@ -1065,12 +1143,29 @@ public static void fetchLocationAddress(Location location, LocationFetchCallback } nameBuilder.append(arg); } + countryCode = address.getCountryCode(); arg = address.getCountryName(); if (!TextUtils.isEmpty(arg)) { if (nameBuilder.length() > 0) { nameBuilder.append(", "); } nameBuilder.append(arg); + String shortCountry = arg; + final String lng = finalLocale.getLanguage(); + if (("US".equals(address.getCountryCode()) || "AE".equals(address.getCountryCode())) && ("en".equals(lng) || "uk".equals(lng) || "ru".equals(lng)) || "GB".equals(address.getCountryCode()) && "en".equals(lng)) { + shortCountry = ""; + String[] words = arg.split(" "); + for (String word : words) { + if (word.length() > 0) + shortCountry += word.charAt(0); + } + } else if ("US".equals(address.getCountryCode())) { + shortCountry = "USA"; + } + if (cityBuilder.length() > 0) { + cityBuilder.append(", "); + } + cityBuilder.append(shortCountry); } arg = address.getCountryName(); @@ -1106,19 +1201,94 @@ public static void fetchLocationAddress(Location location, LocationFetchCallback name = nameBuilder.toString(); displayName = displayNameBuilder.toString(); + city = cityBuilder.toString(); + street = streetBuilder == null ? null : streetBuilder.toString(); } else { name = displayName = String.format(Locale.US, "Unknown address (%f,%f)", location.getLatitude(), location.getLongitude()); + city = null; + street = null; + } + if (!TextUtils.isEmpty(city)) { + cityLocation = new TLRPC.TL_messageMediaVenue(); + cityLocation.geo = new TLRPC.TL_geoPoint(); + cityLocation.geo.lat = location.getLatitude(); + cityLocation.geo._long = location.getLongitude(); + cityLocation.query_id = -1; + cityLocation.title = city; + cityLocation.icon = onlyCountry ? "https://ss3.4sqi.net/img/categories_v2/building/government_capitolbuilding_64.png" : "https://ss3.4sqi.net/img/categories_v2/travel/hotel_64.png"; + cityLocation.emoji = countryCodeToEmoji(countryCode); + cityLocation.address = onlyCountry ? LocaleController.getString("Country", R.string.Country) : LocaleController.getString("PassportCity", R.string.PassportCity); + } + if (!TextUtils.isEmpty(street)) { + streetLocation = new TLRPC.TL_messageMediaVenue(); + streetLocation.geo = new TLRPC.TL_geoPoint(); + streetLocation.geo.lat = location.getLatitude(); + streetLocation.geo._long = location.getLongitude(); + streetLocation.query_id = -1; + streetLocation.title = street; + streetLocation.icon = "pin"; + streetLocation.address = LocaleController.getString("PassportStreet1", R.string.PassportStreet1); + } + if (cityLocation == null && streetLocation == null && location != null) { + String ocean = detectOcean(location.getLongitude(), location.getLatitude()); + if (ocean != null) { + cityLocation = new TLRPC.TL_messageMediaVenue(); + cityLocation.geo = new TLRPC.TL_geoPoint(); + cityLocation.geo.lat = location.getLatitude(); + cityLocation.geo._long = location.getLongitude(); + cityLocation.query_id = -1; + cityLocation.title = ocean; + cityLocation.icon = "pin"; + cityLocation.emoji = "🌊"; + cityLocation.address = "Ocean"; + } } } catch (Exception ignore) { name = displayName = String.format(Locale.US, "Unknown address (%f,%f)", location.getLatitude(), location.getLongitude()); + city = null; + street = null; } final String nameFinal = name; final String displayNameFinal = displayName; + final TLRPC.TL_messageMediaVenue finalCityLocation = cityLocation; + final TLRPC.TL_messageMediaVenue finalStreetLocation = streetLocation; AndroidUtilities.runOnUIThread(() -> { callbacks.remove(callback); - callback.onLocationAddressAvailable(nameFinal, displayNameFinal, location); + callback.onLocationAddressAvailable(nameFinal, displayNameFinal, finalCityLocation, finalStreetLocation, location); }); }, 300); callbacks.put(callback, fetchLocationRunnable); } + + public static String countryCodeToEmoji(String code) { + if (code == null) { + return null; + } + code = code.toUpperCase(); + final int count = code.codePointCount(0, code.length()); + if (count > 2) { + return null; + } + StringBuilder flag = new StringBuilder(); + for (int j = 0; j < count; ++j) { + flag.append(Character.toChars(Character.codePointAt(code, j) - 0x41 + 0x1F1E6)); + } + return flag.toString(); + } + + public static String detectOcean(double x, double y) { + if (y > 65) { + return "Arctic Ocean"; + } + if (x > -88 && x < 40 && y > 0 || x > -60 && x < 20 && y <= 0) { + return "Atlantic Ocean"; + } + if (y <= 30 && x >= 20 && x < 150) { + return "Indian Ocean"; + } + if ((x > 106 || x < -60) && y > 0 || (x > 150 || x < -60) && y <= 0) { + return "Pacific Ocean"; + } + return null; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java index 260962ed375..3cd122e1631 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -918,8 +918,16 @@ public static void checkGallery() { int count = 0; Cursor cursor = null; try { - if (ApplicationLoader.applicationContext.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { - cursor = MediaStore.Images.Media.query(ApplicationLoader.applicationContext.getContentResolver(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{"COUNT(_id)"}, null, null, null); + final Context context = ApplicationLoader.applicationContext; + if ( + Build.VERSION.SDK_INT >= 33 && ( + context.checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED || + context.checkSelfPermission(Manifest.permission.READ_MEDIA_VIDEO) == PackageManager.PERMISSION_GRANTED || + context.checkSelfPermission(Manifest.permission.READ_MEDIA_AUDIO) == PackageManager.PERMISSION_GRANTED + ) || + context.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED + ) { + cursor = MediaStore.Images.Media.query(context.getContentResolver(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{"COUNT(_id)"}, null, null, null); if (cursor != null) { if (cursor.moveToNext()) { count += cursor.getInt(0); @@ -934,8 +942,16 @@ public static void checkGallery() { } } try { - if (ApplicationLoader.applicationContext.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { - cursor = MediaStore.Images.Media.query(ApplicationLoader.applicationContext.getContentResolver(), MediaStore.Video.Media.EXTERNAL_CONTENT_URI, new String[]{"COUNT(_id)"}, null, null, null); + final Context context = ApplicationLoader.applicationContext; + if ( + Build.VERSION.SDK_INT >= 33 && ( + context.checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED || + context.checkSelfPermission(Manifest.permission.READ_MEDIA_VIDEO) == PackageManager.PERMISSION_GRANTED || + context.checkSelfPermission(Manifest.permission.READ_MEDIA_AUDIO) == PackageManager.PERMISSION_GRANTED + ) || + context.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED + ) { + cursor = MediaStore.Images.Media.query(context.getContentResolver(), MediaStore.Video.Media.EXTERNAL_CONTENT_URI, new String[]{"COUNT(_id)"}, null, null, null); if (cursor != null) { if (cursor.moveToNext()) { count += cursor.getInt(0); @@ -1773,8 +1789,32 @@ public void onSensorChanged(SensorEvent event) { if (raisedToBack == minCount || accelerometerVertical) { lastAccelerometerDetected = System.currentTimeMillis(); } - if (proximityTouched && (raisedToBack == minCount || accelerometerVertical || System.currentTimeMillis() - lastAccelerometerDetected < 60) && !VoIPService.isAnyKindOfCallActive() && !manualRecording && !forbidRaiseToListen()) { - if (SharedConfig.enabledRaiseTo(true) && playingMessageObject == null && recordStartRunnable == null && recordingAudio == null && !PhotoViewer.getInstance().isVisible() && ApplicationLoader.isScreenOn && !inputFieldHasText && allowStartRecord && raiseChat != null && !callInProgress) { + final boolean allowRecording = !manualRecording && playingMessageObject == null && SharedConfig.enabledRaiseTo(true) && ApplicationLoader.isScreenOn && !inputFieldHasText && allowStartRecord && raiseChat != null && !callInProgress; + final boolean allowListening = SharedConfig.enabledRaiseTo(false) && playingMessageObject != null && (playingMessageObject.isVoice() || playingMessageObject.isRoundVideo()); + final boolean proximityDetected = proximityTouched; + final boolean accelerometerDetected = raisedToBack == minCount || accelerometerVertical || System.currentTimeMillis() - lastAccelerometerDetected < 60; + final boolean alreadyPlaying = useFrontSpeaker || raiseToEarRecord; + final boolean wakelockAllowed = ( +// proximityDetected || + accelerometerDetected || + alreadyPlaying + ) && !forbidRaiseToListen() && !VoIPService.isAnyKindOfCallActive() && (allowRecording || allowListening) && !PhotoViewer.getInstance().isVisible(); + if (proximityWakeLock != null) { + final boolean held = proximityWakeLock.isHeld(); + if (held && !wakelockAllowed) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("wake lock releasing (proximityDetected=" + proximityDetected + ", accelerometerDetected=" + accelerometerDetected + ", alreadyPlaying=" + alreadyPlaying + ")"); + } + proximityWakeLock.release(); + } else if (!held && wakelockAllowed) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("wake lock acquiring (proximityDetected=" + proximityDetected + ", accelerometerDetected=" + accelerometerDetected + ", alreadyPlaying=" + alreadyPlaying + ")"); + } + proximityWakeLock.acquire(); + } + } + if (proximityTouched && wakelockAllowed) { + if (allowRecording && recordStartRunnable == null && recordingAudio == null) { if (!raiseToEarRecord) { if (BuildVars.LOGS_ENABLED) { FileLog.d("start record"); @@ -1788,40 +1828,40 @@ public void onSensorChanged(SensorEvent event) { if (useFrontSpeaker) { setUseFrontSpeaker(true); } - ignoreOnPause = true; - if (proximityHasDifferentValues && proximityWakeLock != null && !proximityWakeLock.isHeld()) { - proximityWakeLock.acquire(); - } +// ignoreOnPause = true; +// if (proximityHasDifferentValues && proximityWakeLock != null && !proximityWakeLock.isHeld()) { +// proximityWakeLock.acquire(); +// } } - } else if (SharedConfig.enabledRaiseTo(false) && playingMessageObject != null && (playingMessageObject.isVoice() || playingMessageObject.isRoundVideo())) { + } else if (allowListening) { if (!useFrontSpeaker) { if (BuildVars.LOGS_ENABLED) { FileLog.d("start listen"); } - if (proximityHasDifferentValues && proximityWakeLock != null && !proximityWakeLock.isHeld()) { - proximityWakeLock.acquire(); - } +// if (proximityHasDifferentValues && proximityWakeLock != null && !proximityWakeLock.isHeld()) { +// proximityWakeLock.acquire(); +// } setUseFrontSpeaker(true); startAudioAgain(false); - ignoreOnPause = true; +// ignoreOnPause = true; } } raisedToBack = 0; raisedToTop = 0; raisedToTopSign = 0; countLess = 0; - } else if (proximityTouched && ((accelerometerSensor == null || linearSensor == null) && gravitySensor == null || ignoreAccelerometerGestures()) && !VoIPService.isAnyKindOfCallActive()) { - if (playingMessageObject != null && !ApplicationLoader.mainInterfacePaused && (playingMessageObject.isVoice() || playingMessageObject.isRoundVideo()) && SharedConfig.enabledRaiseTo(false)) { + } else if (proximityTouched && ((accelerometerSensor == null || linearSensor == null) && gravitySensor == null) && !VoIPService.isAnyKindOfCallActive()) { + if (playingMessageObject != null && !ApplicationLoader.mainInterfacePaused && allowListening) { if (!useFrontSpeaker && !manualRecording && !forbidRaiseToListen()) { if (BuildVars.LOGS_ENABLED) { FileLog.d("start listen by proximity only"); } - if (proximityHasDifferentValues && proximityWakeLock != null && !proximityWakeLock.isHeld()) { - proximityWakeLock.acquire(); - } +// if (proximityHasDifferentValues && proximityWakeLock != null && !proximityWakeLock.isHeld()) { +// proximityWakeLock.acquire(); +// } setUseFrontSpeaker(true); startAudioAgain(false); - ignoreOnPause = true; +// ignoreOnPause = true; } } } else if (!proximityTouched && !manualRecording) { @@ -1832,9 +1872,9 @@ public void onSensorChanged(SensorEvent event) { stopRecording(2, false, 0); raiseToEarRecord = false; ignoreOnPause = false; - if (proximityHasDifferentValues && proximityWakeLock != null && proximityWakeLock.isHeld()) { - proximityWakeLock.release(); - } +// if (!ignoreAccelerometerGestures() && proximityHasDifferentValues && proximityWakeLock != null && proximityWakeLock.isHeld()) { +// proximityWakeLock.release(); +// } } else if (useFrontSpeaker) { if (BuildVars.LOGS_ENABLED) { FileLog.d("stop listen"); @@ -1842,9 +1882,9 @@ public void onSensorChanged(SensorEvent event) { useFrontSpeaker = false; startAudioAgain(true); ignoreOnPause = false; - if (proximityHasDifferentValues && proximityWakeLock != null && proximityWakeLock.isHeld()) { - proximityWakeLock.release(); - } +// if (!ignoreAccelerometerGestures() && proximityHasDifferentValues && proximityWakeLock != null && proximityWakeLock.isHeld()) { +// proximityWakeLock.release(); +// } } } if (timeSinceRaise != 0 && raisedToBack == minCount && Math.abs(System.currentTimeMillis() - timeSinceRaise) > 1000) { @@ -1990,7 +2030,7 @@ public void stopRaiseToEarSensors(ChatActivity chatActivity, boolean fromChat, b } sensorManager.unregisterListener(MediaController.this, proximitySensor); }); - if (proximityHasDifferentValues && proximityWakeLock != null && proximityWakeLock.isHeld()) { + if (proximityWakeLock != null && proximityWakeLock.isHeld()) { proximityWakeLock.release(); } } @@ -2072,14 +2112,7 @@ public void onAnimationEnd(Animator animation) { stopProgressTimer(); lastProgress = 0; isPaused = false; - if (!useFrontSpeaker && !SharedConfig.enabledRaiseTo(true)) { - ChatActivity chat = raiseChat; - stopRaiseToEarSensors(raiseChat, false, false); - raiseChat = chat; - } - if (proximityWakeLock != null && proximityWakeLock.isHeld() && !proximityTouched) { - proximityWakeLock.release(); - } + boolean playingNext = false; if (playingMessageObject != null) { if (downloadingCurrentMessage) { FileLoader.getInstance(playingMessageObject.currentAccount).cancelLoadFile(playingMessageObject.getDocument()); @@ -2108,10 +2141,10 @@ public void onAnimationEnd(Animator animation) { voiceMessagesPlaylistMap = null; } } - boolean next = false; if (voiceMessagesPlaylist != null && index < voiceMessagesPlaylist.size()) { MessageObject nextVoiceMessage = voiceMessagesPlaylist.get(index); playMessage(nextVoiceMessage); + playingNext = true; if (!nextVoiceMessage.isRoundVideo() && pipRoundVideoView != null) { pipRoundVideoView.close(true); pipRoundVideoView = null; @@ -2133,6 +2166,11 @@ public void onAnimationEnd(Animator animation) { ApplicationLoader.applicationContext.stopService(intent); } } + if (!playingNext && byVoiceEnd && !SharedConfig.enabledRaiseTo(true)) { + ChatActivity chat = raiseChat; + stopRaiseToEarSensors(raiseChat, false, false); + raiseChat = chat; + } } public boolean isGoingToShowMessageObject(MessageObject messageObject) { @@ -3483,9 +3521,7 @@ public boolean needUpdate() { startRaiseToEarSensors(raiseChat); } if (!ApplicationLoader.mainInterfacePaused && proximityWakeLock != null && !proximityWakeLock.isHeld() && (playingMessageObject.isVoice() || playingMessageObject.isRoundVideo()) && SharedConfig.enabledRaiseTo(false)) { - if (ignoreAccelerometerGestures()) { - proximityWakeLock.acquire(); - } +// proximityWakeLock.acquire(); } startProgressTimer(playingMessageObject); NotificationCenter.getInstance(messageObject.currentAccount).postNotificationName(NotificationCenter.messagePlayingDidStart, messageObject, oldMessageObject); @@ -3546,10 +3582,6 @@ public boolean needUpdate() { return true; } - - public static boolean ignoreAccelerometerGestures() { - return Build.MANUFACTURER.equalsIgnoreCase("samsung"); - } public void updateSilent(boolean value) { isSilent = value; @@ -4738,8 +4770,17 @@ public static void loadGalleryPhotosAlbums(final int guid) { Cursor cursor = null; try { - if (Build.VERSION.SDK_INT < 23 || ApplicationLoader.applicationContext.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { - cursor = MediaStore.Images.Media.query(ApplicationLoader.applicationContext.getContentResolver(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projectionPhotos, null, null, (Build.VERSION.SDK_INT > 28 ? MediaStore.Images.Media.DATE_MODIFIED : MediaStore.Images.Media.DATE_TAKEN) + " DESC"); + final Context context = ApplicationLoader.applicationContext; + if ( + Build.VERSION.SDK_INT < 23 || + Build.VERSION.SDK_INT < 33 && context.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED || + Build.VERSION.SDK_INT >= 33 && ( + context.checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED || + context.checkSelfPermission(Manifest.permission.READ_MEDIA_VIDEO) == PackageManager.PERMISSION_GRANTED || + context.checkSelfPermission(Manifest.permission.READ_MEDIA_AUDIO) == PackageManager.PERMISSION_GRANTED + ) + ) { + cursor = MediaStore.Images.Media.query(context.getContentResolver(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projectionPhotos, null, null, (Build.VERSION.SDK_INT > 28 ? MediaStore.Images.Media.DATE_MODIFIED : MediaStore.Images.Media.DATE_TAKEN) + " DESC"); if (cursor != null) { int imageIdColumn = cursor.getColumnIndex(MediaStore.Images.Media._ID); int bucketIdColumn = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_ID); @@ -4820,7 +4861,17 @@ public static void loadGalleryPhotosAlbums(final int guid) { } try { - if (Build.VERSION.SDK_INT < 23 || ApplicationLoader.applicationContext.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { + + final Context context = ApplicationLoader.applicationContext; + if ( + Build.VERSION.SDK_INT < 23 || + Build.VERSION.SDK_INT < 33 && context.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED || + Build.VERSION.SDK_INT >= 33 && ( + context.checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED || + context.checkSelfPermission(Manifest.permission.READ_MEDIA_VIDEO) == PackageManager.PERMISSION_GRANTED || + context.checkSelfPermission(Manifest.permission.READ_MEDIA_AUDIO) == PackageManager.PERMISSION_GRANTED + ) + ) { cursor = MediaStore.Images.Media.query(ApplicationLoader.applicationContext.getContentResolver(), MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projectionVideo, null, null, (Build.VERSION.SDK_INT > 28 ? MediaStore.Video.Media.DATE_MODIFIED : MediaStore.Video.Media.DATE_TAKEN) + " DESC"); if (cursor != null) { int imageIdColumn = cursor.getColumnIndex(MediaStore.Video.Media._ID); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java index 5b28b133101..c916729ae43 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java @@ -5330,7 +5330,7 @@ private static void removeEmptyMessages(ArrayList messages) { } } - public void loadReplyMessagesForMessages(ArrayList messages, long dialogId, boolean scheduled, int threadMessageId, Runnable callback) { + public void loadReplyMessagesForMessages(ArrayList messages, long dialogId, boolean scheduled, int threadMessageId, Runnable callback, int classGuid) { if (DialogObject.isEncryptedDialog(dialogId)) { ArrayList replyMessages = new ArrayList<>(); LongSparseArray> replyMessageRandomOwners = new LongSparseArray<>(); @@ -5542,7 +5542,7 @@ public void loadReplyMessagesForMessages(ArrayList messages, long AndroidUtilities.runOnUIThread(callback); } } - }); + }, classGuid); if (replyMessageOwners.isEmpty()) { requestsCount[0]--; if (requestsCount[0] == 0) { @@ -5617,7 +5617,7 @@ public void loadReplyMessagesForMessages(ArrayList messages, long TLRPC.TL_messages_getScheduledMessages req = new TLRPC.TL_messages_getScheduledMessages(); req.peer = getMessagesController().getInputPeer(dialogId); req.id = dialogReplyMessagesIds.valueAt(a); - getConnectionsManager().sendRequest(req, (response, error) -> { + int reqId = getConnectionsManager().sendRequest(req, (response, error) -> { if (error == null) { TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response; for (int i = 0; i < messagesRes.messages.size(); i++) { @@ -5679,11 +5679,14 @@ public void loadReplyMessagesForMessages(ArrayList messages, long } } }); + if (classGuid != 0) { + getConnectionsManager().bindRequestToGuid(reqId, classGuid); + } } else if (channelId != 0) { TLRPC.TL_channels_getMessages req = new TLRPC.TL_channels_getMessages(); req.channel = getMessagesController().getInputChannel(channelId); req.id = dialogReplyMessagesIds.valueAt(a); - getConnectionsManager().sendRequest(req, (response, error) -> { + int reqId = getConnectionsManager().sendRequest(req, (response, error) -> { if (error == null) { TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response; for (int i = 0; i < messagesRes.messages.size(); i++) { @@ -5705,10 +5708,13 @@ public void loadReplyMessagesForMessages(ArrayList messages, long } } }); + if (classGuid != 0) { + getConnectionsManager().bindRequestToGuid(reqId, classGuid); + } } else { TLRPC.TL_messages_getMessages req = new TLRPC.TL_messages_getMessages(); req.id = dialogReplyMessagesIds.valueAt(a); - getConnectionsManager().sendRequest(req, (response, error) -> { + int reqId = getConnectionsManager().sendRequest(req, (response, error) -> { if (error == null) { TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response; for (int i = 0; i < messagesRes.messages.size(); i++) { @@ -5729,6 +5735,9 @@ public void loadReplyMessagesForMessages(ArrayList messages, long } } }); + if (classGuid != 0) { + getConnectionsManager().bindRequestToGuid(reqId, classGuid); + } } } } else { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index 120700542cc..30c7df37668 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -4649,7 +4649,7 @@ public int getMediaType() { return FileLoader.MEDIA_DIR_CACHE; } - private static boolean containsUrls(CharSequence message) { + public static boolean containsUrls(CharSequence message) { if (message == null || message.length() < 2 || message.length() > 1024 * 20) { return false; } @@ -4835,10 +4835,12 @@ public void generateCaption() { } String text = messageOwner.message; ArrayList entities = messageOwner.entities; + boolean forceManualEntities = false; if (type == TYPE_STORY) { if (messageOwner.media != null && messageOwner.media.storyItem != null) { text = messageOwner.media.storyItem.caption; entities = messageOwner.media.storyItem.entities; + forceManualEntities = true; } else { text = ""; entities = new ArrayList<>(); @@ -4861,16 +4863,16 @@ public void generateCaption() { hasEntities = !entities.isEmpty(); } - boolean useManualParse = !hasEntities && ( - eventId != 0 || - getMedia(messageOwner) instanceof TLRPC.TL_messageMediaPhoto_old || - getMedia(messageOwner) instanceof TLRPC.TL_messageMediaPhoto_layer68 || - getMedia(messageOwner) instanceof TLRPC.TL_messageMediaPhoto_layer74 || - getMedia(messageOwner) instanceof TLRPC.TL_messageMediaDocument_old || - getMedia(messageOwner) instanceof TLRPC.TL_messageMediaDocument_layer68 || - getMedia(messageOwner) instanceof TLRPC.TL_messageMediaDocument_layer74 || - isOut() && messageOwner.send_state != MESSAGE_SEND_STATE_SENT || - messageOwner.id < 0 + boolean useManualParse = forceManualEntities || !hasEntities && ( + eventId != 0 || + getMedia(messageOwner) instanceof TLRPC.TL_messageMediaPhoto_old || + getMedia(messageOwner) instanceof TLRPC.TL_messageMediaPhoto_layer68 || + getMedia(messageOwner) instanceof TLRPC.TL_messageMediaPhoto_layer74 || + getMedia(messageOwner) instanceof TLRPC.TL_messageMediaDocument_old || + getMedia(messageOwner) instanceof TLRPC.TL_messageMediaDocument_layer68 || + getMedia(messageOwner) instanceof TLRPC.TL_messageMediaDocument_layer74 || + isOut() && messageOwner.send_state != MESSAGE_SEND_STATE_SENT || + messageOwner.id < 0 ); if (useManualParse) { @@ -7001,7 +7003,7 @@ public boolean isRoundVideo() { } public boolean shouldAnimateSending() { - return isSending() && (type == MessageObject.TYPE_ROUND_VIDEO || isVoice() || (isAnyKindOfSticker() && sendAnimationData != null) || (messageText != null && sendAnimationData != null)); + return wasJustSent && (type == MessageObject.TYPE_ROUND_VIDEO || isVoice() || (isAnyKindOfSticker() && sendAnimationData != null) || (messageText != null && sendAnimationData != null)); } public boolean hasAttachedStickers() { @@ -7589,7 +7591,7 @@ public void checkMediaExistance(boolean useFileDatabaseQueue) { if (type == TYPE_EXTENDED_MEDIA_PREVIEW) { TLRPC.TL_messageExtendedMediaPreview preview = (TLRPC.TL_messageExtendedMediaPreview) messageOwner.media.extended_media; if (preview.thumb != null) { - File file = FileLoader.getInstance(currentAccount).getPathToAttach(preview.thumb); + File file = FileLoader.getInstance(currentAccount).getPathToAttach(preview.thumb, useFileDatabaseQueue); if (!mediaExists) { mediaExists = file.exists() || preview.thumb instanceof TLRPC.TL_photoStrippedSize; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index e93769d90c8..77c56593680 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -27,6 +27,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Base64; +import android.util.Log; import android.util.Pair; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -72,7 +73,6 @@ import org.telegram.ui.PremiumPreviewFragment; import org.telegram.ui.ProfileActivity; import org.telegram.ui.Stories.StoriesController; -import org.telegram.ui.Stories.recorder.DualCameraView; import org.telegram.ui.TopicsFragment; import java.io.File; @@ -137,9 +137,13 @@ public class MessagesController extends BaseController implements NotificationCe private SparseArray chatlistFoldersUpdates = new SparseArray<>(); public int largeQueueMaxActiveOperations = 2; public int smallQueueMaxActiveOperations = 5; + public int stealthModeFuture; + public int stealthModePast; + public int stealthModeCooldown; public StoriesController storiesController; private boolean hasArchivedChats; private boolean hasStories; + public long storiesChangelogUserId; public static TLRPC.Peer getPeerFromInputPeer(TLRPC.InputPeer peer) { if (peer.chat_id != 0) { @@ -458,6 +462,7 @@ protected boolean useCache(Integer arguments) { public boolean collectDeviceStats; public boolean showFiltersTooltip; public String venueSearchBot; + public String storyVenueSearchBot; public String gifSearchBot; public String imageSearchBot; public String dcDomainName; @@ -504,7 +509,8 @@ protected boolean useCache(Integer arguments) { public int publicLinksLimitPremium; public int captionLengthLimitDefault; public int captionLengthLimitPremium; - public int storyCaptionLengthLimit; + public int storyCaptionLengthLimitDefault; + public int storyCaptionLengthLimitPremium; public int aboutLengthLimitDefault; public int aboutLengthLimitPremium; public int reactionsUserMaxDefault; @@ -518,6 +524,10 @@ protected boolean useCache(Integer arguments) { private int chatlistUpdatePeriod; public int storyExpiringLimitDefault; public int storyExpiringLimitPremium; + public int storiesSentWeeklyLimitDefault; + public int storiesSentWeeklyLimitPremium; + public int storiesSentMonthlyLimitDefault; + public int storiesSentMonthlyLimitPremium; public int uploadMaxFileParts; public int uploadMaxFilePartsPremium; @@ -552,6 +562,7 @@ protected boolean useCache(Integer arguments) { public int chatlistJoinedLimitDefault; public int chatlistJoinedLimitPremium; public String storiesPosting; + public String storiesEntities; public int checkResetLangpack; @@ -622,6 +633,7 @@ public void updatePremium(boolean premium) { getMessagesStorage().saveDialogFiltersOrder(); getNotificationCenter().postNotificationName(NotificationCenter.dialogFiltersUpdated); + getStoriesController().onPremiumChanged(); } public void lockFiltersInternal() { @@ -1285,6 +1297,7 @@ public MessagesController(int num) { promoPsaType = mainPreferences.getString("promo_psa_type", null); proxyDialogAddress = mainPreferences.getString("proxyDialogAddress", null); venueSearchBot = mainPreferences.getString("venueSearchBot", "foursquare"); + storyVenueSearchBot = mainPreferences.getString("storyVenueSearchBot", "foursquare"); gifSearchBot = mainPreferences.getString("gifSearchBot", "gif"); imageSearchBot = mainPreferences.getString("imageSearchBot", "pic"); blockedCountry = mainPreferences.getBoolean("blockedCountry", false); @@ -1327,7 +1340,8 @@ public MessagesController(int num) { publicLinksLimitPremium = mainPreferences.getInt("publicLinksLimitPremium", 20); captionLengthLimitDefault = mainPreferences.getInt("captionLengthLimitDefault", 1024); captionLengthLimitPremium = mainPreferences.getInt("captionLengthLimitPremium", 4096); - storyCaptionLengthLimit = mainPreferences.getInt("storyCaptionLengthLimit", 1024); + storyCaptionLengthLimitDefault = mainPreferences.getInt("storyCaptionLengthLimit", 200); + storyCaptionLengthLimitPremium = mainPreferences.getInt("storyCaptionLengthLimitPremium", 2048); aboutLengthLimitDefault = mainPreferences.getInt("aboutLengthLimitDefault", 70); aboutLengthLimitPremium = mainPreferences.getInt("aboutLengthLimitPremium", 140); reactionsUserMaxDefault = mainPreferences.getInt("reactionsUserMaxDefault", 1); @@ -1351,14 +1365,23 @@ public MessagesController(int num) { checkResetLangpack = mainPreferences.getInt("checkResetLangpack", 0); smallQueueMaxActiveOperations = mainPreferences.getInt("smallQueueMaxActiveOperations", 5); largeQueueMaxActiveOperations = mainPreferences.getInt("largeQueueMaxActiveOperations", 2); + stealthModeFuture = mainPreferences.getInt("stories_stealth_future_period", 25 * 60); + storiesChangelogUserId = mainPreferences.getLong("stories_changelog_user_id", 777000); + stealthModePast = mainPreferences.getInt("stories_stealth_past_period", 5 * 60); + stealthModeCooldown = mainPreferences.getInt("stories_stealth_cooldown_period", 60 * 60); boolean isTest = ConnectionsManager.native_isTestBackend(currentAccount) != 0; chatlistInvitesLimitDefault = mainPreferences.getInt("chatlistInvitesLimitDefault", 3); storyExpiringLimitDefault = mainPreferences.getInt("storyExpiringLimitDefault", 50); storyExpiringLimitPremium = mainPreferences.getInt("storyExpiringLimitPremium", 100); + storiesSentWeeklyLimitDefault = mainPreferences.getInt("storiesSentWeeklyLimitDefault", 7); + storiesSentWeeklyLimitPremium = mainPreferences.getInt("storiesSentWeeklyLimitPremium", 70); + storiesSentMonthlyLimitDefault = mainPreferences.getInt("storiesSentMonthlyLimitDefault", 30); + storiesSentMonthlyLimitPremium = mainPreferences.getInt("storiesSentMonthlyLimitPremium", 300); chatlistInvitesLimitPremium = mainPreferences.getInt("chatlistInvitesLimitPremium", isTest ? 5 : 20); chatlistJoinedLimitDefault = mainPreferences.getInt("chatlistJoinedLimitDefault", 2); chatlistJoinedLimitPremium = mainPreferences.getInt("chatlistJoinedLimitPremium", isTest ? 5 : 20); - storiesPosting = mainPreferences.getString("storiesPosting", "premium"); + storiesPosting = mainPreferences.getString("storiesPosting", "enabled"); + storiesEntities = mainPreferences.getString("storiesEntities", "premium"); storiesExportNopublicLink = mainPreferences.getBoolean("storiesExportNopublicLink", false); BuildVars.GOOGLE_AUTH_CLIENT_ID = mainPreferences.getString("googleAuthClientId", BuildVars.GOOGLE_AUTH_CLIENT_ID); if (mainPreferences.contains("dcDomainName2")) { @@ -1499,9 +1522,7 @@ public MessagesController(int num) { FileLog.e(e); } } - if (BuildVars.DEBUG_VERSION) { - AndroidUtilities.runOnUIThread(this::loadAppConfig, 2000); - } + AndroidUtilities.runOnUIThread(this::loadAppConfig, 2000); topicsController = new TopicsController(num); cacheByChatsController = new CacheByChatsController(num); @@ -2131,6 +2152,34 @@ private void applyAppConfig(TLRPC.TL_jsonObject object) { for (int a = 0, N = object.value.size(); a < N; a++) { TLRPC.TL_jsonObjectValue value = object.value.get(a); switch (value.key) { + case "stories_changelog_user_id": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + storiesChangelogUserId = (long) ((TLRPC.TL_jsonNumber) value.value).value; + editor.putLong("stories_changelog_user_id", storiesChangelogUserId); + } + break; + } + case "stories_stealth_future_period": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + stealthModeFuture = (int) ((TLRPC.TL_jsonNumber) value.value).value; + editor.putInt("stories_stealth_future_period", stealthModeFuture); + } + break; + } + case "stories_stealth_past_period": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + stealthModePast = (int) ((TLRPC.TL_jsonNumber) value.value).value; + editor.putInt("stories_stealth_past_period", stealthModePast); + } + break; + } + case "stories_stealth_cooldown_period": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + stealthModeCooldown = (int) ((TLRPC.TL_jsonNumber) value.value).value; + editor.putInt("stories_stealth_cooldown_period", stealthModeCooldown); + } + break; + } case "large_queue_max_active_operations_count": { if (value.value instanceof TLRPC.TL_jsonNumber) { largeQueueMaxActiveOperations = (int) ((TLRPC.TL_jsonNumber) value.value).value; @@ -2982,12 +3031,23 @@ private void applyAppConfig(TLRPC.TL_jsonObject object) { } break; } - case "story_caption_length_limit": { + case "story_caption_length_limit_default": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber number = (TLRPC.TL_jsonNumber) value.value; + if (number.value != storyCaptionLengthLimitDefault) { + storyCaptionLengthLimitDefault = (int) number.value; + editor.putInt("storyCaptionLengthLimit", storyCaptionLengthLimitDefault); + changed = true; + } + } + break; + } + case "story_caption_length_limit_premium": { if (value.value instanceof TLRPC.TL_jsonNumber) { TLRPC.TL_jsonNumber number = (TLRPC.TL_jsonNumber) value.value; - if (number.value != storyCaptionLengthLimit) { - storyCaptionLengthLimit = (int) number.value; - editor.putInt("storyCaptionLengthLimit", storyCaptionLengthLimit); + if (number.value != storyCaptionLengthLimitPremium) { + storyCaptionLengthLimitPremium = (int) number.value; + editor.putInt("storyCaptionLengthLimitPremium", storyCaptionLengthLimitPremium); changed = true; } } @@ -3174,6 +3234,50 @@ private void applyAppConfig(TLRPC.TL_jsonObject object) { } break; } + case "stories_sent_weekly_limit_default": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != storiesSentWeeklyLimitDefault) { + storiesSentWeeklyLimitDefault = (int) num.value; + editor.putInt("storiesSentWeeklyLimitDefault", storiesSentWeeklyLimitDefault); + changed = true; + } + } + break; + } + case "stories_sent_weekly_limit_premium": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != storiesSentWeeklyLimitPremium) { + storiesSentWeeklyLimitPremium = (int) num.value; + editor.putInt("storiesSentWeeklyLimitPremium", storiesSentWeeklyLimitPremium); + changed = true; + } + } + break; + } + case "stories_sent_monthly_limit_default": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != storiesSentMonthlyLimitDefault) { + storiesSentMonthlyLimitDefault = (int) num.value; + editor.putInt("storiesSentMonthlyLimitDefault", storiesSentMonthlyLimitDefault); + changed = true; + } + } + break; + } + case "stories_sent_monthly_limit_premium": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; + if (num.value != storiesSentMonthlyLimitPremium) { + storiesSentMonthlyLimitPremium = (int) num.value; + editor.putInt("storiesSentMonthlyLimitPremium", storiesSentMonthlyLimitPremium); + changed = true; + } + } + break; + } case "chatlist_invites_limit_premium": { if (value.value instanceof TLRPC.TL_jsonNumber) { TLRPC.TL_jsonNumber num = (TLRPC.TL_jsonNumber) value.value; @@ -3209,14 +3313,24 @@ private void applyAppConfig(TLRPC.TL_jsonObject object) { } case "stories_posting": { if (value.value instanceof TLRPC.TL_jsonString) { - TLRPC.TL_jsonString bool = (TLRPC.TL_jsonString) value.value; - if (!TextUtils.equals(bool.value, storiesPosting)) { - storiesPosting = bool.value; + TLRPC.TL_jsonString str = (TLRPC.TL_jsonString) value.value; + if (!TextUtils.equals(str.value, storiesPosting)) { + storiesPosting = str.value; editor.putString("storiesPosting", storiesPosting); changed = storiesChanged = true; } } } + case "stories_entities": { + if (value.value instanceof TLRPC.TL_jsonString) { + TLRPC.TL_jsonString str = (TLRPC.TL_jsonString) value.value; + if (!TextUtils.equals(str.value, storiesEntities)) { + storiesEntities = str.value; + editor.putString("storiesEntities", storiesEntities); + changed = true; + } + } + } case "stories_export_nopublic_link": { if (value.value instanceof TLRPC.TL_jsonBool) { TLRPC.TL_jsonBool bool = (TLRPC.TL_jsonBool) value.value; @@ -3227,6 +3341,16 @@ private void applyAppConfig(TLRPC.TL_jsonObject object) { } } } + case "stories_venue_search_username": { + if (value.value instanceof TLRPC.TL_jsonString) { + TLRPC.TL_jsonString str = (TLRPC.TL_jsonString) value.value; + if (!TextUtils.equals(storyVenueSearchBot, str.value)) { + storyVenueSearchBot = str.value; + editor.putString("storyVenueSearchBot", storyVenueSearchBot); + changed = true; + } + } + } } } if (changed) { @@ -3256,6 +3380,7 @@ private void resetAppConfig() { private boolean savePremiumFeaturesPreviewOrder(SharedPreferences.Editor editor, ArrayList value) { StringBuilder stringBuilder = new StringBuilder(); + StringBuilder storiesBuilder = new StringBuilder(); premiumFeaturesTypesToPosition.clear(); for (int i = 0; i < value.size(); i++) { String s = null; @@ -3970,6 +4095,8 @@ public void didReceivedNotification(int id, int account, Object... args) { } } } + } else if (id == NotificationCenter.currentUserPremiumStatusChanged) { + loadAppConfig(false); } } @@ -5729,7 +5856,7 @@ public void setUserAdminRole(long chatId, TLRPC.User user, TLRPC.TL_chatAdminRig } } }; - if ((!user.bot || !ChatObject.isChannelAndNotMegaGroup(chat)) && addingNew) { + if (!user.bot && addingNew) { addUserToChat(chatId, user, 0, botHash, parentFragment, true, () -> getConnectionsManager().sendRequest(req, requestDelegate), onError); } else { getConnectionsManager().sendRequest(req, requestDelegate); @@ -6896,10 +7023,10 @@ public void saveRecentSticker(Object parentObject, TLRPC.Document document, bool } public void loadChannelParticipants(Long chatId) { - loadChannelParticipants(chatId, null); + loadChannelParticipants(chatId, null, 32); } - public void loadChannelParticipants(Long chatId, Utilities.Callback whenDone) { + public void loadChannelParticipants(Long chatId, Utilities.Callback whenDone, int count) { if (whenDone == null && (loadingFullParticipants.contains(chatId) || loadedFullParticipants.contains(chatId))) { return; } @@ -6909,7 +7036,7 @@ public void loadChannelParticipants(Long chatId, Utilities.Callback AndroidUtilities.runOnUIThread(() -> { if (error == null) { TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; @@ -8011,6 +8138,7 @@ private void loadMessagesInternal(long dialogId, long mergeDialogId, boolean loa } req.limit = count; req.offset_id = max_id; + long time = System.currentTimeMillis(); int reqId = getConnectionsManager().sendRequest(req, (response, error) -> { if (response != null) { TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; @@ -8415,7 +8543,7 @@ public void processLoadedMessages(TLRPC.messages_Messages messagesRes, int resCo } else { getNotificationCenter().postNotificationName(NotificationCenter.messagesDidLoad, dialogId, count, objects, isCache, finalFirst_unread_final, last_message_id, unread_count, last_date, load_type, isEnd, classGuid, loadIndex, max_id, mentionsCount, mode); } - }); + }, classGuid); } else { getNotificationCenter().postNotificationName(NotificationCenter.messagesDidLoad, dialogId, count, objects, isCache, first_unread_final, last_message_id, unread_count, last_date, load_type, isEnd, classGuid, loadIndex, max_id, mentionsCount, mode); } @@ -12227,17 +12355,21 @@ public void startShortPoll(TLRPC.Chat chat, int guid, boolean stop, Consumer { + needPollConsumer.accept(true); + }); + } getChannelDifference(chat.id, 3, 0, null); + } else { + if (needPollConsumer != null) { + AndroidUtilities.runOnUIThread(() -> { + needPollConsumer.accept(false); + }); + } } - boolean finalNeedGetDifference = needGetDifference; - if (needPollConsumer != null) { - AndroidUtilities.runOnUIThread(() -> { - needPollConsumer.accept(finalNeedGetDifference); - }); - } + if (chat.megagroup) { if (onlineGuids == null) { onlineGuids = new ArrayList<>(); @@ -12750,7 +12882,7 @@ public void getDifference(int pts, int date, int qts, boolean slice) { updateInterfaceWithMessages(dialogId, arr, false); getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); }); - }); + }, 0); } }); @@ -14723,6 +14855,7 @@ public boolean processUpdateArray(ArrayList updates, ArrayList updates, ArrayList(); + } + updatesOnMainThread.add(baseUpdate); } else if (baseUpdate instanceof TLRPC.TL_updateDialogPinned) { if (updatesOnMainThread == null) { updatesOnMainThread = new ArrayList<>(); @@ -14912,7 +15050,7 @@ public boolean processUpdateArray(ArrayList updates, ArrayList(); } updatesOnMainThread.add(baseUpdate); - } else if (baseUpdate instanceof TLRPC.TL_updateChat) { + } else if (baseUpdate instanceof TLRPC.TL_updateChat || baseUpdate instanceof TLRPC.TL_updateSentStoryReaction) { if (updatesOnMainThread == null) { updatesOnMainThread = new ArrayList<>(); } @@ -15799,6 +15937,9 @@ public boolean processUpdateArray(ArrayList updates, ArrayList updates, ArrayList updates, ArrayList openDatabase(1)); } @@ -671,7 +672,7 @@ public static void createTables(SQLiteDatabase database) throws SQLiteException database.executeFast("CREATE TABLE emoji_groups(type INTEGER PRIMARY KEY, data BLOB)").stepThis().dispose(); database.executeFast("CREATE TABLE app_config(data BLOB)").stepThis().dispose(); - database.executeFast("CREATE TABLE stories (dialog_id INTEGER, story_id INTEGER, data BLOB, local_path TEXT, local_thumb_path TEXT, PRIMARY KEY (dialog_id, story_id));").stepThis().dispose(); + database.executeFast("CREATE TABLE stories (dialog_id INTEGER, story_id INTEGER, data BLOB, local_path TEXT, local_thumb_path TEXT, custom_params BLOB, PRIMARY KEY (dialog_id, story_id));").stepThis().dispose(); database.executeFast("CREATE TABLE stories_counter (dialog_id INTEGER PRIMARY KEY, count INTEGER, max_read INTEGER);").stepThis().dispose(); database.executeFast("CREATE TABLE profile_stories (dialog_id INTEGER, story_id INTEGER, data BLOB, PRIMARY KEY(dialog_id, story_id));").stepThis().dispose(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java index 0211c54e9cd..e297dc3bcd6 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -110,6 +110,7 @@ public class NotificationCenter { public static final int paymentFinished = totalEvents++; public static final int channelRightsUpdated = totalEvents++; public static final int openArticle = totalEvents++; + public static final int articleClosed = totalEvents++; public static final int updateMentionsCount = totalEvents++; public static final int didUpdatePollResults = totalEvents++; public static final int chatOnlineCountDidLoad = totalEvents++; @@ -211,6 +212,8 @@ public class NotificationCenter { public static final int didUpdatePremiumGiftStickers = totalEvents++; public static final int didUpdatePremiumGiftFieldIcon = totalEvents++; public static final int storiesEnabledUpdate = totalEvents++; + public static final int storiesBlocklistUpdate = totalEvents++; + public static final int storiesLimitUpdate = totalEvents++; //global public static final int pushMessagesUpdated = totalEvents++; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/PushListenerController.java b/TMessagesProj/src/main/java/org/telegram/messenger/PushListenerController.java index f8250d34ea8..56d685a260f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/PushListenerController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/PushListenerController.java @@ -868,7 +868,7 @@ public static void processRemoteMessage(@PushType int pushType, String data, lon break; } case "CHAT_DELETE_MEMBER": { - messageText = LocaleController.formatString("NotificationGroupKickMember", R.string.NotificationGroupKickMember, args[0], args[1]); + messageText = LocaleController.formatString("NotificationGroupKickMember", R.string.NotificationGroupKickMember, args[0], args[1], args.length <= 2 ? "" : args[2]); break; } case "CHAT_DELETE_YOU": { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java index 3e73d297f66..ab1535634c5 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java @@ -231,11 +231,13 @@ private static boolean isWhitelisted(MediaCodecInfo codecInfo) { public static boolean searchMessagesAsListUsed; public static boolean stickersReorderingHintUsed; public static int dayNightWallpaperSwitchHint; + public static boolean storyReactionsLongPressHint; public static boolean disableVoiceAudioEffects; public static boolean forceDisableTabletMode; public static boolean updateStickersOrderOnSend = true; public static boolean bigCameraForRound; public static boolean useSurfaceInStories; + public static int stealthModeSendMessageConfirm = 2; private static int lastLocalId = -210000; public static String storageCacheDir; @@ -591,6 +593,7 @@ public static void loadConfig() { searchMessagesAsListHintShows = preferences.getInt("searchMessagesAsListHintShows", 0); searchMessagesAsListUsed = preferences.getBoolean("searchMessagesAsListUsed", false); stickersReorderingHintUsed = preferences.getBoolean("stickersReorderingHintUsed", false); + storyReactionsLongPressHint = preferences.getBoolean("storyReactionsLongPressHint", false); textSelectionHintShows = preferences.getInt("textSelectionHintShows", 0); scheduledOrNoSoundHintShows = preferences.getInt("scheduledOrNoSoundHintShows", 0); forwardingOptionsHintShown = preferences.getBoolean("forwardingOptionsHintShown", false); @@ -601,6 +604,7 @@ public static void loadConfig() { messageSeenHintCount = preferences.getInt("messageSeenCount", 3); emojiInteractionsHintCount = preferences.getInt("emojiInteractionsHintCount", 3); dayNightThemeSwitchHintCount = preferences.getInt("dayNightThemeSwitchHintCount", 3); + stealthModeSendMessageConfirm = preferences.getInt("stealthModeSendMessageConfirm", 2); mediaColumnsCount = preferences.getInt("mediaColumnsCount", 3); storiesColumnsCount = preferences.getInt("storiesColumnsCount", 3); fastScrollHintCount = preferences.getInt("fastScrollHintCount", 3); @@ -797,6 +801,7 @@ public static void clearConfig() { messageSeenHintCount = 3; emojiInteractionsHintCount = 3; dayNightThemeSwitchHintCount = 3; + stealthModeSendMessageConfirm = 2; dayNightWallpaperSwitchHint = 0; saveConfig(); } @@ -825,6 +830,14 @@ public static void setStickersReorderingHintUsed(boolean value) { editor.apply(); } + public static void setStoriesReactionsLongPressHintUsed(boolean value) { + storyReactionsLongPressHint = value; + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("storyReactionsLongPressHint", storyReactionsLongPressHint); + editor.apply(); + } + public static void increaseTextSelectionHintShowed() { SharedPreferences preferences = MessagesController.getGlobalMainSettings(); SharedPreferences.Editor editor = preferences.edit(); @@ -1423,6 +1436,12 @@ public static void updateDayNightThemeSwitchHintCount(int count) { preferences.edit().putInt("dayNightThemeSwitchHintCount", dayNightThemeSwitchHintCount).apply(); } + public static void updateStealthModeSendMessageConfirm(int count) { + stealthModeSendMessageConfirm = count; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + preferences.edit().putInt("stealthModeSendMessageConfirm", stealthModeSendMessageConfirm).apply(); + } + public final static int PERFORMANCE_CLASS_LOW = 0; public final static int PERFORMANCE_CLASS_AVERAGE = 1; public final static int PERFORMANCE_CLASS_HIGH = 2; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TranslateController.java b/TMessagesProj/src/main/java/org/telegram/messenger/TranslateController.java index 04548a583c8..8b4f0b8aa21 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TranslateController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TranslateController.java @@ -1016,4 +1016,255 @@ private void saveTranslatingDialogsCache() { private void resetTranslatingDialogsCache() { MessagesController.getMainSettings(currentAccount).edit().remove("translating_dialog_languages2").remove("hidden_translation_at").apply(); } + + private final HashSet detectingStories = new HashSet<>(); + private final HashSet translatingStories = new HashSet<>(); + + // ensure dialogId in storyItem is valid + public void detectStoryLanguage(TLRPC.StoryItem storyItem) { + if (storyItem == null || storyItem.detectedLng != null || storyItem.caption == null || storyItem.caption.length() == 0 || !LanguageDetector.hasSupport()) { + return; + } + + final StoryKey key = new StoryKey(storyItem); + if (detectingStories.contains(key)) { + return; + } + detectingStories.add(key); + + LanguageDetector.detectLanguage(storyItem.caption, lng -> AndroidUtilities.runOnUIThread(() -> { + storyItem.detectedLng = lng; + getMessagesController().getStoriesController().getStoriesStorage().putStoryInternal(storyItem.dialogId, storyItem); + detectingStories.remove(key); + }), err -> AndroidUtilities.runOnUIThread(() -> { + storyItem.detectedLng = UNKNOWN_LANGUAGE; + getMessagesController().getStoriesController().getStoriesStorage().putStoryInternal(storyItem.dialogId, storyItem); + detectingStories.remove(key); + })); + } + + public boolean canTranslateStory(TLRPC.StoryItem storyItem) { + return storyItem != null && !TextUtils.isEmpty(storyItem.caption) && !Emoji.fullyConsistsOfEmojis(storyItem.caption) && ( + storyItem.detectedLng == null && storyItem.translatedText != null && TextUtils.equals(storyItem.translatedLng, TranslateAlert2.getToLanguage()) || + storyItem.detectedLng != null && !RestrictedLanguagesSelectActivity.getRestrictedLanguages().contains(storyItem.detectedLng) + ); + } + + public void translateStory(TLRPC.StoryItem storyItem, Runnable done) { + if (storyItem == null) { + return; + } + + final StoryKey key = new StoryKey(storyItem); + + String toLang = TranslateAlert2.getToLanguage(); + + if (storyItem.translatedText != null && TextUtils.equals(storyItem.translatedLng, toLang)) { + if (done != null) { + done.run(); + } + return; + } + if (translatingStories.contains(key)) { + if (done != null) { + done.run(); + } + return; + } + + translatingStories.add(key); + + TLRPC.TL_messages_translateText req = new TLRPC.TL_messages_translateText(); + req.flags |= 2; + final TLRPC.TL_textWithEntities text = new TLRPC.TL_textWithEntities(); + text.text = storyItem.caption; + text.entities = storyItem.entities; + req.text.add(text); + req.to_lang = toLang; + getConnectionsManager().sendRequest(req, (res, err) -> { + if (res instanceof TLRPC.TL_messages_translateResult) { + ArrayList result = ((TLRPC.TL_messages_translateResult) res).result; + if (result.size() <= 0) { + AndroidUtilities.runOnUIThread(() -> { + storyItem.translatedLng = toLang; + storyItem.translatedText = null; + getMessagesController().getStoriesController().getStoriesStorage().putStoryInternal(storyItem.dialogId, storyItem); + translatingStories.remove(key); + if (done != null) { + done.run(); + } + }); + return; + } + final TLRPC.TL_textWithEntities textWithEntities = result.get(0); + AndroidUtilities.runOnUIThread(() -> { + storyItem.translatedLng = toLang; + storyItem.translatedText = TranslateAlert2.preprocess(text, textWithEntities); + getMessagesController().getStoriesController().getStoriesStorage().putStoryInternal(storyItem.dialogId, storyItem); + translatingStories.remove(key); + if (done != null) { + done.run(); + } + }); + } else { + AndroidUtilities.runOnUIThread(() -> { + storyItem.translatedLng = toLang; + storyItem.translatedText = null; + getMessagesController().getStoriesController().getStoriesStorage().putStoryInternal(storyItem.dialogId, storyItem); + translatingStories.remove(key); + if (done != null) { + done.run(); + } + }); + } + }); + } + + public boolean isTranslatingStory(TLRPC.StoryItem storyItem) { + if (storyItem == null) { + return false; + } + return translatingStories.contains(new StoryKey(storyItem)); + } + + private static class StoryKey { + public long dialogId; + public int storyId; + + public StoryKey(TLRPC.StoryItem storyItem) { + dialogId = storyItem.dialogId; + storyId = storyItem.id; + } + } + + private final HashSet detectingPhotos = new HashSet<>(); + private final HashSet translatingPhotos = new HashSet<>(); + + public void detectPhotoLanguage(MessageObject messageObject, Utilities.Callback done) { + if (messageObject == null || messageObject.messageOwner == null || !LanguageDetector.hasSupport() || TextUtils.isEmpty(messageObject.messageOwner.message)) { + return; + } + if (!TextUtils.isEmpty(messageObject.messageOwner.originalLanguage)) { + if (done != null) { + done.run(messageObject.messageOwner.originalLanguage); + } + return; + } + + MessageKey key = new MessageKey(messageObject); + if (detectingPhotos.contains(key)) { + return; + } + detectingPhotos.add(key); + + LanguageDetector.detectLanguage(messageObject.messageOwner.message, lng -> AndroidUtilities.runOnUIThread(() -> { + messageObject.messageOwner.originalLanguage = lng; + getMessagesStorage().updateMessageCustomParams(key.dialogId, messageObject.messageOwner); + detectingPhotos.remove(key); + if (done != null) { + done.run(lng); + } + }), err -> AndroidUtilities.runOnUIThread(() -> { + messageObject.messageOwner.originalLanguage = UNKNOWN_LANGUAGE; + getMessagesStorage().updateMessageCustomParams(key.dialogId, messageObject.messageOwner); + detectingPhotos.remove(key); + if (done != null) { + done.run(UNKNOWN_LANGUAGE); + } + })); + } + + public boolean canTranslatePhoto(MessageObject messageObject, String detectedLanguage) { + if (messageObject != null && messageObject.messageOwner != null && messageObject.messageOwner.originalLanguage != null) { + detectedLanguage = messageObject.messageOwner.originalLanguage; + } + return messageObject != null && messageObject.messageOwner != null && !TextUtils.isEmpty(messageObject.messageOwner.message) && ( + detectedLanguage == null && messageObject.messageOwner.translatedText != null && TextUtils.equals(messageObject.messageOwner.translatedToLanguage, TranslateAlert2.getToLanguage()) || + detectedLanguage != null && !RestrictedLanguagesSelectActivity.getRestrictedLanguages().contains(messageObject.messageOwner.originalLanguage) + ) && !messageObject.translated; + } + + public void translatePhoto(MessageObject messageObject, Runnable done) { + if (messageObject == null || messageObject.messageOwner == null) { + return; + } + + final MessageKey key = new MessageKey(messageObject); + + String toLang = TranslateAlert2.getToLanguage(); + + if (messageObject.messageOwner.translatedText != null && TextUtils.equals(messageObject.messageOwner.translatedToLanguage, toLang)) { + if (done != null) { + done.run(); + } + return; + } + if (translatingPhotos.contains(key)) { + if (done != null) { + done.run(); + } + return; + } + + translatingPhotos.add(key); + + TLRPC.TL_messages_translateText req = new TLRPC.TL_messages_translateText(); + req.flags |= 2; + final TLRPC.TL_textWithEntities text = new TLRPC.TL_textWithEntities(); + text.text = messageObject.messageOwner.message; + text.entities = messageObject.messageOwner.entities; + if (text.entities == null) { + text.entities = new ArrayList<>(); + } + req.text.add(text); + req.to_lang = toLang; + final long start = System.currentTimeMillis(); + getConnectionsManager().sendRequest(req, (res, err) -> { + if (res instanceof TLRPC.TL_messages_translateResult) { + ArrayList result = ((TLRPC.TL_messages_translateResult) res).result; + if (result.size() <= 0) { + AndroidUtilities.runOnUIThread(() -> { + messageObject.messageOwner.translatedToLanguage = toLang; + messageObject.messageOwner.translatedText = null; + getMessagesStorage().updateMessageCustomParams(key.dialogId, messageObject.messageOwner); + translatingPhotos.remove(key); + if (done != null) { + AndroidUtilities.runOnUIThread(done, Math.max(0, 400L - (System.currentTimeMillis() - start))); + } + }); + return; + } + final TLRPC.TL_textWithEntities textWithEntities = result.get(0); + AndroidUtilities.runOnUIThread(() -> { + messageObject.messageOwner.translatedToLanguage = toLang; + messageObject.messageOwner.translatedText = TranslateAlert2.preprocess(text, textWithEntities); + getMessagesStorage().updateMessageCustomParams(key.dialogId, messageObject.messageOwner); + translatingPhotos.remove(key); + if (done != null) { + AndroidUtilities.runOnUIThread(done, Math.max(0, 400L - (System.currentTimeMillis() - start))); + } + }); + } else { + AndroidUtilities.runOnUIThread(() -> { + messageObject.messageOwner.translatedToLanguage = toLang; + messageObject.messageOwner.translatedText = null; + getMessagesStorage().updateMessageCustomParams(key.dialogId, messageObject.messageOwner); + translatingPhotos.remove(key); + if (done != null) { + AndroidUtilities.runOnUIThread(done, Math.max(0, 400L - (System.currentTimeMillis() - start))); + } + }); + } + }); + } + + private static class MessageKey { + public long dialogId; + public int id; + + public MessageKey(MessageObject msg) { + dialogId = msg.getDialogId(); + id = msg.getId(); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java index 8f7838a846c..0eb03d41f07 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java @@ -107,6 +107,7 @@ public static class MediaEntity { public static final int TYPE_STICKER = 0; public static final int TYPE_TEXT = 1; public static final int TYPE_PHOTO = 2; + public static final int TYPE_LOCATION = 3; public byte type; public byte subType; @@ -115,6 +116,7 @@ public static class MediaEntity { public float rotation; public float width; public float height; + public float additionalWidth, additionalHeight; public String text; public ArrayList entities = new ArrayList<>(); public int color; @@ -146,6 +148,12 @@ public static class MediaEntity { public AnimatedFileDrawable animatedFileDrawable; public Canvas roundRadiusCanvas; + public TLRPC.MediaArea mediaArea; + public TLRPC.MessageMedia mediaGeo; + public float density; + + public int W, H; + public MediaEntity() { } @@ -185,6 +193,20 @@ public MediaEntity(AbstractSerializedData data, boolean full) { document = TLRPC.Document.TLdeserialize(data, magic, false); } } + if (type == TYPE_LOCATION) { + density = data.readFloat(false); + mediaArea = TLRPC.MediaArea.TLdeserialize(data, data.readInt32(false), false); + mediaGeo = TLRPC.MessageMedia.TLdeserialize(data, data.readInt32(false), false); + if (data.remaining() > 0) { + int magic = data.readInt32(false); + if (magic == 0xdeadbeef) { + String emoji = data.readString(false); + if (mediaGeo instanceof TLRPC.TL_messageMediaVenue) { + ((TLRPC.TL_messageMediaVenue) mediaGeo).emoji = emoji; + } + } + } + } } public void serializeTo(AbstractSerializedData data, boolean full) { @@ -218,6 +240,26 @@ public void serializeTo(AbstractSerializedData data, boolean full) { document.serializeToStream(data); } } + if (type == TYPE_LOCATION) { + data.writeFloat(density); + mediaArea.serializeToStream(data); + if (mediaGeo.provider == null) { + mediaGeo.provider = ""; + } + if (mediaGeo.venue_id == null) { + mediaGeo.venue_id = ""; + } + if (mediaGeo.venue_type == null) { + mediaGeo.venue_type = ""; + } + mediaGeo.serializeToStream(data); + if (mediaGeo instanceof TLRPC.TL_messageMediaVenue && ((TLRPC.TL_messageMediaVenue) mediaGeo).emoji != null) { + data.writeInt32(0xdeadbeef); + data.writeString(((TLRPC.TL_messageMediaVenue) mediaGeo).emoji); + } else { + data.writeInt32(TLRPC.TL_null.constructor); + } + } } public MediaEntity copy() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java b/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java index 5db3620d51f..4c91e75553e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java @@ -254,7 +254,7 @@ public static void openUrl(final Context context, Uri uri, final boolean allowCu if (tryTelegraph) { try { String host = AndroidUtilities.getHostAuthority(uri); - if (isTelegraphUrl(host, true) || uri.toString().toLowerCase().contains("telegram.org/faq") || uri.toString().toLowerCase().contains("telegram.org/privacy")) { + if (isTelegraphUrl(host, true) || "telegram.org".equalsIgnoreCase(host) && (uri.toString().toLowerCase().contains("telegram.org/faq") || uri.toString().toLowerCase().contains("telegram.org/privacy") || uri.toString().toLowerCase().contains("telegram.org/blog"))) { final AlertDialog[] progressDialog = new AlertDialog[] { new AlertDialog(context, AlertDialog.ALERT_TYPE_SPINNER) }; @@ -515,6 +515,8 @@ public static boolean isInternalUri(Uri uri, boolean all, boolean[] forceBrowser } return true; } + } else if ("telegram.org".equals(host) && uri != null && uri.getPath() != null && uri.getPath().startsWith("/blog/")) { + return true; } else if (all) { if (host.endsWith("telegram.org") || host.endsWith("telegra.ph") || host.endsWith("telesco.pe")) { return true; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java index 224baaac423..f9621437267 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java @@ -57,12 +57,14 @@ import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.messenger.VideoEditedInfo; +import org.telegram.tgnet.TLRPC; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.EditTextEffects; import org.telegram.ui.Components.FilterShaders; import org.telegram.ui.Components.Paint.Views.EditTextOutline; +import org.telegram.ui.Components.Paint.Views.LocationMarker; import org.telegram.ui.Components.Paint.Views.PaintTextOptionsView; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.Rect; @@ -556,10 +558,13 @@ public void drawFrame(SurfaceTexture st) { private void drawEntity(VideoEditedInfo.MediaEntity entity, int textColor) { if (entity.ptr != 0) { - RLottieDrawable.getFrame(entity.ptr, (int) entity.currentFrame, stickerBitmap, 512, 512, stickerBitmap.getRowBytes(), true); - applyRoundRadius(entity, stickerBitmap, (entity.subType & 8) != 0 ? textColor : 0); + if (entity.bitmap == null || entity.W <= 0 || entity.H <= 0) { + return; + } + RLottieDrawable.getFrame(entity.ptr, (int) entity.currentFrame, entity.bitmap, entity.W, entity.H, entity.bitmap.getRowBytes(), true); + applyRoundRadius(entity, entity.bitmap, (entity.subType & 8) != 0 ? textColor : 0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); - GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, stickerBitmap, 0); + GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, entity.bitmap, 0); entity.currentFrame += entity.framesPerDraw; if (entity.currentFrame >= entity.metadata[0]) { entity.currentFrame = 0; @@ -594,7 +599,7 @@ private void drawEntity(VideoEditedInfo.MediaEntity entity, int textColor) { if (entity.bitmap != null) { GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, entity.bitmap, 0); - drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, entity.type == VideoEditedInfo.MediaEntity.TYPE_PHOTO && (entity.subType & 2) != 0); + drawTexture(false, stickerTexture[0], entity.x - entity.additionalWidth / 2f, entity.y - entity.additionalHeight / 2f, entity.width + entity.additionalWidth, entity.height + entity.additionalHeight, entity.rotation, entity.type == VideoEditedInfo.MediaEntity.TYPE_PHOTO && (entity.subType & 2) != 0); } if (entity.entities != null && !entity.entities.isEmpty()) { for (int i = 0; i < entity.entities.size(); ++i) { @@ -899,6 +904,7 @@ public void surfaceCreated() { initStickerEntity(entity); } else if (entity.type == VideoEditedInfo.MediaEntity.TYPE_TEXT) { EditTextOutline editText = new EditTextOutline(ApplicationLoader.applicationContext); + editText.getPaint().setAntiAlias(true); editText.betterFraming = useMatrixForImagePath; editText.drawAnimatedEmojiDrawables = false; editText.setBackgroundColor(Color.TRANSPARENT); @@ -916,7 +922,6 @@ public void surfaceCreated() { e.entity = new VideoEditedInfo.MediaEntity(); e.entity.text = e.documentAbsolutePath; e.entity.subType = e.subType; - initStickerEntity(e.entity); AnimatedEmojiSpan span = new AnimatedEmojiSpan(0L, 1f, editText.getPaint().getFontMetricsInt()) { @Override public void draw(@NonNull Canvas canvas, CharSequence charSequence, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) { @@ -940,6 +945,9 @@ public void draw(@NonNull Canvas canvas, CharSequence charSequence, int start, i e.entity.x = tcx - e.entity.width / 2f; e.entity.y = tcy - e.entity.height / 2f; e.entity.rotation = entity.rotation; + + if (e.entity.bitmap == null) + initStickerEntity(e.entity); } }; text.setSpan(span, e.offset, e.offset + e.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); @@ -1013,6 +1021,57 @@ public void draw(@NonNull Canvas canvas, CharSequence charSequence, int start, i entity.bitmap = Bitmap.createBitmap(entity.viewWidth, entity.viewHeight, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(entity.bitmap); editText.draw(canvas); + } else if (entity.type == VideoEditedInfo.MediaEntity.TYPE_LOCATION) { + LocationMarker marker = new LocationMarker(ApplicationLoader.applicationContext, entity.density); + marker.setText(entity.text); + marker.setType(entity.subType, entity.color); + marker.setMaxWidth(entity.viewWidth); + if (entity.entities.size() == 1) { + marker.forceEmoji(); + } + marker.measure(View.MeasureSpec.makeMeasureSpec(entity.viewWidth, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(entity.viewHeight, View.MeasureSpec.EXACTLY)); + marker.layout(0, 0, entity.viewWidth, entity.viewHeight); + float scale = entity.width * transformedWidth / entity.viewWidth; + int w = (int) (entity.viewWidth * scale), h = (int) (entity.viewHeight * scale), pad = 8; + entity.bitmap = Bitmap.createBitmap(w + pad + pad, h + pad + pad, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(entity.bitmap); + canvas.translate(pad, pad); + canvas.scale(scale, scale); + marker.draw(canvas); + entity.additionalWidth = (2 * pad) * scale / transformedWidth; + entity.additionalHeight = (2 * pad) * scale / transformedHeight; + if (entity.entities.size() == 1) { + VideoEditedInfo.EmojiEntity e = entity.entities.get(0); + e.entity = new VideoEditedInfo.MediaEntity(); + e.entity.text = e.documentAbsolutePath; + e.entity.subType = e.subType; + + RectF bounds = new RectF(); + marker.getEmojiBounds(bounds); + + float tcx = entity.x + (bounds.centerX()) / entity.viewWidth * entity.width; + float tcy = entity.y + (bounds.centerY()) / entity.viewHeight * entity.height; + + if (entity.rotation != 0) { + float mx = entity.x + entity.width / 2f; + float my = entity.y + entity.height / 2f; + float ratio = transformedWidth / (float) transformedHeight; + float x1 = tcx - mx; + float y1 = (tcy - my) / ratio; + tcx = (float) (x1 * Math.cos(-entity.rotation) - y1 * Math.sin(-entity.rotation)) + mx; + tcy = (float) (x1 * Math.sin(-entity.rotation) + y1 * Math.cos(-entity.rotation)) * ratio + my; + } + + e.entity.width = (float) bounds.width() / entity.viewWidth * entity.width; + e.entity.height = (float) bounds.height() / entity.viewHeight * entity.height; + e.entity.width *= LocationMarker.SCALE; + e.entity.height *= LocationMarker.SCALE; + e.entity.x = tcx - e.entity.width / 2f; + e.entity.y = tcy - e.entity.height / 2f; + e.entity.rotation = entity.rotation; + + initStickerEntity(e.entity); + } } } } catch (Throwable e) { @@ -1022,9 +1081,23 @@ public void draw(@NonNull Canvas canvas, CharSequence charSequence, int start, i } private void initStickerEntity(VideoEditedInfo.MediaEntity entity) { + entity.W = (int) (entity.width * transformedWidth); + entity.H = (int) (entity.height * transformedHeight); + if (entity.W > 512) { + entity.H = (int) (entity.H / (float) entity.W * 512); + entity.W = 512; + } + if (entity.H > 512) { + entity.W = (int) (entity.W / (float) entity.H * 512); + entity.H = 512; + } if ((entity.subType & 1) != 0) { + if (entity.W <= 0 || entity.H <= 0) { + return; + } + entity.bitmap = Bitmap.createBitmap(entity.W, entity.H, Bitmap.Config.ARGB_8888); entity.metadata = new int[3]; - entity.ptr = RLottieDrawable.create(entity.text, null, 512, 512, entity.metadata, false, null, false, 0); + entity.ptr = RLottieDrawable.create(entity.text, null, entity.W, entity.H, entity.metadata, false, null, false, 0); entity.framesPerDraw = entity.metadata[1] / videoFps; } else if ((entity.subType & 4) != 0) { entity.animatedFileDrawable = new AnimatedFileDrawable(new File(entity.text), true, 0, 0, null, null, null, 0, UserConfig.selectedAccount, true, 512, 512, null); @@ -1149,6 +1222,10 @@ public void release() { if (entity.view instanceof EditTextEffects) { ((EditTextEffects) entity.view).recycleEmojis(); } + if (entity.bitmap != null) { + entity.bitmap.recycle(); + entity.bitmap = null; + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java b/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java index 5a5d00fbd52..401d60e2e37 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java @@ -10,6 +10,7 @@ import android.text.TextUtils; import android.util.Base64; +import com.google.android.exoplayer2.util.Log; import com.google.firebase.remoteconfig.FirebaseRemoteConfig; import org.json.JSONArray; @@ -412,6 +413,9 @@ public void cancelRequestsForGuid(int guid) { } public void bindRequestToGuid(int requestToken, int guid) { + if (guid == 0) { + return; + } native_bindRequestToGuid(currentAccount, requestToken, guid); } diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java index d9ee03b66cb..996df75f869 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -25,6 +25,7 @@ import org.telegram.messenger.Utilities; import org.telegram.ui.Stories.MessageMediaStoryFull; import org.telegram.ui.Stories.MessageMediaStoryFull_old; +import org.telegram.ui.Stories.recorder.StoryPrivacyBottomSheet; import java.util.ArrayList; import java.util.HashMap; @@ -73,7 +74,7 @@ public class TLRPC { public static final int MESSAGE_FLAG_HAS_BOT_ID = 0x00000800; public static final int MESSAGE_FLAG_EDITED = 0x00008000; - public static final int LAYER = 160; + public static final int LAYER = 161; public static class TL_stats_megagroupStats extends TLObject { public static int constructor = 0xef7ff916; @@ -8796,6 +8797,10 @@ public void serializeToStream(AbstractSerializedData stream) { public static class TL_messageMediaVenue extends MessageMedia { public static int constructor = 0x2ec0533f; + public String icon; //custom + public String emoji; //custom + public long query_id; //custom + public String result_id; //custom public void readParams(AbstractSerializedData stream, boolean exception) { geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); @@ -23810,8 +23815,12 @@ public void readParams(AbstractSerializedData stream, boolean exception) { usernames.add(object); } } - if ((flags2 & 32) != 0) { - stories_max_id = stream.readInt32(exception); + try { + if ((flags2 & 32) != 0) { + stories_max_id = stream.readInt32(exception); + } + } catch (Throwable e) { + FileLog.e(e); } } @@ -32931,7 +32940,7 @@ public static Update TLdeserialize(AbstractSerializedData stream, int constructo case 0x26ffde7d: result = new TL_updateDialogFilter(); break; - case 0x246a4b22: + case 0xebe07752: result = new TL_updatePeerBlocked(); break; case 0xed85eab5: @@ -32949,6 +32958,9 @@ public static Update TLdeserialize(AbstractSerializedData stream, int constructo case 0x74d8be99: result = new TL_updateSavedRingtones(); break; + case 0x2c084dc1: + result = new TL_updateStoriesStealthMode(); + break; case 0x84cd5a: result = new TL_updateTranscribedAudio(); break; @@ -32985,6 +32997,9 @@ public static Update TLdeserialize(AbstractSerializedData stream, int constructo case 0xc32d5b12: result = new TL_updateDeleteChannelMessages(); break; + case 0xe3a73d20: + result = new TL_updateSentStoryReaction(); + break; case 0xf227868c: result = new TL_updateUserPhoto(); break; @@ -34556,20 +34571,26 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_updatePeerBlocked extends Update { - public static int constructor = 0x246a4b22; + public static int constructor = 0xebe07752; - public Peer peer_id; + public int flags; public boolean blocked; + public boolean blocked_my_stories_from; + public Peer peer_id; public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + blocked = (flags & 1) != 0; + blocked_my_stories_from = (flags & 2) != 0; peer_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); - blocked = stream.readBool(exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + flags = blocked ? (flags | 1) : (flags &~ 1); + flags = blocked_my_stories_from ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); peer_id.serializeToStream(stream); - stream.writeBool(blocked); } } @@ -34908,6 +34929,27 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_updateSentStoryReaction extends Update { + public static int constructor = 0xe3a73d20; + + public long user_id; + public int story_id; + public Reaction reaction; + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt64(exception); + story_id = stream.readInt32(exception); + reaction = Reaction.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(user_id); + stream.writeInt32(story_id); + reaction.serializeToStream(stream); + } + } + public static class TL_updateChannelMessageForwards extends Update { public static int constructor = 0xd29a27f4; @@ -48673,6 +48715,7 @@ public static abstract class UserFull extends TLObject { public boolean voice_messages_forbidden; public boolean translations_disabled; public boolean stories_pinned_available; + public boolean blocked_my_stories_from; public User user; public String about; public TL_contacts_link_layer101 link; @@ -48759,6 +48802,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { voice_messages_forbidden = (flags & 1048576) != 0; translations_disabled = (flags & 8388608) != 0; stories_pinned_available = (flags & 67108864) != 0; + blocked_my_stories_from = (flags & 134217728) != 0; id = stream.readInt64(exception); if ((flags & 2) != 0) { about = stream.readString(exception); @@ -48835,6 +48879,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags = voice_messages_forbidden ? (flags | 1048576) : (flags &~ 1048576); flags = translations_disabled ? (flags | 8388608) : (flags &~ 8388608); flags = stories_pinned_available ? (flags | 67108864) : (flags &~ 67108864); + flags = blocked_my_stories_from ? (flags | 134217728) : (flags &~ 134217728); stream.writeInt32(flags); stream.writeInt64(id); if ((flags & 2) != 0) { @@ -52547,8 +52592,6 @@ public void serializeToStream(AbstractSerializedData stream) { } } - - public static abstract class Reaction extends TLObject { public static Reaction TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { @@ -53365,8 +53408,10 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_contacts_block extends TLObject { - public static int constructor = 0x68cc1411; + public static int constructor = 0x2e2e8734; + public int flags; + public boolean my_stories_from; public InputPeer id; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { @@ -53375,13 +53420,17 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + flags = my_stories_from ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); id.serializeToStream(stream); } } public static class TL_contacts_unblock extends TLObject { - public static int constructor = 0xbea65d50; + public static int constructor = 0xb550d328; + public int flags; + public boolean my_stories_from; public InputPeer id; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { @@ -53390,13 +53439,17 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + flags = my_stories_from ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); id.serializeToStream(stream); } } public static class TL_contacts_getBlocked extends TLObject { - public static int constructor = 0xf57c350f; + public static int constructor = 0x9a868f80; + public int flags; + public boolean my_stories_from; public int offset; public int limit; @@ -53406,6 +53459,8 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + flags = my_stories_from ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); stream.writeInt32(offset); stream.writeInt32(limit); } @@ -69221,8 +69276,10 @@ public static abstract class StoryItem extends TLObject { public boolean edited; public ArrayList entities = new ArrayList<>(); public MessageMedia media; + public ArrayList media_areas = new ArrayList(); public ArrayList privacy = new ArrayList<>(); - public TL_storyViews views; + public StoryViews views; + public Reaction sent_reaction; public long lastUpdateTime; //custom public String attachPath; //custom public String firstFramePath; //custom @@ -69231,13 +69288,21 @@ public static abstract class StoryItem extends TLObject { public int messageId;//custom public int messageType;//custom public int fileReference; + public String detectedLng; //custom + public String translatedLng; //custom + public boolean translated; //custom + public TLRPC.TL_textWithEntities translatedText; //custom + public StoryPrivacyBottomSheet.StoryPrivacy parsedPrivacy; //custom public static StoryItem TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { StoryItem result = null; switch (constructor) { - case 0x562aa637: + case 0x44c457ce: result = new TL_storyItem(); break; + case 0x562aa637: + result = new TL_storyItem_layer160(); + break; case 0x51e6ee4f: result = new TL_storyItemDeleted(); break; @@ -69255,29 +69320,76 @@ public static StoryItem TLdeserialize(AbstractSerializedData stream, int constru } } - public static class TL_storyViews extends TLObject { - public static int constructor = 0xd36760cf; + public static abstract class StoryViews extends TLObject { public int flags; public int views_count; + public int reactions_count; public ArrayList recent_viewers = new ArrayList<>(); - public static TL_storyViews TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_storyViews.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_storyViews", constructor)); - } else { - return null; - } + public static StoryViews TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + StoryViews result = null; + switch (constructor) { + case 0xd36760cf: + result = new TL_storyViews_layer160(); + break; + case 0xc64c0b97: + result = new TL_storyViews(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in StoryViews", constructor)); + } + if (result != null) { + result.readParams(stream, exception); } - TL_storyViews result = new TL_storyViews(); - result.readParams(stream, exception); return result; } + } + + public static class TL_storyViews_layer160 extends StoryViews { + public static int constructor = 0xd36760cf; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + views_count = stream.readInt32(exception); + if ((flags & 1) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + recent_viewers.add(stream.readInt64(exception)); + } + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt32(views_count); + if ((flags & 1) != 0) { + stream.writeInt32(0x1cb5c415); + int count = recent_viewers.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(recent_viewers.get(a)); + } + } + } + } + + public static class TL_storyViews extends StoryViews { + public static int constructor = 0xc64c0b97; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); views_count = stream.readInt32(exception); + reactions_count = stream.readInt32(exception); if ((flags & 1) != 0) { int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { @@ -69297,6 +69409,7 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); stream.writeInt32(flags); stream.writeInt32(views_count); + stream.writeInt32(reactions_count); if ((flags & 1) != 0) { stream.writeInt32(0x1cb5c415); int count = recent_viewers.size(); @@ -69309,6 +69422,136 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_storyItem extends StoryItem { + public static int constructor = 0x44c457ce; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + pinned = (flags & 32) != 0; + isPublic = (flags & 128) != 0; + close_friends = (flags & 256) != 0; + min = (flags & 512) != 0; + noforwards = (flags & 1024) != 0; + edited = (flags & 2048) != 0; + contacts = (flags & 4096) != 0; + selected_contacts = (flags & 8192) != 0; + id = stream.readInt32(exception); + date = stream.readInt32(exception); + expire_date = stream.readInt32(exception); + if ((flags & 1) != 0) { + caption = stream.readString(exception); + } + if ((flags & 2) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 16384) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MediaArea object = MediaArea.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + media_areas.add(object); + } + } + if ((flags & 4) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + PrivacyRule object = PrivacyRule.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + privacy.add(object); + } + } + if ((flags & 8) != 0) { + views = StoryViews.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32768) != 0) { + sent_reaction = Reaction.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = pinned ? (flags | 32) : (flags &~ 32); + flags = isPublic ? (flags | 128) : (flags &~ 128); + flags = close_friends ? (flags | 256) : (flags &~ 256); + flags = min ? (flags | 512) : (flags &~ 512); + flags = noforwards ? (flags | 1024) : (flags &~ 1024); + flags = edited ? (flags | 2048) : (flags &~ 2048); + flags = contacts ? (flags | 4096) : (flags &~ 4096); + flags = selected_contacts ? (flags | 8192) : (flags &~ 8192); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeInt32(date); + stream.writeInt32(expire_date); + if ((flags & 1) != 0) { + stream.writeString(caption); + } + if ((flags & 2) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + media.serializeToStream(stream); + if ((flags & 16384) != 0) { + stream.writeInt32(0x1cb5c415); + int count = media_areas.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + media_areas.get(a).serializeToStream(stream); + } + } + if ((flags & 4) != 0) { + stream.writeInt32(0x1cb5c415); + int count = privacy.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + privacy.get(a).serializeToStream(stream); + } + } + if ((flags & 8) != 0) { + views.serializeToStream(stream); + } + if ((flags & 32768) != 0) { + sent_reaction.serializeToStream(stream); + } + } + } + + public static class TL_storyItem_layer160 extends TL_storyItem { public static int constructor = 0x562aa637; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -69363,7 +69606,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { } } if ((flags & 8) != 0) { - views = TL_storyViews.TLdeserialize(stream, stream.readInt32(exception), exception); + views = StoryViews.TLdeserialize(stream, stream.readInt32(exception), exception); } } @@ -69440,11 +69683,154 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(expire_date); } } + + public static class TL_mediaAreaCoordinates extends TLObject { + public static final int constructor = 0x3d1ea4e; + + public double x; + public double y; + public double w; + public double h; + public double rotation; + + public static TL_mediaAreaCoordinates TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_mediaAreaCoordinates.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_mediaAreaCoordinates", constructor)); + } else { + return null; + } + } + TL_mediaAreaCoordinates result = new TL_mediaAreaCoordinates(); + result.readParams(stream, exception); + return result; + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + x = stream.readDouble(exception); + y = stream.readDouble(exception); + w = stream.readDouble(exception); + h = stream.readDouble(exception); + rotation = stream.readDouble(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeDouble(x); + stream.writeDouble(y); + stream.writeDouble(w); + stream.writeDouble(h); + stream.writeDouble(rotation); + } + } + + public static class MediaArea extends TLObject { + public TL_mediaAreaCoordinates coordinates; + + public static MediaArea TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + MediaArea result = null; + switch (constructor) { + case TL_mediaAreaVenue.constructor: + result = new TL_mediaAreaVenue(); + break; + case TL_mediaAreaGeoPoint.constructor: + result = new TL_mediaAreaGeoPoint(); + break; + case TL_inputMediaAreaVenue.constructor: + result = new TL_inputMediaAreaVenue(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in MediaArea", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_mediaAreaVenue extends MediaArea { + public static final int constructor = 0xbe82db9c; + + public GeoPoint geo; + public String title; + public String address; + public String provider; + public String venue_id; + public String venue_type; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + coordinates = TL_mediaAreaCoordinates.TLdeserialize(stream, stream.readInt32(exception), exception); + geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + title = stream.readString(exception); + address = stream.readString(exception); + provider = stream.readString(exception); + venue_id = stream.readString(exception); + venue_type = stream.readString(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + coordinates.serializeToStream(stream); + geo.serializeToStream(stream); + stream.writeString(title); + stream.writeString(address); + stream.writeString(provider); + stream.writeString(venue_id); + stream.writeString(venue_type); + } + } + + public static class TL_inputMediaAreaVenue extends MediaArea { + public static final int constructor = 0xb282217f; + + public long query_id; + public String result_id; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + coordinates = TL_mediaAreaCoordinates.TLdeserialize(stream, stream.readInt32(exception), exception); + query_id = stream.readInt64(exception); + result_id = stream.readString(exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + coordinates.serializeToStream(stream); + stream.writeInt64(query_id); + stream.writeString(result_id); + } + } + + public static class TL_mediaAreaGeoPoint extends MediaArea { + public static final int constructor = 0xdf8b3b22; + + public GeoPoint geo; + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + coordinates = TL_mediaAreaCoordinates.TLdeserialize(stream, stream.readInt32(exception), exception); + geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + coordinates.serializeToStream(stream); + geo.serializeToStream(stream); + } + } public static class TL_stories_storyViews extends TLObject { public static int constructor = 0xde9eed1d; - public ArrayList views = new ArrayList<>(); + public ArrayList views = new ArrayList<>(); public ArrayList users = new ArrayList<>(); public static TL_stories_storyViews TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { @@ -69470,7 +69856,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { } int count = stream.readInt32(exception); for (int a = 0; a < count; a++) { - TL_storyViews object = TL_storyViews.TLdeserialize(stream, stream.readInt32(exception), exception); + StoryViews object = StoryViews.TLdeserialize(stream, stream.readInt32(exception), exception); if (object == null) { return; } @@ -69511,10 +69897,14 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_storyView extends TLObject { - public static int constructor = 0xa71aacc2; + public static int constructor = 0xb0bdeac5; + public int flags; + public boolean blocked; + public boolean blocked_my_stories_from; public long user_id; public int date; + public Reaction reaction; public static TL_storyView TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_storyView.constructor != constructor) { @@ -69530,14 +69920,26 @@ public static TL_storyView TLdeserialize(AbstractSerializedData stream, int cons } public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + blocked = (flags & 1) != 0; + blocked_my_stories_from = (flags & 2) != 0; user_id = stream.readInt64(exception); date = stream.readInt32(exception); + if ((flags & 4) != 0) { + reaction = Reaction.TLdeserialize(stream, stream.readInt32(exception), exception); + } } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + flags = blocked ? (flags | 1) : (flags &~ 1); + flags = blocked_my_stories_from ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); stream.writeInt64(user_id); stream.writeInt32(date); + if ((flags & 4) != 0) { + reaction.serializeToStream(stream); + } } } @@ -69657,10 +70059,10 @@ public static abstract class stories_AllStories extends TLObject { public static stories_AllStories TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { stories_AllStories result = null; switch (constructor) { - case 0x47e0a07e: + case 0x1158fe3e: result = new TL_stories_allStoriesNotModified(); break; - case 0x839e0428: + case 0x519d899e: result = new TL_stories_allStories(); break; } @@ -69675,22 +70077,28 @@ public static stories_AllStories TLdeserialize(AbstractSerializedData stream, in } public static class TL_stories_allStoriesNotModified extends stories_AllStories { - public static int constructor = 0x47e0a07e; + public static int constructor = 0x1158fe3e; + public int flags; public String state; + public TL_storiesStealthMode stealth_mode; public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); state = stream.readString(exception); + stealth_mode = TL_storiesStealthMode.TLdeserialize(stream, stream.readInt32(exception), exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + stream.writeInt32(flags); stream.writeString(state); + stealth_mode.serializeToStream(stream); } } public static class TL_stories_allStories extends stories_AllStories { - public static int constructor = 0x839e0428; + public static int constructor = 0x519d899e; public int flags; public boolean has_more; @@ -69698,6 +70106,7 @@ public static class TL_stories_allStories extends stories_AllStories { public String state; public ArrayList user_stories = new ArrayList<>(); public ArrayList users = new ArrayList<>(); + public TL_storiesStealthMode stealth_mode; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -69734,6 +70143,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { } users.add(object); } + stealth_mode = TL_storiesStealthMode.TLdeserialize(stream, stream.readInt32(exception), exception); } public void serializeToStream(AbstractSerializedData stream) { @@ -69754,16 +70164,30 @@ public void serializeToStream(AbstractSerializedData stream) { for (int a = 0; a < count; a++) { users.get(a).serializeToStream(stream); } + stealth_mode.serializeToStream(stream); + } + } + + public static class TL_stories_canSendStory extends TLObject { + public static int constructor = 0xb100d45d; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); } } public static class TL_stories_sendStory extends TLObject { - public static int constructor = 0x424cd47a; + public static int constructor = 0xd455fcec; public int flags; public boolean pinned; public boolean noforwards; public InputMedia media; + public ArrayList media_areas = new ArrayList<>(); public String caption; public ArrayList entities = new ArrayList<>(); public ArrayList privacy_rules = new ArrayList<>(); @@ -69780,6 +70204,14 @@ public void serializeToStream(AbstractSerializedData stream) { flags = noforwards ? (flags | 16) : (flags &~ 16); stream.writeInt32(flags); media.serializeToStream(stream); + if ((flags & 32) != 0) { + stream.writeInt32(0x1cb5c415); + int count = media_areas.size(); + stream.writeInt32(count); + for (int a = 0; a < count; ++a) { + media_areas.get(a).serializeToStream(stream); + } + } if ((flags & 1) != 0) { stream.writeString(caption); } @@ -69857,11 +70289,12 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stories_editStory extends TLObject { - public static int constructor = 0x2aae7a41; + public static int constructor = 0xa9b91ae4; public int flags; public int id; public InputMedia media; + public ArrayList media_areas = new ArrayList<>(); public String caption; public ArrayList entities = new ArrayList<>(); public ArrayList privacy_rules = new ArrayList<>(); @@ -69877,6 +70310,14 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 1) != 0) { media.serializeToStream(stream); } + if ((flags & 8) != 0) { + stream.writeInt32(0x1cb5c415); + int count = media_areas.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + media_areas.get(a).serializeToStream(stream); + } + } if ((flags & 2) != 0) { stream.writeString(caption); } @@ -69938,6 +70379,31 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeBool(hidden); } } + + public static class TL_contacts_setBlocked extends TLObject { + public static int constructor = 0x94c65c76; + + public int flags; + public boolean my_stories_from; + public ArrayList id = new ArrayList<>(); + public int limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = my_stories_from ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeInt32(0x1cb5c415); + stream.writeInt32(id.size()); + for (int i = 0; i < id.size(); ++i) { + id.get(i).serializeToStream(stream); + } + stream.writeInt32(limit); + } + } public static class TL_stories_stories extends TLObject { public static int constructor = 0x4fe57df1; @@ -70099,11 +70565,14 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stories_storyViewsList extends TLObject { - public static int constructor = 0xfb3f77ac; + public static int constructor = 0x46e9b9ec; + public int flags; public int count; + public int reactions_count; public ArrayList views = new ArrayList<>(); public ArrayList users = new ArrayList<>(); + public String next_offset = ""; public static TL_stories_storyViewsList TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_stories_storyViewsList.constructor != constructor) { @@ -70119,7 +70588,9 @@ public static TL_stories_storyViewsList TLdeserialize(AbstractSerializedData str } public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); count = stream.readInt32(exception); + reactions_count = stream.readInt32(exception); int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { if (exception) { @@ -70150,11 +70621,16 @@ public void readParams(AbstractSerializedData stream, boolean exception) { } users.add(object); } + if ((flags & 1) != 0) { + next_offset = stream.readString(exception); + } } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + stream.writeInt32(flags); stream.writeInt32(count); + stream.writeInt32(reactions_count); stream.writeInt32(0x1cb5c415); int count = views.size(); stream.writeInt32(count); @@ -70167,6 +70643,9 @@ public void serializeToStream(AbstractSerializedData stream) { for (int a = 0; a < count; a++) { users.get(a).serializeToStream(stream); } + if ((flags & 1) != 0) { + stream.writeString(next_offset); + } } } @@ -70193,11 +70672,14 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_stories_getStoryViewsList extends TLObject { - public static int constructor = 0x4b3b5e97; + public static int constructor = 0xf95f61a4; + public int flags; + public boolean just_contacts; + public boolean reactions_first; + public String q; public int id; - public int offset_date; - public long offset_id; + public String offset; public int limit; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { @@ -70206,9 +70688,14 @@ public TLObject deserializeResponse(AbstractSerializedData stream, int construct public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + flags = just_contacts ? (flags | 1) : (flags &~ 1); + flags = reactions_first ? (flags | 4) : (flags &~ 4); + stream.writeInt32(flags); + if ((flags & 2) != 0) { + stream.writeString(q); + } stream.writeInt32(id); - stream.writeInt32(offset_date); - stream.writeInt64(offset_id); + stream.writeString(offset); stream.writeInt32(limit); } } @@ -70497,6 +70984,104 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_updateStoriesStealthMode extends Update { + public static int constructor = 0x2c084dc1; + + public TL_storiesStealthMode stealth_mode; + + public void readParams(AbstractSerializedData stream, boolean exception) { + stealth_mode = TL_storiesStealthMode.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stealth_mode.serializeToStream(stream); + } + } + + public static class TL_storiesStealthMode extends TLObject { + public static int constructor = 0x712e27fd; + + public int flags; + public int active_until_date; + public int cooldown_until_date; + + public static TL_storiesStealthMode TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_storiesStealthMode.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_storiesStealthMode", constructor)); + } else { + return null; + } + } + TL_storiesStealthMode result = new TL_storiesStealthMode(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + if ((flags & 1) != 0) { + active_until_date = stream.readInt32(exception); + } + if ((flags & 2) != 0) { + cooldown_until_date = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + stream.writeInt32(active_until_date); + } + if ((flags & 2) != 0) { + stream.writeInt32(cooldown_until_date); + } + } + } + + public static class TL_stories_activateStealthMode extends TLObject { + public static int constructor = 0x57bbd166; + + public int flags; + public boolean past; + public boolean future; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = past ? (flags | 1) : (flags &~ 1); + flags = future ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + } + } + + public static class TL_stories_sendReaction extends TLObject { + public static int constructor = 0x49aaa9b3; + + public int flags; + public boolean add_to_recent; + public InputUser user_id; + public int story_id; + public Reaction reaction; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = add_to_recent ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + user_id.serializeToStream(stream); + stream.writeInt32(story_id); + reaction.serializeToStream(stream); + } + } //functions public static class Vector extends TLObject { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java index 48123b2100b..5d301f725a7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java @@ -1226,8 +1226,8 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (searchFieldIsVisible && !this.isSearchFieldVisible) { menuWidth = MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST); menu.measure(menuWidth, actionBarHeightSpec); - int itemsWidth = menu.getItemsMeasuredWidth(); - menuWidth = MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(AndroidUtilities.isTablet() ? 74 : 66) + menu.getItemsMeasuredWidth(), MeasureSpec.EXACTLY); + int itemsWidth = menu.getItemsMeasuredWidth(true); + menuWidth = MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(AndroidUtilities.isTablet() ? 74 : 66) + menu.getItemsMeasuredWidth(true), MeasureSpec.EXACTLY); if (!isMenuOffsetSuppressed) { menu.translateXItems(-itemsWidth); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java index 377ba1e51dc..ad5365bbdde 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java @@ -964,7 +964,7 @@ public void onBackPressed() { if (GroupCallPip.onBackPressed()) { return; } - if (currentActionBar != null && !currentActionBar.isActionModeShowed() && currentActionBar.isSearchFieldVisible) { + if (!storyViewerAttached() && currentActionBar != null && !currentActionBar.isActionModeShowed() && currentActionBar.isSearchFieldVisible) { currentActionBar.closeSearchField(); return; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java index 21fcfb6430d..9256e033790 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java @@ -518,11 +518,14 @@ public void setEnabled(boolean enabled) { } } - public int getItemsMeasuredWidth() { + public int getItemsMeasuredWidth(boolean ignoreAlpha) { int w = 0; int count = getChildCount(); for (int a = 0; a < count; a++) { View view = getChildAt(a); + if (!ignoreAlpha && (view.getAlpha() == 0 || view.getVisibility() != View.VISIBLE)) { + continue; + } if (view instanceof ActionBarMenuItem) { w += view.getMeasuredWidth(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java index 82d88c38659..28c1b073cfa 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java @@ -81,6 +81,17 @@ public class ActionBarMenuItem extends FrameLayout { private FrameLayout wrappedSearchFrameLayout; + public static void addText(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout, String text, Theme.ResourcesProvider resourcesProvider) { + final TextView textView = new TextView(popupLayout.getContext()); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + textView.setPadding(AndroidUtilities.dp(13), AndroidUtilities.dp(8), AndroidUtilities.dp(13), AndroidUtilities.dp(8)); + textView.setText(text); + textView.setTag(R.id.fit_width_tag, 1); + textView.setMaxWidth(AndroidUtilities.dp(200)); + popupLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } + public void setSearchPaddingStart(int padding) { searchItemPaddingStart = padding; if (searchContainer != null) { @@ -525,6 +536,7 @@ public static View addGap(int id, ActionBarPopupWindow.ActionBarPopupWindowLayou View cell = new View(popupLayout.getContext()); cell.setTag(id); cell.setTag(R.id.object_tag, 1); + cell.setTag(R.id.fit_width_tag, 1); popupLayout.addView(cell); LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) cell.getLayoutParams(); if (LocaleController.isRTL) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java index 8affa932177..dd3cb892cda 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java @@ -203,6 +203,10 @@ public void setIcon(int resId) { imageView.setImageResource(resId); } + public void setIcon(Drawable drawable) { + imageView.setImageDrawable(drawable); + } + public void setAnimatedIcon(int resId) { imageView.setAnimation(resId, 24, 24); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java index 7116843f00b..cde9699d6f4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java @@ -950,6 +950,9 @@ public void setRemovingFromStack(boolean b) { } public boolean isLightStatusBar() { + if (storyViewer != null && storyViewer.isShown()) { + return false; + } if (hasForceLightStatusBar() && !Theme.getCurrentTheme().isDark()) { return true; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java index 1fe0fb575ae..65566b2be6c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java @@ -31,6 +31,7 @@ import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; +import android.view.KeyEvent; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; @@ -770,6 +771,10 @@ private int getAdditionalMandatoryOffsets() { return !keyboardVisible && drawNavigationBar && insets != null && (insets.left != 0 || insets.right != 0) ? insets.bottom : 0; } + public boolean isKeyboardVisible() { + return keyboardVisible; + } + public interface BottomSheetDelegateInterface { void onOpenAnimationStart(); void onOpenAnimationEnd(); @@ -1905,6 +1910,11 @@ private void setShowing(boolean showing) { } } + @Override + public boolean dispatchKeyEvent(@NonNull KeyEvent event) { + return super.dispatchKeyEvent(event); + } + public void setImageReceiverNumLevel(int playingImages, int onShowing) { this.playingImagesLayerNum = playingImages; this.openedLayerNum = onShowing; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/FloatingToolbar.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/FloatingToolbar.java index 1d531c5e155..aa2f89f452d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/FloatingToolbar.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/FloatingToolbar.java @@ -25,6 +25,8 @@ import android.graphics.Color; import android.graphics.Outline; import android.graphics.Point; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.Region; import android.graphics.drawable.AnimatedVectorDrawable; @@ -32,6 +34,7 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.text.TextUtils; +import android.util.Log; import android.util.Size; import android.util.TypedValue; import android.view.Gravity; @@ -49,23 +52,30 @@ import android.view.animation.Interpolator; import android.view.animation.Transformation; import android.widget.ArrayAdapter; +import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.PopupWindow; import android.widget.RelativeLayout; +import android.widget.Space; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.LocaleController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Objects; @@ -90,6 +100,11 @@ public final class FloatingToolbar { public static final int STYLE_THEME = 1; public static final int STYLE_BLACK = 2; + private Runnable premiumLockClickListener; + public void setOnPremiumLockClick(Runnable listener) { + premiumLockClickListener = listener; + } + private final OnLayoutChangeListener mOrientationChangeHandler = new OnLayoutChangeListener() { private final Rect mNewRect = new Rect(); private final Rect mOldRect = new Rect(); @@ -220,7 +235,7 @@ private List getVisibleAndEnabledMenuItems(Menu menu) { Menu subMenu = menuItem.getSubMenu(); if (subMenu != null) { menuItems.addAll(getVisibleAndEnabledMenuItems(subMenu)); - } else if (menuItem.getItemId() != TRANSLATE) { + } else if (menuItem.getItemId() != TRANSLATE && (menuItem.getItemId() != R.id.menu_regular || premiumLockClickListener == null)) { menuItems.add(menuItem); } } @@ -237,6 +252,16 @@ private void unregisterOrientationHandler() { mWindowView.removeOnLayoutChangeListener(mOrientationChangeHandler); } + private static final List premiumOptions = Arrays.asList( + R.id.menu_bold, + R.id.menu_italic, + R.id.menu_strike, + R.id.menu_link, + R.id.menu_mono, + R.id.menu_underline, + R.id.menu_spoiler + ); + private final class FloatingToolbarPopup { private static final int MIN_OVERFLOW_SIZE = 2; @@ -251,7 +276,10 @@ private final class FloatingToolbarPopup { private final ViewGroup mContentContainer; private final ViewGroup mMainPanel; private final OverflowPanel mOverflowPanel; - private final ImageButton mOverflowButton; + private final FrameLayout mOverflowButton; + private final View mOverflowButtonShadow; + private final ImageView mOverflowButtonIcon; + private final TextView mOverflowButtonText; private final Drawable mArrow; private final Drawable mOverflow; @@ -338,8 +366,52 @@ public FloatingToolbarPopup(Context context, View parent) { mToOverflow = (AnimatedVectorDrawable) mContext.getDrawable(R.drawable.ft_avd_tooverflow_animation).mutate(); mToOverflow.setAutoMirrored(true); - mOverflowButton = createOverflowButton(); - mOverflowButtonSize = measure(mOverflowButton); + mOverflowButton = new FrameLayout(mContext); + mOverflowButtonIcon = new ImageButton(mContext) { + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + if (mIsOverflowOpen) { + return false; + } + return super.dispatchTouchEvent(event); + } + }; + mOverflowButtonIcon.setLayoutParams(new ViewGroup.LayoutParams(AndroidUtilities.dp(56), AndroidUtilities.dp(48))); + mOverflowButtonIcon.setPaddingRelative(AndroidUtilities.dp(16), AndroidUtilities.dp(12), AndroidUtilities.dp(16), AndroidUtilities.dp(12)); + mOverflowButtonIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + mOverflowButtonIcon.setImageDrawable(mOverflow); + mOverflowButtonText = new TextView(mContext); + mOverflowButtonText.setText(LocaleController.getString(R.string.Back)); + mOverflowButtonText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + mOverflowButtonText.setAlpha(0f); + mOverflowButtonShadow = new View(mContext); + int color; + if (currentStyle == STYLE_DIALOG) { + color = getThemedColor(Theme.key_dialogTextBlack); + mOverflowButtonIcon.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), Theme.RIPPLE_MASK_CIRCLE_20DP)); + mOverflowButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), Theme.RIPPLE_MASK_ALL)); + mOverflowButtonShadow.setBackgroundColor(Theme.multAlpha(getThemedColor(Theme.key_dialogTextBlack), .4f)); + } else if (currentStyle == STYLE_BLACK) { + color = 0xfffafafa; + mOverflowButtonIcon.setBackground(Theme.createSelectorDrawable(0x20ffffff, Theme.RIPPLE_MASK_CIRCLE_20DP)); + mOverflowButton.setBackground(Theme.createSelectorDrawable(0x20ffffff, Theme.RIPPLE_MASK_ALL)); + mOverflowButtonShadow.setBackgroundColor(0xff000000); + } else { + color = getThemedColor(Theme.key_windowBackgroundWhiteBlackText); + mOverflowButtonIcon.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), Theme.RIPPLE_MASK_CIRCLE_20DP)); + mOverflowButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), Theme.RIPPLE_MASK_ALL)); + mOverflowButtonShadow.setBackgroundColor(getThemedColor(Theme.key_divider)); + } + mOverflow.setTint(color); + mArrow.setTint(color); + mToArrow.setTint(color); + mToOverflow.setTint(color); + mOverflowButtonText.setTextColor(color); + mOverflowButtonIcon.setOnClickListener(v -> onBackPressed()); + mOverflowButton.addView(mOverflowButtonIcon, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.LEFT)); + mOverflowButton.addView(mOverflowButtonText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.LEFT, 56, 0, 0, 0)); + mOverflowButton.addView(mOverflowButtonShadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1f / AndroidUtilities.density, Gravity.TOP | Gravity.FILL_HORIZONTAL)); + mOverflowButtonSize = measure(mOverflowButtonIcon); mMainPanel = createMainPanel(); mOverflowPanelViewHelper = new OverflowPanelViewHelper(mContext, mIconTextSpacing); mOverflowPanel = createOverflowPanel(); @@ -369,6 +441,26 @@ public void onAnimationEnd(Animator animation) { }); } + private void onBackPressed() { + if (mIsOverflowOpen) { + mOverflowButtonIcon.setImageDrawable(mToOverflow); + mToOverflow.start(); + closeOverflow(); + mOverflowButton.setClickable(false); + mOverflowButton.setOnClickListener(null); + mOverflowButtonIcon.setClickable(true); + mOverflowButtonIcon.setOnClickListener(v -> onBackPressed()); + } else { + mOverflowButtonIcon.setImageDrawable(mToArrow); + mToArrow.start(); + openOverflow(); + mOverflowButton.setClickable(true); + mOverflowButton.setOnClickListener(v -> onBackPressed()); + mOverflowButtonIcon.setClickable(false); + mOverflowButtonIcon.setOnClickListener(null); + } + } + public boolean setOutsideTouchable(boolean outsideTouchable, PopupWindow.OnDismissListener onDismiss) { boolean ret = false; if (mPopupWindow.isOutsideTouchable() ^ outsideTouchable) { @@ -562,7 +654,7 @@ protected void applyTransformation(float interpolatedTime, Transformation t) { } }; final float overflowButtonStartX = mOverflowButton.getX(); - final float overflowButtonTargetX = isInRTLMode() ? overflowButtonStartX + targetWidth - mOverflowButton.getWidth() : overflowButtonStartX - targetWidth + mOverflowButton.getWidth(); + final float overflowButtonTargetX = isInRTLMode() ? overflowButtonStartX + targetWidth - mOverflowButtonIcon.getWidth() : overflowButtonStartX - targetWidth + mOverflowButtonIcon.getWidth(); Animation overflowButtonAnimation = new Animation() { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { @@ -570,6 +662,8 @@ protected void applyTransformation(float interpolatedTime, Transformation t) { float deltaContainerWidth = isInRTLMode() ? 0 : mContentContainer.getWidth() - startWidth; float actualOverflowButtonX = overflowButtonX + deltaContainerWidth; mOverflowButton.setX(actualOverflowButtonX); + mOverflowButtonText.setAlpha(interpolatedTime); + mOverflowButtonShadow.setAlpha(interpolatedTime); } }; widthAnimation.setInterpolator(mLogAccelerateInterpolator); @@ -585,6 +679,9 @@ protected void applyTransformation(float interpolatedTime, Transformation t) { mContentContainer.startAnimation(mOpenOverflowAnimation); mIsOverflowOpen = true; mMainPanel.animate().alpha(0).withLayer().setInterpolator(mLinearOutSlowInInterpolator).setDuration(250).start(); + RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) mOverflowButton.getLayoutParams(); + lp.width = mOverflowPanel.getWidth(); + mOverflowButton.setLayoutParams(lp); mOverflowPanel.setAlpha(1); } @@ -624,7 +721,7 @@ protected void applyTransformation(float interpolatedTime, Transformation t) { } }; final float overflowButtonStartX = mOverflowButton.getX(); - final float overflowButtonTargetX = isInRTLMode() ? overflowButtonStartX - startWidth + mOverflowButton.getWidth() : overflowButtonStartX + startWidth - mOverflowButton.getWidth(); + final float overflowButtonTargetX = isInRTLMode() ? overflowButtonStartX - startWidth + mOverflowButtonIcon.getWidth() : overflowButtonStartX + startWidth - mOverflowButtonIcon.getWidth(); Animation overflowButtonAnimation = new Animation() { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { @@ -632,6 +729,8 @@ protected void applyTransformation(float interpolatedTime, Transformation t) { float deltaContainerWidth = isInRTLMode() ? 0 : mContentContainer.getWidth() - startWidth; float actualOverflowButtonX = overflowButtonX + deltaContainerWidth; mOverflowButton.setX(actualOverflowButtonX); + mOverflowButtonText.setAlpha(1f - interpolatedTime); + mOverflowButtonShadow.setAlpha(1f - interpolatedTime); } }; widthAnimation.setInterpolator(mFastOutSlowInInterpolator); @@ -668,7 +767,7 @@ private void setPanelsStatesAtRestingPosition() { mMainPanel.setVisibility(View.INVISIBLE); mOverflowPanel.setAlpha(1); mOverflowPanel.setVisibility(View.VISIBLE); - mOverflowButton.setImageDrawable(mArrow); + mOverflowButtonIcon.setImageDrawable(mArrow); mOverflowButton.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); if (isInRTLMode()) { @@ -700,7 +799,7 @@ private void setPanelsStatesAtRestingPosition() { mMainPanel.setVisibility(View.VISIBLE); mOverflowPanel.setAlpha(0); mOverflowPanel.setVisibility(View.INVISIBLE); - mOverflowButton.setImageDrawable(mOverflow); + mOverflowButtonIcon.setImageDrawable(mOverflow); mOverflowButton.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); if (hasOverflow()) { if (isInRTLMode()) { @@ -832,9 +931,15 @@ public List layoutMainPanelItems(List menuItems, final int t mMainPanel.removeAllViews(); mMainPanel.setPaddingRelative(0, 0, 0, 0); boolean isFirstItem = true; - while (!remainingMenuItems.isEmpty()) { - final MenuItem menuItem = remainingMenuItems.peek(); - boolean isLastItem = remainingMenuItems.size() == 1; + Iterator it = remainingMenuItems.iterator(); + while (it.hasNext()) { + final MenuItem menuItem = it.next(); + boolean isLastItem = !it.hasNext(); + if (menuItem != null && premiumLockClickListener != null) { + if (premiumOptions.contains(menuItem.getItemId())) { + continue; + } + } /*if (!isFirstItem && menuItem.requiresOverflow()) { break; }*/ @@ -855,7 +960,7 @@ public List layoutMainPanelItems(List menuItems, final int t params.width = menuItemButtonWidth; menuItemButton.setLayoutParams(params); availableWidth -= menuItemButtonWidth; - remainingMenuItems.pop(); + it.remove(); } else { break; } @@ -876,6 +981,13 @@ private void updateMainPanelItemsSelectors() { private void layoutOverflowPanelItems(List menuItems) { ArrayAdapter overflowPanelAdapter = (ArrayAdapter) mOverflowPanel.getAdapter(); overflowPanelAdapter.clear(); + if (premiumLockClickListener != null) { + Collections.sort(menuItems, (a, b) -> { + final int aPremium = premiumOptions.contains(a.getItemId()) ? 1 : 0; + final int bPremium = premiumOptions.contains(b.getItemId()) ? 1 : 0; + return aPremium - bPremium; + }); + } final int size = menuItems.size(); for (int i = 0; i < size; i++) { overflowPanelAdapter.add(menuItems.get(i)); @@ -987,40 +1099,7 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { }; } - private ImageButton createOverflowButton() { - final ImageButton overflowButton = new ImageButton(mContext); - overflowButton.setLayoutParams(new ViewGroup.LayoutParams(AndroidUtilities.dp(56), AndroidUtilities.dp(48))); - overflowButton.setPaddingRelative(AndroidUtilities.dp(16), AndroidUtilities.dp(12), AndroidUtilities.dp(16), AndroidUtilities.dp(12)); - overflowButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - overflowButton.setImageDrawable(mOverflow); - int color; - if (currentStyle == STYLE_DIALOG) { - color = getThemedColor(Theme.key_dialogTextBlack); - overflowButton.setBackgroundDrawable(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), 1)); - } else if (currentStyle == STYLE_BLACK) { - color = 0xfffafafa; - overflowButton.setBackgroundDrawable(Theme.createSelectorDrawable(0x40ffffff, 1)); - } else { - color = getThemedColor(Theme.key_windowBackgroundWhiteBlackText); - overflowButton.setBackgroundDrawable(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), 1)); - } - mOverflow.setTint(color); - mArrow.setTint(color); - mToArrow.setTint(color); - mToOverflow.setTint(color); - overflowButton.setOnClickListener(v -> { - if (mIsOverflowOpen) { - overflowButton.setImageDrawable(mToOverflow); - mToOverflow.start(); - closeOverflow(); - } else { - overflowButton.setImageDrawable(mToArrow); - mToArrow.start(); - openOverflow(); - } - }); - return overflowButton; - } + private int shiftDp = -4; private OverflowPanel createOverflowPanel() { final OverflowPanel overflowPanel = new OverflowPanel(this); @@ -1036,7 +1115,11 @@ public View getView(int position, View convertView, ViewGroup parent) { overflowPanel.setAdapter(adapter); overflowPanel.setOnItemClickListener((parent, view, position, id) -> { MenuItem menuItem = (MenuItem) overflowPanel.getAdapter().getItem(position); - if (mOnMenuItemClickListener != null) { + if (premiumLockClickListener != null && premiumOptions.contains(menuItem.getItemId())) { + AndroidUtilities.shakeViewSpring(view, shiftDp = -shiftDp); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + premiumLockClickListener.run(); + } else if (mOnMenuItemClickListener != null) { mOnMenuItemClickListener.onMenuItemClick(menuItem); } }); @@ -1167,7 +1250,7 @@ public OverflowPanelViewHelper(Context context, int iconTextSpacing) { public View getView(MenuItem menuItem, int minimumWidth, View convertView) { if (convertView != null) { - updateMenuItemButton(convertView, menuItem, mIconTextSpacing); + updateMenuItemButton(convertView, menuItem, mIconTextSpacing, premiumLockClickListener != null); } else { convertView = createMenuButton(menuItem); } @@ -1176,7 +1259,7 @@ public View getView(MenuItem menuItem, int minimumWidth, View convertView) { } public int calculateWidth(MenuItem menuItem) { - updateMenuItemButton(mCalculator, menuItem, mIconTextSpacing); + updateMenuItemButton(mCalculator, menuItem, mIconTextSpacing, premiumLockClickListener != null); mCalculator.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); return mCalculator.getMeasuredWidth(); } @@ -1206,30 +1289,43 @@ private View createMenuItemButton(Context context, MenuItem menuItem, int iconTe textView.setFocusable(false); textView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); textView.setFocusableInTouchMode(false); + int color; int selectorColor = getThemedColor(Theme.key_listSelector); if (currentStyle == STYLE_DIALOG) { - textView.setTextColor(getThemedColor(Theme.key_dialogTextBlack)); + textView.setTextColor(color = getThemedColor(Theme.key_dialogTextBlack)); } else if (currentStyle == STYLE_BLACK) { - textView.setTextColor(0xfffafafa); - selectorColor = 0x40ffffff; + textView.setTextColor(color = 0xfffafafa); + selectorColor = 0x20ffffff; } else if (currentStyle == STYLE_THEME) { - textView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); + textView.setTextColor(color = getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); + } else { + color = getThemedColor(Theme.key_windowBackgroundWhiteBlackText); } if (first || last) { - menuItemButton.setBackgroundDrawable(Theme.createRadSelectorDrawable(selectorColor, first ? 6 : 0, last ? 6 : 0, last ? 6 : 0, first ? 6 : 0)); + menuItemButton.setBackground(Theme.createRadSelectorDrawable(selectorColor, first ? 6 : 0, last ? 6 : 0, last ? 6 : 0, first ? 6 : 0)); } else { - menuItemButton.setBackgroundDrawable(Theme.getSelectorDrawable(selectorColor, false)); + menuItemButton.setBackground(Theme.getSelectorDrawable(selectorColor, false)); } textView.setPaddingRelative(AndroidUtilities.dp(11), 0, 0, 0); menuItemButton.addView(textView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, AndroidUtilities.dp(48))); + + menuItemButton.addView(new Space(context), new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1, 1)); + + ImageView lockView = new ImageView(context); + lockView.setImageResource(R.drawable.msg_mini_lock3); + lockView.setScaleType(ImageView.ScaleType.CENTER); + lockView.setColorFilter(new PorterDuffColorFilter(Theme.multAlpha(color, .4f), PorterDuff.Mode.SRC_IN)); + lockView.setVisibility(View.GONE); + menuItemButton.addView(lockView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, 0, 0, 12, 0, 0, 0)); + if (menuItem != null) { - updateMenuItemButton(menuItemButton, menuItem, iconTextSpacing); + updateMenuItemButton(menuItemButton, menuItem, iconTextSpacing, premiumLockClickListener != null); } return menuItemButton; } - private static void updateMenuItemButton(View menuItemButton, MenuItem menuItem, int iconTextSpacing) { + private static void updateMenuItemButton(View menuItemButton, MenuItem menuItem, int iconTextSpacing, boolean containsPremium) { ViewGroup viewGroup = (ViewGroup) menuItemButton; final TextView buttonText = (TextView) viewGroup.getChildAt(0); buttonText.setEllipsize(null); @@ -1240,6 +1336,9 @@ private static void updateMenuItemButton(View menuItemButton, MenuItem menuItem, buttonText.setText(menuItem.getTitle()); } buttonText.setPaddingRelative(0, 0, 0, 0); + + final boolean premium = containsPremium && premiumOptions.contains(menuItem.getItemId()); + viewGroup.getChildAt(2).setVisibility(premium ? View.VISIBLE : View.GONE); /*final CharSequence contentDescription = menuItem.getContentDescription(); TODO if (TextUtils.isEmpty(contentDescription)) { menuItemButton.setContentDescription(menuItem.getTitle()); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java index 6b67ebb38be..70c02ca0a09 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java @@ -161,8 +161,8 @@ protected void onDetachedFromWindow() { wasLayout = false; } - public void setTextSize(int size) { - int newSize = AndroidUtilities.dp(size); + public void setTextSize(int sizeInDp) { + int newSize = AndroidUtilities.dp(sizeInDp); if (newSize == textPaint.getTextSize()) { return; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java index 3ee0b432ed2..b932f502af6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java @@ -4015,6 +4015,13 @@ public void run() { public static final int key_topics_unreadCounter = colorsCount++; public static final int key_topics_unreadCounterMuted = colorsCount++; + public static final int key_stories_circle1 = colorsCount++; + public static final int key_stories_circle2 = colorsCount++; + public static final int key_stories_circle_dialog1 = colorsCount++; + public static final int key_stories_circle_dialog2 = colorsCount++; + public static final int key_stories_circle_closeFriends1 = colorsCount++; + public static final int key_stories_circle_closeFriends2 = colorsCount++; + public static final String key_drawable_botInline = "drawableBotInline"; public static final String key_drawable_botLink = "drawableBotLink"; public static final String key_drawable_botWebView = "drawableBotWebView"; @@ -4357,6 +4364,13 @@ public void run() { themeAccentExclusionKeys.add(key_premiumStartSmallStarsColor); themeAccentExclusionKeys.add(key_premiumStartGradient1); themeAccentExclusionKeys.add(key_premiumStartGradient2); + themeAccentExclusionKeys.add(key_stories_circle1); + themeAccentExclusionKeys.add(key_stories_circle2); + themeAccentExclusionKeys.add(key_stories_circle_dialog1); + themeAccentExclusionKeys.add(key_stories_circle_dialog2); + themeAccentExclusionKeys.add(key_stories_circle_closeFriends1); + themeAccentExclusionKeys.add(key_stories_circle_closeFriends2); + themes = new ArrayList<>(); otherThemes = new ArrayList<>(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java index 8e2f8b31117..d8ab63133d4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeColors.java @@ -760,6 +760,13 @@ public static int[] createDefaultColors() { defaultColors[key_topics_unreadCounter] = 0xff4ecc5e; defaultColors[key_topics_unreadCounterMuted] = 0xff8b8d8f; + defaultColors[key_stories_circle1] = 0xFF39DF3C; + defaultColors[key_stories_circle2] = 0xFF4DBBFF; + defaultColors[key_stories_circle_dialog1] = 0xFF4AED55; + defaultColors[key_stories_circle_dialog2] = 0xFF4DC3FF; + defaultColors[key_stories_circle_closeFriends1] = 0xFFC9EB38; + defaultColors[key_stories_circle_closeFriends2] = 0xFF09C167; + return defaultColors; } @@ -1481,6 +1488,12 @@ public static SparseArray createColorKeysMap() { colorKeysMap.put(key_premiumGradientBottomSheet3, "premiumGradientBottomSheet3"); colorKeysMap.put(key_topics_unreadCounter, "topics_unreadCounter"); colorKeysMap.put(key_topics_unreadCounterMuted, "topics_unreadCounterMuted"); + colorKeysMap.put(key_stories_circle1, "stories_circle1"); + colorKeysMap.put(key_stories_circle2, "stories_circle2"); + colorKeysMap.put(key_stories_circle_dialog1, "stories_circle_dialog1"); + colorKeysMap.put(key_stories_circle_dialog2, "stories_circle_dialog2"); + colorKeysMap.put(key_stories_circle_closeFriends1, "stories_circle_closeFriends1"); + colorKeysMap.put(key_stories_circle_closeFriends2, "stories_circle_closeFriends2"); return colorKeysMap; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionIntroActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionIntroActivity.java index 24ca40293f6..b8cddf34b04 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionIntroActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionIntroActivity.java @@ -775,7 +775,7 @@ protected void onDraw(Canvas canvas) { } @Override - public void onLocationAddressAvailable(String address, String displayAddress, Location location) { + public void onLocationAddressAvailable(String address, String displayAddress, TLRPC.TL_messageMediaVenue city, TLRPC.TL_messageMediaVenue street, Location location) { if (subtitleTextView == null) { return; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseLocationAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseLocationAdapter.java index 7ca2aa577b2..9d2835a5f11 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseLocationAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseLocationAdapter.java @@ -8,13 +8,20 @@ package org.telegram.ui.Adapters; +import android.location.Address; +import android.location.Geocoder; import android.location.Location; import android.os.Build; +import android.text.TextUtils; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.DialogObject; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.LocationController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.tgnet.ConnectionsManager; @@ -23,17 +30,27 @@ import org.telegram.ui.Components.RecyclerListView; import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; public abstract class BaseLocationAdapter extends RecyclerListView.SelectionAdapter { + public final boolean stories; + + public BaseLocationAdapter(boolean stories) { + this.stories = stories; + } + public interface BaseLocationAdapterDelegate { void didLoadSearchResult(ArrayList places); } protected boolean searched = false; protected boolean searching; + protected boolean searchingLocations; + protected ArrayList locations = new ArrayList<>(); protected ArrayList places = new ArrayList<>(); - protected ArrayList iconUrls = new ArrayList<>(); private Location lastSearchLocation; private String lastSearchQuery; private String lastFoundQuery; @@ -43,7 +60,7 @@ public interface BaseLocationAdapterDelegate { private int currentAccount = UserConfig.selectedAccount; private long dialogId; private boolean searchingUser; - private boolean searchInProgress; + protected boolean searchInProgress; public void destroy() { if (currentRequestNum != 0) { @@ -60,6 +77,7 @@ public void setDelegate(long did, BaseLocationAdapterDelegate delegate) { public void searchDelayed(final String query, final Location coordinate) { if (query == null || query.length() == 0) { places.clear(); + locations.clear(); searchInProgress = false; notifyDataSetChanged(); } else { @@ -82,7 +100,9 @@ private void searchBotUser() { } searchingUser = true; TLRPC.TL_contacts_resolveUsername req = new TLRPC.TL_contacts_resolveUsername(); - req.username = MessagesController.getInstance(currentAccount).venueSearchBot; + req.username = stories ? + MessagesController.getInstance(currentAccount).venueSearchBot : // MessagesController.getInstance(currentAccount).storyVenueSearchBot : + MessagesController.getInstance(currentAccount).venueSearchBot; ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { if (response != null) { AndroidUtilities.runOnUIThread(() -> { @@ -118,7 +138,7 @@ protected void notifyStartSearch(boolean wasSearching, int oldItemCount, boolean notifyItemRangeRemoved(fromIndex, getItemCount() - fromIndex); } } else { - int placesCount = places.size() + 3; + int placesCount = 3 + places.size() + locations.size(); int offset = oldItemCount - placesCount; notifyItemInserted(offset); notifyItemRangeRemoved(offset, placesCount); @@ -129,10 +149,10 @@ protected void notifyStartSearch(boolean wasSearching, int oldItemCount, boolean } public void searchPlacesWithQuery(final String query, final Location coordinate, boolean searchUser, boolean animated) { - if (coordinate == null || lastSearchLocation != null && coordinate.distanceTo(lastSearchLocation) < 200) { + if (coordinate == null && !stories || lastSearchLocation != null && coordinate != null && coordinate.distanceTo(lastSearchLocation) < 200) { return; } - lastSearchLocation = new Location(coordinate); + lastSearchLocation = coordinate == null ? null : new Location(coordinate); lastSearchQuery = query; if (searching) { searching = false; @@ -147,7 +167,11 @@ public void searchPlacesWithQuery(final String query, final Location coordinate, boolean wasSearched = searched; searched = true; - TLObject object = MessagesController.getInstance(currentAccount).getUserOrChat(MessagesController.getInstance(currentAccount).venueSearchBot); + TLObject object = MessagesController.getInstance(currentAccount).getUserOrChat( + stories ? + MessagesController.getInstance(currentAccount).venueSearchBot : // MessagesController.getInstance(currentAccount).storyVenueSearchBot : + MessagesController.getInstance(currentAccount).venueSearchBot + ); if (!(object instanceof TLRPC.User)) { if (searchUser) { searchBotUser(); @@ -161,10 +185,12 @@ public void searchPlacesWithQuery(final String query, final Location coordinate, req.bot = MessagesController.getInstance(currentAccount).getInputUser(user); req.offset = ""; - req.geo_point = new TLRPC.TL_inputGeoPoint(); - req.geo_point.lat = AndroidUtilities.fixLocationCoord(coordinate.getLatitude()); - req.geo_point._long = AndroidUtilities.fixLocationCoord(coordinate.getLongitude()); - req.flags |= 1; + if (coordinate != null) { + req.geo_point = new TLRPC.TL_inputGeoPoint(); + req.geo_point.lat = AndroidUtilities.fixLocationCoord(coordinate.getLatitude()); + req.geo_point._long = AndroidUtilities.fixLocationCoord(coordinate.getLongitude()); + req.flags |= 1; + } if (DialogObject.isEncryptedDialog(dialogId)) { req.peer = new TLRPC.TL_inputPeerEmpty(); @@ -172,12 +198,174 @@ public void searchPlacesWithQuery(final String query, final Location coordinate, req.peer = MessagesController.getInstance(currentAccount).getInputPeer(dialogId); } + if (!TextUtils.isEmpty(query) && stories) { + searchingLocations = true; + final Locale locale = LocaleController.getInstance().getCurrentLocale(); + final String finalQuery = query; + Utilities.globalQueue.postRunnable(() -> { + final ArrayList locations = new ArrayList<>(); + try { + Geocoder geocoder = new Geocoder(ApplicationLoader.applicationContext, locale); + List
addresses = geocoder.getFromLocationName(finalQuery, 5); + HashSet countries = new HashSet<>(); + HashSet cities = new HashSet<>(); + String arg, lc; + for (int i = 0; i < addresses.size(); ++i) { + Address address = addresses.get(i); + if (!address.hasLatitude() || !address.hasLongitude()) + continue; + double lat = address.getLatitude(); + double _long = address.getLongitude(); + + StringBuilder countryBuilder = new StringBuilder(); + StringBuilder cityBuilder = new StringBuilder(); + StringBuilder streetBuilder = new StringBuilder(); + boolean onlyCountry = true; + boolean onlyCity = true; + + String locality = address.getLocality(); + if (TextUtils.isEmpty(locality)) { + locality = address.getAdminArea(); + } + arg = address.getThoroughfare(); + if (!TextUtils.isEmpty(arg) && !TextUtils.equals(arg, address.getAdminArea())) { + if (streetBuilder.length() > 0) { + streetBuilder.append(", "); + } + streetBuilder.append(arg); + onlyCity = false; + } else { + arg = address.getSubLocality(); + if (!TextUtils.isEmpty(arg)) { + if (streetBuilder.length() > 0) { + streetBuilder.append(", "); + } + streetBuilder.append(arg); + onlyCity = false; + } else { + arg = address.getLocality(); + if (!TextUtils.isEmpty(arg) && !TextUtils.equals(arg, locality)) { + if (streetBuilder.length() > 0) { + streetBuilder.append(", "); + } + streetBuilder.append(arg); + onlyCity = false; + } else { + streetBuilder = null; + } + } + } + if (!TextUtils.isEmpty(locality)) { + if (cityBuilder.length() > 0) { + cityBuilder.append(", "); + } + cityBuilder.append(locality); + onlyCountry = false; + if (streetBuilder != null) { + if (streetBuilder.length() > 0) { + streetBuilder.append(", "); + } + streetBuilder.append(locality); + } + } + arg = address.getCountryName(); + if (!TextUtils.isEmpty(arg)) { + String shortCountry = arg; + if ("US".equals(address.getCountryCode()) || "AE".equals(address.getCountryCode()) || "GB".equals(address.getCountryCode()) && "en".equals(locale.getLanguage())) { + shortCountry = ""; + String[] words = arg.split(" "); + for (String word : words) { + if (word.length() > 0) + shortCountry += word.charAt(0); + } + } + if (cityBuilder.length() > 0) { + cityBuilder.append(", "); + } + cityBuilder.append(shortCountry); + if (countryBuilder.length() > 0) { + countryBuilder.append(", "); + } + countryBuilder.append(arg); + } + + if (countryBuilder.length() > 0 && !countries.contains(countryBuilder.toString())) { + TLRPC.TL_messageMediaVenue countryLocation = new TLRPC.TL_messageMediaVenue(); + countryLocation.geo = new TLRPC.TL_geoPoint(); + countryLocation.geo.lat = lat; + countryLocation.geo._long = _long; + countryLocation.query_id = -1; + countryLocation.title = countryBuilder.toString(); + countryLocation.icon = "https://ss3.4sqi.net/img/categories_v2/building/government_capitolbuilding_64.png"; + countryLocation.emoji = LocationController.countryCodeToEmoji(address.getCountryCode()); + countries.add(countryLocation.title); + countryLocation.address = LocaleController.getString("Country", R.string.Country); + locations.add(countryLocation); + if (locations.size() >= 5) { + break; + } + } + + if (!onlyCountry && !cities.contains(cityBuilder.toString())) { + TLRPC.TL_messageMediaVenue cityLocation = new TLRPC.TL_messageMediaVenue(); + cityLocation.geo = new TLRPC.TL_geoPoint(); + cityLocation.geo.lat = lat; + cityLocation.geo._long = _long; + cityLocation.query_id = -1; + cityLocation.title = cityBuilder.toString(); + cityLocation.icon = "https://ss3.4sqi.net/img/categories_v2/travel/hotel_64.png"; + cityLocation.emoji = LocationController.countryCodeToEmoji(address.getCountryCode()); + cities.add(cityLocation.title); + cityLocation.address = LocaleController.getString("PassportCity", R.string.PassportCity); + locations.add(cityLocation); + if (locations.size() >= 5) { + break; + } + } + + if (streetBuilder != null && streetBuilder.length() > 0) { + TLRPC.TL_messageMediaVenue streetLocation = new TLRPC.TL_messageMediaVenue(); + streetLocation.geo = new TLRPC.TL_geoPoint(); + streetLocation.geo.lat = lat; + streetLocation.geo._long = _long; + streetLocation.query_id = -1; + streetLocation.title = streetBuilder.toString(); + streetLocation.icon = "pin"; + streetLocation.address = onlyCity ? LocaleController.getString("PassportCity", R.string.PassportCity) : LocaleController.getString("PassportStreet1", R.string.PassportStreet1); + locations.add(streetLocation); + if (locations.size() >= 5) { + break; + } + } + } + } catch (Exception ignore) {} + AndroidUtilities.runOnUIThread(() -> { + searchingLocations = false; + if (coordinate == null) { + currentRequestNum = 0; + searching = false; + places.clear(); + searchInProgress = false; + lastFoundQuery = query; + } + BaseLocationAdapter.this.locations.clear(); + BaseLocationAdapter.this.locations.addAll(locations); + notifyDataSetChanged(); + }); + }); + } else { + searchingLocations = false; + } + + if (coordinate == null) { + return; + } + currentRequestNum = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (error == null) { currentRequestNum = 0; searching = false; places.clear(); - iconUrls.clear(); searchInProgress = false; lastFoundQuery = query; @@ -188,14 +376,16 @@ public void searchPlacesWithQuery(final String query, final Location coordinate, continue; } TLRPC.TL_botInlineMessageMediaVenue mediaVenue = (TLRPC.TL_botInlineMessageMediaVenue) result.send_message; - iconUrls.add("https://ss3.4sqi.net/img/categories_v2/" + mediaVenue.venue_type + "_64.png"); TLRPC.TL_messageMediaVenue venue = new TLRPC.TL_messageMediaVenue(); venue.geo = mediaVenue.geo; venue.address = mediaVenue.address; venue.title = mediaVenue.title; + venue.icon = "https://ss3.4sqi.net/img/categories_v2/" + mediaVenue.venue_type + "_64.png"; venue.venue_type = mediaVenue.venue_type; venue.venue_id = mediaVenue.venue_id; venue.provider = mediaVenue.provider; + venue.query_id = res.query_id; + venue.result_id = result.id; places.add(venue); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java index 1a897adb7dc..d718af337d0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java @@ -94,7 +94,7 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements VIEW_TYPE_HEADER = 7, VIEW_TYPE_SHADOW = 8, // VIEW_TYPE_ARCHIVE = 9, - VIEW_TYPE_LAST_EMPTY = 10, + VIEW_TYPE_LAST_EMPTY = 10, VIEW_TYPE_NEW_CHAT_HINT = 11, VIEW_TYPE_TEXT = 12, VIEW_TYPE_CONTACTS_FLICKER = 13, @@ -312,7 +312,7 @@ public ItemInternal(int viewTypeMeUrl, TLRPC.RecentMeUrl recentMeUrl) { public ItemInternal(int viewTypeEmpty) { super(viewTypeEmpty, true); - this.emptyType = emptyType; + this.emptyType = viewTypeEmpty; if (viewTypeEmpty == VIEW_TYPE_LAST_EMPTY) { stableId = 1; } else { @@ -728,14 +728,6 @@ protected void onTextDraw() { case VIEW_TYPE_FOLDER_UPDATE_HINT: view = new DialogsHintCell(mContext); break; - case VIEW_TYPE_TEXT: - default: { - view = new TextCell(mContext); - if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { - view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - } - break; - } case VIEW_TYPE_STORIES: { view = new View(mContext) { @Override @@ -745,6 +737,14 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { }; break; } + case VIEW_TYPE_TEXT: + default: { + view = new TextCell(mContext); + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + } + break; + } } view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, viewType == VIEW_TYPE_EMPTY || viewType == VIEW_TYPE_ARCHIVE_FULLSCREEN ? RecyclerView.LayoutParams.MATCH_PARENT : RecyclerView.LayoutParams.WRAP_CONTENT)); return new RecyclerListView.Holder(view); @@ -955,6 +955,9 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) { break; } case VIEW_TYPE_TEXT: { + if (!(holder.itemView instanceof TextCell)) { + return; + } TextCell cell = (TextCell) holder.itemView; cell.setColors(Theme.key_windowBackgroundWhiteBlueText4, Theme.key_windowBackgroundWhiteBlueText4); if (requestPeerType != null) { @@ -1107,7 +1110,7 @@ public void openHiddenStories() { } } - parentFragment.getOrCreateStoryViewer().open(mContext, null, peerIds, 0, null, null, StoriesListPlaceProvider.of(recyclerListView, true), false); + parentFragment.getOrCreateStoryViewer().open(mContext, null, peerIds, 0, null, null, StoriesListPlaceProvider.of(recyclerListView), false); } public void setIsTransitionSupport() { @@ -1307,6 +1310,8 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } else { dialogsHeight += cellHeight; } + } else if (itemInternals.get(i).viewType == VIEW_TYPE_FLICKER) { + dialogsHeight += cellHeight; } } dialogsHeight += size - 1; @@ -1480,6 +1485,7 @@ private void updateItemList() { if (dialogsCount != 0) { itemInternals.add(new ItemInternal(VIEW_TYPE_FLICKER)); } + itemInternals.add(new ItemInternal(VIEW_TYPE_LAST_EMPTY)); } else if (dialogsCount == 0) { isEmpty = true; if (requestPeerType != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivityAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivityAdapter.java index f2adcc30fb2..90af25e5345 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivityAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivityAdapter.java @@ -17,6 +17,7 @@ import android.view.ViewGroup; import android.widget.FrameLayout; +import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.LocaleController; import org.telegram.messenger.LocationController; import org.telegram.messenger.MessageObject; @@ -32,6 +33,7 @@ import org.telegram.ui.Cells.SendLocationCell; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.SharingLiveLocationCell; +import org.telegram.ui.Components.ChatAttachAlertLocationLayout; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.FlickerLoadingView; import org.telegram.ui.Components.RecyclerListView; @@ -64,25 +66,30 @@ public class LocationActivityAdapter extends BaseLocationAdapter implements Loca private Runnable updateRunnable; private final Theme.ResourcesProvider resourcesProvider; - private FlickerLoadingView globalGradientView; + public boolean animated = true; + public TLRPC.TL_messageMediaVenue city, street; + + public LocationActivityAdapter(Context context, int type, long did, boolean emptyView, Theme.ResourcesProvider resourcesProvider, boolean stories) { + super(stories); - public LocationActivityAdapter(Context context, int type, long did, boolean emptyView, Theme.ResourcesProvider resourcesProvider) { - super(); mContext = context; locationType = type; dialogId = did; needEmptyView = emptyView; this.resourcesProvider = resourcesProvider; - - globalGradientView = new FlickerLoadingView(context); - globalGradientView.setIsSingleCell(true); } private boolean myLocationDenied = false; - public void setMyLocationDenied(boolean myLocationDenied) { - if (this.myLocationDenied == myLocationDenied) + private boolean askingForMyLocation = false; + public void setMyLocationDenied(boolean myLocationDenied, boolean askingForLocation) { + if (this.myLocationDenied == myLocationDenied && this.askingForMyLocation == askingForLocation) return; this.myLocationDenied = myLocationDenied; + this.askingForMyLocation = askingForLocation; + if (askingForMyLocation) { + city = null; + street = null; + } notifyDataSetChanged(); } @@ -200,11 +207,33 @@ private String getAddressName() { } @Override - public void onLocationAddressAvailable(String address, String displayAddress, Location location) { + public void onLocationAddressAvailable(String address, String displayAddress, TLRPC.TL_messageMediaVenue city, TLRPC.TL_messageMediaVenue street, Location location) { fetchingLocation = false; previousFetchedLocation = location; addressName = address; - updateCell(); + + if (locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_STORY && askingForMyLocation) { + this.city = null; + this.street = null; + } + + boolean wasStreet = this.street != null; + if (locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_STORY) { + this.city = city; + this.street = street; + if (wasStreet == (this.street == null)) { + notifyItemChanged(1); + if (this.street == null) { + notifyItemRemoved(2); + } else { + notifyItemInserted(2); + } + } else { + notifyItemRangeChanged(1, 2); + } + } else { + updateCell(); + } } protected void onDirectionClick() { @@ -257,9 +286,21 @@ public int getItemCount() { return 2 + currentLiveLocations.size(); } else { if (searching || !searched || places.isEmpty()) { - return (locationType != LocationActivity.LOCATION_TYPE_SEND ? 6 : 5) + (!myLocationDenied && (searching || !searched) ? 2 : 0) + (needEmptyView ? 1 : 0) - (myLocationDenied ? 2 : 0); + int count = 6; + if (locationType == LocationActivity.LOCATION_TYPE_SEND) { + count = 5; + } else if (locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_STORY) { + count = 5 + (this.street != null ? 1 : 0); + } + return count + (!myLocationDenied && (searching || !searched) ? 2 : 0) + (needEmptyView ? 1 : 0) - (myLocationDenied ? 2 : 0); + } + int count = 5; + if (locationType == LocationActivity.LOCATION_TYPE_SEND_WITH_LIVE) { + count = 6; + } else if (locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_STORY) { + count = 5;// + (this.street != null ? 1 : 0); } - return (locationType == LocationActivity.LOCATION_TYPE_SEND_WITH_LIVE ? 6 : 5) + places.size() + (needEmptyView ? 1 : 0); + return count + locations.size() + places.size() + (needEmptyView ? 1 : 0); } } @@ -269,7 +310,7 @@ public int getItemCount() { public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view; switch (viewType) { - case 0: + case VIEW_TYPE_PADDING: // view = emptyCell = new EmptyCell(mContext) { // @Override // public ViewPropertyAnimator animate() { @@ -287,38 +328,38 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType view = emptyCell = new FrameLayout(mContext); emptyCell.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, overScrollHeight)); break; - case 1: + case VIEW_TYPE_SEND_LOCATION: view = new SendLocationCell(mContext, false, resourcesProvider); break; - case 2: + case VIEW_TYPE_HEADER: view = new HeaderCell(mContext, resourcesProvider); break; - case 3: + case VIEW_TYPE_LOCATION: LocationCell locationCell = new LocationCell(mContext, false, resourcesProvider); view = locationCell; break; - case 4: + case VIEW_TYPE_LOADING: view = new LocationLoadingCell(mContext, resourcesProvider); break; - case 5: + case VIEW_TYPE_FOOTER: view = new LocationPoweredCell(mContext, resourcesProvider); break; - case 6: { + case VIEW_TYPE_LIVE_LOCATION: { SendLocationCell cell = new SendLocationCell(mContext, true, resourcesProvider); cell.setDialogId(dialogId); view = cell; break; } - case 7: + case VIEW_TYPE_SHARING: view = new SharingLiveLocationCell(mContext, true, locationType == LocationActivity.LOCATION_TYPE_GROUP || locationType == LocationActivity.LOCATION_TYPE_GROUP_VIEW ? 16 : 54, resourcesProvider); break; - case 8: { + case VIEW_TYPE_DIRECTION: { LocationDirectionCell cell = new LocationDirectionCell(mContext, resourcesProvider); cell.setOnButtonClick(v -> onDirectionClick()); view = cell; break; } - case 9: { + case VIEW_TYPE_SHADOW: { view = new ShadowSectionCell(mContext); Drawable drawable = Theme.getThemedDrawableByKey(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow); CombinedDrawable combinedDrawable = new CombinedDrawable(new ColorDrawable(getThemedColor(Theme.key_windowBackgroundGray)), drawable); @@ -326,7 +367,13 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType view.setBackgroundDrawable(combinedDrawable); break; } - case 10: + case VIEW_TYPE_STORY_LOCATION: { + LocationCell locationCell2 = new LocationCell(mContext, false, resourcesProvider); + locationCell2.setAllowTextAnimation(true); + view = locationCell2; + break; + } + case VIEW_TYPE_EMPTY: default: { view = new View(mContext); break; @@ -335,10 +382,23 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType return new RecyclerListView.Holder(view); } + public static final int VIEW_TYPE_PADDING = 0; + public static final int VIEW_TYPE_SEND_LOCATION = 1; + public static final int VIEW_TYPE_HEADER = 2; + public static final int VIEW_TYPE_LOCATION = 3; + public static final int VIEW_TYPE_LOADING = 4; + public static final int VIEW_TYPE_FOOTER = 5; + public static final int VIEW_TYPE_LIVE_LOCATION = 6; + public static final int VIEW_TYPE_SHARING = 7; + public static final int VIEW_TYPE_DIRECTION = 8; + public static final int VIEW_TYPE_SHADOW = 9; + public static final int VIEW_TYPE_EMPTY = 10; + public static final int VIEW_TYPE_STORY_LOCATION = 11; + @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { - case 0: + case VIEW_TYPE_PADDING: RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) holder.itemView.getLayoutParams(); if (lp == null) { lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, overScrollHeight); @@ -347,11 +407,11 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } holder.itemView.setLayoutParams(lp); break; - case 1: + case VIEW_TYPE_SEND_LOCATION: sendLocationCell = (SendLocationCell) holder.itemView; updateCell(); break; - case 2: { + case VIEW_TYPE_HEADER: { HeaderCell cell = (HeaderCell) holder.itemView; if (currentMessageObject != null) { cell.setText(LocaleController.getString("LiveLocations", R.string.LiveLocations)); @@ -360,25 +420,43 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } break; } - case 3: { + case VIEW_TYPE_LOCATION: { LocationCell cell = (LocationCell) holder.itemView; + if (locationType == 0) { position -= 4; + } else if (locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_STORY) { + position -= 4; + if (this.street != null) { + position--; + } } else { position -= 5; } - TLRPC.TL_messageMediaVenue place = position < 0 || position >= places.size() || !searched ? null : places.get(position); - String iconUrl = position < 0 || position >= iconUrls.size() || !searched ? null : iconUrls.get(position); - cell.setLocation(place, iconUrl, position, true); + boolean shouldHave = searched && (locationType != ChatAttachAlertLocationLayout.LOCATION_TYPE_STORY || !searching); + TLRPC.TL_messageMediaVenue place = null; + int p = position; + if (shouldHave) { + if (position >= 0 && position < locations.size()) { + place = locations.get(position); + p = 2; + } else { + position -= locations.size(); + if (position >= 0 && position < places.size()) { + place = places.get(position); + } + } + } + cell.setLocation(place, p, true); break; } - case 4: + case VIEW_TYPE_LOADING: ((LocationLoadingCell) holder.itemView).setLoading(searching); break; - case 6: + case VIEW_TYPE_LIVE_LOCATION: ((SendLocationCell) holder.itemView).setHasLocation(gpsLocation != null); break; - case 7: + case VIEW_TYPE_SHARING: SharingLiveLocationCell locationCell = (SharingLiveLocationCell) holder.itemView; if (locationType == LocationActivity.LOCATION_TYPE_LIVE_VIEW) { locationCell.setDialog(currentMessageObject, gpsLocation, myLocationDenied); @@ -390,9 +468,21 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { locationCell.setDialog(currentLiveLocations.get(position - (currentMessageObject != null ? 5 : 2)), gpsLocation); } break; - case 10: + case VIEW_TYPE_EMPTY: View emptyView = holder.itemView; - emptyView.setBackgroundColor(Theme.getColor(myLocationDenied ? Theme.key_dialogBackgroundGray : Theme.key_dialogBackground)); + emptyView.setBackgroundColor(Theme.getColor(myLocationDenied ? Theme.key_dialogBackgroundGray : Theme.key_dialogBackground, resourcesProvider)); + break; + case VIEW_TYPE_STORY_LOCATION: + LocationCell cell = (LocationCell) holder.itemView; + if (askingForMyLocation) { + cell.setLocation(null, 2, position == 1 && this.street != null); + } else { + if (position == 1) { + cell.setLocation(city, null, 2, this.street != null, animated); + } else { + cell.setLocation(street, null, 2, false, animated); + } + } break; } } @@ -425,10 +515,19 @@ public Object getItem(int i) { return currentLiveLocations.get(i - 2); } return null; - } else if (locationType == 1) { + } else if (locationType == LocationActivity.LOCATION_TYPE_SEND_WITH_LIVE) { if (i > 4 && i < places.size() + 5) { return places.get(i - 5); } + } else if (locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_STORY) { + int x = this.street == null ? 3 : 4; + if (i > x && i < locations.size() + (x + 1)) { + return locations.get(i - (x + 1)); + } + x += locations.size(); + if (i > x && i < places.size() + (x + 1)) { + return places.get(i - (x + 1)); + } } else { if (i > 3 && i < places.size() + 4) { return places.get(i - 4); @@ -440,87 +539,101 @@ public Object getItem(int i) { @Override public int getItemViewType(int position) { if (position == 0) { - return 0; + return VIEW_TYPE_PADDING; } if (locationType == LocationActivity.LOCATION_TYPE_LIVE_VIEW) { - return 7; + return VIEW_TYPE_SHARING; } if (needEmptyView && position == getItemCount() - 1) { - return 10; + return VIEW_TYPE_EMPTY; } if (locationType == LocationActivity.LOCATION_TYPE_GROUP_VIEW) { - return 7; + return VIEW_TYPE_SHARING; } if (locationType == LocationActivity.LOCATION_TYPE_GROUP) { - return 1; + return VIEW_TYPE_SEND_LOCATION; } if (currentMessageObject != null) { if (currentLiveLocations.isEmpty()) { if (position == 2) { - return 8; + return VIEW_TYPE_DIRECTION; } } else { if (position == 2) { - return 9; + return VIEW_TYPE_SHADOW; } else if (position == 3) { - return 2; + return VIEW_TYPE_HEADER; } else if (position == 4) { shareLiveLocationPotistion = position; - return 6; + return VIEW_TYPE_LIVE_LOCATION; } } - return 7; + return VIEW_TYPE_SHARING; } if (locationType == 2) { if (position == 1) { shareLiveLocationPotistion = position; - return 6; + return VIEW_TYPE_LIVE_LOCATION; } else { - return 7; + return VIEW_TYPE_SHARING; } } if (locationType == LocationActivity.LOCATION_TYPE_SEND_WITH_LIVE) { if (position == 1) { - return 1; + return VIEW_TYPE_SEND_LOCATION; } else if (position == 2) { shareLiveLocationPotistion = position; - return 6; + return VIEW_TYPE_LIVE_LOCATION; } else if (position == 3) { - return 9; + return VIEW_TYPE_SHADOW; } else if (position == 4) { - return 2; + return VIEW_TYPE_HEADER; } else if (searching || places.isEmpty() || !searched) { if (position <= 4 + 3 && (searching || !searched) && !myLocationDenied) - return 3; - return 4; + return VIEW_TYPE_LOCATION; + return VIEW_TYPE_LOADING; } else if (position == places.size() + 5) { - return 5; + return VIEW_TYPE_FOOTER; } } else { + int i = 4; + int placesCount = places.size() + locations.size(); + if (locationType == ChatAttachAlertLocationLayout.LOCATION_TYPE_STORY) { + if (position == 1) { + return VIEW_TYPE_STORY_LOCATION; + } + if (this.street != null) { + if (position == 2) { + return VIEW_TYPE_STORY_LOCATION; + } + position--; + i--; + } + } if (position == 1) { - return 1; + return VIEW_TYPE_SEND_LOCATION; } else if (position == 2) { - return 9; + return VIEW_TYPE_SHADOW; } else if (position == 3) { - return 2; - } else if (searching || places.isEmpty()) { + return VIEW_TYPE_HEADER; + } else if (searching || places.isEmpty() && locations.isEmpty()) { if (position <= 3 + 3 && (searching || !searched) && !myLocationDenied) - return 3; - return 4; - } else if (position == places.size() + 4) { - return 5; + return VIEW_TYPE_LOCATION; + return VIEW_TYPE_LOADING; + } else if (position == placesCount + i) { + return VIEW_TYPE_FOOTER; } } - return 3; + return VIEW_TYPE_LOCATION; } @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { int viewType = holder.getItemViewType(); - if (viewType == 6) { + if (viewType == VIEW_TYPE_LIVE_LOCATION) { return !(LocationController.getInstance(currentAccount).getSharingLocationInfo(dialogId) == null && gpsLocation == null); } - return viewType == 1 || viewType == 3 || viewType == 7; + return viewType == VIEW_TYPE_SEND_LOCATION || viewType == VIEW_TYPE_LOCATION || viewType == VIEW_TYPE_SHARING || viewType == VIEW_TYPE_STORY_LOCATION; } private int getThemedColor(int key) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivitySearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivitySearchAdapter.java index 81083b49be9..fcf362dfa43 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivitySearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivitySearchAdapter.java @@ -9,9 +9,14 @@ package org.telegram.ui.Adapters; import android.content.Context; +import android.view.View; import android.view.ViewGroup; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.GraySectionCell; import org.telegram.ui.Cells.LocationCell; import org.telegram.ui.Components.FlickerLoadingView; import org.telegram.ui.Components.RecyclerListView; @@ -20,12 +25,25 @@ public class LocationActivitySearchAdapter extends BaseLocationAdapter { + private static final int VIEW_TYPE_LOCATION = 0; + private static final int VIEW_TYPE_SECTION = 1; + private Context mContext; + private Theme.ResourcesProvider resourcesProvider; + + private boolean myLocationDenied = false; + public void setMyLocationDenied(boolean myLocationDenied) { + if (this.myLocationDenied == myLocationDenied) + return; + this.myLocationDenied = myLocationDenied; + } private FlickerLoadingView globalGradientView; - public LocationActivitySearchAdapter(Context context) { - super(); + public LocationActivitySearchAdapter(Context context, Theme.ResourcesProvider resourcesProvider, boolean stories) { + super(stories); + mContext = context; + this.resourcesProvider = resourcesProvider; globalGradientView = new FlickerLoadingView(context); globalGradientView.setIsSingleCell(true); @@ -33,31 +51,93 @@ public LocationActivitySearchAdapter(Context context) { @Override public int getItemCount() { - return (isSearching() ? 3 : places.size()); + int count = 0; + if (!locations.isEmpty()) { + count += 1 + locations.size(); + } + if (!myLocationDenied) { + if (isSearching()) { + count += 3; + } else { + if (!locations.isEmpty() && !places.isEmpty()) { + count++; + } + count += places.size(); + } + } + return count; } - public boolean isEmpty() { return places.size() == 0; } + public boolean isEmpty() { return places.size() == 0 && locations.size() == 0; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - LocationCell locationCell = new LocationCell(mContext, false, null); - return new RecyclerListView.Holder(locationCell); + View view; + if (viewType == VIEW_TYPE_LOCATION) { + view = new LocationCell(mContext, false, resourcesProvider); + } else { + view = new GraySectionCell(mContext, resourcesProvider); + } + return new RecyclerListView.Holder(view); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - TLRPC.TL_messageMediaVenue place = getItem(position); - String iconUrl = !isSearching() && position >= 0 && position < iconUrls.size() ? iconUrls.get(position) : null; + if (holder.getItemViewType() == VIEW_TYPE_LOCATION) { + TLRPC.TL_messageMediaVenue place = null; + String iconUrl = null; + int oposition = position; + int p = position; + if (!locations.isEmpty()) { + position--; + } + if (position >= 0 && position < locations.size()) { + place = locations.get(position); + iconUrl = "pin"; + p = 2; + } else if (!isSearching()) { + position -= locations.size(); + if (!searchingLocations && !locations.isEmpty()) { + position -= 1; + } + if (position >= 0 && position < places.size()) { + place = places.get(position); + p = position; + } + } + LocationCell locationCell = (LocationCell) holder.itemView; + locationCell.setLocation(place, p, oposition != getItemCount() - 1 && (searchingLocations || locations.isEmpty() || oposition != (locations.size()))); + } else if (holder.getItemViewType() == VIEW_TYPE_SECTION) { + if (position == 0 && !locations.isEmpty()) { + ((GraySectionCell) holder.itemView).setText(LocaleController.getString("LocationOnMap", R.string.LocationOnMap)); + } else { + ((GraySectionCell) holder.itemView).setText(LocaleController.getString("NearbyVenue", R.string.NearbyVenue)); + } + } + } - LocationCell locationCell = (LocationCell) holder.itemView; - locationCell.setLocation(place, iconUrl, position, position != getItemCount() - 1); + @Override + public int getItemViewType(int position) { + if ((position == 0 || position == (1 + locations.size())) && !locations.isEmpty()) { + return VIEW_TYPE_SECTION; + } + return VIEW_TYPE_LOCATION; } - public TLRPC.TL_messageMediaVenue getItem(int i) { - if (isSearching()) - return null; - if (i >= 0 && i < places.size()) { - return places.get(i); + public TLRPC.TL_messageMediaVenue getItem(int position) { + if (!locations.isEmpty()) { + position--; + } + if (position >= 0 && position < locations.size()) { + return locations.get(position); + } else if (!isSearching()) { + position -= locations.size(); + if (!locations.isEmpty()) { + position -= 1; + } + if (position >= 0 && position < places.size()) { + return places.get(position); + } } return null; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java index e6d92221402..5049357640e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java @@ -4680,6 +4680,7 @@ private void onClosed() { FileLog.e(e); } }); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.articleClosed); } private void loadChannel(final BlockChannelCell cell, WebpageAdapter adapter, TLRPC.Chat channel) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/BasePermissionsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/BasePermissionsActivity.java index 36307bbfe49..c9183971b0b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/BasePermissionsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/BasePermissionsActivity.java @@ -31,7 +31,8 @@ public class BasePermissionsActivity extends Activity { REQUEST_CODE_VIDEO_MESSAGE = 150, REQUEST_CODE_EXTERNAL_STORAGE_FOR_AVATAR = 151, REQUEST_CODE_SIGN_IN_WITH_GOOGLE = 200, - REQUEST_CODE_PAYMENT_FORM = 210; + REQUEST_CODE_PAYMENT_FORM = 210, + REQUEST_CODE_MEDIA_GEO = 211; protected int currentAccount = -1; @@ -95,6 +96,8 @@ protected boolean checkPermissionsResult(int requestCode, String[] permissions, } } else if (requestCode == REQUEST_CODE_GEOLOCATION) { NotificationCenter.getGlobalInstance().postNotificationName(granted ? NotificationCenter.locationPermissionGranted : NotificationCenter.locationPermissionDenied); + } else if (requestCode == REQUEST_CODE_MEDIA_GEO) { + NotificationCenter.getGlobalInstance().postNotificationName(granted ? NotificationCenter.locationPermissionGranted : NotificationCenter.locationPermissionDenied, 1); } return true; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java index 83af78d8e6e..bdb9b620a29 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java @@ -2595,7 +2595,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else { selected = CacheControlActivity.this.selected[item.index]; } - cell.setText(getCheckBoxTitle(item.headerName, percents[item.index < 0 ? 8 : item.index], item.index < 0), AndroidUtilities.formatFileSize(item.size), selected, item.index < 0 ? !collapsed : !item.last); + cell.setText(getCheckBoxTitle(item.headerName, percents[item.index < 0 ? 9 : item.index], item.index < 0), AndroidUtilities.formatFileSize(item.size), selected, item.index < 0 ? !collapsed : !item.last); cell.setCheckBoxColor(item.colorKey, Theme.key_windowBackgroundWhiteGrayIcon, Theme.key_checkboxCheck); cell.setCollapsed(item.index < 0 ? collapsed : null); if (item.index == -1) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CameraScanActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CameraScanActivity.java index 676458d93d9..69f471c5f4f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CameraScanActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CameraScanActivity.java @@ -648,9 +648,15 @@ protected void onDraw(Canvas canvas) { if (getParentActivity() == null) { return; } - if (Build.VERSION.SDK_INT >= 23) { - if (getParentActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - getParentActivity().requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE); + final Activity activity = getParentActivity(); + if (Build.VERSION.SDK_INT >= 33) { + if (activity.checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) { + activity.requestPermissions(new String[]{Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VIDEO}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE); + return; + } + } else if (Build.VERSION.SDK_INT >= 23) { + if (activity.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + activity.requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE); return; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java index 8d2a8be2ae7..7ebed445cfe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -1119,13 +1119,13 @@ class LoadingDrawableLocation { private boolean drawName; private boolean drawNameLayout; - private StaticLayout[] forwardedNameLayout = new StaticLayout[2]; + private final StaticLayout[] forwardedNameLayout = new StaticLayout[2]; private int forwardedNameWidth; private boolean drawForwardedName; private float forwardNameX; private int forwardNameY; private int forwardHeight; - private float[] forwardNameOffsetX = new float[2]; + private final float[] forwardNameOffsetX = new float[2]; private float drawTimeX; private float drawTimeY; @@ -1292,11 +1292,11 @@ public void run() { // Public for enter transition public List replySpoilers = new ArrayList<>(); - private Stack replySpoilersPool = new Stack<>(); - private List captionSpoilers = new ArrayList<>(); - private Stack captionSpoilersPool = new Stack<>(); - private AtomicReference captionPatchedSpoilersLayout = new AtomicReference<>(); - private Path sPath = new Path(); + private final Stack replySpoilersPool = new Stack<>(); + private final List captionSpoilers = new ArrayList<>(); + private final Stack captionSpoilersPool = new Stack<>(); + private final AtomicReference captionPatchedSpoilersLayout = new AtomicReference<>(); + private final Path sPath = new Path(); public boolean isBlurred; public ChatMessageCell(Context context) { @@ -7467,7 +7467,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe photoHeight += AndroidUtilities.dp(1); } } else if (currentPosition != null && currentMessageObject.isDocument()) { - if ((currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && !messageObject.isOutOwner()) { + if ((currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && !messageObject.isOutOwner() && !drawPhotoImage) { totalHeight -= AndroidUtilities.dp(2); } } @@ -12721,7 +12721,11 @@ private void setMessageObjectInternal(MessageObject messageObject) { } else { currentNameString = ""; } - CharSequence nameStringFinal = TextUtils.ellipsize(currentNameString.replace('\n', ' ').replace('\u200F', ' '), Theme.chat_namePaint, nameWidth - (viaBot ? viaWidth : 0), TextUtils.TruncateAt.END); + CharSequence nameStringFinal = currentNameString.replace('\n', ' ').replace('\u200F', ' '); + try { + nameStringFinal = Emoji.replaceEmoji(nameStringFinal, Theme.chat_namePaint.getFontMetricsInt(), AndroidUtilities.dp(14), false); + } catch (Exception ignore) {} + nameStringFinal = TextUtils.ellipsize(nameStringFinal, Theme.chat_namePaint, nameWidth - (viaBot ? viaWidth : 0), TextUtils.TruncateAt.END); if (viaBot) { viaNameWidth = (int) Math.ceil(Theme.chat_namePaint.measureText(nameStringFinal, 0, nameStringFinal.length())); if (viaNameWidth != 0) { @@ -12747,10 +12751,6 @@ private void setMessageObjectInternal(MessageObject messageObject) { } nameStringFinal = TextUtils.ellipsize(nameStringFinal, Theme.chat_namePaint, nameWidth, TextUtils.TruncateAt.END); } - try { - nameStringFinal = Emoji.replaceEmoji(nameStringFinal, Theme.chat_namePaint.getFontMetricsInt(), AndroidUtilities.dp(14), false); - } catch (Exception ignore) { - } try { nameLayout = new StaticLayout(nameStringFinal, Theme.chat_namePaint, nameWidth + AndroidUtilities.dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (nameLayout.getLineCount() > 0) { @@ -13909,7 +13909,7 @@ public void drawBackgroundInternal(Canvas canvas, boolean fromParent) { if (isDrawSelectionBackground() && (currentPosition == null || currentMessageObject.isMusic() || currentMessageObject.isDocument() || getBackground() != null)) { if (currentPosition != null) { canvas.save(); -// canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight()); + canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight()); } currentSelectedBackgroundAlpha = 1f; currentBackgroundSelectedDrawable.setAlpha((int) (255 * alphaInternal)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ContextLinkCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ContextLinkCell.java index d78c3ae948c..2cfc4a9f72f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ContextLinkCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ContextLinkCell.java @@ -47,8 +47,11 @@ import org.telegram.messenger.Utilities; import org.telegram.messenger.WebFile; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.AnimationProperties; +import org.telegram.ui.Components.ButtonBounce; import org.telegram.ui.Components.CheckBox2; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LetterDrawable; import org.telegram.ui.ActionBar.Theme; @@ -119,9 +122,7 @@ public interface ContextLinkCellDelegate { private int buttonState; private RadialProgress2 radialProgress; - private long lastUpdateTime; private boolean scaled; - private float scale; private static AccelerateInterpolator interpolator = new AccelerateInterpolator(0.5f); private boolean hideLoadProgress; @@ -130,6 +131,8 @@ public interface ContextLinkCellDelegate { private ContextLinkCellDelegate delegate; + private ButtonBounce buttonBounce; + public ContextLinkCell(Context context) { this(context, false, null); } @@ -165,6 +168,12 @@ public ContextLinkCell(Context context, boolean needsCheckBox, Theme.ResourcesPr setWillNotDraw(false); } + public void allowButtonBounce(boolean allow) { + if (allow != (buttonBounce != null)) { + buttonBounce = allow ? new ButtonBounce(this, 1f, 3f).setReleaseDelay(120L) : null; + } + } + @SuppressLint("DrawAllocation") @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @@ -591,8 +600,9 @@ public ImageReceiver getPhotoImage() { public void setScaled(boolean value) { scaled = value; - lastUpdateTime = System.currentTimeMillis(); - invalidate(); + if (buttonBounce != null) { + buttonBounce.setPressed(isPressed() || scaled); + } } public void setCanPreviewGif(boolean value) { @@ -816,24 +826,11 @@ protected void onDraw(Canvas canvas) { linkImageView.setVisible(!PhotoViewer.isShowingImage(inlineResult), false); } canvas.save(); - if (scaled && scale != 0.8f || !scaled && scale != 1.0f) { - long newTime = System.currentTimeMillis(); - long dt = (newTime - lastUpdateTime); - lastUpdateTime = newTime; - if (scaled && scale != 0.8f) { - scale -= dt / 400.0f; - if (scale < 0.8f) { - scale = 0.8f; - } - } else { - scale += dt / 400.0f; - if (scale > 1.0f) { - scale = 1.0f; - } - } - invalidate(); + float s = imageScale; + if (buttonBounce != null) { + s *= buttonBounce.getScale(.1f); } - canvas.scale(scale * imageScale, scale * imageScale, getMeasuredWidth() / 2, getMeasuredHeight() / 2); + canvas.scale(s, s, getMeasuredWidth() / 2, getMeasuredHeight() / 2); linkImageView.draw(canvas); canvas.restore(); } @@ -1148,4 +1145,12 @@ public void onAnimationCancel(Animator animation) { invalidate(); } } + + @Override + public void setPressed(boolean pressed) { + super.setPressed(pressed); + if (buttonBounce != null) { + buttonBounce.setPressed(pressed || scaled); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java index eea62e77c97..211d1173221 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -188,6 +188,7 @@ public void onLongPress() { private Path thumbPath; private SpoilerEffect thumbSpoiler = new SpoilerEffect(); + private boolean drawForwardIcon; public void setMoving(boolean moving) { this.moving = moving; @@ -951,6 +952,7 @@ public void buildLayout() { drawNameLock = false; drawVerified = false; drawPremium = false; + drawForwardIcon = false; drawScam = 0; drawPinBackground = false; thumbsCount = 0; @@ -1577,6 +1579,15 @@ public void buildLayout() { } } } + if (message.isForwarded()) { + drawForwardIcon = true; + SpannableStringBuilder builder = SpannableStringBuilder.valueOf(messageString); + builder.insert(0, "d "); + ColoredImageSpan coloredImageSpan = new ColoredImageSpan(ContextCompat.getDrawable(getContext(), R.drawable.mini_forwarded).mutate()); + coloredImageSpan.setAlpha(0.9f); + builder.setSpan(coloredImageSpan, 0, 1, 0); + messageString = builder; + } } } if (currentDialogFolderId != 0) { @@ -2355,7 +2366,7 @@ private void updateThumbsPosition() { float x1 = layout.getPrimaryHorizontal(spanOffset); float x2 = layout.getPrimaryHorizontal(spanOffset + 1); int offset = (int) Math.ceil(Math.min(x1, x2)); - if (offset != 0) { + if (offset != 0 && !drawForwardIcon) { offset += AndroidUtilities.dp(3); } for (int i = 0; i < thumbsCount; ++i) { @@ -3829,9 +3840,9 @@ protected void onDraw(Canvas canvas) { } else { drawCounterMuted = chat != null && chat.forum && forumTopic == null ? !hasUnmutedTopics : dialogMuted; } - int countLeftLocal = (int) (storyParams.originalAvatarRect.left + avatarImage.getImageWidth() - countWidth - AndroidUtilities.dp(5f)); - int countLeftOld = (int) (storyParams.originalAvatarRect.left + avatarImage.getImageWidth() - countWidthOld - AndroidUtilities.dp(5f)); - int countTop = (int) (avatarImage.getImageY() + avatarImage.getImageHeight() - AndroidUtilities.dp(22)); + int countLeftLocal = (int) (storyParams.originalAvatarRect.left + storyParams.originalAvatarRect.width() - countWidth - AndroidUtilities.dp(5f)); + int countLeftOld = (int) (storyParams.originalAvatarRect.left + storyParams.originalAvatarRect.width() - countWidthOld - AndroidUtilities.dp(5f)); + int countTop = (int) (avatarImage.getImageY() + storyParams.originalAvatarRect.height() - AndroidUtilities.dp(22)); drawCounter(canvas, drawCounterMuted, countTop, countLeftLocal, countLeftOld, rightFragmentOpenedProgress, true); } @@ -4884,7 +4895,7 @@ public SpannableStringBuilder getMessageStringFormatted(String messageFormat, St @Override public boolean onInterceptTouchEvent(MotionEvent ev) { - if (rightFragmentOpenedProgress == 0 && storyParams.checkOnTouchEvent(ev, this)) { + if (rightFragmentOpenedProgress == 0 && !isTopic && storyParams.checkOnTouchEvent(ev, this)) { return true; } return super.onInterceptTouchEvent(ev); @@ -4892,7 +4903,7 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { @Override public boolean dispatchTouchEvent(MotionEvent ev) { - if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) { + if (!isTopic && ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) { storyParams.checkOnTouchEvent(ev, this); } return super.dispatchTouchEvent(ev); @@ -4900,7 +4911,7 @@ public boolean dispatchTouchEvent(MotionEvent ev) { @Override public boolean onTouchEvent(MotionEvent event) { - if (rightFragmentOpenedProgress == 0 && storyParams.checkOnTouchEvent(event, this)) { + if (rightFragmentOpenedProgress == 0 && !isTopic && storyParams.checkOnTouchEvent(event, this)) { return true; } if (delegate == null || delegate.canClickButtonInside()) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java index 9873e8a90f2..f18798daec5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java @@ -50,23 +50,13 @@ public DrawerActionCell(Context context) { textView.setTextColor(Theme.getColor(Theme.key_chats_menuItemText)); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - textView.setGravity(Gravity.CENTER_VERTICAL); - toggleRTL(true); + textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT); + addView(imageView, LayoutHelper.createFrame(24, 24, Gravity.LEFT | Gravity.TOP, 19, 12, 0, 0)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 72, 0, 16, 0)); setWillNotDraw(false); } - private boolean wasRTL; - - public void toggleRTL(boolean force) { - if (wasRTL != LocaleController.isRTL || force) { - wasRTL = LocaleController.isRTL; - removeAllViews(); - addView(imageView, LayoutHelper.createFrame(24, 24, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 19, 12, LocaleController.isRTL ? 19 : 0, 0)); - addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 16 : 72, 0, LocaleController.isRTL ? 72 : 16, 0)); - } - } - @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); @@ -76,7 +66,7 @@ protected void onDraw(Canvas canvas) { if (suggestions.contains("VALIDATE_PHONE_NUMBER") || suggestions.contains("VALIDATE_PASSWORD")) { int countTop = AndroidUtilities.dp(12.5f); int countWidth = AndroidUtilities.dp(9); - int countLeft = LocaleController.isRTL ? countWidth + AndroidUtilities.dp(25) : getMeasuredWidth() - countWidth - AndroidUtilities.dp(25); + int countLeft = getMeasuredWidth() - countWidth - AndroidUtilities.dp(25); int x = countLeft - AndroidUtilities.dp(5.5f); rect.set(x, countTop, x + countWidth + AndroidUtilities.dp(14), countTop + AndroidUtilities.dp(23)); @@ -103,7 +93,6 @@ protected void onAttachedToWindow() { } public void setTextAndIcon(int id, String text, int resId) { - toggleRTL(false); currentId = id; try { textView.setText(text); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/LocationCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/LocationCell.java index e903a569e25..dc392ca5313 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/LocationCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/LocationCell.java @@ -14,6 +14,10 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.graphics.drawable.ShapeDrawable; import android.os.SystemClock; import android.text.TextUtils; @@ -24,18 +28,26 @@ import android.widget.FrameLayout; import android.widget.TextView; +import androidx.core.graphics.ColorUtils; + import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Emoji; import org.telegram.messenger.LocaleController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AnimatedTextView; import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.CombinedDrawable; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.FlickerLoadingView; import org.telegram.ui.Components.LayoutHelper; public class LocationCell extends FrameLayout { - private TextView nameTextView; - private TextView addressTextView; + private AnimatedTextView nameTextView; + private AnimatedTextView addressTextView; private BackupImageView imageView; private ShapeDrawable circleDrawable; private boolean needDivider; @@ -52,24 +64,24 @@ public LocationCell(Context context, boolean wrap, Theme.ResourcesProvider resou imageView.setSize(AndroidUtilities.dp(30), AndroidUtilities.dp(30)); addView(imageView, LayoutHelper.createFrame(42, 42, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 0 : 15, 11, LocaleController.isRTL ? 15 : 0, 0)); - nameTextView = new TextView(context); - nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - nameTextView.setMaxLines(1); - nameTextView.setEllipsize(TextUtils.TruncateAt.END); - nameTextView.setSingleLine(true); + nameTextView = new AnimatedTextView(context, true, true, true); + nameTextView.setAnimationProperties(0.4f, 0, 240, CubicBezierInterpolator.EASE_OUT_QUINT); + nameTextView.setTextSize(AndroidUtilities.dp(16)); + nameTextView.setEllipsizeByGradient(true); nameTextView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); nameTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); nameTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); - addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), (LocaleController.isRTL ? 16 : 73), 10, (LocaleController.isRTL ? 73 : 16), 0)); - - addressTextView = new TextView(context); - addressTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - addressTextView.setMaxLines(1); - addressTextView.setEllipsize(TextUtils.TruncateAt.END); - addressTextView.setSingleLine(true); + nameTextView.getDrawable().setOverrideFullWidth(AndroidUtilities.displaySize.x); + NotificationCenter.listenEmojiLoading(nameTextView); + addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 22, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), (LocaleController.isRTL ? 16 : 73), 10, (LocaleController.isRTL ? 73 : 16), 0)); + + addressTextView = new AnimatedTextView(context, true, true, true); + addressTextView.setAnimationProperties(0.4f, 0, 240, CubicBezierInterpolator.EASE_OUT_QUINT); + addressTextView.setTextSize(AndroidUtilities.dp(14)); + addressTextView.setEllipsizeByGradient(true); addressTextView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText3)); addressTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); - addView(addressTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), (LocaleController.isRTL ? 16 : 73), 35, (LocaleController.isRTL ? 73 : 16), 0)); + addView(addressTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 20, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), (LocaleController.isRTL ? 16 : 73), 35, (LocaleController.isRTL ? 73 : 16), 0)); imageView.setAlpha(enterAlpha); nameTextView.setAlpha(enterAlpha); @@ -89,8 +101,13 @@ public BackupImageView getImageView() { return imageView; } - public void setLocation(TLRPC.TL_messageMediaVenue location, String icon, int pos, boolean divider) { - setLocation(location, icon, null, pos, divider); + public void setLocation(TLRPC.TL_messageMediaVenue location, int pos, boolean divider) { + setLocation(location, null, pos, divider, false); + } + + private boolean allowTextAnimation; + public void setAllowTextAnimation(boolean allow) { + allowTextAnimation = allow; } public static int getColorForIndex(int index) { @@ -113,20 +130,51 @@ public static int getColorForIndex(int index) { } } + private CharSequence lastCompleteTitle; + private String lastEmoji, lastTitle; + private CharSequence getTitle(TLRPC.TL_messageMediaVenue location) { + if (location == null) { + return ""; + } + if (TextUtils.equals(lastEmoji, location.emoji) && TextUtils.equals(lastTitle, location.title)) { + return lastCompleteTitle; + } + CharSequence title = location.title; + if (!TextUtils.isEmpty(location.emoji)) { + title = location.emoji + " " + title; + title = Emoji.replaceEmoji(title, nameTextView.getPaint().getFontMetricsInt(), false); + } + lastEmoji = location.emoji; + lastTitle = location.title; + return lastCompleteTitle = title; + } + private float enterAlpha = 0f; private ValueAnimator enterAnimator; - public void setLocation(TLRPC.TL_messageMediaVenue location, String icon, String label, int pos, boolean divider) { + public void setLocation(TLRPC.TL_messageMediaVenue location, String label, int pos, boolean divider, boolean animated) { needDivider = divider; - circleDrawable.getPaint().setColor(getColorForIndex(pos)); - if (location != null) - nameTextView.setText(location.title); + if (location != null) { + nameTextView.setText(getTitle(location), allowTextAnimation && !LocaleController.isRTL && animated); + } if (label != null) { - addressTextView.setText(label); + addressTextView.setText(label, allowTextAnimation && !LocaleController.isRTL); } else if (location != null) { - addressTextView.setText(location.address); + addressTextView.setText(location.address, allowTextAnimation && !LocaleController.isRTL && animated); + } + int color = getColorForIndex(pos); + if (location != null && location.icon != null) { + if ("pin".equals(location.icon) || location.icon.startsWith("emoji")) { + Drawable drawable = getResources().getDrawable(R.drawable.pin).mutate(); + drawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_location_sendLocationIcon), PorterDuff.Mode.MULTIPLY)); + CombinedDrawable combinedDrawable = new CombinedDrawable(Theme.createCircleDrawable(AndroidUtilities.dp(42), 0), drawable); + combinedDrawable.setCustomSize(AndroidUtilities.dp(42), AndroidUtilities.dp(42)); + combinedDrawable.setIconSize(AndroidUtilities.dp(24), AndroidUtilities.dp(24)); + imageView.setImageDrawable(combinedDrawable); + } else { + imageView.setImage(location.icon, null, null); + } } - if (icon != null) - imageView.setImage(icon, null, null); + circleDrawable.getPaint().setColor(color); setWillNotDraw(false); setClickable(location == null); @@ -163,7 +211,7 @@ public void setLocation(TLRPC.TL_messageMediaVenue location, String icon, String @Override protected void onDraw(Canvas canvas) { if (globalGradientView == null) { - globalGradientView = new FlickerLoadingView(getContext()); + globalGradientView = new FlickerLoadingView(getContext(), resourcesProvider); globalGradientView.setIsSingleCell(true); } @@ -180,12 +228,16 @@ protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (needDivider) { + Paint dividerPaint = resourcesProvider == null ? null : resourcesProvider.getPaint(Theme.key_paint_divider); + if (dividerPaint == null) { + dividerPaint = Theme.dividerPaint; + } canvas.drawLine( LocaleController.isRTL ? 0 : AndroidUtilities.dp(72), getHeight() - 1, LocaleController.isRTL ? getWidth() - AndroidUtilities.dp(72) : getWidth(), getHeight() - 1, - Theme.dividerPaint + dividerPaint ); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/LocationDirectionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/LocationDirectionCell.java index 63529ec6dd7..8ecf1423484 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/LocationDirectionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/LocationDirectionCell.java @@ -23,7 +23,7 @@ public LocationDirectionCell(Context context, Theme.ResourcesProvider resourcesP this.resourcesProvider = resourcesProvider; frameLayout = new FrameLayout(context); - frameLayout.setBackground(Theme.AdaptiveRipple.filledRect(getThemedColor(Theme.key_featuredStickers_addButton), 4)); + frameLayout.setBackground(Theme.AdaptiveRipple.filledRect(getThemedColor(Theme.key_featuredStickers_addButton), 8)); addView(frameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.TOP, 16, 10, 16, 0)); buttonTextView = new SimpleTextView(context); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ReactedUserHolderView.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ReactedUserHolderView.java index edf2236190c..50c933c07cb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ReactedUserHolderView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ReactedUserHolderView.java @@ -1,7 +1,12 @@ package org.telegram.ui.Cells; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.view.Gravity; @@ -12,6 +17,7 @@ import android.widget.FrameLayout; import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; @@ -32,6 +38,7 @@ import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.MessageSeenCheckDrawable; import org.telegram.ui.Components.Premium.PremiumGradient; @@ -40,6 +47,7 @@ import org.telegram.ui.Stories.StoriesUtilities; public class ReactedUserHolderView extends FrameLayout { + public boolean drawDivider; int currentAccount; public static int STYLE_DEFAULT = 0; @@ -57,12 +65,7 @@ public class ReactedUserHolderView extends FrameLayout { Theme.ResourcesProvider resourcesProvider; int style; public long dialogId; - public StoriesUtilities.AvatarStoryParams params = new StoriesUtilities.AvatarStoryParams(false) { - @Override - public void openStory(long dialogId, Runnable onDone) { - ReactedUserHolderView.this.openStory(dialogId, onDone); - } - }; + public StoriesUtilities.AvatarStoryParams params; public void openStory(long dialogId, Runnable onDone) { @@ -76,6 +79,12 @@ public ReactedUserHolderView(int style, int currentAccount, @NonNull Context con this.style = style; this.currentAccount = currentAccount; this.resourcesProvider = resourcesProvider; + this.params = new StoriesUtilities.AvatarStoryParams(false, resourcesProvider) { + @Override + public void openStory(long dialogId, Runnable onDone) { + ReactedUserHolderView.this.openStory(dialogId, onDone); + } + }; setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, AndroidUtilities.dp(ITEM_HEIGHT_DP))); int avatarSize = style == STYLE_STORY ? 48 : 34; @@ -140,7 +149,7 @@ public boolean setText(CharSequence value) { addView(overlaySelectorView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); } - public void setUserReaction(TLRPC.User user, TLRPC.Chat chat, TLRPC.Reaction reaction, long date, boolean dateIsSeen, boolean animated) { + public void setUserReaction(TLRPC.User user, TLRPC.Chat chat, TLRPC.Reaction reaction, boolean like, long date, boolean dateIsSeen, boolean animated) { TLObject u = user; if (u == null) { u = chat; @@ -184,7 +193,13 @@ public void setUserReaction(TLRPC.User user, TLRPC.Chat chat, TLRPC.Reaction rea String contentDescription; boolean hasReactImage = false; - if (reaction != null) { + if (like) { + hasReactImage = true; + Drawable likeDrawableFilled = ContextCompat.getDrawable(getContext(), R.drawable.media_like_active).mutate(); + reactView.setColorFilter(new PorterDuffColorFilter(0xFFFF2E38, PorterDuff.Mode.MULTIPLY)); + reactView.setImageDrawable(likeDrawableFilled); + contentDescription = LocaleController.formatString("AccDescrLike", R.string.AccDescrLike); + } else if (reaction != null) { ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(reaction); if (visibleReaction.emojicon != null) { TLRPC.TL_availableReaction r = MediaDataController.getInstance(currentAccount).getReactionsMap().get(visibleReaction.emojicon); @@ -195,6 +210,7 @@ public void setUserReaction(TLRPC.User user, TLRPC.Chat chat, TLRPC.Reaction rea } else { reactView.setImageDrawable(null); } + reactView.setColorFilter(null); } else { AnimatedEmojiDrawable drawable = new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, currentAccount, visibleReaction.documentId); drawable.setColorFilter(Theme.getAnimatedEmojiColorFilter(resourcesProvider)); @@ -203,6 +219,7 @@ public void setUserReaction(TLRPC.User user, TLRPC.Chat chat, TLRPC.Reaction rea } contentDescription = LocaleController.formatString("AccDescrReactedWith", R.string.AccDescrReactedWith, titleView.getText(), visibleReaction.emojicon != null ? visibleReaction.emojicon : reaction); } else { + reactView.setAnimatedEmojiDrawable(null); reactView.setImageDrawable(null); contentDescription = LocaleController.formatString("AccDescrPersonHasSeen", R.string.AccDescrPersonHasSeen, titleView.getText()); } @@ -247,7 +264,7 @@ public void setUserReaction(TLRPC.MessagePeerReaction reaction) { } else { chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); } - setUserReaction(user, chat, reaction.reaction, reaction.date, reaction.dateIsSeen, false); + setUserReaction(user, chat, reaction.reaction, false, reaction.date, reaction.dateIsSeen, false); } @Override @@ -282,4 +299,62 @@ protected void onDetachedFromWindow() { public void setObject(TLRPC.User user, long date, boolean b) { } + + private float alphaInternal = 1f; + private ValueAnimator alphaAnimator; + public void animateAlpha(float alpha, boolean animated) { + if (alphaAnimator != null) { + alphaAnimator.cancel(); + alphaAnimator = null; + } + if (animated) { + alphaAnimator = ValueAnimator.ofFloat(alphaInternal, alpha); + alphaAnimator.addUpdateListener(anm -> { + alphaInternal = (float) anm.getAnimatedValue(); + invalidate(); + }); + alphaAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + alphaInternal = alpha; + invalidate(); + } + }); + alphaAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + alphaAnimator.setDuration(420); + alphaAnimator.start(); + } else { + alphaInternal = alpha; + invalidate(); + } + } + + public float getAlphaInternal() { + return alphaInternal; + } + + @Override + protected void dispatchDraw(Canvas canvas) { + boolean restore = false; + if (alphaInternal < 1) { + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), (int) (0xFF * alphaInternal), Canvas.ALL_SAVE_FLAG); + restore = true; + } + super.dispatchDraw(canvas); + if (drawDivider) { + float leftMargin = AndroidUtilities.dp(style == STYLE_STORY ? 73 : 55); + if (LocaleController.isRTL) { + canvas.drawLine(0, getMeasuredHeight() - 1, getMeasuredWidth() - leftMargin, getMeasuredHeight() - 1, Theme.getThemePaint(Theme.key_paint_divider, resourcesProvider)); + } else { + canvas.drawLine(leftMargin, getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight() - 1, Theme.getThemePaint(Theme.key_paint_divider, resourcesProvider)); + } + } + if (restore) { + canvas.restore(); + } + } + + public Theme.ResourcesProvider getResourcesProvider() { + return resourcesProvider; + } } \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SendLocationCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SendLocationCell.java index 0df8883cba2..60a9f99e69e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SendLocationCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SendLocationCell.java @@ -71,7 +71,7 @@ public SendLocationCell(Context context, boolean live, Theme.ResourcesProvider r AndroidUtilities.runOnUIThread(invalidateRunnable, 1000); setWillNotDraw(false); } else { - Drawable drawable = getResources().getDrawable(R.drawable.pin); + Drawable drawable = getResources().getDrawable(R.drawable.pin).mutate(); drawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_location_sendLocationIcon), PorterDuff.Mode.MULTIPLY)); CombinedDrawable combinedDrawable = new CombinedDrawable(circle, drawable); combinedDrawable.setCustomSize(AndroidUtilities.dp(42), AndroidUtilities.dp(42)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java index 417345c9f62..4ad4eb637ac 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharingLiveLocationCell.java @@ -14,22 +14,30 @@ import android.graphics.PorterDuffColorFilter; import android.graphics.RectF; import android.graphics.drawable.Drawable; +import android.location.Address; +import android.location.Geocoder; import android.location.Location; +import android.text.SpannableString; +import android.text.Spanned; import android.text.TextUtils; import android.view.Gravity; import android.widget.FrameLayout; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.ContactsController; import org.telegram.messenger.DialogObject; +import org.telegram.messenger.Emoji; import org.telegram.messenger.IMapsProvider; import org.telegram.messenger.LocaleController; import org.telegram.messenger.LocationController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; +import org.telegram.messenger.Utilities; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.SimpleTextView; @@ -38,8 +46,14 @@ import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LoadingSpan; +import org.telegram.ui.Components.Paint.Views.LocationView; import org.telegram.ui.LocationActivity; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + public class SharingLiveLocationCell extends FrameLayout { private BackupImageView avatarImageView; @@ -74,14 +88,16 @@ public SharingLiveLocationCell(Context context, boolean distance, int padding, T avatarDrawable = new AvatarDrawable(); nameTextView = new SimpleTextView(context); + NotificationCenter.listenEmojiLoading(nameTextView); nameTextView.setTextSize(16); nameTextView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); nameTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); nameTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + nameTextView.setScrollNonFitText(true); if (distance) { addView(avatarImageView, LayoutHelper.createFrame(42, 42, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 0 : 15, 12, LocaleController.isRTL ? 15 : 0, 0)); - addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 20, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? padding : 73, 12, LocaleController.isRTL ? 73 : padding, 0)); + addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 20, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? padding : 73, 12, LocaleController.isRTL ? 73 : 16, 0)); distanceTextView = new SimpleTextView(context); distanceTextView.setTextSize(14); @@ -141,6 +157,66 @@ public void setDialog(long dialogId, TLRPC.TL_channelLocation chatLocation) { distanceTextView.setText(address); } + private boolean loading; + private double lastLat, lastLong; + private SpannableString loadingString; + private CharSequence lastName = ""; + private CharSequence getName(double lat, double _long) { + if (loading) { + return lastName; + } + if (Math.abs(lastLat - lat) > 0.000001d || Math.abs(lastLong - _long) > 0.000001d || TextUtils.isEmpty(lastName)) { + loading = true; + Utilities.globalQueue.postRunnable(() -> { + try { + Geocoder geocoder = new Geocoder(ApplicationLoader.applicationContext, LocaleController.getInstance().getCurrentLocale()); + List
addresses = geocoder.getFromLocation(lat, _long, 1); + if (addresses.isEmpty()) { + lastName = LocationController.detectOcean(_long, lat); + if (lastName == null) { + lastName = ""; + } else { + lastName = "🌊 " + lastName; + } + } else { + Address addr = addresses.get(0); + + StringBuilder sb = new StringBuilder(); + + HashSet parts = new HashSet<>(); + parts.add(addr.getSubAdminArea()); + parts.add(addr.getAdminArea()); + parts.add(addr.getLocality()); + parts.add(addr.getCountryName()); + for (String part : parts) { + if (TextUtils.isEmpty(part)) { + continue; + } + if (sb.length() > 0) { + sb.append(", "); + } + sb.append(part); + } + lastName = sb.toString(); + String emoji = LocationController.countryCodeToEmoji(addr.getCountryCode()); + if (emoji != null && Emoji.getEmojiDrawable(emoji) != null) { + lastName = emoji + " " + lastName; + } + } + } catch (Exception ignore) {} + AndroidUtilities.runOnUIThread(() -> { + lastLat = lat; + lastLong = _long; + loading = false; + lastName = Emoji.replaceEmoji(lastName, nameTextView.getPaint().getFontMetricsInt(), false); + nameTextView.setText(lastName); + }); + }); + } + return lastName; + } + + public void setDialog(MessageObject messageObject, Location userLocation, boolean userLocationDenied) { long fromId = messageObject.getFromChatId(); if (messageObject.isForwarded()) { @@ -148,22 +224,12 @@ public void setDialog(MessageObject messageObject, Location userLocation, boolea } currentAccount = messageObject.currentAccount; String address = null; - String name; + CharSequence name = ""; if (!TextUtils.isEmpty(messageObject.messageOwner.media.address)) { address = messageObject.messageOwner.media.address; } - if (!TextUtils.isEmpty(messageObject.messageOwner.media.title)) { - name = messageObject.messageOwner.media.title; - - Drawable drawable = getResources().getDrawable(R.drawable.pin); - drawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_location_sendLocationIcon), PorterDuff.Mode.MULTIPLY)); - int color = getThemedColor(Theme.key_location_placeLocationBackground); - Drawable circle = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(42), color, color); - CombinedDrawable combinedDrawable = new CombinedDrawable(circle, drawable); - combinedDrawable.setCustomSize(AndroidUtilities.dp(42), AndroidUtilities.dp(42)); - combinedDrawable.setIconSize(AndroidUtilities.dp(24), AndroidUtilities.dp(24)); - avatarImageView.setImageDrawable(combinedDrawable); - } else { + boolean noTitle = TextUtils.isEmpty(messageObject.messageOwner.media.title); + if (noTitle) { name = ""; avatarDrawable = null; if (fromId > 0) { @@ -172,6 +238,9 @@ public void setDialog(MessageObject messageObject, Location userLocation, boolea avatarDrawable = new AvatarDrawable(user); name = UserObject.getUserName(user); avatarImageView.setForUserOrChat(user, avatarDrawable); + } else { + noTitle = false; + name = getName(messageObject.messageOwner.media.geo.lat, messageObject.messageOwner.media.geo._long); } } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-fromId); @@ -179,8 +248,34 @@ public void setDialog(MessageObject messageObject, Location userLocation, boolea avatarDrawable = new AvatarDrawable(chat); name = chat.title; avatarImageView.setForUserOrChat(chat, avatarDrawable); + } else { + noTitle = false; + name = getName(messageObject.messageOwner.media.geo.lat, messageObject.messageOwner.media.geo._long); } } + } else { + name = ""; + } + if (TextUtils.isEmpty(name)) { + if (loadingString == null) { + loadingString = new SpannableString("dkaraush has been here"); + loadingString.setSpan(new LoadingSpan(nameTextView, AndroidUtilities.dp(100), 0, resourcesProvider), 0, loadingString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + name = loadingString; + } + if (!noTitle) { + if (!TextUtils.isEmpty(messageObject.messageOwner.media.title)) { + name = messageObject.messageOwner.media.title; + } + + Drawable drawable = getResources().getDrawable(R.drawable.pin); + drawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_location_sendLocationIcon), PorterDuff.Mode.MULTIPLY)); + int color = getThemedColor(Theme.key_location_placeLocationBackground); + Drawable circle = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(42), color, color); + CombinedDrawable combinedDrawable = new CombinedDrawable(circle, drawable); + combinedDrawable.setCustomSize(AndroidUtilities.dp(42), AndroidUtilities.dp(42)); + combinedDrawable.setIconSize(AndroidUtilities.dp(24), AndroidUtilities.dp(24)); + avatarImageView.setImageDrawable(combinedDrawable); } nameTextView.setText(name); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java index b3559708e67..ea575db55ed 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java @@ -19,6 +19,7 @@ import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.StaticLayout; +import android.util.Log; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.TypedValue; @@ -69,6 +70,7 @@ public abstract class TextSelectionHelper touchSlop) { + if (r > touchSlop * touchSlop) { AndroidUtilities.cancelRunOnUIThread(startSelectionRunnable); tryCapture = false; } @@ -788,6 +804,7 @@ public boolean onTouchEvent(MotionEvent event) { } movingHandle = false; + allowDiscard = true; break; case MotionEvent.ACTION_MOVE: if (movingHandle) { @@ -827,7 +844,7 @@ public boolean onTouchEvent(MotionEvent event) { y -= coordsInParent[1]; x -= coordsInParent[0]; - boolean canScrollDown = event.getY() - touchSlop > parentView.getMeasuredHeight() - getParentBottomPadding() && (multiselect || selectedView.getBottom() > parentView.getMeasuredHeight() - getParentBottomPadding()); + boolean canScrollDown = event.getY() - touchSlop > parentView.getMeasuredHeight() - getParentBottomPadding() && (allowScrollPrentRelative || multiselect || selectedView.getBottom() > parentView.getMeasuredHeight() - getParentBottomPadding()); boolean canScrollUp = event.getY() < ((View) parentView.getParent()).getTop() + getParentTopPadding() && (multiselect || selectedView.getTop() < getParentTopPadding()); if (canScrollDown || canScrollUp) { if (!scrolling) { @@ -1253,17 +1270,19 @@ public void checkCancel(float lastMotionX, float lastMotionY, boolean inParent) int[] coordsInParent = getCoordsInParent(); lastMotionY += coordsInParent[1] + textY; } - if (!movingHandle && (lastMotionY < startArea.top - AndroidUtilities.dp(8) || lastMotionY > endArea.bottom + AndroidUtilities.dp(8))) { + if (!movingHandle && allowDiscard) { clear(); } } float cancelPressedX, cancelPressedY; + public void checkCancelAction(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { cancelPressedX = ev.getX(); cancelPressedY = ev.getY(); - } else if (Math.abs(ev.getX() - cancelPressedX) < AndroidUtilities.touchSlop && Math.abs(ev.getY() - cancelPressedY) < AndroidUtilities.touchSlop && (ev.getAction() == MotionEvent.ACTION_CANCEL || ev.getAction() == MotionEvent.ACTION_UP)) { + allowDiscard = isInSelectionMode(); + } else if (allowDiscard && Math.abs(ev.getX() - cancelPressedX) < AndroidUtilities.touchSlop && Math.abs(ev.getY() - cancelPressedY) < AndroidUtilities.touchSlop && (ev.getAction() == MotionEvent.ACTION_CANCEL || ev.getAction() == MotionEvent.ACTION_UP)) { checkCancel(ev.getX(), ev.getY(), true); } } @@ -1755,14 +1774,19 @@ protected int getCharOffsetFromCord(int x, int y, int offsetX, int offsetY, Simp int line = -1; for (int i = 0; i < layout.getLineCount(); i++) { - if (y > layoutBlock.yOffset + layout.getLineTop(i) && y < layoutBlock.yOffset + layout.getLineBottom(i)) { + if (y > offsetY + layout.getLineTop(i) && y < offsetY + layout.getLineBottom(i)) { line = i; break; } } if (line >= 0) { - int k = layoutBlock.charOffset + layout.getOffsetForHorizontal(line, x);; - return k; + try { + int k = layoutBlock.charOffset + layout.getOffsetForHorizontal(line, x); + return k; + } catch (Exception e) { + FileLog.e(e); + } + } return -1; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 2d716c02bd7..1e423d5b137 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -2131,7 +2131,7 @@ public boolean onFragmentCreate() { } dialog_id = -chatId; if (ChatObject.isChannel(currentChat)) { - if (ChatObject.isNotInChat(currentChat)) { + if (ChatObject.isNotInChat(currentChat) && !isThreadChat() && !isInScheduleMode()) { waitingForGetDifference = true; getMessagesController().startShortPoll(currentChat, classGuid, false, isGettingDifference -> { waitingForGetDifference = isGettingDifference; @@ -7212,7 +7212,7 @@ private void checkInstantSearch() { } private void createTopPanel() { - if (topChatPanelView != null || getContext() == null) { + if (contentView == null || topChatPanelView != null || getContext() == null) { return; } @@ -7395,6 +7395,9 @@ protected void dispatchDraw(Canvas canvas) { args.putBoolean("addContact", true); ContactAddActivity activity = new ContactAddActivity(args); activity.setDelegate(() -> { + if (undoView != null || getContext() == null) { + return; + } createUndoView(); undoView.showWithAction(dialog_id, UndoView.ACTION_CONTACT_ADDED, currentUser); }); @@ -10452,13 +10455,21 @@ private void processSelectedAttach(int which) { FileLog.e(e); } } else if (which == attach_gallery) { - if (Build.VERSION.SDK_INT >= 23 && getParentActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - try { - getParentActivity().requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE); - } catch (Throwable ignore) { - + final Activity activity = getParentActivity(); + if (Build.VERSION.SDK_INT >= 33) { + if (activity.checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) { + try { + getParentActivity().requestPermissions(new String[]{Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VIDEO}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE); + } catch (Throwable ignore) {} + return; + } + } else if (Build.VERSION.SDK_INT >= 23) { + if (activity.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + try { + getParentActivity().requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE); + } catch (Throwable ignore) {} + return; } - return; } boolean allowGifs; if (ChatObject.isChannel(currentChat) && currentChat.banned_rights != null && currentChat.banned_rights.send_gifs) { @@ -15609,7 +15620,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { Collections.reverse(messArr); } if (currentEncryptedChat == null) { - getMediaDataController().loadReplyMessagesForMessages(messArr, dialog_id, chatMode == MODE_SCHEDULED, 0, null); + getMediaDataController().loadReplyMessagesForMessages(messArr, dialog_id, chatMode == MODE_SCHEDULED, 0, null, classGuid); } int approximateHeightSum = 0; if (!chatWasReset && (load_type == 2 || load_type == 1) && messArr.isEmpty() && !isCache) { @@ -16760,7 +16771,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { ArrayList messArr = new ArrayList<>(); messArr.add(obj); if (currentEncryptedChat == null) { - getMediaDataController().loadReplyMessagesForMessages(messArr, dialog_id, chatMode == MODE_SCHEDULED, 0, null); + getMediaDataController().loadReplyMessagesForMessages(messArr, dialog_id, chatMode == MODE_SCHEDULED, 0, null, classGuid); } if (chatAdapter != null) { chatAdapter.updateRowWithMessageObject(obj, false, false); @@ -17558,7 +17569,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { } boolean updated = false; if (arrayList != null) { - getMediaDataController().loadReplyMessagesForMessages(arrayList, dialog_id, false, 0, null); + getMediaDataController().loadReplyMessagesForMessages(arrayList, dialog_id, false, 0, null, classGuid); } for (int a = 0, N = ids.size(); a < N; a++) { Integer mid = ids.get(a); @@ -17651,7 +17662,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { } loadingPinnedMessages.remove(message.getId()); } - getMediaDataController().loadReplyMessagesForMessages(arrayList, dialog_id, false, 0, null); + getMediaDataController().loadReplyMessagesForMessages(arrayList, dialog_id, false, 0, null, classGuid); updateMessagesVisiblePart(false); } else { pinnedMessageIds.clear(); @@ -17997,7 +18008,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { totalPinnedMessagesCount = (Integer) args[3]; pinnedEndReached = (Boolean) args[4]; - getMediaDataController().loadReplyMessagesForMessages(new ArrayList<>(pinnedMessageObjects.values()), dialog_id, false, 0, null); + getMediaDataController().loadReplyMessagesForMessages(new ArrayList<>(pinnedMessageObjects.values()), dialog_id, false, 0, null, classGuid); if (!inMenuMode && !loadingPinnedMessagesList && totalPinnedMessagesCount == 0 && !pinnedEndReached) { getMediaDataController().loadPinnedMessages(dialog_id, 0, fallbackId); @@ -20231,6 +20242,8 @@ public void onBecomeFullyHidden() { } flagSecure.detach(); + + super.onBecomeFullyHidden(); } public void saveKeyboardPositionBeforeTransition() { @@ -23151,6 +23164,9 @@ private CharSequence getMessageCaption(MessageObject messageObject, MessageObjec } private CharSequence getMessageCaption(MessageObject messageObject, MessageObject.GroupedMessages group, int[] msgId) { + if (messageObject == null) { + return null; + } String restrictionReason = MessagesController.getRestrictionReason(messageObject.messageOwner.restriction_reason); if (!TextUtils.isEmpty(restrictionReason)) { return restrictionReason; @@ -26683,6 +26699,9 @@ public void sendMedia(MediaController.PhotoEntry photoEntry, VideoEditedInfo vid } private void runCloseInstantCameraAnimation() { + if (instantCameraView == null) { + return; + } instantCameraView.cancelBlur(); final InstantCameraView.InstantViewCameraContainer cameraContainer = instantCameraView.getCameraContainer(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java index 4293ce0baeb..a460bbbe34a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java @@ -628,6 +628,7 @@ protected void dispatchDraw(Canvas canvas) { flickerLoadingView.setViewType(FlickerLoadingView.USERS_TYPE); flickerLoadingView.showDate(false); flickerLoadingView.setUseHeaderOffset(true); + flickerLoadingView.setColors(Theme.key_actionBarDefaultSubmenuBackground, Theme.key_listSelector, Theme.key_listSelector); progressLayout.addView(flickerLoadingView); progressBar = new RadialProgressView(context); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java index 40d422a4b44..00a7f3f6b04 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -17,14 +17,17 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Outline; +import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; +import android.media.AudioManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -34,6 +37,7 @@ import android.text.Html; import android.text.InputFilter; import android.text.InputType; +import android.text.Layout; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; @@ -55,10 +59,12 @@ import android.widget.Button; import android.widget.EditText; import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.annotation.RawRes; import androidx.annotation.RequiresApi; import androidx.core.util.Consumer; @@ -108,6 +114,7 @@ import org.telegram.ui.LanguageSelectActivity; import org.telegram.ui.LaunchActivity; import org.telegram.ui.LoginActivity; +import org.telegram.ui.NotificationPermissionDialog; import org.telegram.ui.NotificationsCustomSettingsActivity; import org.telegram.ui.NotificationsSettingsActivity; import org.telegram.ui.ProfileNotificationsActivity; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java index 2ee416349b2..85931eec648 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java @@ -481,7 +481,7 @@ public AnimatedFileDrawable(File file, boolean createDecoder, long streamSize, i public AnimatedFileDrawable(File file, boolean createDecoder, long streamSize, int streamLoadingPriority, TLRPC.Document document, ImageLocation location, Object parentObject, long seekTo, int account, boolean preview, int w, int h, BitmapsCache.CacheOptions cacheOptions) { path = file; - PRERENDER_FRAME = SharedConfig.deviceIsAboveAverage() && limitFps; + PRERENDER_FRAME = SharedConfig.deviceIsAboveAverage(); streamFileSize = streamSize; this.streamLoadingPriority = streamLoadingPriority; currentAccount = account; @@ -518,8 +518,8 @@ public AnimatedFileDrawable(File file, boolean createDecoder, long streamSize, i public void setIsWebmSticker(boolean b) { isWebmSticker = b; - PRERENDER_FRAME = false; if (isWebmSticker) { + PRERENDER_FRAME = false; useSharedQueue = true; } } @@ -723,6 +723,7 @@ public void setUseSharedQueue(boolean value) { @Override protected void finalize() throws Throwable { try { + secondParentViews.clear(); recycle(); } finally { super.finalize(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedTextView.java index 0046ce03f4f..8051053d118 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedTextView.java @@ -58,6 +58,10 @@ public static class AnimatedTextDrawable extends Drawable { private Part[] oldParts; private CharSequence oldText; + public void setSplitByWords(boolean b) { + splitByWords = b; + } + private static class Part { StaticLayout layout; float offset; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomSheetWithRecyclerListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomSheetWithRecyclerListView.java index 5de35c21b16..c7fee6d3819 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomSheetWithRecyclerListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BottomSheetWithRecyclerListView.java @@ -39,7 +39,7 @@ public abstract class BottomSheetWithRecyclerListView extends BottomSheet { private float shadowAlpha = 1f; public BottomSheetWithRecyclerListView(BaseFragment fragment, boolean needFocus, boolean hasFixedSize) { - this(fragment, needFocus, hasFixedSize, false, null); + this(fragment, needFocus, hasFixedSize, false, fragment == null ? null : fragment.getResourceProvider()); } public BottomSheetWithRecyclerListView(BaseFragment fragment, boolean needFocus, boolean hasFixedSize, boolean useNested, Theme.ResourcesProvider resourcesProvider) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java index b67a0533bd5..9c44539de20 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java @@ -186,6 +186,12 @@ public static void hideVisible() { } } + public static void hideVisible(ViewGroup container) { + if (visibleBulletin != null && visibleBulletin.containerLayout == container) { + visibleBulletin.hide(); + } + } + public Bulletin setDuration(int duration) { this.duration = duration; return this; @@ -1745,32 +1751,20 @@ protected void onDraw(Canvas canvas) { // to make bulletin above everything // use as BulletinFactory.of(BulletinWindow.make(context), resourcesProvider)... public static class BulletinWindow extends Dialog { - public static FrameLayout make(Context context) { - return new BulletinWindow(context).container; + + public static BulletinWindowLayout make(Context context, Delegate delegate) { + return new BulletinWindow(context, delegate).container; } - private final FrameLayout container; - private BulletinWindow(Context context) { + public static BulletinWindowLayout make(Context context) { + return new BulletinWindow(context, null).container; + } + + private final BulletinWindowLayout container; + private BulletinWindow(Context context, Delegate delegate) { super(context); setContentView( - container = new FrameLayout(context) { - @Override - public void addView(View child) { - super.addView(child); - BulletinWindow.this.show(); - } - - @Override - public void removeView(View child) { - super.removeView(child); - try { - BulletinWindow.this.dismiss(); - } catch (Exception ignore) { - - } - removeDelegate(container); - } - }, + container = new BulletinWindowLayout(context), new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) ); if (Build.VERSION.SDK_INT >= 21) { @@ -1794,12 +1788,17 @@ public void removeView(View child) { addDelegate(container, new Delegate() { @Override public int getBottomOffset(int tag) { - return 0; + return delegate == null ? 0 : delegate.getBottomOffset(tag); } @Override public int getTopOffset(int tag) { - return AndroidUtilities.statusBarHeight; + return delegate == null ? AndroidUtilities.statusBarHeight : delegate.getTopOffset(tag); + } + + @Override + public boolean clipWithGradient(int tag) { + return delegate != null && delegate.clipWithGradient(tag); } }); @@ -1807,8 +1806,9 @@ public int getTopOffset(int tag) { Window window = getWindow(); window.setWindowAnimations(R.style.DialogNoAnimation); window.setBackgroundDrawable(null); - WindowManager.LayoutParams params = window.getAttributes(); + params = window.getAttributes(); params.width = ViewGroup.LayoutParams.MATCH_PARENT; + params.height = ViewGroup.LayoutParams.MATCH_PARENT; params.gravity = Gravity.TOP | Gravity.LEFT; params.dimAmount = 0; params.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND; @@ -1823,7 +1823,6 @@ public int getTopOffset(int tag) { WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; } params.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN; - params.height = ViewGroup.LayoutParams.MATCH_PARENT; if (Build.VERSION.SDK_INT >= 28) { params.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; } @@ -1843,6 +1842,52 @@ private void applyInsets(WindowInsets insets) { ); } } + + private WindowManager.LayoutParams params; + + public class BulletinWindowLayout extends FrameLayout { + public BulletinWindowLayout(Context context) { + super(context); + } + + @Override + public void addView(View child) { + super.addView(child); + BulletinWindow.this.show(); + } + + @Override + public void removeView(View child) { + super.removeView(child); + try { + BulletinWindow.this.dismiss(); + } catch (Exception ignore) { + + } + removeDelegate(container); + } + + public void setTouchable(boolean touchable) { + if (params == null) { + return; + } + if (!touchable) { + params.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + } else { + params.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + } + BulletinWindow.this.getWindow().setAttributes(params); + } + + @Nullable + public WindowManager.LayoutParams getLayout() { + return params; + } + + public void updateLayout() { + BulletinWindow.this.getWindow().setAttributes(params); + } + } } public Bulletin setTag(int tag) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java index d4c274e8dd3..84d46bf3cda 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java @@ -171,6 +171,17 @@ public Bulletin createSimpleBulletin(int iconRawId, CharSequence text) { return create(layout, text.length() < 20 ? Bulletin.DURATION_SHORT : Bulletin.DURATION_LONG); } + public Bulletin createSimpleLargeBulletin(int iconRawId, CharSequence title, CharSequence subtitle) { + final Bulletin.TwoLineLayout layout = new Bulletin.TwoLineLayout(getContext(), resourcesProvider); + layout.imageView.setImageResource(iconRawId); + layout.titleTextView.setText(title); + + layout.subtitleTextView.setText(subtitle); + layout.subtitleTextView.setSingleLine(false); + layout.subtitleTextView.setMaxLines(5); + return create(layout, Bulletin.DURATION_PROLONG); + } + public Bulletin createSimpleBulletin(int iconRawId, CharSequence text, int maxLines) { final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), resourcesProvider); layout.setAnimation(iconRawId, 36, 36); @@ -1032,6 +1043,21 @@ public static Bulletin createBanBulletin(BaseFragment fragment, boolean banned) return Bulletin.make(fragment, layout, Bulletin.DURATION_SHORT); } + @CheckResult + public Bulletin createBanBulletin(boolean banned) { + final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), resourcesProvider); + final String text; + if (banned) { + layout.setAnimation(R.raw.ic_ban, "Hand"); + text = LocaleController.getString("UserBlocked", R.string.UserBlocked); + } else { + layout.setAnimation(R.raw.ic_unban, "Main", "Finger 1", "Finger 2", "Finger 3", "Finger 4"); + text = LocaleController.getString("UserUnblocked", R.string.UserUnblocked); + } + layout.textView.setText(AndroidUtilities.replaceTags(text)); + return create(layout, Bulletin.DURATION_SHORT); + } + @CheckResult public static Bulletin createCopyLinkBulletin(BaseFragment fragment) { return of(fragment).createCopyLinkBulletin(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ButtonBounce.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ButtonBounce.java index 3726e8b5f8f..64d51ace75e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ButtonBounce.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ButtonBounce.java @@ -4,6 +4,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; +import android.util.Log; import android.view.View; import android.view.animation.OvershootInterpolator; @@ -11,15 +12,24 @@ public class ButtonBounce { private View view; private final float durationMultiplier; + private final float overshoot; + private long releaseDelay = 0; public ButtonBounce(View viewToInvalidate) { view = viewToInvalidate; durationMultiplier = 1f; + overshoot = 5.0f; } - public ButtonBounce(View viewToInvalidate, float durationMultiplier) { + public ButtonBounce(View viewToInvalidate, float durationMultiplier, float overshoot) { view = viewToInvalidate; this.durationMultiplier = durationMultiplier; + this.overshoot = overshoot; + } + + public ButtonBounce setReleaseDelay(long releaseDelay) { + this.releaseDelay = releaseDelay; + return this; } public void setView(View view) { @@ -33,8 +43,10 @@ public void setView(View view) { public void setPressed(boolean pressed) { if (isPressed != pressed) { isPressed = pressed; - if (animator != null) { - animator.cancel(); + ValueAnimator pastAnimator = animator; + animator = null; + if (pastAnimator != null) { + pastAnimator.cancel(); } animator = ValueAnimator.ofFloat(pressedT, pressed ? 1 : 0); animator.addUpdateListener(anm -> { @@ -44,17 +56,21 @@ public void setPressed(boolean pressed) { animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - animator = null; - pressedT = pressed ? 1 : 0; - invalidate(); + if (animation == animator) { + animator = null; + pressedT = pressed ? 1 : 0; + invalidate(); + } } }); if (isPressed) { animator.setInterpolator(CubicBezierInterpolator.DEFAULT); animator.setDuration((long) (60 * durationMultiplier)); + animator.setStartDelay(0); } else { - animator.setInterpolator(new OvershootInterpolator(5.0f)); + animator.setInterpolator(new OvershootInterpolator(overshoot)); animator.setDuration((long) (350 * durationMultiplier)); + animator.setStartDelay(releaseDelay); } animator.start(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CacheChart.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CacheChart.java index 9e61dfa0a07..f1fac083918 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CacheChart.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CacheChart.java @@ -108,7 +108,9 @@ public class CacheChart extends View { private static long particlesStart = -1; class Sector { - Paint particlePaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); + Paint particlePaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); { + particlePaint.setColor(0xFFFFFFFF); + } Bitmap particle; float angleCenter, angleSize; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java index 36730d03c56..f48d7c9961a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -180,6 +180,8 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific private Runnable animationEndRunnable; private float attachLayoutTranslationX; private float attachLayoutPaddingTranslationX; + private float attachLayoutAlpha = 1f; + private float attachLayoutPaddingAlpha = 1f; private float messageTextTranslationX; private float messageTextPaddingTranslationX; private float horizontalPadding = 0; @@ -935,6 +937,19 @@ public void set(View object, Float value) { } }; + private final Property ATTACH_LAYOUT_ALPHA = new Property(Float.class, "attach_scale") { + @Override + public Float get(View object) { + return attachLayoutAlpha; + } + + @Override + public void set(View object, Float value) { + attachLayoutAlpha = value; + updateAttachLayoutParams(); + } + }; + private final Property EMOJI_BUTTON_ALPHA = new Property(Float.class, "emoji_button_alpha") { @Override public Float get(View object) { @@ -2089,7 +2104,7 @@ public void onClick(View v) { } attachLayout.addView(attachButton, LayoutHelper.createLinear(48, 48)); attachButton.setOnClickListener(v -> { - if (adjustPanLayoutHelper != null && adjustPanLayoutHelper.animationInProgress()) { + if (adjustPanLayoutHelper != null && adjustPanLayoutHelper.animationInProgress() || attachLayoutPaddingAlpha == 0f) { return; } delegate.didPressAttachButton(); @@ -3624,7 +3639,12 @@ public boolean onTouch(View v, MotionEvent event) { if (sendPopupWindow != null && sendPopupWindow.isShowing()) { sendPopupWindow.dismiss(); } - AlertsCreator.createScheduleDatePickerDialog(parentActivity, parentFragment.getDialogId(), this::sendMessageInternal, resourcesProvider); + AlertsCreator.createScheduleDatePickerDialog(parentActivity, parentFragment.getDialogId(), new AlertsCreator.ScheduleDatePickerDelegate() { + @Override + public void didSelectDate(boolean notify, int scheduleDate) { + sendMessageInternal(notify, scheduleDate, true); + } + }, resourcesProvider); }); sendPopupLayout.addView(scheduleButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); if (!self && dialog_id > 0) { @@ -3635,7 +3655,7 @@ public boolean onTouch(View v, MotionEvent event) { if (sendPopupWindow != null && sendPopupWindow.isShowing()) { sendPopupWindow.dismiss(); } - sendMessageInternal(true, 0x7FFFFFFE); + sendMessageInternal(true, 0x7FFFFFFE, true); }); sendPopupLayout.addView(sendWhenOnlineButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); } @@ -3648,7 +3668,7 @@ public boolean onTouch(View v, MotionEvent event) { if (sendPopupWindow != null && sendPopupWindow.isShowing()) { sendPopupWindow.dismiss(); } - sendMessageInternal(false, 0); + sendMessageInternal(false, 0, true); }); sendPopupLayout.addView(sendWithoutSoundButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); } @@ -5486,14 +5506,19 @@ private void hideRecordedAudioPanelInternal() { private void sendMessage() { if (isInScheduleMode()) { - AlertsCreator.createScheduleDatePickerDialog(parentActivity, parentFragment.getDialogId(), this::sendMessageInternal, resourcesProvider); + AlertsCreator.createScheduleDatePickerDialog(parentActivity, parentFragment.getDialogId(), new AlertsCreator.ScheduleDatePickerDelegate() { + @Override + public void didSelectDate(boolean notify, int scheduleDate) { + sendMessageInternal(notify, scheduleDate, true); + } + }, resourcesProvider); } else { - sendMessageInternal(true, 0); + sendMessageInternal(true, 0, true); } } private boolean premiumEmojiBulletin = true; - private void sendMessageInternal(boolean notify, int scheduleDate) { + private void sendMessageInternal(boolean notify, int scheduleDate, boolean allowConfirm) { if (slowModeTimer == Integer.MAX_VALUE && !isInScheduleMode()) { if (delegate != null) { delegate.scrollToSendingMessage(); @@ -5514,6 +5539,11 @@ private void sendMessageInternal(boolean notify, int scheduleDate) { emojiView.hideSearchKeyboard(); } } + if (allowConfirm && showConfirmAlert(() -> { + sendMessageInternal(notify, scheduleDate, false); + })) { + return; + } if (videoToSendMessageObject != null) { delegate.needStartRecordVideo(4, notify, scheduleDate); hideRecordedAudioPanel(true); @@ -5579,6 +5609,10 @@ private void sendMessageInternal(boolean notify, int scheduleDate) { } } + protected boolean showConfirmAlert(Runnable onConfirmed) { + return false; + } + public static boolean checkPremiumAnimatedEmoji(int currentAccount, long dialogId, BaseFragment parentFragment, FrameLayout container, CharSequence message) { if (message == null || parentFragment == null) { return false; @@ -5850,7 +5884,7 @@ private void checkSendButton(boolean animated) { if (attachLayout != null) { runningAnimation2 = new AnimatorSet(); ArrayList animators = new ArrayList<>(); - animators.add(ObjectAnimator.ofFloat(attachLayout, View.ALPHA, 0.0f)); + animators.add(ObjectAnimator.ofFloat(attachLayout, ATTACH_LAYOUT_ALPHA, 0.0f)); animators.add(ObjectAnimator.ofFloat(attachLayout, View.SCALE_X, 0.0f)); scheduleButtonHidden = false; boolean hasScheduled = delegate != null && delegate.hasScheduledMessages(); @@ -6034,7 +6068,7 @@ public void onAnimationCancel(Animator animation) { if (attachLayout != null) { runningAnimation2 = new AnimatorSet(); ArrayList animators = new ArrayList<>(); - animators.add(ObjectAnimator.ofFloat(attachLayout, View.ALPHA, 0.0f)); + animators.add(ObjectAnimator.ofFloat(attachLayout, ATTACH_LAYOUT_ALPHA, 0.0f)); animators.add(ObjectAnimator.ofFloat(attachLayout, View.SCALE_X, 0.0f)); boolean hasScheduled = delegate != null && delegate.hasScheduledMessages(); scheduleButtonHidden = true; @@ -6226,7 +6260,7 @@ public void onAnimationCancel(Animator animation) { attachLayout.setVisibility(VISIBLE); runningAnimation2 = new AnimatorSet(); ArrayList animators = new ArrayList<>(); - animators.add(ObjectAnimator.ofFloat(attachLayout, View.ALPHA, 1.0f)); + animators.add(ObjectAnimator.ofFloat(attachLayout, ATTACH_LAYOUT_ALPHA, 1.0f)); animators.add(ObjectAnimator.ofFloat(attachLayout, View.SCALE_X, 1.0f)); boolean hasScheduled = delegate != null && delegate.hasScheduledMessages(); scheduleButtonHidden = false; @@ -6386,12 +6420,13 @@ public void onAnimationCancel(Animator animation) { if (attachLayout != null) { if (attachLayout.getVisibility() != View.VISIBLE) { attachLayout.setVisibility(VISIBLE); - attachLayout.setAlpha(0f); + attachLayoutAlpha = 0f; + updateAttachLayoutParams(); attachLayout.setScaleX(0f); } runningAnimation2 = new AnimatorSet(); ArrayList animators = new ArrayList<>(); - animators.add(ObjectAnimator.ofFloat(attachLayout, View.ALPHA, 1.0f)); + animators.add(ObjectAnimator.ofFloat(attachLayout, ATTACH_LAYOUT_ALPHA, 1.0f)); animators.add(ObjectAnimator.ofFloat(attachLayout, View.SCALE_X, 1.0f)); boolean hasScheduled = delegate != null && delegate.hasScheduledMessages(); scheduleButtonHidden = false; @@ -6524,7 +6559,8 @@ public void onAnimationCancel(Animator animation) { if (getVisibility() == VISIBLE) { delegate.onAttachButtonShow(); } - attachLayout.setAlpha(1.0f); + attachLayoutAlpha = 1.0f; + updateAttachLayoutParams(); attachLayout.setScaleX(1.0f); attachLayout.setVisibility(VISIBLE); updateFieldRight(1); @@ -6715,7 +6751,7 @@ protected void updateRecordInterface(int recordState) { if (attachLayout != null) { viewTransition.playTogether( ObjectAnimator.ofFloat(attachLayout, ATTACH_LAYOUT_TRANSLATION_X, AndroidUtilities.dp(30)), - ObjectAnimator.ofFloat(attachLayout, View.ALPHA, 0f) + ObjectAnimator.ofFloat(attachLayout, ATTACH_LAYOUT_ALPHA, 0f) ); } @@ -6826,7 +6862,7 @@ public void onAnimationEnd(Animator animator) { if (attachLayout != null) { runningAnimationAudio.playTogether( ObjectAnimator.ofFloat(attachLayout, ATTACH_LAYOUT_TRANSLATION_X, 0), - ObjectAnimator.ofFloat(attachLayout, View.ALPHA, 1f) + ObjectAnimator.ofFloat(attachLayout, ATTACH_LAYOUT_ALPHA, 1f) ); } @@ -7072,7 +7108,7 @@ public void onAnimationEnd(Animator animation) { ); if (attachLayout != null) { iconsAnimator.playTogether( - ObjectAnimator.ofFloat(attachLayout, View.ALPHA, 1f), + ObjectAnimator.ofFloat(attachLayout, ATTACH_LAYOUT_ALPHA, 1f), ObjectAnimator.ofFloat(attachLayout, ATTACH_LAYOUT_TRANSLATION_X, 0) ); } @@ -7108,7 +7144,7 @@ public void onAnimationEnd(Animator animation) { if (attachLayout != null) { icons2.playTogether( ObjectAnimator.ofFloat(attachLayout, ATTACH_LAYOUT_TRANSLATION_X, 0), - ObjectAnimator.ofFloat(attachLayout, View.ALPHA, 1f) + ObjectAnimator.ofFloat(attachLayout, ATTACH_LAYOUT_ALPHA, 1f) ); } if (scheduledButton != null) { @@ -7198,7 +7234,7 @@ public void onAnimationEnd(Animator animation) { attachLayoutTranslationX = 0; updateAttachLayoutParams(); iconsAnimator.playTogether( - ObjectAnimator.ofFloat(attachLayout, View.ALPHA, 1f) + ObjectAnimator.ofFloat(attachLayout, ATTACH_LAYOUT_ALPHA, 1f) ); } if (scheduledButton != null) { @@ -7546,7 +7582,8 @@ public void setEditingMessageObject(MessageObject messageObject, boolean caption setSlowModeButtonVisible(true); } attachLayout.setScaleX(0.01f); - attachLayout.setAlpha(0.0f); + attachLayoutAlpha = 0f; + updateAttachLayoutParams(); attachLayout.setVisibility(GONE); audioVideoButtonContainer.setScaleX(0.1f); audioVideoButtonContainer.setScaleY(0.1f); @@ -7562,7 +7599,8 @@ public void setEditingMessageObject(MessageObject messageObject, boolean caption slowModeButton.setAlpha(0.0f); setSlowModeButtonVisible(false); attachLayout.setScaleX(1.0f); - attachLayout.setAlpha(1.0f); + attachLayoutAlpha = 1.0f; + updateAttachLayoutParams(); attachLayout.setVisibility(VISIBLE); audioVideoButtonContainer.setScaleX(1.0f); audioVideoButtonContainer.setScaleY(1.0f); @@ -8642,50 +8680,56 @@ public void onGifSelected(View view, Object gif, String query, Object parent, bo } return; } - if (stickersExpanded) { - if (searchingType != 0) { - emojiView.hideSearchKeyboard(); - } - setStickersExpanded(false, true, false); - } - TLRPC.StoryItem storyItem = delegate != null ? delegate.getReplyToStory() : null; - if (gif instanceof TLRPC.Document) { - TLRPC.Document document = (TLRPC.Document) gif; - SendMessagesHelper.getInstance(currentAccount).sendSticker(document, query, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, null, notify, scheduleDate, false, parent); - MediaDataController.getInstance(currentAccount).addRecentGif(document, (int) (System.currentTimeMillis() / 1000), true); - if (DialogObject.isEncryptedDialog(dialog_id)) { - accountInstance.getMessagesController().saveGif(parent, document); - } - } else if (gif instanceof TLRPC.BotInlineResult) { - TLRPC.BotInlineResult result = (TLRPC.BotInlineResult) gif; + Runnable runnable = () -> { - if (result.document != null) { - MediaDataController.getInstance(currentAccount).addRecentGif(result.document, (int) (System.currentTimeMillis() / 1000), false); - if (DialogObject.isEncryptedDialog(dialog_id)) { - accountInstance.getMessagesController().saveGif(parent, result.document); + if (stickersExpanded) { + if (searchingType != 0) { + emojiView.hideSearchKeyboard(); } + setStickersExpanded(false, true, false); } + TLRPC.StoryItem storyItem = delegate != null ? delegate.getReplyToStory() : null; + if (gif instanceof TLRPC.Document) { + TLRPC.Document document = (TLRPC.Document) gif; + SendMessagesHelper.getInstance(currentAccount).sendSticker(document, query, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, null, notify, scheduleDate, false, parent); + MediaDataController.getInstance(currentAccount).addRecentGif(document, (int) (System.currentTimeMillis() / 1000), true); + if (DialogObject.isEncryptedDialog(dialog_id)) { + accountInstance.getMessagesController().saveGif(parent, document); + } + } else if (gif instanceof TLRPC.BotInlineResult) { + TLRPC.BotInlineResult result = (TLRPC.BotInlineResult) gif; - TLRPC.User bot = (TLRPC.User) parent; + if (result.document != null) { + MediaDataController.getInstance(currentAccount).addRecentGif(result.document, (int) (System.currentTimeMillis() / 1000), false); + if (DialogObject.isEncryptedDialog(dialog_id)) { + accountInstance.getMessagesController().saveGif(parent, result.document); + } + } - HashMap params = new HashMap<>(); - params.put("id", result.id); - params.put("query_id", "" + result.query_id); - params.put("force_gif", "1"); + TLRPC.User bot = (TLRPC.User) parent; - if (storyItem == null) { - SendMessagesHelper.prepareSendingBotContextResult(parentFragment, accountInstance, result, params, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, notify, scheduleDate); - } else { - SendMessagesHelper.getInstance(currentAccount).sendSticker(result.document, query, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, null, notify, scheduleDate, false, parent); + HashMap params = new HashMap<>(); + params.put("id", result.id); + params.put("query_id", "" + result.query_id); + params.put("force_gif", "1"); + + if (storyItem == null) { + SendMessagesHelper.prepareSendingBotContextResult(parentFragment, accountInstance, result, params, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, notify, scheduleDate); + } else { + SendMessagesHelper.getInstance(currentAccount).sendSticker(result.document, query, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, null, notify, scheduleDate, false, parent); + } + if (searchingType != 0) { + setSearchingTypeInternal(0, true); + emojiView.closeSearch(true); + emojiView.hideSearchKeyboard(); + } } - if (searchingType != 0) { - setSearchingTypeInternal(0, true); - emojiView.closeSearch(true); - emojiView.hideSearchKeyboard(); + if (delegate != null) { + delegate.onMessageSend(null, notify, scheduleDate); } - } - if (delegate != null) { - delegate.onMessageSend(null, notify, scheduleDate); + }; + if (!showConfirmAlert(runnable)) { + runnable.run(); } } } @@ -8911,27 +8955,32 @@ public void onStickerSelected(TLRPC.Document sticker, String query, Object paren if (isInScheduleMode() && scheduleDate == 0) { AlertsCreator.createScheduleDatePickerDialog(parentActivity, parentFragment.getDialogId(), (n, s) -> onStickerSelected(sticker, query, parent, sendAnimationData, clearsInputField, n, s), resourcesProvider); } else { - if (slowModeTimer > 0 && !isInScheduleMode()) { + Runnable runnable = () -> { + if (slowModeTimer > 0 && !isInScheduleMode()) { + if (delegate != null) { + delegate.onUpdateSlowModeButton(slowModeButton, true, slowModeButton.getText()); + } + return; + } + if (searchingType != 0) { + setSearchingTypeInternal(0, true); + emojiView.closeSearch(true); + emojiView.hideSearchKeyboard(); + } + setStickersExpanded(false, true, false); + TLRPC.StoryItem storyItem = delegate != null ? delegate.getReplyToStory() : null; + SendMessagesHelper.getInstance(currentAccount).sendSticker(sticker, query, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, sendAnimationData, notify, scheduleDate, parent instanceof TLRPC.TL_messages_stickerSet, parent); if (delegate != null) { - delegate.onUpdateSlowModeButton(slowModeButton, true, slowModeButton.getText()); + delegate.onMessageSend(null, true, scheduleDate); } - return; - } - if (searchingType != 0) { - setSearchingTypeInternal(0, true); - emojiView.closeSearch(true); - emojiView.hideSearchKeyboard(); - } - setStickersExpanded(false, true, false); - TLRPC.StoryItem storyItem = delegate != null ? delegate.getReplyToStory() : null; - SendMessagesHelper.getInstance(currentAccount).sendSticker(sticker, query, dialog_id, replyingMessageObject, getThreadMessage(), storyItem, sendAnimationData, notify, scheduleDate, parent instanceof TLRPC.TL_messages_stickerSet, parent); - if (delegate != null) { - delegate.onMessageSend(null, true, scheduleDate); - } - if (clearsInputField) { - setFieldText(""); + if (clearsInputField) { + setFieldText(""); + } + MediaDataController.getInstance(currentAccount).addRecentSticker(MediaDataController.TYPE_IMAGE, parent, sticker, (int) (System.currentTimeMillis() / 1000), false); + }; + if (!showConfirmAlert(runnable)) { + runnable.run(); } - MediaDataController.getInstance(currentAccount).addRecentSticker(MediaDataController.TYPE_IMAGE, parent, sticker, (int) (System.currentTimeMillis() / 1000), false); } } @@ -10330,7 +10379,7 @@ protected void onDraw(Canvas canvas) { float offsetY = enableTransition ? 0 : cancelToProgress * AndroidUtilities.dp(12); if (cancelToProgress != 1) { - int slideDelta = (int) (-getMeasuredWidth() / 4 * (1f - slideProgress)); + int slideDelta = (int) (-getMeasuredWidth() / 4 * (1f - slideProgress) + recordCircle.getTranslationX() * 0.3f); canvas.save(); canvas.clipRect((recordTimerView == null ? 0 : recordTimerView.getLeftProperty()) + AndroidUtilities.dp(4), 0, getMeasuredWidth(), getMeasuredHeight()); canvas.save(); @@ -10774,29 +10823,34 @@ public void setChatSearchExpandOffset(float chatSearchExpandOffset) { } public void setHorizontalPadding(float padding, float progress, boolean allowShare) { - float v = -padding * (1f - progress); + float leftPadding = -padding * (1f - progress); + float rightPadding = -(padding + AndroidUtilities.dp(40)) * (1f - progress); float s = 0.5f + 0.5f * progress; emojiButtonPaddingScale = s; emojiButtonPaddingAlpha = progress; updateEmojiButtonParams(); - emojiButton.setTranslationX(-v); - messageTextPaddingTranslationX = -v - AndroidUtilities.dp(31) * (1f - progress); + emojiButton.setTranslationX(-leftPadding); + messageTextPaddingTranslationX = -leftPadding - AndroidUtilities.dp(31) * (1f - progress); if (recordDeleteImageView != null) { - recordDeleteImageView.setTranslationX(-v); + recordDeleteImageView.setTranslationX(-leftPadding); + } + if (recordCircle != null) { + recordCircle.setTranslationX(rightPadding); } if (recordTimeContainer != null) { - recordTimeContainer.setTranslationX(-v); + recordTimeContainer.setTranslationX(-leftPadding); } if (recordedAudioPlayButton != null) { - recordedAudioPlayButton.setTranslationX(-v); + recordedAudioPlayButton.setTranslationX(-leftPadding); } if (recordedAudioTimeTextView != null) { - recordedAudioTimeTextView.setTranslationX(v); + recordedAudioTimeTextView.setTranslationX(leftPadding); } - sendButtonContainer.setTranslationX(v); + sendButtonContainer.setTranslationX(rightPadding); sendButtonContainer.setAlpha(allowShare ? progress : 1f); sendButtonEnabled = allowShare ? progress == 1f : true; - attachLayoutPaddingTranslationX = v; + attachLayoutPaddingTranslationX = rightPadding; + attachLayoutPaddingAlpha = progress; updateAttachLayoutParams(); updateMessageTextParams(); float newPadding = padding * (1f - progress); @@ -10823,6 +10877,8 @@ private void updateMessageTextParams() { private void updateAttachLayoutParams() { if (attachLayout != null) { attachLayout.setTranslationX(attachLayoutPaddingTranslationX + attachLayoutTranslationX); + attachLayout.setAlpha(attachLayoutAlpha * attachLayoutPaddingAlpha); + attachLayout.setVisibility(attachLayout.getAlpha() > 0 ? View.VISIBLE : View.GONE); } } @@ -10833,8 +10889,12 @@ private void updateEmojiButtonParams() { } public void setOverrideHint(CharSequence overrideHint) { + setOverrideHint(overrideHint, false); + } + + public void setOverrideHint(CharSequence overrideHint, boolean animated) { this.overrideHint = overrideHint; - updateFieldHint(false); + updateFieldHint(animated); } public void setOverrideKeyboardAnimation(boolean overrideKeyboardAnimation) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java index 88a529c0d37..cb60f4b81c1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java @@ -15,6 +15,7 @@ import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; import android.content.ContextWrapper; import android.content.DialogInterface; @@ -109,6 +110,7 @@ import org.telegram.ui.PhotoPickerSearchActivity; import org.telegram.ui.PremiumPreviewFragment; +import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -127,6 +129,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N public boolean canOpenPreview = false; private boolean isSoundPicker = false; + public boolean isStoryLocationPicker = false; private ImageUpdater.AvatarFor setAvatarFor; public boolean pinnedToTop; @@ -1514,6 +1517,38 @@ public void requestLayout() { super.requestLayout(); } + private float getY(View child) { + if (child instanceof AttachAlertLayout) { + AttachAlertLayout layout = (AttachAlertLayout) child; + int actionBarType = layout.needsActionBar(); + + int offset = AndroidUtilities.dp(13) + (int) ((headerView != null ? headerView.getAlpha() : 0f) * AndroidUtilities.dp(26)); + int top = getScrollOffsetY(0) - backgroundPaddingTop - offset; + if (currentSheetAnimationType == 1 || viewChangeAnimator != null) { + top += child.getTranslationY(); + } + int y = top + AndroidUtilities.dp(20); + int h = (actionBarType != 0 ? ActionBar.getCurrentActionBarHeight() : backgroundPaddingTop); + if (actionBarType != 2 && top + backgroundPaddingTop < h) { + float toMove = offset; + if (layout == locationLayout) { + toMove += AndroidUtilities.dp(11); + } else if (layout == pollLayout) { + toMove -= AndroidUtilities.dp(3); + } else { + toMove += AndroidUtilities.dp(4); + } + float availableToMove = h - toMove + AndroidUtilities.statusBarHeight; + y -= (int) (availableToMove * actionBar.getAlpha()); + } + if (Build.VERSION.SDK_INT >= 21 && !inBubbleMode) { + y += AndroidUtilities.statusBarHeight; + } + return y; + } + return 0; + } + private void drawChildBackground(Canvas canvas, View child) { if (child instanceof AttachAlertLayout) { canvas.save(); @@ -1522,7 +1557,7 @@ private void drawChildBackground(Canvas canvas, View child) { AttachAlertLayout layout = (AttachAlertLayout) child; int actionBarType = layout.needsActionBar(); - int offset = AndroidUtilities.dp(13) + (headerView != null ? AndroidUtilities.dp(headerView.getAlpha() * 26) : 0); + int offset = AndroidUtilities.dp(13) + (int) ((headerView != null ? headerView.getAlpha() : 0f) * AndroidUtilities.dp(26)); int top = getScrollOffsetY(0) - backgroundPaddingTop - offset; if (currentSheetAnimationType == 1 || viewChangeAnimator != null) { top += child.getTranslationY(); @@ -1537,7 +1572,7 @@ private void drawChildBackground(Canvas canvas, View child) { if (top < h) { rad = Math.max(0, 1.0f - (h - top) / (float) backgroundPaddingTop); } - } else if (top + backgroundPaddingTop < h) { + } else { float toMove = offset; if (layout == locationLayout) { toMove += AndroidUtilities.dp(11); @@ -1546,8 +1581,8 @@ private void drawChildBackground(Canvas canvas, View child) { } else { toMove += AndroidUtilities.dp(4); } - float moveProgress = Math.min(1.0f, (h - top - backgroundPaddingTop) / toMove); - float availableToMove = h - toMove; + float moveProgress = actionBar.getAlpha(); + float availableToMove = h - toMove + AndroidUtilities.statusBarHeight; int diff = (int) (availableToMove * moveProgress); top -= diff; @@ -1673,24 +1708,10 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { } } - boolean clip = !drawBackground && (headerView != null && headerView.getAlpha() > .9f) && (currentAttachLayout instanceof ChatAttachAlertPhotoLayoutPreview || nextAttachLayout instanceof ChatAttachAlertPhotoLayoutPreview) && (viewChangeAnimator instanceof SpringAnimation && ((SpringAnimation) viewChangeAnimator).isRunning()); - if (clip) { - canvas.save(); - int finalMove; - if (AndroidUtilities.isTablet()) { - finalMove = 16; - } else if (AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { - finalMove = 6; - } else { - finalMove = 12; - } - int clipTop = (int) (baseSelectedTextViewTranslationY + AndroidUtilities.statusBarHeight + headerView.getHeight() + AndroidUtilities.dp(finalMove * headerView.getAlpha())); - canvas.clipRect(backgroundPaddingLeft, clipTop, getMeasuredWidth() - backgroundPaddingLeft, getMeasuredHeight()); - } + canvas.save(); + canvas.clipRect(backgroundPaddingLeft, actionBar.getY() + actionBar.getMeasuredHeight() - currentPanTranslationY, getMeasuredWidth() - backgroundPaddingLeft, getMeasuredHeight()); boolean result = super.drawChild(canvas, child, drawingTime); - if (clip) { - canvas.restore(); - } + canvas.restore(); if (drawBackground) { if (rad != 1.0f && actionBarType != 2) { @@ -1723,6 +1744,19 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { } canvas.restore(); return result; + } else if (child == actionBar) { + final float alpha = actionBar.getAlpha(); + if (alpha <= 0) { + return false; + } + if (alpha >= 1) { + return super.drawChild(canvas, child, drawingTime); + } + canvas.save(); + canvas.clipRect(actionBar.getX(), getY(currentAttachLayout), actionBar.getX() + actionBar.getWidth(), actionBar.getY() + actionBar.getHeight()); + boolean result = super.drawChild(canvas, child, drawingTime); + canvas.restore(); + return result; } return super.drawChild(canvas, child, drawingTime); } @@ -1732,10 +1766,10 @@ protected void onDraw(Canvas canvas) { if (inBubbleMode) { return; } - int color1 = currentAttachLayout.hasCustomBackground() ? currentAttachLayout.getCustomBackground() : getThemedColor(forceDarkTheme ? Theme.key_voipgroup_listViewBackground : Theme.key_dialogBackground); - int finalColor = Color.argb((int) (255 * actionBar.getAlpha()), Color.red(color1), Color.green(color1), Color.blue(color1)); - Theme.dialogs_onlineCirclePaint.setColor(finalColor); - canvas.drawRect(backgroundPaddingLeft, currentPanTranslationY, getMeasuredWidth() - backgroundPaddingLeft, AndroidUtilities.statusBarHeight + currentPanTranslationY, Theme.dialogs_onlineCirclePaint); +// int color1 = currentAttachLayout.hasCustomBackground() ? currentAttachLayout.getCustomBackground() : getThemedColor(forceDarkTheme ? Theme.key_voipgroup_listViewBackground : Theme.key_dialogBackground); +// int finalColor = Color.argb((int) (255 * actionBar.getAlpha()), Color.red(color1), Color.green(color1), Color.blue(color1)); +// Theme.dialogs_onlineCirclePaint.setColor(finalColor); +// canvas.drawRect(backgroundPaddingLeft, currentPanTranslationY, getMeasuredWidth() - backgroundPaddingLeft, AndroidUtilities.statusBarHeight + currentPanTranslationY, Theme.dialogs_onlineCirclePaint); } private int getCurrentTop() { @@ -1749,7 +1783,7 @@ private int getCurrentTop() { @Override protected void dispatchDraw(Canvas canvas) { canvas.save(); - canvas.clipRect(0, getPaddingTop() + currentPanTranslationY, getMeasuredWidth(), getMeasuredHeight() + currentPanTranslationY - getPaddingBottom()); +// canvas.clipRect(0, getPaddingTop() + currentPanTranslationY, getMeasuredWidth(), getMeasuredHeight() + currentPanTranslationY - getPaddingBottom()); if (currentAttachLayout == photoPreviewLayout || nextAttachLayout == photoPreviewLayout || (currentAttachLayout == photoLayout && nextAttachLayout == null)) { drawChildBackground(canvas, currentAttachLayout); } @@ -2083,6 +2117,7 @@ public void setTranslationY(float translationY) { return; } if (view instanceof AttachButton) { + final Activity activity = baseFragment.getParentActivity(); int num = (Integer) view.getTag(); if (num == 1) { if (!photosEnabled && !videosEnabled) { @@ -2090,13 +2125,24 @@ public void setTranslationY(float translationY) { } showLayout(photoLayout); } else if (num == 3) { - if (Build.VERSION.SDK_INT >= 23 && getContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + if (Build.VERSION.SDK_INT >= 33) { + if (activity.checkSelfPermission(Manifest.permission.READ_MEDIA_AUDIO) != PackageManager.PERMISSION_GRANTED) { + activity.requestPermissions(new String[]{Manifest.permission.READ_MEDIA_AUDIO}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE); + return; + } + } else if (Build.VERSION.SDK_INT >= 23 && activity.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { AndroidUtilities.findActivity(getContext()).requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE); return; } openAudioLayout(true); } else if (num == 4) { - if (Build.VERSION.SDK_INT >= 23 && getContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + if (Build.VERSION.SDK_INT >= 33) { + if (activity.checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED || + activity.checkSelfPermission(Manifest.permission.READ_MEDIA_VIDEO) != PackageManager.PERMISSION_GRANTED) { + activity.requestPermissions(new String[]{Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VIDEO}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE); + return; + } + } else if (Build.VERSION.SDK_INT >= 23 && activity.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { AndroidUtilities.findActivity(getContext()).requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE); return; } @@ -3771,6 +3817,8 @@ public void onAnimationCancel(Animator animation) { actionBarAnimation = null; } }); + actionBarAnimation.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + actionBarAnimation.setDuration(380); actionBarAnimation.start(); } else { if (show) { @@ -3813,7 +3861,7 @@ protected void updateLayout(AttachAlertLayout layout, boolean animated, int dy) animated = false; } if (layout == currentAttachLayout) { - updateActionBarVisibility(show, animated); + updateActionBarVisibility(show, true); } FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) layout.getLayoutParams(); newOffset += (layoutParams == null ? 0 : layoutParams.topMargin) - AndroidUtilities.dp(11); @@ -3969,7 +4017,14 @@ public void init() { enterCommentEventSent = false; setFocusable(false); ChatAttachAlert.AttachAlertLayout layoutToSet; - if (isSoundPicker) { + if (isStoryLocationPicker) { + if (locationLayout == null) { + layouts[5] = locationLayout = new ChatAttachAlertLocationLayout(this, getContext(), resourcesProvider); + locationLayout.setDelegate((location, live, notify, scheduleDate) -> ((ChatActivity) baseFragment).didSelectLocation(location, live, notify, scheduleDate)); + } + selectedId = 5; + layoutToSet = locationLayout; + } else if (isSoundPicker) { openDocumentsLayout(false); layoutToSet = documentLayout; selectedId = 4; @@ -4106,6 +4161,29 @@ public void setSoundPicker() { selectedTextView.setText(LocaleController.getString("ChoosePhotoOrVideo", R.string.ChoosePhotoOrVideo)); } + public boolean storyLocationPickerFileIsVideo; + public File storyLocationPickerPhotoFile; + public double[] storyLocationPickerLatLong; + public void setStoryLocationPicker() { + isStoryLocationPicker = true; + buttonsRecyclerView.setVisibility(View.GONE); + shadow.setVisibility(View.GONE); + } + public void setStoryLocationPicker(boolean isVideo, File photo) { + storyLocationPickerFileIsVideo = isVideo; + storyLocationPickerPhotoFile = photo; + isStoryLocationPicker = true; + buttonsRecyclerView.setVisibility(View.GONE); + shadow.setVisibility(View.GONE); + } + + public void setStoryLocationPicker(double lat, double lon) { + storyLocationPickerLatLong = new double[] { lat, lon }; + isStoryLocationPicker = true; + buttonsRecyclerView.setVisibility(View.GONE); + shadow.setVisibility(View.GONE); + } + public void setMaxSelectedPhotos(int value, boolean order) { if (editingMessageObject != null) { return; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java index b2c21220f9f..939cf17372b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java @@ -29,6 +29,8 @@ import android.graphics.drawable.Drawable; import android.location.Location; import android.location.LocationManager; +import android.media.ExifInterface; +import android.media.MediaMetadataRetriever; import android.os.Build; import android.text.TextUtils; import android.util.TypedValue; @@ -44,6 +46,7 @@ import android.widget.LinearLayout; import android.widget.TextView; +import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearSmoothScroller; import androidx.recyclerview.widget.RecyclerView; @@ -69,6 +72,7 @@ import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Adapters.LocationActivityAdapter; import org.telegram.ui.Adapters.LocationActivitySearchAdapter; +import org.telegram.ui.BasePermissionsActivity; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.LocationCell; import org.telegram.ui.Cells.LocationDirectionCell; @@ -79,9 +83,12 @@ import org.telegram.ui.Cells.SharingLiveLocationCell; import org.telegram.ui.ChatActivity; +import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLayout implements NotificationCenter.NotificationCenterDelegate { @@ -119,6 +126,7 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa private boolean currentMapStyleDark; private boolean checkGpsEnabled = true; + private boolean askedForLocation = false; private boolean locationDenied = false; private boolean isFirstLocation = true; @@ -151,6 +159,7 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa private Location userLocation; private int markerTop; + private boolean ignoreIdleCamera; private boolean userLocationMoved; private boolean searchedForCustomLocations; private boolean firstWas; @@ -169,6 +178,7 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa public final static int LOCATION_TYPE_SEND = 0; public final static int LOCATION_TYPE_SEND_WITH_LIVE = 1; + public final static int LOCATION_TYPE_STORY = 7; public static class VenueLocation { public int num; @@ -362,7 +372,9 @@ public ChatAttachAlertLocationLayout(ChatAttachAlert alert, Context context, The AndroidUtilities.fixGoogleMapsBug(); ChatActivity chatActivity = (ChatActivity) parentAlert.baseFragment; dialogId = chatActivity.getDialogId(); - if (chatActivity.getCurrentEncryptedChat() == null && !chatActivity.isInScheduleMode() && !UserObject.isUserSelf(chatActivity.getCurrentUser())) { + if (parentAlert.isStoryLocationPicker) { + locationType = LOCATION_TYPE_STORY; + } else if (chatActivity.getCurrentEncryptedChat() == null && !chatActivity.isInScheduleMode() && !UserObject.isUserSelf(chatActivity.getCurrentUser())) { locationType = LOCATION_TYPE_SEND_WITH_LIVE; } else { locationType = LOCATION_TYPE_SEND; @@ -443,7 +455,7 @@ public void onTextChanged(EditText editText) { searchAdapter.searchDelayed(text, userLocation); } }); - searchItem.setVisibility(locationDenied ? View.GONE : View.VISIBLE); + searchItem.setVisibility(locationDenied && !parentAlert.isStoryLocationPicker ? View.GONE : View.VISIBLE); searchItem.setSearchFieldHint(LocaleController.getString("Search", R.string.Search)); searchItem.setContentDescription(LocaleController.getString("Search", R.string.Search)); EditTextBoldCursor editText = searchItem.getSearchField(); @@ -676,9 +688,15 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { } }; listView.setClipToPadding(false); - listView.setAdapter(adapter = new LocationActivityAdapter(context, locationType, dialogId, true, resourcesProvider)); + listView.setAdapter(adapter = new LocationActivityAdapter(context, locationType, dialogId, true, resourcesProvider, parentAlert.isStoryLocationPicker)); + DefaultItemAnimator itemAnimator = new DefaultItemAnimator(); + itemAnimator.setDurations(350); + itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + itemAnimator.setDelayAnimations(false); + itemAnimator.setSupportsChangeAnimations(false); + listView.setItemAnimator(itemAnimator); adapter.setUpdateRunnable(this::updateClipView); - adapter.setMyLocationDenied(locationDenied); + adapter.setMyLocationDenied(locationDenied, askedForLocation); listView.setVerticalScrollBarEnabled(false); listView.setLayoutManager(layoutManager = new FillLastLinearLayoutManager(context, LinearLayoutManager.VERTICAL, false, 0, listView) { @Override @@ -732,7 +750,17 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { } }); listView.setOnItemClickListener((view, position) -> { - if (position == 1) { + if (locationType == LOCATION_TYPE_STORY) { + if (position == 1 && adapter.city != null) { + delegate.didSelectLocation(adapter.city, locationType, true, 0); + parentAlert.dismiss(true); + return; + } else if (position == 2 && adapter.street != null) { + delegate.didSelectLocation(adapter.street, locationType, true, 0); + parentAlert.dismiss(true); + return; + } + } else if (position == 1) { if (delegate != null && userLocation != null) { if (lastPressedMarkerView != null) { lastPressedMarkerView.callOnClick(); @@ -754,6 +782,7 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { } else if (locationDenied) { AlertsCreator.createLocationRequiredDialog(getParentActivity(), true).show(); } + return; } else if (position == 2 && locationType == LOCATION_TYPE_SEND_WITH_LIVE) { if (getLocationController().isSharingLocation(dialogId)) { getLocationController().removeSharingLocation(dialogId); @@ -765,22 +794,23 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { openShareLiveLocation(); } } - } else { - Object object = adapter.getItem(position); - if (object instanceof TLRPC.TL_messageMediaVenue) { - if (chatActivity.isInScheduleMode()) { - AlertsCreator.createScheduleDatePickerDialog(getParentActivity(), chatActivity.getDialogId(), (notify, scheduleDate) -> { - delegate.didSelectLocation((TLRPC.TL_messageMediaVenue) object, locationType, notify, scheduleDate); - parentAlert.dismiss(true); - }, resourcesProvider); - } else { - delegate.didSelectLocation((TLRPC.TL_messageMediaVenue) object, locationType, true, 0); + return; + } + + Object object = adapter.getItem(position); + if (object instanceof TLRPC.TL_messageMediaVenue) { + if (chatActivity.isInScheduleMode()) { + AlertsCreator.createScheduleDatePickerDialog(getParentActivity(), chatActivity.getDialogId(), (notify, scheduleDate) -> { + delegate.didSelectLocation((TLRPC.TL_messageMediaVenue) object, locationType, notify, scheduleDate); parentAlert.dismiss(true); - } - } else if (object instanceof LiveLocation) { - LiveLocation liveLocation = (LiveLocation) object; - map.animateCamera(ApplicationLoader.getMapsProvider().newCameraUpdateLatLngZoom(new IMapsProvider.LatLng(liveLocation.marker.getPosition().latitude, liveLocation.marker.getPosition().longitude), map.getMaxZoomLevel() - 4)); + }, resourcesProvider); + } else { + delegate.didSelectLocation((TLRPC.TL_messageMediaVenue) object, locationType, true, 0); + parentAlert.dismiss(true); } + } else if (object instanceof LiveLocation) { + LiveLocation liveLocation = (LiveLocation) object; + map.animateCamera(ApplicationLoader.getMapsProvider().newCameraUpdateLatLngZoom(new IMapsProvider.LatLng(liveLocation.marker.getPosition().latitude, liveLocation.marker.getPosition().longitude), map.getMaxZoomLevel() - 4)); } }); adapter.setDelegate(dialogId, this::updatePlacesMarkers); @@ -819,7 +849,7 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { animatorSet.setDuration(200); animatorSet.playTogether(ObjectAnimator.ofFloat(markerImageView, View.TRANSLATION_Y, markerTop)); animatorSet.start(); - adapter.fetchLocationAddress(); +// adapter.fetchLocationAddress(); } if (ev.getAction() == MotionEvent.ACTION_MOVE) { if (!userLocationMoved) { @@ -880,7 +910,7 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { searchListView = new RecyclerListView(context, resourcesProvider); searchListView.setVisibility(GONE); searchListView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); - searchAdapter = new LocationActivitySearchAdapter(context) { + searchAdapter = new LocationActivitySearchAdapter(context, resourcesProvider, parentAlert.isStoryLocationPicker) { @Override public void notifyDataSetChanged() { if (searchItem != null) { @@ -892,6 +922,7 @@ public void notifyDataSetChanged() { super.notifyDataSetChanged(); } }; + searchAdapter.setMyLocationDenied(locationDenied); searchAdapter.setDelegate(0, places -> { searchInProgress = false; updateEmptyView(); @@ -1109,6 +1140,9 @@ private void updateEmptyView() { } private void showSearchPlacesButton(boolean show) { + if (locationDenied) { + show = false; + } if (show && searchAreaButton != null && searchAreaButton.getTag() == null) { if (myLocation == null || userLocation == null || userLocation.distanceTo(myLocation) < 300) { show = false; @@ -1262,11 +1296,28 @@ private void onMapInit() { } } }); + map.setOnCameraIdleListener(() -> { + if (ignoreIdleCamera) { + ignoreIdleCamera = false; + return; + } + if (map != null) { + if (userLocation != null) { + userLocation.setLatitude(map.getCameraPosition().target.latitude); + userLocation.setLongitude(map.getCameraPosition().target.longitude); + } + } + adapter.setCustomLocation(userLocation); + adapter.fetchLocationAddress(); + }); map.setOnMyLocationChangeListener(location -> { if (parentAlert == null || parentAlert.baseFragment == null) { return; } positionMarker(location); + if (adapter != null && locationType == LOCATION_TYPE_STORY && !userLocationMoved) { + adapter.setCustomLocation(userLocation); + } getLocationController().setMapLocation(location, isFirstLocation); isFirstLocation = false; }); @@ -1288,12 +1339,12 @@ private void onMapInit() { overlayView.updatePositions(); } }); + positionMarker(); AndroidUtilities.runOnUIThread(() -> { if (loadingMapView.getTag() == null) { loadingMapView.animate().alpha(0.0f).setDuration(180).start(); } }, 200); - positionMarker(myLocation = getLastLocation()); if (checkGpsEnabled && getParentActivity() != null) { checkGpsEnabled = false; @@ -1306,7 +1357,7 @@ private void onMapInit() { LocationManager lm = (LocationManager) ApplicationLoader.applicationContext.getSystemService(Context.LOCATION_SERVICE); if (!lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity(), resourcesProvider); - builder.setTopAnimation(R.raw.permission_request_location, AlertsCreator.PERMISSIONS_REQUEST_TOP_ICON_SIZE, false, Theme.getColor(Theme.key_dialogTopBackground)); + builder.setTopAnimation(R.raw.permission_request_location, AlertsCreator.PERMISSIONS_REQUEST_TOP_ICON_SIZE, false, Theme.getColor(Theme.key_dialogTopBackground, resourcesProvider)); builder.setMessage(LocaleController.getString("GpsDisabledAlertText", R.string.GpsDisabledAlertText)); builder.setPositiveButton(LocaleController.getString("ConnectingToProxyEnable", R.string.ConnectingToProxyEnable), (dialog, id) -> { if (getParentActivity() == null) { @@ -1328,6 +1379,48 @@ private void onMapInit() { updateClipView(); } + private void resetMapPosition(double lat, double _long) { + if (map == null) { + return; + } + if (lat != 0 && _long != 0) { + userLocation = new Location(""); + userLocation.reset(); + userLocation.setLatitude(lat); + userLocation.setLongitude(_long); + } else { + myLocation = new Location(""); + myLocation.reset(); + myLocation.setLatitude(lat); + myLocation.setLongitude(_long); + } + IMapsProvider.LatLng latLng = new IMapsProvider.LatLng(lat, _long); + IMapsProvider.ICameraUpdate position; + if (lat != 0 && _long != 0) { + position = ApplicationLoader.getMapsProvider().newCameraUpdateLatLngZoom(latLng, map.getMaxZoomLevel() - 4); + } else { + position = ApplicationLoader.getMapsProvider().newCameraUpdateLatLngZoom(latLng, map.getMinZoomLevel()); + } + forceUpdate = position; + map.moveCamera(position); + if (lat != 0 && _long != 0) { + adapter.setCustomLocation(userLocation); + } else { + adapter.setGpsLocation(myLocation); + } + adapter.fetchLocationAddress(); + listView.smoothScrollBy(0, 1); + ignoreIdleCamera = true; + + if (lat != 0 && _long != 0) { + userLocationMoved = true; + showSearchPlacesButton(false); + adapter.searchPlacesWithQuery(null, userLocation, true, true); + searchedForCustomLocations = true; + showResults(); + } + } + private void removeInfoView() { if (lastPressedMarker != null) { markerImageView.setVisibility(VISIBLE); @@ -1418,7 +1511,7 @@ private void updateClipView() { IMapsProvider.LatLng location; if (lastPressedMarker != null) { location = new IMapsProvider.LatLng(lastPressedMarker.getPosition().latitude, lastPressedMarker.getPosition().longitude); - } else if (userLocationMoved) { + } else if (userLocationMoved && userLocation != null) { location = new IMapsProvider.LatLng(userLocation.getLatitude(), userLocation.getLongitude()); } else if (myLocation != null) { location = new IMapsProvider.LatLng(myLocation.getLatitude(), myLocation.getLongitude()); @@ -1450,7 +1543,7 @@ private boolean isTypeSend() { private int buttonsHeight() { int buttonsHeight = AndroidUtilities.dp(66); - if (locationType == LOCATION_TYPE_SEND_WITH_LIVE) + if (locationType == LOCATION_TYPE_SEND_WITH_LIVE || locationType == LOCATION_TYPE_STORY) buttonsHeight += AndroidUtilities.dp(66); return buttonsHeight; } @@ -1513,6 +1606,55 @@ private Location getLastLocation() { return l; } + private void positionMarker() { + if (parentAlert.isStoryLocationPicker) { + if (parentAlert.storyLocationPickerLatLong != null) { + AndroidUtilities.runOnUIThread(() -> resetMapPosition(parentAlert.storyLocationPickerLatLong[0], parentAlert.storyLocationPickerLatLong[1])); + } else if (!locationDenied) { + boolean reset = true; + final File file = parentAlert.storyLocationPickerPhotoFile; + final boolean isVideo = parentAlert.storyLocationPickerFileIsVideo; + if (file != null) { + try { + if (isVideo) { + MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever(); + mediaMetadataRetriever.setDataSource(file.getAbsolutePath()); + String location = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_LOCATION); + if (location != null) { + Matcher m = Pattern.compile("([+\\-][0-9.]+)([+\\-][0-9.]+)").matcher(location); + if (m.find() && m.groupCount() == 2) { + String latstr = m.group(1); + String lonstr = m.group(2); + try { + double lat = Double.parseDouble(latstr); + double lon = Double.parseDouble(lonstr); + AndroidUtilities.runOnUIThread(() -> resetMapPosition(lat, lon)); + reset = false; + } catch (NumberFormatException ignored) { + } + } + } + } else { + ExifInterface ei = new ExifInterface(file.getAbsolutePath()); + float[] latlong = new float[2]; + if (ei.getLatLong(latlong)) { + AndroidUtilities.runOnUIThread(() -> resetMapPosition(latlong[0], latlong[1])); + reset = false; + } + } + } catch (Exception e) {} + } + if (reset) { + positionMarker(myLocation = getLastLocation()); + } + } else { + AndroidUtilities.runOnUIThread(() -> resetMapPosition(0, 0)); + } + } else { + positionMarker(myLocation = getLastLocation()); + } + } + private void positionMarker(Location location) { if (location == null) { return; @@ -1547,8 +1689,13 @@ private void positionMarker(Location location) { public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.locationPermissionGranted) { locationDenied = false; + askedForLocation = false; + positionMarker(); if (adapter != null) { - adapter.setMyLocationDenied(locationDenied); + adapter.setMyLocationDenied(locationDenied, askedForLocation); + } + if (searchAdapter != null) { + searchAdapter.setMyLocationDenied(locationDenied); } if (map != null) { try { @@ -1559,12 +1706,16 @@ public void didReceivedNotification(int id, int account, Object... args) { } } else if (id == NotificationCenter.locationPermissionDenied) { locationDenied = true; + askedForLocation = false; if (adapter != null) { - adapter.setMyLocationDenied(locationDenied); + adapter.setMyLocationDenied(locationDenied, askedForLocation); + } + if (searchAdapter != null) { + searchAdapter.setMyLocationDenied(locationDenied); } } fixLayoutInternal(true); - searchItem.setVisibility(locationDenied ? View.GONE : View.VISIBLE); + searchItem.setVisibility(locationDenied && !parentAlert.isStoryLocationPicker ? View.GONE : View.VISIBLE); } @Override @@ -1612,7 +1763,20 @@ void onShow(ChatAttachAlert.AttachAlertLayout previousLayout) { if (activity != null) { checkPermission = false; if (activity.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - activity.requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 2); + String[] permissions = parentAlert.isStoryLocationPicker && parentAlert.storyLocationPickerPhotoFile != null && Build.VERSION.SDK_INT >= 29 ? + new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_MEDIA_LOCATION} : + new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}; + askedForLocation = true; + if (adapter != null) { + adapter.setMyLocationDenied(locationDenied, askedForLocation); + } + activity.requestPermissions(permissions, BasePermissionsActivity.REQUEST_CODE_GEOLOCATION); + } else if (Build.VERSION.SDK_INT >= 29 && parentAlert.isStoryLocationPicker && parentAlert.storyLocationPickerPhotoFile != null && activity.checkSelfPermission(Manifest.permission.ACCESS_MEDIA_LOCATION) != PackageManager.PERMISSION_GRANTED) { + askedForLocation = true; + if (adapter != null) { + adapter.setMyLocationDenied(locationDenied, askedForLocation); + } + activity.requestPermissions(new String[]{Manifest.permission.ACCESS_MEDIA_LOCATION}, BasePermissionsActivity.REQUEST_CODE_MEDIA_GEO); } } } @@ -1730,4 +1894,16 @@ public ArrayList getThemeDescriptions() { return themeDescriptions; } + + @Override + public void onPanTransitionStart(boolean keyboardVisible, int contentHeight) { + if (keyboardVisible) { + adapter.animated = false; + } + } + + @Override + public void onPanTransitionEnd() { + adapter.animated = parentAlert != null && !parentAlert.isKeyboardVisible(); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java index 607a3c34922..c2cc7b17aab 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java @@ -16,6 +16,7 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; +import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -738,10 +739,14 @@ public int getSpanSize(int position) { } return; } else if (noGalleryPermissions) { - try { - fragment.getParentActivity().requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE); - } catch (Exception ignore) { - + if (Build.VERSION.SDK_INT >= 33) { + try { + fragment.getParentActivity().requestPermissions(new String[]{Manifest.permission.READ_MEDIA_VIDEO, Manifest.permission.READ_MEDIA_IMAGES}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE); + } catch (Exception ignore) {} + } else { + try { + fragment.getParentActivity().requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE); + } catch (Exception ignore) {} } return; } @@ -2898,9 +2903,26 @@ public void updateSelected(HashMap newSelectedPhotos, ArrayList< } } + private boolean isNoGalleryPermissions() { + Activity activity = AndroidUtilities.findActivity(getContext()); + if (activity == null) { + activity = parentAlert.baseFragment.getParentActivity(); + } + return Build.VERSION.SDK_INT >= 23 && ( + activity == null || + Build.VERSION.SDK_INT >= 33 && ( + activity.checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED || + activity.checkSelfPermission(Manifest.permission.READ_MEDIA_VIDEO) != PackageManager.PERMISSION_GRANTED + ) || + Build.VERSION.SDK_INT < 33 && activity.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED + ); + } + public void checkStorage() { if (noGalleryPermissions && Build.VERSION.SDK_INT >= 23) { - noGalleryPermissions = parentAlert.baseFragment.getParentActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED; + final Activity activity = parentAlert.baseFragment.getParentActivity(); + + noGalleryPermissions = isNoGalleryPermissions(); if (!noGalleryPermissions) { loadGalleryPhotos(); } @@ -3255,7 +3277,7 @@ void onInit(boolean hasVideo, boolean hasPhoto, boolean hasDocuments) { } } if (Build.VERSION.SDK_INT >= 23) { - noGalleryPermissions = parentAlert.getContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED; + noGalleryPermissions = isNoGalleryPermissions(); } if (galleryAlbumEntry != null) { for (int a = 0; a < Math.min(100, galleryAlbumEntry.photos.size()); a++) { @@ -4014,7 +4036,7 @@ public int getItemCount() { return 1; } int count = 0; - if (needCamera && selectedAlbumEntry != null && galleryAlbumEntry != null && selectedAlbumEntry.bucketId == galleryAlbumEntry.bucketId) { + if (needCamera && selectedAlbumEntry == galleryAlbumEntry) { count++; } if (showAvatarConstructor) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ColoredImageSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ColoredImageSpan.java index 34e95b01b43..a8cb2bc9e1f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ColoredImageSpan.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ColoredImageSpan.java @@ -23,7 +23,9 @@ public class ColoredImageSpan extends ReplacementSpan { boolean usePaintColor = true; int colorKey; private int topOffset = 0; - private float translateX; + private float translateX, translateY; + private float alpha = 1f; + private int overrideColor; private int size; private int sizeWidth; @@ -32,7 +34,7 @@ public class ColoredImageSpan extends ReplacementSpan { public static final int ALIGN_BASELINE = 1; public static final int ALIGN_CENTER = 2; private final int verticalAlignment; - private float scale = 1f; + private float scaleX = 1f, scaleY = 1f; private Runnable checkColorDelegate; public ColoredImageSpan(int imageRes) { @@ -59,10 +61,20 @@ public void setSize(int size) { this.size = size; drawable.setBounds(0, 0, size, size); } + public void setTranslateX(float tx) { translateX = tx; } + public void setTranslateY(float ty) { + translateY = ty; + } + + public void translate(float tx, float ty) { + translateX = tx; + translateY = ty; + } + public void setWidth(int width) { sizeWidth = width; } @@ -70,8 +82,8 @@ public void setWidth(int width) { @Override public int getSize(@NonNull Paint paint, CharSequence charSequence, int i, int i1, @Nullable Paint.FontMetricsInt fontMetricsInt) { if (sizeWidth != 0) - return (int) (scale * sizeWidth); - return (int) (scale * (size != 0 ? size : drawable.getIntrinsicWidth())); + return (int) (Math.abs(scaleX) * sizeWidth); + return (int) (Math.abs(scaleX) * (size != 0 ? size : drawable.getIntrinsicWidth())); } @Override @@ -80,7 +92,9 @@ public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, if (checkColorDelegate != null) { checkColorDelegate.run(); } else { - if (usePaintColor) { + if (overrideColor != 0) { + color = overrideColor; + } else if (usePaintColor) { color = paint.getColor(); } else { color = Theme.getColor(colorKey); @@ -103,10 +117,13 @@ public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, int padding = (lineHeight - drawableHeight) / 2; transY = top + padding + AndroidUtilities.dp(topOffset); } - canvas.translate(x + translateX, transY); + canvas.translate(x + translateX, transY + translateY); if (drawable != null) { - if (scale != 1f) { - canvas.scale(scale, scale, 0, drawable.getBounds().centerY()); + if (scaleX != 1f || scaleY != 1f) { + canvas.scale(scaleX, scaleY, 0, drawable.getBounds().centerY()); + } + if (alpha != 1f) { + drawable.setAlpha((int) (alpha * 255)); } drawable.draw(canvas); } @@ -126,7 +143,20 @@ public void setCheckColorDelegate(Runnable checkColorDelegate) { this.checkColorDelegate = checkColorDelegate; } - public void setScale(float v) { - scale = v; + public void setScale(float sx) { + scaleX = sx; + } + + public void setScale(float sx, float sy) { + scaleX = sx; + scaleY = sy; + } + + public void setOverrideColor(int red) { + overrideColor = red; + } + + public void setAlpha(float v) { + this.alpha = v; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CombinedDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CombinedDrawable.java index d723a4bea7c..4359b7e4302 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CombinedDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CombinedDrawable.java @@ -125,8 +125,10 @@ public ConstantState getConstantState() { @Override public void draw(Canvas canvas) { - background.setBounds(getBounds()); - background.draw(canvas); + if (background != null) { + background.setBounds(getBounds()); + background.draw(canvas); + } if (icon != null) { if (fullSize) { android.graphics.Rect bounds = getBounds(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextBoldCursor.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextBoldCursor.java index ef2e96033e2..f4fcf4ff960 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextBoldCursor.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextBoldCursor.java @@ -26,6 +26,7 @@ import android.os.SystemClock; import androidx.annotation.Keep; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; @@ -99,6 +100,7 @@ public void run() { private float lineSpacingExtra; private Rect rect = new Rect(); private StaticLayout hintLayout; + private AnimatedTextView.AnimatedTextDrawable hintAnimatedDrawable; private CharSequence hint; private StaticLayout errorLayout; private CharSequence errorText; @@ -193,6 +195,17 @@ public EditTextBoldCursor(Context context) { init(); } + public void useAnimatedTextDrawable() { + hintAnimatedDrawable = new AnimatedTextView.AnimatedTextDrawable() { + @Override + public void invalidateSelf() { + invalidate(); + } + }; + hintAnimatedDrawable.setTextColor(hintColor); + hintAnimatedDrawable.setTextSize(getPaint().getTextSize()); + } + @Override public void addTextChangedListener(TextWatcher watcher) { registeredTextWatchers.add(watcher); @@ -462,6 +475,9 @@ public void setHintVisible(boolean value, boolean animated) { public void setHintColor(int value) { hintColor = value; + if (hintAnimatedDrawable != null) { + hintAnimatedDrawable.setTextColor(hintColor); + } invalidate(); } @@ -470,6 +486,14 @@ public void setHeaderHintColor(int value) { invalidate(); } + @Override + public void setTextSize(int unit, float size) { + if (hintAnimatedDrawable != null) { + hintAnimatedDrawable.setTextSize(AndroidUtilities.dp(size)); + } + super.setTextSize(unit, size); + } + public void setNextSetTextAnimated(boolean value) { nextSetTextAnimated = value; } @@ -521,7 +545,10 @@ public void setText(CharSequence text, BufferType type) { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int currentSize = getMeasuredHeight() + (getMeasuredWidth() << 16); - if (hintLayout != null) { + if (hintAnimatedDrawable != null) { + hintAnimatedDrawable.setBounds(getPaddingLeft(), getPaddingTop(), getMeasuredWidth() - getPaddingRight(), getMeasuredHeight() - getPaddingBottom()); + } + if (hintLayout != null && hintAnimatedDrawable == null) { if (lastSize != currentSize) { setHintText(hint); } @@ -537,30 +564,34 @@ public void setHintText(CharSequence text) { } public void setHintText(CharSequence text, boolean animated) { - if (text == null) { - text = ""; - } - if (getMeasuredWidth() == 0) { - animated = false; - } - if (animated) { - if (hintAnimator == null) { - hintAnimator = new SubstringLayoutAnimator(this); - } - hintAnimator.create(hintLayout, hint, text, getPaint()); + if (hintAnimatedDrawable != null) { + hintAnimatedDrawable.setText(text, true); } else { - if (hintAnimator != null) { - hintAnimator.cancel(); + if (text == null) { + text = ""; } - } - hint = text; - if (getMeasuredWidth() != 0) { - text = TextUtils.ellipsize(text, getPaint(), getMeasuredWidth(), TextUtils.TruncateAt.END); - if (hintLayout != null && TextUtils.equals(hintLayout.getText(), text)) { - return; + if (getMeasuredWidth() == 0) { + animated = false; + } + if (animated) { + if (hintAnimator == null) { + hintAnimator = new SubstringLayoutAnimator(this); + } + hintAnimator.create(hintLayout, hint, text, getPaint()); + } else { + if (hintAnimator != null) { + hintAnimator.cancel(); + } + } + hint = text; + if (getMeasuredWidth() != 0) { + text = TextUtils.ellipsize(text, getPaint(), getMeasuredWidth(), TextUtils.TruncateAt.END); + if (hintLayout != null && TextUtils.equals(hintLayout.getText(), text)) { + return; + } } + hintLayout = new StaticLayout(text, getPaint(), AndroidUtilities.dp(1000), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } - hintLayout = new StaticLayout(text, getPaint(), AndroidUtilities.dp(1000), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } public Layout getHintLayoutEx() { @@ -665,7 +696,7 @@ public void invalidateForce() { @Override protected void onDraw(Canvas canvas) { - if ((length() == 0 || transformHintToHeader) && hintLayout != null && (hintVisible || hintAlpha != 0)) { + if (length() == 0 || transformHintToHeader) { if (hintVisible && hintAlpha != 1.0f || !hintVisible && hintAlpha != 0.0f) { long newTime = System.currentTimeMillis(); long dt = newTime - hintLastUpdateTime; @@ -686,46 +717,51 @@ protected void onDraw(Canvas canvas) { } invalidate(); } - int oldColor = getPaint().getColor(); - - canvas.save(); - int left = 0; - float lineLeft = hintLayout.getLineLeft(0); - float hintWidth = hintLayout.getLineWidth(0); - if (lineLeft != 0) { - left -= lineLeft; - } - if (supportRtlHint && LocaleController.isRTL) { - float offset = getMeasuredWidth() - hintWidth; - canvas.translate(left + getScrollX() + offset, lineY - hintLayout.getHeight() - AndroidUtilities.dp(7)); - } else { - canvas.translate(left + getScrollX(), lineY - hintLayout.getHeight() - AndroidUtilities.dp2(7)); - } - if (transformHintToHeader) { - float scale = 1.0f - 0.3f * headerAnimationProgress; + if (hintAnimatedDrawable != null && !TextUtils.isEmpty(hintAnimatedDrawable.getText()) && (hintVisible || hintAlpha != 0)) { + hintAnimatedDrawable.setAlpha((int) (Color.alpha(hintColor) * hintAlpha)); + hintAnimatedDrawable.draw(canvas); + } else if (hintLayout != null && (hintVisible || hintAlpha != 0)) { + int oldColor = getPaint().getColor(); + canvas.save(); + int left = 0; + float lineLeft = hintLayout.getLineLeft(0); + float hintWidth = hintLayout.getLineWidth(0); + if (lineLeft != 0) { + left -= lineLeft; + } if (supportRtlHint && LocaleController.isRTL) { - canvas.translate((hintWidth + lineLeft) - (hintWidth + lineLeft) * scale, 0); - } else if (lineLeft != 0) { - canvas.translate(lineLeft * (1.0f - scale), 0); + float offset = getMeasuredWidth() - hintWidth; + canvas.translate(left + getScrollX() + offset, lineY - hintLayout.getHeight() - AndroidUtilities.dp(7)); + } else { + canvas.translate(left + getScrollX(), lineY - hintLayout.getHeight() - AndroidUtilities.dp2(7)); } - canvas.scale(scale, scale); - canvas.translate(0, -AndroidUtilities.dp(22) * headerAnimationProgress); - getPaint().setColor(ColorUtils.blendARGB(hintColor, headerHintColor, headerAnimationProgress)); - } else { - getPaint().setColor(hintColor); - getPaint().setAlpha((int) (255 * hintAlpha * (Color.alpha(hintColor) / 255.0f))); - } - if (hintAnimator != null && hintAnimator.animateTextChange) { - canvas.save(); - canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight()); - hintAnimator.draw(canvas, getPaint()); + if (transformHintToHeader) { + float scale = 1.0f - 0.3f * headerAnimationProgress; + + if (supportRtlHint && LocaleController.isRTL) { + canvas.translate((hintWidth + lineLeft) - (hintWidth + lineLeft) * scale, 0); + } else if (lineLeft != 0) { + canvas.translate(lineLeft * (1.0f - scale), 0); + } + canvas.scale(scale, scale); + canvas.translate(0, -AndroidUtilities.dp(22) * headerAnimationProgress); + getPaint().setColor(ColorUtils.blendARGB(hintColor, headerHintColor, headerAnimationProgress)); + } else { + getPaint().setColor(hintColor); + getPaint().setAlpha((int) (255 * hintAlpha * (Color.alpha(hintColor) / 255.0f))); + } + if (hintAnimator != null && hintAnimator.animateTextChange) { + canvas.save(); + canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight()); + hintAnimator.draw(canvas, getPaint()); + canvas.restore(); + } else { + hintLayout.draw(canvas); + } + getPaint().setColor(oldColor); canvas.restore(); - } else { - hintLayout.draw(canvas); } - getPaint().setColor(oldColor); - canvas.restore(); } int topPadding = getExtendedPaddingTop(); @@ -999,6 +1035,7 @@ public ActionMode startActionMode(ActionMode.Callback callback) { } cleanupFloatingActionModeViews(); floatingToolbar = new FloatingToolbar(getContext(), windowView != null ? windowView : attachedToWindow, getActionModeStyle(), getResourcesProvider()); + floatingToolbar.setOnPremiumLockClick(onPremiumMenuLockClickListener); floatingActionMode = new FloatingActionMode(getContext(), new ActionModeCallback2Wrapper(callback), this, floatingToolbar); floatingToolbarPreDrawListener = () -> { if (floatingActionMode != null) { @@ -1091,4 +1128,9 @@ public void setHandlesColor(int color) { setTextSelectHandleRight(right); } catch (Exception ignore) {} } + + private Runnable onPremiumMenuLockClickListener; + public void setOnPremiumMenuLockClickListener(Runnable listener) { + onPremiumMenuLockClickListener = listener; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java index 7ca022730e9..ce5650be19c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java @@ -597,9 +597,9 @@ public void updateEmojiPacks(ArrayList emojiPacks) { } } else { final boolean free = newPack.free; // isFreeEmojiPack(newPack.set, newPack.documents); - DelayedAnimatedEmojiDrawable drawable = currentPackButton == null ? null : (DelayedAnimatedEmojiDrawable) currentPackButton.getDrawable(); + DelayedAnimatedEmojiDrawable drawable = currentPackButton == null || !(currentPackButton.getDrawable() instanceof DelayedAnimatedEmojiDrawable) ? null : (DelayedAnimatedEmojiDrawable) currentPackButton.getDrawable(); TLRPC.Document thumbDocument = getThumbDocument(newPack.set, newPack.documents); - if (thumbDocument != null && (drawable == null || !drawable.equals(thumbDocument.id))) { + if (thumbDocument != null && (drawable == null || drawable.documentId != thumbDocument.id)) { drawable = new DelayedAnimatedEmojiDrawable(UserConfig.selectedAccount, animatedEmojiCacheType, thumbDocument); } if (currentPackButton == null) { @@ -610,6 +610,7 @@ public void updateEmojiPacks(ArrayList emojiPacks) { } else if (currentPackButton.getDrawable() != drawable) { currentPackButton.setDrawable(drawable); } + currentPackButton.updateSelect(selected == i, false); if (currentType == SelectAnimatedEmojiDialog.TYPE_AVATAR_CONSTRUCTOR) { currentPackButton.setLock(null); } else if (!isPremium && !free) { @@ -1065,14 +1066,14 @@ public void invalidate(int l, int t, int r, int b) { @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); - if (lottieDrawable != null && wasVisible) { + if (lottieDrawable != null && isVisible) { lottieDrawable.draw(canvas); } } @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - if (!wasVisible) { + if (!isVisible) { return true; } return super.drawChild(canvas, child, drawingTime); @@ -1080,7 +1081,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { @Override protected void onDraw(Canvas canvas) { - if (!wasVisible) { + if (!isVisible) { return; } super.onDraw(canvas); @@ -1118,17 +1119,17 @@ private void stopAnimation() { } } - private boolean wasVisible; + private boolean isVisible; public void updateVisibilityInbounds(boolean visible, boolean ignore) { - if (!wasVisible && visible) { + if (!isVisible && visible) { if (lottieDrawable != null && !lottieDrawable.isRunning() && !ignore) { lottieDrawable.setProgress(0); lottieDrawable.start(); } } - if (wasVisible != visible) { - wasVisible = visible; + if (isVisible != visible) { + isVisible = visible; if (visible) { invalidate(); if (lockView != null) { @@ -1254,14 +1255,14 @@ public void setDrawable(Drawable drawable) { newEmoji = (DelayedAnimatedEmojiDrawable) drawable; } if (animatedEmoji != newEmoji) { - if (animatedEmoji != null && attached && wasVisible) { + if (animatedEmoji != null) { animatedEmoji.removeView(); } animatedEmoji = newEmoji; - if (animatedEmoji != null && attached && wasVisible) { + if (animatedEmoji != null && attached && isVisible) { animatedEmoji.updateView(imageView); } - if (wasVisible && animatedEmoji != null) { + if (isVisible && animatedEmoji != null) { animatedEmoji.load(); } initLock(); @@ -1287,7 +1288,7 @@ protected void onDetachedFromWindow() { private void updateAttachState() { if (animatedEmoji != null) { - if ((keepAttached || attached) && wasVisible) { + if ((keepAttached || attached) && isVisible) { animatedEmoji.updateView(imageView); } else { animatedEmoji.removeView(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FillLastLinearLayoutManager.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FillLastLinearLayoutManager.java index 34a1e865945..c857e405a68 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FillLastLinearLayoutManager.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FillLastLinearLayoutManager.java @@ -20,6 +20,7 @@ public class FillLastLinearLayoutManager extends LinearLayoutManager { private boolean canScrollVertically = true; boolean fixedLastItemHeight; private int minimumHeight; + private boolean setMeassuredHeightToLastItem = true; public FillLastLinearLayoutManager(Context context, int h, RecyclerView recyclerView) { super(context); @@ -163,11 +164,13 @@ public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int ite @Override public void measureChildWithMargins(View child, int widthUsed, int heightUsed) { - RecyclerView.ViewHolder holder = listView.findContainingViewHolder(child); - int pos = holder.getAdapterPosition(); - if (pos == getItemCount() - 1) { - RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams(); - layoutParams.height = Math.max(lastItemHeight, 0); + if (setMeassuredHeightToLastItem) { + RecyclerView.ViewHolder holder = listView.findContainingViewHolder(child); + int pos = holder.getAdapterPosition(); + if (pos == getItemCount() - 1) { + RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams(); + layoutParams.height = Math.max(lastItemHeight, 0); + } } super.measureChildWithMargins(child, 0, 0); } @@ -179,4 +182,12 @@ public void setFixedLastItemHeight() { public void setMinimumLastViewHeight(int height) { minimumHeight = height; } + + public void setSetMeassuredHeightToLastItem(boolean setMeassuredHeightToLastItem) { + this.setMeassuredHeightToLastItem = setMeassuredHeightToLastItem; + } + + public int getLastItemHeight() { + return lastItemHeight; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FlickerLoadingView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FlickerLoadingView.java index 7d8b56903b3..9b92541ca10 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FlickerLoadingView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FlickerLoadingView.java @@ -69,7 +69,7 @@ public class FlickerLoadingView extends View { private int colorKey1 = Theme.key_actionBarDefaultSubmenuBackground; private int colorKey2 = Theme.key_listSelector; - private int colorKey3; + private int colorKey3 = -1; private int itemsCount = 1; private final Theme.ResourcesProvider resourcesProvider; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/GradientTools.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/GradientTools.java index b1077983c9f..265d6172edd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/GradientTools.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GradientTools.java @@ -33,9 +33,10 @@ public class GradientTools { Bitmap gradientBitmap = null; int[] colors = new int[4]; + public boolean isLinear; public void setColors(int color1, int color2) { - setColors(color1, color2, 0, 0); + setColors(color1, color2, 0, 0); } public void setColors(int color1, int color2, int color3) { @@ -60,11 +61,19 @@ public void setColors(int color1, int color2, int color3, int color4) { paint.setShader(shader = new LinearGradient(isDiagonal ? INTERNAL_HEIGHT : 0, 0, 0, INTERNAL_HEIGHT, new int[]{color1, color2}, null, Shader.TileMode.CLAMP)); } } else { - if (gradientBitmap == null) { - gradientBitmap = Bitmap.createBitmap(INTERNAL_WIDTH, INTERNAL_HEIGHT, Bitmap.Config.ARGB_8888); + if (isLinear) { + if (isDiagonal && isRotate) { + paint.setShader(shader = new LinearGradient(0, 0, INTERNAL_HEIGHT, INTERNAL_HEIGHT, new int[]{color1, color2, color3}, null, Shader.TileMode.CLAMP)); + } else { + paint.setShader(shader = new LinearGradient(isDiagonal ? INTERNAL_HEIGHT : 0, 0, 0, INTERNAL_HEIGHT, new int[]{color1, color2, color3}, null, Shader.TileMode.CLAMP)); + } + } else { + if (gradientBitmap == null) { + gradientBitmap = Bitmap.createBitmap(INTERNAL_WIDTH, INTERNAL_HEIGHT, Bitmap.Config.ARGB_8888); + } + Utilities.generateGradient(gradientBitmap, true, 0, 0, gradientBitmap.getWidth(), gradientBitmap.getHeight(), gradientBitmap.getRowBytes(), colors); + paint.setShader(shader = new BitmapShader(gradientBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); } - Utilities.generateGradient(gradientBitmap, true, 0, 0, gradientBitmap.getWidth(), gradientBitmap.getHeight(), gradientBitmap.getRowBytes(), colors); - paint.setShader(shader = new BitmapShader(gradientBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); } updateBounds(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ImageUpdater.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ImageUpdater.java index 936e22e3010..918dd5bcc77 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ImageUpdater.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ImageUpdater.java @@ -688,9 +688,15 @@ public void openGallery() { if (parentFragment == null) { return; } - if (Build.VERSION.SDK_INT >= 23 && parentFragment.getParentActivity() != null) { - if (parentFragment.getParentActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - parentFragment.getParentActivity().requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE_FOR_AVATAR); + final Activity activity = parentFragment.getParentActivity(); + if (Build.VERSION.SDK_INT >= 33 && activity != null) { + if (activity.checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED || activity.checkSelfPermission(Manifest.permission.READ_MEDIA_VIDEO) != PackageManager.PERMISSION_GRANTED) { + activity.requestPermissions(new String[]{Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VIDEO}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE_FOR_AVATAR); + return; + } + } else if (Build.VERSION.SDK_INT >= 23 && activity != null) { + if (activity.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + activity.requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE_FOR_AVATAR); return; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java index fa4a45f46ea..30a02492bdd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java @@ -1906,9 +1906,6 @@ public void run() { public void startRecording(File outputFile, android.opengl.EGLContext sharedContext) { int resolution = MessagesController.getInstance(currentAccount).roundVideoSize; int bitrate = MessagesController.getInstance(currentAccount).roundVideoBitrate * 1024; - AndroidUtilities.runOnUIThread(() -> { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); - }); videoFile = outputFile; videoWidth = resolution; @@ -1950,9 +1947,6 @@ public void startRecording(File outputFile, android.opengl.EGLContext sharedCont public void stopRecording(int send) { handler.sendMessage(handler.obtainMessage(MSG_STOP_RECORDING, send, 0)); - AndroidUtilities.runOnUIThread(() -> { - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); - }); } long prevTimestamp; @@ -2885,6 +2879,7 @@ public void drainEncoder(boolean endOfStream) throws Exception { } } + @Override protected void finalize() throws Throwable { if (fileWriteQueue != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ItemOptions.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ItemOptions.java index b5e22efca9f..29133a3908b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ItemOptions.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ItemOptions.java @@ -28,6 +28,7 @@ import com.google.android.exoplayer2.util.Consumer; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; import org.telegram.ui.ActionBar.ActionBarMenuSubItem; @@ -36,6 +37,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.UserCell; import org.telegram.ui.ProfileActivity; +import org.telegram.ui.Stories.recorder.HintView2; public class ItemOptions { @@ -59,6 +61,7 @@ public static ItemOptions makeOptions(@NonNull ViewGroup container, @Nullable Th private View scrimView; private Drawable scrimViewBackground; private int gravity = Gravity.RIGHT; + private boolean ignoreX; private ActionBarPopupWindow actionBarPopupWindow; private final float[] point = new float[2]; @@ -84,10 +87,6 @@ private ItemOptions(BaseFragment fragment, View scrimView) { this.scrimView = scrimView; this.dimAlpha = AndroidUtilities.computePerceivedBrightness(Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider)) > .705 ? 0x66 : 0x33; - if (fragment.getFragmentView() != null) { - //discard all scrolls/gestures - fragment.getFragmentView().getRootView().dispatchTouchEvent(AndroidUtilities.emptyMotionEvent()); - } init(); } @@ -115,11 +114,9 @@ private void init() { layout = lastLayout; } - public ItemOptions addIf(boolean condition, int iconResId, CharSequence text, Runnable onClickListener) { - if (!condition) { - return this; - } - return add(iconResId, text, onClickListener); + public ItemOptions ignoreX() { + ignoreX = true; + return this; } public ItemOptions addIf(boolean condition, int iconResId, CharSequence text, boolean isRed, Runnable onClickListener) { @@ -129,11 +126,11 @@ public ItemOptions addIf(boolean condition, int iconResId, CharSequence text, bo return add(iconResId, text, isRed, onClickListener); } - public ItemOptions addIf(boolean condition, int iconResId, CharSequence text, Runnable onClickListener, Consumer onVewCreated) { + public ItemOptions addIf(boolean condition, int iconResId, CharSequence text, Runnable onClickListener) { if (!condition) { return this; } - return add(iconResId, text, Theme.key_actionBarDefaultSubmenuItemIcon, Theme.key_actionBarDefaultSubmenuItem, onClickListener, onVewCreated); + return add(iconResId, text, Theme.key_actionBarDefaultSubmenuItemIcon, Theme.key_actionBarDefaultSubmenuItem, onClickListener); } public ItemOptions add(int iconResId, CharSequence text, Runnable onClickListener) { @@ -141,14 +138,14 @@ public ItemOptions add(int iconResId, CharSequence text, Runnable onClickListene } public ItemOptions add(int iconResId, CharSequence text, boolean isRed, Runnable onClickListener) { - return add(iconResId, text, isRed ? Theme.key_text_RedRegular : Theme.key_actionBarDefaultSubmenuItemIcon, isRed ? Theme.key_text_RedRegular : Theme.key_actionBarDefaultSubmenuItem, onClickListener, null); + return add(iconResId, text, isRed ? Theme.key_text_RedRegular : Theme.key_actionBarDefaultSubmenuItemIcon, isRed ? Theme.key_text_RedRegular : Theme.key_actionBarDefaultSubmenuItem, onClickListener); } public ItemOptions add(int iconResId, CharSequence text, int color, Runnable onClickListener) { - return add(iconResId, text, color, color, onClickListener, null); + return add(iconResId, text, color, color, onClickListener); } - public ItemOptions add(int iconResId, CharSequence text, int iconColorKey, int textColorKey, Runnable onClickListener, Consumer onViewCreated) { + public ItemOptions add(int iconResId, CharSequence text, int iconColorKey, int textColorKey, Runnable onClickListener) { if (context == null) { return this; } @@ -170,16 +167,43 @@ public ItemOptions add(int iconResId, CharSequence text, int iconColorKey, int t }); if (minWidthDp > 0) { subItem.setMinimumWidth(AndroidUtilities.dp(minWidthDp)); + lastLayout.addView(subItem, LayoutHelper.createLinear(minWidthDp, LayoutHelper.WRAP_CONTENT)); + } else { + lastLayout.addView(subItem, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); } - if (onViewCreated != null) { - onViewCreated.accept(subItem); + + return this; + } + + public ItemOptions makeMultiline(boolean changeSize) { + if (context == null || lastLayout.getItemsCount() <= 0) { + return this; } - lastLayout.addView(subItem, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); + View lastChild = lastLayout.getItemAt(lastLayout.getItemsCount() - 1); + if (lastChild instanceof ActionBarMenuSubItem) { + ((ActionBarMenuSubItem) lastChild).setMultiline(changeSize); + } + return this; + } + + public ItemOptions cutTextInFancyHalf() { + if (context == null || lastLayout.getItemsCount() <= 0) { + return this; + } + + View lastChild = lastLayout.getItemAt(lastLayout.getItemsCount() - 1); + if (lastChild instanceof ActionBarMenuSubItem) { + TextView textView = ((ActionBarMenuSubItem) lastChild).getTextView(); + textView.setMaxWidth( + HintView2.cutInFancyHalf(textView.getText(), textView.getPaint()) + textView.getPaddingLeft() + textView.getPaddingRight() + ); + } return this; } + private int shiftDp = -4; public ItemOptions putPremiumLock(Runnable onLockClick) { if (onLockClick == null || context == null || lastLayout.getItemsCount() <= 0) { return this; @@ -193,6 +217,8 @@ public ItemOptions putPremiumLock(Runnable onLockClick) { lastSubItem.getRightIcon().setAlpha(.4f); lastSubItem.setOnClickListener(view1 -> { if (onLockClick != null) { + AndroidUtilities.shakeViewSpring(view1, shiftDp = -shiftDp); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); onLockClick.run(); } }); @@ -223,7 +249,12 @@ public ItemOptions addSpaceGap() { return this; } - public ItemOptions addView() { + public ItemOptions addView(View view) { + if (view == null) { + return this; + } + view.setTag(R.id.fit_width_tag, 1); + lastLayout.addView(view, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); return this; } @@ -333,6 +364,9 @@ public ItemOptions show() { getPointOnScreen(scrimView, container, point); y = point[1]; } + if (ignoreX) { + point[0] = 0; + } final Bitmap cachedBitmap; final Paint cachedBitmapPaint; @@ -449,6 +483,14 @@ public void onDismiss() { } else { Y = (container.getHeight() - layout.getMeasuredHeight()) / 2; // at the center } + + // discard all scrolls/gestures + if (fragment != null && fragment.getFragmentView() != null) { + fragment.getFragmentView().getRootView().dispatchTouchEvent(AndroidUtilities.emptyMotionEvent()); + } else if (this.container != null) { + container.dispatchTouchEvent(AndroidUtilities.emptyMotionEvent()); + } + actionBarPopupWindow.showAtLocation( container, 0, diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/LoadingDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/LoadingDrawable.java index 9b879abcd15..24fb9ab070e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/LoadingDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/LoadingDrawable.java @@ -370,6 +370,7 @@ public int getPaintAlpha() { @Override public void setAlpha(int i) { paint.setAlpha(i); + strokePaint.setAlpha(i); if (i > 0) { invalidateSelf(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MapPlaceholderDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MapPlaceholderDrawable.java index a218649aa31..b20ea912177 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MapPlaceholderDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MapPlaceholderDrawable.java @@ -22,12 +22,16 @@ public class MapPlaceholderDrawable extends Drawable { private Paint linePaint; public MapPlaceholderDrawable() { + this(Theme.getCurrentTheme().isDark()); + } + + public MapPlaceholderDrawable(boolean isDark) { super(); paint = new Paint(); linePaint = new Paint(); linePaint.setStrokeWidth(AndroidUtilities.dp(1)); - if (Theme.getCurrentTheme().isDark()) { + if (isDark) { paint.setColor(0xff1d2c4d); linePaint.setColor(0xff0e1626); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java index 428f59f09b5..6108e1791e9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActivity.java @@ -626,6 +626,10 @@ protected int getInitialTab() { @Override protected void showActionMode(boolean show) { + if (type == TYPE_MEDIA) { + super.showActionMode(show); + return; + } if (isActionModeShowed == show) { return; } @@ -707,13 +711,15 @@ public void onAnimationEnd(Animator animation) { protected void onActionModeSelectedUpdate(SparseArray messageObjects) { final int count = messageObjects.size(); actionModeMessageObjects = messageObjects; - selectedTextView.cancelAnimation(); - selectedTextView.setText(LocaleController.formatPluralString("StoriesSelected", count), !LocaleController.isRTL); - if (button != null) { - button.setEnabled(count > 0); - button.setCount(count, true); - if (sharedMediaLayout.getClosestTab() == SharedMediaLayout.TAB_STORIES) { - button.setText(LocaleController.formatPluralString("ArchiveStories", count), true); + if (type == TYPE_STORIES) { + selectedTextView.cancelAnimation(); + selectedTextView.setText(LocaleController.formatPluralString("StoriesSelected", count), !LocaleController.isRTL); + if (button != null) { + button.setEnabled(count > 0); + button.setCount(count, true); + if (sharedMediaLayout.getClosestTab() == SharedMediaLayout.TAB_STORIES) { + button.setText(LocaleController.formatPluralString("ArchiveStories", count), true); + } } } } @@ -1106,6 +1112,9 @@ public ArrayList getThemeDescriptions() { @Override public boolean isLightStatusBar() { + if (storyViewer != null && storyViewer.isShown()) { + return false; + } int color = Theme.getColor(Theme.key_windowBackgroundWhite); if (actionBar.isActionModeShowed()) { color = Theme.getColor(Theme.key_actionBarActionModeDefault); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MentionsContainerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MentionsContainerView.java index 9ca164e8038..c122cebc634 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MentionsContainerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MentionsContainerView.java @@ -7,6 +7,7 @@ import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; +import android.os.Build; import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; @@ -26,19 +27,29 @@ import org.telegram.messenger.ChatObject; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; +import org.telegram.messenger.VideoEditedInfo; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.MentionsAdapter; import org.telegram.ui.Adapters.PaddedListAdapter; +import org.telegram.ui.Cells.ContextLinkCell; import org.telegram.ui.Cells.StickerCell; +import org.telegram.ui.ChatActivity; import org.telegram.ui.ContentPreviewViewer; +import org.telegram.ui.PhotoViewer; + +import java.util.ArrayList; public class MentionsContainerView extends BlurredFrameLayout implements NotificationCenter.NotificationCenterDelegate { @@ -56,6 +67,7 @@ public class MentionsContainerView extends BlurredFrameLayout implements Notific private float containerTop, containerBottom, containerPadding, listViewPadding; private boolean allowBlur; private RecyclerListView.OnItemClickListener mentionsOnItemClickListener; + private Delegate delegate; public MentionsContainerView(@NonNull Context context, long dialogId, int threadMessageId, BaseFragment baseFragment, SizeNotifierFrameLayout container, Theme.ResourcesProvider resourcesProvider) { super(context, container); @@ -418,7 +430,7 @@ public void updateVisibility(boolean show) { if (listViewTranslationAnimator != null) { listViewTranslationAnimator.cancel(); } - AndroidUtilities.runOnUIThread(updateVisibilityRunnable, baseFragment.getFragmentBeginToShow() ? 0 : 100); + AndroidUtilities.runOnUIThread(updateVisibilityRunnable, (baseFragment != null && baseFragment.getFragmentBeginToShow()) ? 0 : 100); if (show) { onOpen(); } else { @@ -529,7 +541,54 @@ public void setDialogId(long dialogId) { adapter.setDialogId(dialogId); } + private ArrayList botContextResults; + private PhotoViewer.PhotoViewerProvider botContextProvider = new PhotoViewer.EmptyPhotoViewerProvider() { + + @Override + public PhotoViewer.PlaceProviderObject getPlaceForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index, boolean needPreview) { + if (index < 0 || index >= botContextResults.size()) { + return null; + } + int count = getListView().getChildCount(); + Object result = botContextResults.get(index); + + for (int a = 0; a < count; a++) { + ImageReceiver imageReceiver = null; + View view = getListView().getChildAt(a); + if (view instanceof ContextLinkCell) { + ContextLinkCell cell = (ContextLinkCell) view; + if (cell.getResult() == result) { + imageReceiver = cell.getPhotoImage(); + } + } + + if (imageReceiver != null) { + int[] coords = new int[2]; + view.getLocationInWindow(coords); + PhotoViewer.PlaceProviderObject object = new PhotoViewer.PlaceProviderObject(); + object.viewX = coords[0]; + object.viewY = coords[1] - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight); + object.parentView = getListView(); + object.imageReceiver = imageReceiver; + object.thumb = imageReceiver.getBitmapSafe(); + object.radius = imageReceiver.getRoundRadius(); + return object; + } + } + return null; + } + + @Override + public void sendButtonPressed(int index, VideoEditedInfo videoEditedInfo, boolean notify, int scheduleDate, boolean forceDocument) { + if (index < 0 || index >= botContextResults.size()) { + return; + } + delegate.sendBotInlineResult((TLRPC.BotInlineResult) botContextResults.get(index), notify, scheduleDate); + } + }; + public void withDelegate(Delegate delegate) { + this.delegate = delegate; getListView().setOnItemClickListener(mentionsOnItemClickListener = (view, position) -> { if (position == 0 || getAdapter().isBannedInline()) { return; @@ -596,10 +655,20 @@ public void withDelegate(Delegate delegate) { delegate.replaceText(start, len, code, true); } updateVisibility(false); + } if (object instanceof TLRPC.BotInlineResult) { + TLRPC.BotInlineResult result = (TLRPC.BotInlineResult) object; + if ((result.type.equals("photo") && (result.photo != null || result.content != null) || + result.type.equals("gif") && (result.document != null || result.content != null) || + result.type.equals("video") && (result.document != null/* || result.content_url != null*/))) { + ArrayList arrayList = botContextResults = new ArrayList<>(getAdapter().getSearchResultBotContext()); + PhotoViewer.getInstance().setParentActivity(baseFragment, resourcesProvider); + PhotoViewer.getInstance().openPhotoForSelect(arrayList, getAdapter().getItemPosition(position), 3, false, botContextProvider, null); + } else { + delegate.sendBotInlineResult(result, true, 0); + } } }); getListView().setOnTouchListener((v, event) -> ContentPreviewViewer.getInstance().onTouch(event, getListView(), 0, mentionsOnItemClickListener, null, resourcesProvider)); - } public class MentionsListView extends RecyclerListView { @@ -784,6 +853,9 @@ default void onStickerSelected(TLRPC.TL_document document, String query, Object default void addEmojiToRecent(String code) { } + + default void sendBotInlineResult(TLRPC.BotInlineResult botInlineResult, boolean notify, int scheduleDate) {} + } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MessageContainsEmojiButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MessageContainsEmojiButton.java index f733033efe1..ac1f16f6553 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MessageContainsEmojiButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MessageContainsEmojiButton.java @@ -55,6 +55,7 @@ public class MessageContainsEmojiButton extends FrameLayout implements Notificat public final static int EMOJI_TYPE = 0; public final static int REACTIONS_TYPE = 1; public final static int EMOJI_STICKER_TYPE = 2; + public final static int SINGLE_REACTION_TYPE = 3; int type; private class BoldAndAccent extends CharacterStyle { @@ -67,8 +68,9 @@ public void updateDrawState(TextPaint textPaint) { } } - private MessageContainsEmojiButton(int currentAccount, Context context, Theme.ResourcesProvider resourcesProvider, int type) { + public MessageContainsEmojiButton(int currentAccount, Context context, Theme.ResourcesProvider resourcesProvider, @NonNull ArrayList inputStickerSets, int type) { super(context); + this.currentAccount = currentAccount; this.type = type; @@ -77,28 +79,6 @@ private MessageContainsEmojiButton(int currentAccount, Context context, Theme.Re textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); textPaint.setTextSize(AndroidUtilities.dp(13)); textPaint.setColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem, resourcesProvider)); - } - - public MessageContainsEmojiButton(int currentAccount, Context context, Theme.ResourcesProvider resourcesProvider, TLObject object) { - this(currentAccount, context, resourcesProvider, EMOJI_STICKER_TYPE); - - String string; - if (type == EMOJI_TYPE) { - string = LocaleController.getString("MessageContainsEmojiPack", R.string.MessageContainsEmojiPack); - } else { - string = LocaleController.getString("MessageContainsReactionsPack", R.string.MessageContainsReactionsPack); - } - String[] parts = string.split("%s"); - mainText = parts[0]; - endText = parts[1]; - loadingDrawable = new LoadingDrawable(resourcesProvider); - loadingDrawable.colorKey1 = Theme.key_actionBarDefaultSubmenuBackground; - loadingDrawable.colorKey2 = Theme.key_listSelector; - loadingDrawable.setRadiiDp(4); - } - - public MessageContainsEmojiButton(int currentAccount, Context context, Theme.ResourcesProvider resourcesProvider, @NonNull ArrayList inputStickerSets, int type) { - this(currentAccount, context, resourcesProvider, type); if (inputStickerSets.size() > 1) { String string; @@ -120,6 +100,8 @@ public MessageContainsEmojiButton(int currentAccount, Context context, Theme.Res String string; if (type == EMOJI_TYPE) { string = LocaleController.getString("MessageContainsEmojiPack", R.string.MessageContainsEmojiPack); + } else if (type == SINGLE_REACTION_TYPE) { + string = LocaleController.getString("MessageContainsReactionPack", R.string.MessageContainsReactionPack); } else { string = LocaleController.getString("MessageContainsReactionsPack", R.string.MessageContainsReactionsPack); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/PaintTypeface.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/PaintTypeface.java index c80d44ad53d..80922d0be3b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/PaintTypeface.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/PaintTypeface.java @@ -36,11 +36,12 @@ public class PaintTypeface { public static final PaintTypeface ROBOTO_MEDIUM = new PaintTypeface("roboto", "PhotoEditorTypefaceRoboto", new LazyTypeface(() -> AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM))); public static final PaintTypeface ROBOTO_ITALIC = new PaintTypeface("italic", "PhotoEditorTypefaceItalic", new LazyTypeface(() -> AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM_ITALIC))); public static final PaintTypeface ROBOTO_SERIF = new PaintTypeface("serif", "PhotoEditorTypefaceSerif", new LazyTypeface(() -> Typeface.create("serif", Typeface.BOLD))); + public static final PaintTypeface ROBOTO_CONDENSED = new PaintTypeface("condensed", "PhotoEditorTypefaceCondensed", new LazyTypeface(() -> AndroidUtilities.getTypeface("fonts/rcondensedbold.ttf"))); public static final PaintTypeface ROBOTO_MONO = new PaintTypeface ("mono", "PhotoEditorTypefaceMono", new LazyTypeface(() -> AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MONO))); public static final PaintTypeface MW_BOLD = new PaintTypeface("mw_bold", "PhotoEditorTypefaceMerriweather", new LazyTypeface(() -> AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_MERRIWEATHER_BOLD))); public static final PaintTypeface COURIER_NEW_BOLD = new PaintTypeface("courier_new_bold", "PhotoEditorTypefaceCourierNew", new LazyTypeface(() -> AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_COURIER_NEW_BOLD))); - public final static List BUILT_IN_FONTS = Arrays.asList(ROBOTO_MEDIUM, ROBOTO_ITALIC, ROBOTO_SERIF, ROBOTO_MONO, MW_BOLD, COURIER_NEW_BOLD); + public final static List BUILT_IN_FONTS = Arrays.asList(ROBOTO_MEDIUM, ROBOTO_ITALIC, ROBOTO_SERIF, ROBOTO_CONDENSED, ROBOTO_MONO, MW_BOLD, COURIER_NEW_BOLD); private static final List preferable = Arrays.asList( "Google Sans", diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EditTextOutline.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EditTextOutline.java index 384255308e7..c42127e7c84 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EditTextOutline.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EditTextOutline.java @@ -20,8 +20,6 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.ui.Components.EditTextBoldCursor; -import java.util.Arrays; - public class EditTextOutline extends EditTextBoldCursor { private Canvas mCanvas = new Canvas(); @@ -37,6 +35,7 @@ public class EditTextOutline extends EditTextBoldCursor { public boolean betterFraming; private RectF[] lines; + public RectF framePadding; private boolean isFrameDirty; public EditTextOutline(Context context) { @@ -201,6 +200,21 @@ protected void onDraw(Canvas canvas) { lines[i - 1].bottom = lines[i].top; } } + if (framePadding == null) { + framePadding = new RectF(); + } + framePadding.left = getMeasuredWidth(); + framePadding.top = getMeasuredHeight(); + framePadding.bottom = 0; + framePadding.right = 0; + for (int i = 0; i < lines.length; ++i) { + framePadding.left = Math.min(framePadding.left, getPaddingLeft() + lines[i].left); + framePadding.top = Math.min(framePadding.top, getPaddingTop() + lines[i].top); + framePadding.right = Math.max(framePadding.right, getPaddingLeft() + lines[i].right); + framePadding.bottom = Math.max(framePadding.bottom, getPaddingTop() + lines[i].bottom); + } + framePadding.right = getMeasuredWidth() - framePadding.right; + framePadding.bottom = getMeasuredHeight() - framePadding.bottom; } path.rewind(); float h = getHeight(); @@ -251,6 +265,8 @@ protected void onDraw(Canvas canvas) { setFrameRoundRadius(r); canvas.drawPath(path, paint); canvas.restore(); + } else { + framePadding = null; } super.onDraw(canvas); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntitiesContainerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntitiesContainerView.java index ba87a238b90..0b6d45679f3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntitiesContainerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntitiesContainerView.java @@ -41,11 +41,6 @@ public int entitiesCount() { return count; } - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - return ev.getPointerCount() == 2 && delegate.shouldReceiveTouches(); - } - @Override public boolean onTouchEvent(MotionEvent event) { EntityView selectedEntity = delegate.onSelectedEntityRequest(); @@ -65,8 +60,8 @@ public boolean onTouchEvent(MotionEvent event) { } } - gestureDetector.onTouchEvent(event); - rotationGestureDetector.onTouchEvent(event); +// gestureDetector.onTouchEvent(event); +// rotationGestureDetector.onTouchEvent(event); return true; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntityView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntityView.java index dc0a6f2ee82..e5f6d17343d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntityView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/EntityView.java @@ -1,5 +1,7 @@ package org.telegram.ui.Components.Paint.Views; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -7,11 +9,13 @@ import android.graphics.Canvas; import android.graphics.DashPathEffect; import android.graphics.Paint; +import android.os.Build; import android.util.Log; import android.view.GestureDetector; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.FrameLayout; @@ -33,11 +37,15 @@ public class EntityView extends FrameLayout { private final static List STICKY_ANGLES = Arrays.asList( -90, 0, 90, 180 ); - private final static float STICKY_THRESHOLD_ANGLE = 15; - private final static float STICKY_TRIGGER_ANGLE = 5; + private final static float STICKY_THRESHOLD_ANGLE = 12; + private final static float STICKY_TRIGGER_ANGLE = 4; + + private final static float STICKY_TRIGGER_DP = 12; - private final static float STICKY_THRESHOLD_DP = 16; - private final static float STICKY_TRIGGER_DP = 6; + public final static float STICKY_PADDING_X_DP = 8; + public final static float STICKY_PADDING_Y_DP = 64; + + public final static long STICKY_DURATION = 250; private ButtonBounce bounce = new ButtonBounce(this); @@ -46,22 +54,26 @@ public interface EntityViewDelegate { boolean onEntityLongClicked(EntityView entityView); boolean allowInteraction(EntityView entityView); int[] getCenterLocation(EntityView entityView); - float[] getTransformedTouch(MotionEvent e, float x, float y); + void getTransformedTouch(float x, float y, float[] output); float getCropRotation(); default void onEntityDraggedTop(boolean value) {} default void onEntityDraggedBottom(boolean value) {} default void onEntityDragStart() {} + default void onEntityDragMultitouchStart() {} + default void onEntityDragMultitouchEnd() {} default void onEntityDragEnd(boolean delete) {} default void onEntityDragTrash(boolean enter) {} } - private float previousLocationX; - private float previousLocationY; + private float previousLocationX, previousLocationY; + private float previousLocationX2, previousLocationY2; + private float previousLocationCX, previousLocationCY; private boolean hasPanned = false; private boolean hasReleased = false; private boolean hasTransformed = false; private boolean announcedDrag = false; + private boolean announcedMultitouchDrag = false; private boolean announcedSelection = false; private boolean announcedTrash = false; private boolean recognizedLongPress = false; @@ -71,12 +83,20 @@ default void onEntityDragTrash(boolean enter) {} private Point position; protected SelectionView selectionView; - private GestureDetector gestureDetector; + private final Runnable longPressRunnable = () -> { + recognizedLongPress = true; + if (delegate != null) { + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + delegate.onEntityLongClicked(EntityView.this); + } + }; private UUID uuid; private boolean hasStickyAngle = true; private int currentStickyAngle = 0; + private int stickyAngleRunnableValue = -1; + private Runnable setStickyAngleRunnable; private float stickyAnimatedAngle; private ValueAnimator angleAnimator; @@ -85,30 +105,21 @@ default void onEntityDragTrash(boolean enter) {} private float fromStickyToAngle; private ValueAnimator fromStickyAngleAnimator; - private boolean hasStickyX, hasStickyY; - private float fromStickyX, fromStickyY; + public static final int STICKY_NONE = 0; + public static final int STICKY_START = 1; + public static final int STICKY_CENTER = 2; + public static final int STICKY_END = 3; + + private int stickyX = STICKY_NONE, stickyY = STICKY_NONE; + private Runnable setStickyXRunnable = this::updateStickyX, setStickyYRunnable = this::updateStickyY; + private int stickyXRunnableValue, stickyYRunnableValue; private ValueAnimator stickyXAnimator, stickyYAnimator; - private boolean hasFromStickyXAnimation, hasFromStickyYAnimation; public EntityView(Context context, Point pos) { super(context); uuid = UUID.randomUUID(); position = pos; - - gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { - public void onLongPress(MotionEvent e) { - if (hasPanned || hasTransformed || hasReleased) { - return; - } - - recognizedLongPress = true; - if (delegate != null) { - performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - delegate.onEntityLongClicked(EntityView.this); - } - } - }); } public UUID getUUID() { @@ -124,11 +135,16 @@ public void setPosition(Point value) { updatePosition(); } + protected float getMaxScale() { + return 100f; + } + public float getScale() { return getScaleX(); } public void setScale(float scale) { + this.scale = scale; setScaleX(scale); setScaleY(scale); } @@ -142,22 +158,42 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { return delegate.allowInteraction(this); } - private boolean onTouchMove(float x, float y) { + private boolean onTouchMove(float x1, float y1, boolean multitouch, float x2, float y2) { if (getParent() == null) { return false; } float scale = ((View) getParent()).getScaleX(); - float tx = (x - previousLocationX) / scale; - float ty = (y - previousLocationY) / scale; + float x = multitouch ? (x1 + x2) / 2f : x1; + float y = multitouch ? (y1 + y2) / 2f : y1; + float tx = (x - previousLocationCX) / scale; + float ty = (y - previousLocationCY) / scale; float distance = (float) Math.hypot(tx, ty); float minDistance = hasPanned ? 6 : 16; - if (distance > minDistance) { + if (distance > minDistance || multitouch) { + AndroidUtilities.cancelRunOnUIThread(longPressRunnable); pan(tx, ty); - previousLocationX = x; - previousLocationY = y; + + if (multitouch) { + float d = MathUtils.distance(x1, y1, x2, y2); + float pd = MathUtils.distance(previousLocationX, previousLocationY, previousLocationX2, previousLocationY2); + if (pd > 0) { + scale(d / pd); + } + double angleDiff = Math.atan2(y1 - y2, x1 - x2) - Math.atan2(previousLocationY - previousLocationY2, previousLocationX - previousLocationX2); + rotate(this.angle + (float) Math.toDegrees(angleDiff) - delegate.getCropRotation()); + } + + previousLocationX = x1; + previousLocationY = y1; + previousLocationCX = x; + previousLocationCY = y; + if (multitouch) { + previousLocationX2 = x2; + previousLocationY2 = y2; + } hasPanned = true; - if (getParent() instanceof EntitiesContainerView && (hasStickyX || hasStickyY)) { + if (getParent() instanceof EntitiesContainerView && (stickyX != STICKY_NONE || stickyY != STICKY_NONE)) { ((EntitiesContainerView) getParent()).invalidate(); } @@ -165,17 +201,25 @@ private boolean onTouchMove(float x, float y) { announcedDrag = true; delegate.onEntityDragStart(); } + if (!announcedMultitouchDrag && multitouch && delegate != null) { + announcedMultitouchDrag = true; + delegate.onEntityDragMultitouchStart(); + } + if (announcedMultitouchDrag && !multitouch && delegate != null) { + announcedMultitouchDrag = false; + delegate.onEntityDragMultitouchEnd(); + } if (!isSelected() && !announcedSelection && delegate != null) { delegate.onEntitySelected(this); announcedSelection = true; } if (delegate != null) { - delegate.onEntityDraggedTop(position.y - getHeight() / 2f * scale < AndroidUtilities.dp(66)); - delegate.onEntityDraggedBottom(position.y + getHeight() / 2f * scale > ((View) getParent()).getHeight() - AndroidUtilities.dp(64 + 50)); + delegate.onEntityDraggedTop(position.y - getHeight() / 2f * scale < dp(66)); + delegate.onEntityDraggedBottom(position.y + getHeight() / 2f * scale > ((View) getParent()).getHeight() - dp(64 + 50)); } - updateTrash(MathUtils.distance(x, y, ((View) getParent()).getWidth() / 2f, ((View) getParent()).getHeight() - AndroidUtilities.dp(76)) < AndroidUtilities.dp(32)); + updateTrash(!multitouch && MathUtils.distance(x, y, ((View) getParent()).getWidth() / 2f, ((View) getParent()).getHeight() - dp(76)) < dp(32)); bounce.setPressed(false); @@ -189,6 +233,7 @@ private void onTouchUp() { delegate.onEntityDragEnd(announcedTrash); announcedDrag = false; } + announcedMultitouchDrag = false; if (!recognizedLongPress && !hasPanned && !hasTransformed && !announcedSelection && delegate != null) { delegate.onEntitySelected(this); } @@ -196,12 +241,22 @@ private void onTouchUp() { delegate.onEntityDraggedTop(false); delegate.onEntityDraggedBottom(false); } + AndroidUtilities.cancelRunOnUIThread(longPressRunnable); recognizedLongPress = false; hasPanned = false; hasTransformed = false; hasReleased = true; announcedSelection = false; + stickyAngleRunnableValue = currentStickyAngle; + if (setStickyAngleRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(setStickyAngleRunnable); + setStickyAngleRunnable = null; + } + stickyXRunnableValue = stickyX; + AndroidUtilities.cancelRunOnUIThread(setStickyXRunnable); + stickyYRunnableValue = stickyY; + AndroidUtilities.cancelRunOnUIThread(setStickyYRunnable); if (getParent() instanceof EntitiesContainerView) { ((EntitiesContainerView) getParent()).invalidate(); } @@ -211,72 +266,138 @@ public final boolean hasTouchDown() { return !hasReleased; } - public void setHasStickyX(boolean hasStickyX) { - this.hasStickyX = hasStickyX; + public void setStickyX(int stickyX) { + this.stickyX = this.stickyXRunnableValue = stickyX; } - public final boolean hasStickyX() { - return hasStickyX; + public final int getStickyX() { + return stickyX; } - public void setHasStickyY(boolean hasStickyY) { - this.hasStickyY = hasStickyY; + public void setStickyY(int stickyY) { + this.stickyY = this.stickyYRunnableValue = stickyY; } - public final boolean hasStickyY() { - return hasStickyY; + public final int getStickyY() { + return stickyY; } public boolean hasPanned() { return hasPanned; } + protected float getStickyPaddingLeft() { + return 0; + } + + protected float getStickyPaddingTop() { + return 0; + } + + protected float getStickyPaddingRight() { + return 0; + } + + protected float getStickyPaddingBottom() { + return 0; + } + + private boolean lastIsMultitouch; + private boolean hadMultitouch; + private final float[] xy = new float[2]; + private final float[] xy2 = new float[2]; + private final float[] cxy = new float[2]; + @Override public boolean onTouchEvent(MotionEvent event) { - if (event.getPointerCount() > 1 || !delegate.allowInteraction(this)) { + if (!delegate.allowInteraction(this)) { return false; } - float[] xy = delegate.getTransformedTouch(event, event.getRawX(), event.getRawY()); + delegate.getTransformedTouch(event.getRawX(), event.getRawY(), xy); + boolean isMultitouch = event.getPointerCount() > 1; + if (isMultitouch) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + delegate.getTransformedTouch(event.getRawX(1), event.getRawY(1), xy2); + } else { + isMultitouch = false; + // TODO + } + } + if (isMultitouch) { + cxy[0] = (xy[0] + xy2[0]) / 2f; + cxy[1] = (xy[1] + xy2[1]) / 2f; + } else { + cxy[0] = xy[0]; + cxy[1] = xy[1]; + } + if (lastIsMultitouch != isMultitouch) { + previousLocationX = xy[0]; + previousLocationY = xy[1]; + previousLocationX2 = xy2[0]; + previousLocationY2 = xy2[1]; + previousLocationCX = cxy[0]; + previousLocationCY = cxy[1]; + if (selectionView != null) { + selectionView.hide(isMultitouch); + } + } + lastIsMultitouch = isMultitouch; + float x = cxy[0]; + float y = cxy[1]; int action = event.getActionMasked(); boolean handled = false; switch (action) { - case MotionEvent.ACTION_POINTER_DOWN: +// case MotionEvent.ACTION_POINTER_DOWN: case MotionEvent.ACTION_DOWN: { + hadMultitouch = false; previousLocationX = xy[0]; previousLocationY = xy[1]; + previousLocationCX = x; + previousLocationCY = y; handled = true; hasReleased = false; - if (getParent() instanceof EntitiesContainerView && (hasStickyX || hasStickyY)) { + if (getParent() instanceof EntitiesContainerView && (stickyX != STICKY_NONE || stickyY != STICKY_NONE)) { ((EntitiesContainerView) getParent()).invalidate(); } bounce.setPressed(true); + + AndroidUtilities.cancelRunOnUIThread(longPressRunnable); + if (!isMultitouch) { + AndroidUtilities.runOnUIThread(longPressRunnable, ViewConfiguration.getLongPressTimeout()); + } } break; case MotionEvent.ACTION_MOVE: { - handled = onTouchMove(xy[0], xy[1]); + handled = onTouchMove(xy[0], xy[1], isMultitouch, xy2[0], xy2[1]); } break; - case MotionEvent.ACTION_POINTER_UP: +// case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { onTouchUp(); bounce.setPressed(false); handled = true; + if (selectionView != null) { + selectionView.hide(false); + } } break; } - gestureDetector.onTouchEvent(event); + hadMultitouch = isMultitouch; return super.onTouchEvent(event) || handled; } private void runStickyXAnimator(float... values) { + if (stickyXAnimator != null) { + stickyXAnimator.cancel(); + } stickyXAnimator = ValueAnimator.ofFloat(values).setDuration(150); stickyXAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); stickyXAnimator.addUpdateListener(animation -> updatePosition()); @@ -285,8 +406,6 @@ private void runStickyXAnimator(float... values) { public void onAnimationEnd(Animator animation) { if (animation == stickyXAnimator) { stickyXAnimator = null; - - hasFromStickyXAnimation = false; } } }); @@ -294,6 +413,9 @@ public void onAnimationEnd(Animator animation) { } private void runStickyYAnimator(float... values) { + if (stickyYAnimator != null) { + stickyYAnimator.cancel(); + } stickyYAnimator = ValueAnimator.ofFloat(values).setDuration(150); stickyYAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); stickyYAnimator.addUpdateListener(animation -> updatePosition()); @@ -302,89 +424,95 @@ private void runStickyYAnimator(float... values) { public void onAnimationEnd(Animator animation) { if (animation == stickyYAnimator) { stickyYAnimator = null; - - hasFromStickyYAnimation = false; } } }); stickyYAnimator.start(); } - public void pan(float tx, float ty) { - position.x += tx; - position.y += ty; + private void updateStickyX() { + AndroidUtilities.cancelRunOnUIThread(setStickyXRunnable); + if (stickyX == stickyXRunnableValue) { + return; + } + stickyX = stickyXRunnableValue; + if (getParent() instanceof EntitiesContainerView) { + ((EntitiesContainerView) getParent()).invalidate(); + } + if (stickyXAnimator != null) { + stickyXAnimator.cancel(); + } + if (stickyXRunnableValue == STICKY_NONE) { + runStickyXAnimator(1, 0); + } else { + try { + performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignored) {} + runStickyXAnimator(0, 1); + } + } - if (hasFromStickyXAnimation) { - fromStickyX = position.x; + private void updateStickyY() { + AndroidUtilities.cancelRunOnUIThread(setStickyYRunnable); + if (stickyY == stickyYRunnableValue) { + return; + } + stickyY = stickyYRunnableValue; + if (getParent() instanceof EntitiesContainerView) { + ((EntitiesContainerView) getParent()).invalidate(); } - if (hasFromStickyYAnimation) { - fromStickyY = position.y; + if (stickyYAnimator != null) { + stickyYAnimator.cancel(); + } + if (stickyYRunnableValue == STICKY_NONE) { + runStickyYAnimator(1, 0); + } else { + try { + performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignored) {} + runStickyYAnimator(0, 1); } + } + + public void pan(float tx, float ty) { + position.x += tx; + position.y += ty; View parent = (View) getParent(); if (parent != null) { - if (!hasStickyX) { - if (Math.abs(position.x - parent.getMeasuredWidth() / 2f) <= AndroidUtilities.dp(STICKY_TRIGGER_DP) && position.y < parent.getMeasuredHeight() - AndroidUtilities.dp(112 + 64)) { - hasStickyX = true; - try { - performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - } catch (Exception ignored) {} - if (getParent() instanceof EntitiesContainerView) { - ((EntitiesContainerView) getParent()).invalidate(); - } - - if (stickyXAnimator != null) { - stickyXAnimator.cancel(); - } - - fromStickyX = position.x; - hasFromStickyXAnimation = false; - runStickyXAnimator(0, 1); + int newStickyX = STICKY_NONE; + if (!lastIsMultitouch) { + if (Math.abs(position.x - parent.getMeasuredWidth() / 2f) <= dp(STICKY_TRIGGER_DP) && position.y < parent.getMeasuredHeight() - dp(112 + 64)) { + newStickyX = STICKY_CENTER; + } else if (Math.abs(position.x - (width() / 2f + getStickyPaddingLeft()) * getScaleX() - dp(STICKY_PADDING_X_DP)) <= dp(STICKY_TRIGGER_DP)) { + newStickyX = STICKY_START; + } else if (Math.abs(position.x + (width() / 2f - getStickyPaddingRight()) * getScaleX() - (parent.getMeasuredWidth() - dp(STICKY_PADDING_X_DP))) <= dp(STICKY_TRIGGER_DP)) { + newStickyX = STICKY_END; } - } else { - if (Math.abs(position.x - parent.getMeasuredWidth() / 2f) > AndroidUtilities.dp(STICKY_THRESHOLD_DP) || position.y >= parent.getMeasuredHeight() - AndroidUtilities.dp(112 + 64)) { - hasStickyX = false; - if (getParent() instanceof EntitiesContainerView) { - ((EntitiesContainerView) getParent()).invalidate(); - } - - if (stickyXAnimator != null) { - stickyXAnimator.cancel(); - } - hasFromStickyXAnimation = true; - runStickyXAnimator(1, 0); + } + if (stickyXRunnableValue != newStickyX) { + if ((stickyXRunnableValue = newStickyX) == STICKY_NONE) { + updateStickyX(); + } else { + AndroidUtilities.runOnUIThread(setStickyXRunnable, STICKY_DURATION); } } - if (!hasStickyY) { - if (Math.abs(position.y - parent.getMeasuredHeight() / 2f) <= AndroidUtilities.dp(STICKY_TRIGGER_DP)) { - hasStickyY = true; - try { - performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - } catch (Exception ignored) {} - if (getParent() instanceof EntitiesContainerView) { - ((EntitiesContainerView) getParent()).invalidate(); - } - - if (stickyYAnimator != null) { - stickyYAnimator.cancel(); - } - fromStickyY = position.y; - hasFromStickyYAnimation = false; - runStickyYAnimator(0, 1); + int newStickyY = STICKY_NONE; + if (!lastIsMultitouch) { + if (Math.abs(position.y - parent.getMeasuredHeight() / 2f) <= dp(STICKY_TRIGGER_DP)) { + newStickyY = STICKY_CENTER; + } else if (Math.abs(position.y - (height() / 2f + getStickyPaddingTop()) * getScaleY() - dp(STICKY_PADDING_Y_DP)) <= dp(STICKY_TRIGGER_DP)) { + newStickyY = STICKY_START; + } else if (Math.abs(position.y + (height() / 2f - getStickyPaddingBottom()) * getScaleY() - (parent.getMeasuredHeight() - dp(STICKY_PADDING_Y_DP))) <= dp(STICKY_TRIGGER_DP)) { + newStickyY = STICKY_END; } - } else { - if (Math.abs(position.y - parent.getMeasuredHeight() / 2f) > AndroidUtilities.dp(STICKY_THRESHOLD_DP)) { - hasStickyY = false; - if (getParent() instanceof EntitiesContainerView) { - ((EntitiesContainerView) getParent()).invalidate(); - } - - if (stickyYAnimator != null) { - stickyYAnimator.cancel(); - } - hasFromStickyYAnimation = true; - runStickyYAnimator(1, 0); + } + if (stickyYRunnableValue != newStickyY) { + if ((stickyYRunnableValue = newStickyY) == STICKY_NONE) { + updateStickyY(); + } else { + AndroidUtilities.runOnUIThread(setStickyYRunnable, STICKY_DURATION); } } } @@ -392,14 +520,30 @@ public void pan(float tx, float ty) { updatePosition(); } + private float width() { + return (float) (Math.abs(Math.cos(getRotation() / 180 * Math.PI)) * getMeasuredWidth() + Math.abs(Math.sin(getRotation() / 180 * Math.PI)) * getMeasuredHeight()); + } + + private float height() { + return (float) (Math.abs(Math.cos(getRotation() / 180 * Math.PI)) * getMeasuredHeight() + Math.abs(Math.sin(getRotation() / 180 * Math.PI)) * getMeasuredWidth()); + } + protected float getPositionX() { float x = position.x; if (getParent() != null) { View parent = (View) getParent(); + float stickyX = x; + if (this.stickyX == STICKY_START) { + stickyX = dp(STICKY_PADDING_X_DP) + (width() / 2f - getStickyPaddingLeft()) * getScaleX(); + } else if (this.stickyX == STICKY_CENTER) { + stickyX = parent.getMeasuredWidth() / 2f; + } else if (this.stickyX == STICKY_END) { + stickyX = parent.getMeasuredWidth() - dp(STICKY_PADDING_X_DP) - (width() / 2f + getStickyPaddingRight()) * getScaleX(); + } if (stickyXAnimator != null) { - x = AndroidUtilities.lerp(fromStickyX, parent.getMeasuredWidth() / 2f, (Float) stickyXAnimator.getAnimatedValue()); - } else if (hasStickyX) { - x = parent.getMeasuredWidth() / 2f; + x = AndroidUtilities.lerp(x, stickyX, (Float) stickyXAnimator.getAnimatedValue()); + } else if (stickyX != STICKY_NONE) { + x = stickyX; } } return x; @@ -409,10 +553,18 @@ protected float getPositionY() { float y = position.y; if (getParent() != null) { View parent = (View) getParent(); + float stickyY = y; + if (this.stickyY == STICKY_START) { + stickyY = dp(STICKY_PADDING_Y_DP) + (height() / 2f - getStickyPaddingTop()) * getScaleY(); + } else if (this.stickyY == STICKY_CENTER) { + stickyY = parent.getMeasuredHeight() / 2f; + } else if (this.stickyY == STICKY_END) { + stickyY = parent.getMeasuredHeight() - dp(STICKY_PADDING_Y_DP) - (height() / 2f + getStickyPaddingBottom()) * getScaleY(); + } if (stickyYAnimator != null) { - y = AndroidUtilities.lerp(fromStickyY, parent.getMeasuredHeight() / 2f, (Float) stickyYAnimator.getAnimatedValue()); - } else if (hasStickyY) { - y = parent.getMeasuredHeight() / 2f; + y = AndroidUtilities.lerp(y, stickyY, (Float) stickyYAnimator.getAnimatedValue()); + } else if (stickyY != STICKY_NONE) { + y = stickyY; } } return y; @@ -426,64 +578,94 @@ protected void updatePosition() { updateSelectionView(); } + private float scale = 1f; + public void scale(float scale) { - float newScale = Math.max(getScale() * scale, 0.1f); - setScale(newScale); - updateSelectionView(); + this.scale *= scale; + float newScale = Math.max(this.scale, 0.1f); + newScale = Math.min(newScale, getMaxScale()); + if (getScale() < getMaxScale() && newScale >= getMaxScale()) { + try { + performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); + } catch (Exception ignore) {} + } + setScaleX(newScale); + setScaleY(newScale); +// updateSelectionView(); } + private float angle; public void rotate(float angle) { - if (!hasStickyAngle) { + if (stickyX != STICKY_NONE) { + stickyXRunnableValue = STICKY_NONE; + updateStickyX(); + } + if (stickyY != STICKY_NONE) { + stickyYRunnableValue = STICKY_NONE; + updateStickyY(); + } + + this.angle = angle; + if (!hasStickyAngle && !lastIsMultitouch) { for (int stickyAngle : STICKY_ANGLES) { if (Math.abs(stickyAngle - angle) < STICKY_TRIGGER_ANGLE) { - currentStickyAngle = stickyAngle; - hasStickyAngle = true; - try { - performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - } catch (Exception ignored) {} - - if (angleAnimator != null) { - angleAnimator.cancel(); - } - if (fromStickyAngleAnimator != null) { - fromStickyAngleAnimator.cancel(); - } - angleAnimator = ValueAnimator.ofFloat(0, 1).setDuration(150); - angleAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); - float from = angle; - angleAnimator.addUpdateListener(animation -> { - stickyAnimatedAngle = AndroidUtilities.lerpAngle(from, currentStickyAngle, animation.getAnimatedFraction()); - rotateInternal(stickyAnimatedAngle); - }); - angleAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (animation == angleAnimator) { - angleAnimator = null; - stickyAnimatedAngle = 0; - } + if (stickyAngleRunnableValue != stickyAngle) { + stickyAngleRunnableValue = stickyAngle; + if (setStickyAngleRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(setStickyAngleRunnable); } - }); - angleAnimator.start(); + AndroidUtilities.runOnUIThread(setStickyAngleRunnable = () -> { + currentStickyAngle = stickyAngle; + hasStickyAngle = true; + try { + performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignored) {} + + if (angleAnimator != null) { + angleAnimator.cancel(); + } + if (fromStickyAngleAnimator != null) { + fromStickyAngleAnimator.cancel(); + } + angleAnimator = ValueAnimator.ofFloat(0, 1).setDuration(150); + angleAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + angleAnimator.addUpdateListener(animation -> { + stickyAnimatedAngle = AndroidUtilities.lerpAngle(this.angle, currentStickyAngle, animation.getAnimatedFraction()); + rotateInternal(stickyAnimatedAngle); + }); + angleAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (animation == angleAnimator) { + angleAnimator = null; + stickyAnimatedAngle = 0; + } + } + }); + angleAnimator.start(); + }, STICKY_DURATION); + break; + } break; } } - } else { - if (Math.abs(currentStickyAngle - angle) >= STICKY_THRESHOLD_ANGLE) { + } else if (hasStickyAngle) { + if (Math.abs(currentStickyAngle - angle) >= STICKY_THRESHOLD_ANGLE || lastIsMultitouch) { + stickyAngleRunnableValue = -1; + if (setStickyAngleRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(setStickyAngleRunnable); + setStickyAngleRunnable = null; + } if (angleAnimator != null) { angleAnimator.cancel(); } - if (fromStickyAngleAnimator != null) { fromStickyAngleAnimator.cancel(); } - fromStickyAnimatedAngle = currentStickyAngle; - fromStickyToAngle = angle; - fromStickyAngleAnimator = ValueAnimator.ofFloat(0, 1).setDuration(150); fromStickyAngleAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); - fromStickyAngleAnimator.addUpdateListener(animation -> rotateInternal(AndroidUtilities.lerpAngle(fromStickyAnimatedAngle, fromStickyToAngle, fromStickyAngleAnimator.getAnimatedFraction()))); + fromStickyAngleAnimator.addUpdateListener(animation -> rotateInternal(AndroidUtilities.lerpAngle(currentStickyAngle, this.angle, fromStickyAngleAnimator.getAnimatedFraction()))); fromStickyAngleAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -512,6 +694,9 @@ public void onAnimationEnd(Animator animation) { private void rotateInternal(float angle) { setRotation(angle); + if (stickyX != STICKY_NONE || stickyY != STICKY_NONE) { + updatePosition(); + } updateSelectionView(); } @@ -550,6 +735,7 @@ private void updateSelect(ViewGroup selectionContainer, boolean select) { return; } selectionView = createSelectionView(); + selectionView.hide(lastIsMultitouch); selectionContainer.addView(selectionView); selectT = 0; } @@ -579,12 +765,13 @@ public void onAnimationEnd(Animator animation) { } } + private ViewGroup lastSelectionContainer; public void select(ViewGroup selectionContainer) { - updateSelect(selectionContainer, true); + updateSelect(lastSelectionContainer = selectionContainer, true); } public void deselect() { - updateSelect(null, false); + updateSelect(lastSelectionContainer, false); } public void setSelectionVisibility(boolean visible) { @@ -612,9 +799,9 @@ public SelectionView(Context context) { paint.setColor(0xffffffff); paint.setStyle(Paint.Style.STROKE); - paint.setStrokeWidth(AndroidUtilities.dp(2)); + paint.setStrokeWidth(dp(2)); paint.setStrokeCap(Paint.Cap.ROUND); - paint.setPathEffect(new DashPathEffect(new float[]{AndroidUtilities.dp(10), AndroidUtilities.dp(10)}, .5f)); + paint.setPathEffect(new DashPathEffect(new float[]{dp(10), dp(10)}, .5f)); paint.setShadowLayer(AndroidUtilities.dpf2(0.75f), 0, 0, 0x50000000); dotPaint.setColor(0xff1A9CFF); @@ -646,17 +833,46 @@ public boolean onTouchEvent(MotionEvent event) { float rawX = event.getRawX(); float rawY = event.getRawY(); - float[] xy = delegate.getTransformedTouch(event, rawX, rawY); - float x = xy[0]; - float y = xy[1]; + delegate.getTransformedTouch(rawX, rawY, xy); + boolean isMultitouch = event.getPointerCount() > 1 && currentHandle == SELECTION_WHOLE_HANDLE; + if (isMultitouch) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + delegate.getTransformedTouch(event.getRawX(1), event.getRawY(1), xy2); + } else { + isMultitouch = false; + // TODO + } + } + if (isMultitouch) { + cxy[0] = (xy[0] + xy2[0]) / 2f; + cxy[1] = (xy[1] + xy2[1]) / 2f; + } else { + cxy[0] = xy[0]; + cxy[1] = xy[1]; + } + if (lastIsMultitouch != isMultitouch) { + previousLocationX = xy[0]; + previousLocationY = xy[1]; + previousLocationX2 = xy2[0]; + previousLocationY2 = xy2[1]; + previousLocationCX = cxy[0]; + previousLocationCY = cxy[1]; + hide(isMultitouch); + } + lastIsMultitouch = isMultitouch; + float x = cxy[0]; + float y = cxy[1]; switch (action) { - case MotionEvent.ACTION_POINTER_DOWN: +// case MotionEvent.ACTION_POINTER_DOWN: case MotionEvent.ACTION_DOWN: { + hadMultitouch = false; int handle = pointInsideHandle(event.getX(), event.getY()); if (handle != 0) { currentHandle = handle; - previousLocationX = x; - previousLocationY = y; + previousLocationX = xy[0]; + previousLocationY = xy[1]; + previousLocationCX = x; + previousLocationCY = y; hasReleased = false; handled = true; @@ -669,24 +885,15 @@ public boolean onTouchEvent(MotionEvent event) { case MotionEvent.ACTION_MOVE: { if (currentHandle == SELECTION_WHOLE_HANDLE) { - handled = onTouchMove(x, y); + handled = onTouchMove(xy[0], xy[1], isMultitouch, xy2[0], xy2[1]); } else if (currentHandle != 0) { float tx = x - previousLocationX; float ty = y - previousLocationY; - if (hasTransformed || Math.abs(tx) > AndroidUtilities.dp(2) || Math.abs(ty) > AndroidUtilities.dp(2)) { + if (hasTransformed || Math.abs(tx) > dp(2) || Math.abs(ty) > dp(2)) { hasTransformed = true; -// float radAngle = (float) Math.toRadians(getRotation()); -// float delta = (float) (tx * Math.cos(radAngle) + ty * Math.sin(radAngle)); -// if (currentHandle == SELECTION_LEFT_HANDLE) { -// delta *= -1; -// } -// -// if (getMeasuredWidth() != 0) { -// float scaleDelta = 1 + (delta * 2) / getMeasuredWidth(); -// scale(scaleDelta); -// } + AndroidUtilities.cancelRunOnUIThread(longPressRunnable); int[] pos = delegate.getCenterLocation(EntityView.this); float pd = MathUtils.distance(pos[0], pos[1], previousLocationX, previousLocationY); @@ -714,22 +921,33 @@ public boolean onTouchEvent(MotionEvent event) { } break; - case MotionEvent.ACTION_POINTER_UP: +// case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { onTouchUp(); currentHandle = 0; handled = true; + hide(false); } break; } - if (currentHandle == SELECTION_WHOLE_HANDLE) { - gestureDetector.onTouchEvent(event); - } + hadMultitouch = isMultitouch; return super.onTouchEvent(event) || handled; } + + private final AnimatedFloat showAlpha = new AnimatedFloat(this, 0, 250, CubicBezierInterpolator.EASE_OUT_QUINT); + private boolean shown = true; + + public void hide(boolean hide) { + shown = !hide; + invalidate(); + } + + protected float getShowAlpha() { + return showAlpha.set(shown); + } } private float trashScale = 1f; @@ -769,9 +987,15 @@ protected void dispatchDraw(Canvas canvas) { canvas.scale(scale, scale, getWidth() / 2f, getHeight() / 2f); if (getParent() instanceof View) { View p = (View) getParent(); - canvas.scale(trashScale, trashScale, p.getWidth() / 2f - getX(), p.getHeight() - AndroidUtilities.dp(76) - getY()); + float px = p.getWidth() / 2f - getX(); + float py = p.getHeight() - dp(76) - getY(); + canvas.scale(trashScale, trashScale, px, py); } super.dispatchDraw(canvas); canvas.restore(); } + + public boolean hadMultitouch() { + return hadMultitouch; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java index a4af78ac1fe..e81339f0996 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java @@ -388,26 +388,27 @@ protected void onDraw(Canvas canvas) { long dt = Math.min(16, System.currentTimeMillis() - lastUpdate); lastUpdate = System.currentTimeMillis(); - boolean drawStickyX = false, drawStickyY = false; + int stickyX = EntityView.STICKY_NONE, stickyY = EntityView.STICKY_NONE; if (currentEntityView != null && currentEntityView.hasTouchDown() && currentEntityView.hasPanned()) { - drawStickyX = currentEntityView.hasStickyX(); - drawStickyY = currentEntityView.hasStickyY(); + stickyX = currentEntityView.getStickyX(); + stickyY = currentEntityView.getStickyY(); } - if (drawStickyX && stickyXAlpha != 1f) { - stickyXAlpha = Math.min(1f, stickyXAlpha + dt / 150f); + final float STICKY_DURATION = 150; + if (stickyX != EntityView.STICKY_NONE && stickyXAlpha != 1f) { + stickyXAlpha = Math.min(1f, stickyXAlpha + dt / STICKY_DURATION); invalidate(); - } else if (!drawStickyX && stickyXAlpha != 0f) { - stickyXAlpha = Math.max(0f, stickyXAlpha - dt / 150f); + } else if (stickyX == EntityView.STICKY_NONE && stickyXAlpha != 0f) { + stickyXAlpha = Math.max(0f, stickyXAlpha - dt / STICKY_DURATION); invalidate(); } - if (drawStickyY && stickyYAlpha != 1f) { - stickyYAlpha = Math.min(1f, stickyYAlpha + dt / 150f); + if (stickyY != EntityView.STICKY_NONE && stickyYAlpha != 1f) { + stickyYAlpha = Math.min(1f, stickyYAlpha + dt / STICKY_DURATION); invalidate(); - } else if (!drawStickyY && stickyYAlpha != 0f) { - stickyYAlpha = Math.max(0f, stickyYAlpha - dt / 150f); + } else if (stickyY == EntityView.STICKY_NONE && stickyYAlpha != 0f) { + stickyYAlpha = Math.max(0f, stickyYAlpha - dt / STICKY_DURATION); invalidate(); } @@ -919,10 +920,10 @@ private TextPaintView createText(boolean select) { Point position = startPositionRelativeToEntity(null); TextPaintView view = new TextPaintView(getContext(), position, (int) (paintingSize.width / 9), "", colorSwatch, selectedTextType); if (position.x == entitiesView.getMeasuredWidth() / 2f) { - view.setHasStickyX(true); + view.setStickyX(EntityView.STICKY_CENTER); } if (position.y == entitiesView.getMeasuredHeight() / 2f) { - view.setHasStickyY(true); + view.setStickyY(EntityView.STICKY_CENTER); } view.setDelegate(this); view.setMaxWidth((int) (paintingSize.width - 20)); @@ -2728,10 +2729,10 @@ protected void didSetAnimatedSticker(RLottieDrawable drawable) { }; view.centerImage.setLayerNum(4 + 8); if (position.position.x == entitiesView.getMeasuredWidth() / 2f) { - view.setHasStickyX(true); + view.setStickyX(EntityView.STICKY_CENTER); } if (position.position.y == entitiesView.getMeasuredHeight() / 2f) { - view.setHasStickyY(true); + view.setStickyY(EntityView.STICKY_CENTER); } view.setDelegate(this); entitiesView.addView(view); @@ -2782,15 +2783,13 @@ public boolean onEntityLongClicked(EntityView entityView) { return true; } - private float[] temp = new float[2]; @Override - public float[] getTransformedTouch(MotionEvent e, float x, float y) { + public void getTransformedTouch(float x, float y, float[] output) { float x2 = (x - AndroidUtilities.displaySize.x / 2f); float y2 = (y - AndroidUtilities.displaySize.y / 2f); float rotation = (float) Math.toRadians(-entitiesView.getRotation()); - temp[0] = (float) (x2 * Math.cos(rotation) - y2 * Math.sin(rotation)) + AndroidUtilities.displaySize.x / 2f; - temp[1] = (float) (x2 * Math.sin(rotation) + y2 * Math.cos(rotation)) + AndroidUtilities.displaySize.y / 2f; - return temp; + output[0] = (float) (x2 * Math.cos(rotation) - y2 * Math.sin(rotation)) + AndroidUtilities.displaySize.x / 2f; + output[1] = (float) (x2 * Math.sin(rotation) + y2 * Math.cos(rotation)) + AndroidUtilities.displaySize.y / 2f; } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LocationMarker.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LocationMarker.java new file mode 100644 index 00000000000..72986f3c72a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LocationMarker.java @@ -0,0 +1,336 @@ +package org.telegram.ui.Components.Paint.Views; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.drawable.Drawable; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.checkerframework.checker.units.qual.A; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Emoji; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.AnimatedEmojiDrawable; +import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.Paint.PaintTypeface; +import org.telegram.ui.Stories.recorder.HintView2; + +import java.util.concurrent.CountDownLatch; + +public class LocationMarker extends View { + + private int maxWidth; + private String text = ""; + private boolean relayout; + + public final static float SCALE = 1.2f; + + private final RectF padding = new RectF(4, 4.33f, 7.66f, 3); + private final float iconPadding = 3.25f; + private final float flagIconPadding = 2.25f; + private final float iconSize = 21.33f; + + private final TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + private final Paint outlinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Drawable icon; + + private boolean hasFlag; + private final ImageReceiver flagImageReceiver = new ImageReceiver(this); + private TLRPC.Document flagDocument; + private boolean forceEmoji; + + public final float density; + private float textScale = 1; + private StaticLayout layout; + private float layoutWidth, layoutLeft; + + public final int padx, pady; + + public LocationMarker(Context context, float density) { + super(context); + this.density = density; + + flagImageReceiver.setCrossfadeWithOldImage(true); + + padx = (int) (3 * density); + pady = (int) (1 * density); + + icon = context.getResources().getDrawable(R.drawable.map_pin3).mutate(); + textPaint.setTextSize(24 * density); + textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rcondensedbold.ttf")); + } + + public void setMaxWidth(int maxWidth) { + this.maxWidth = maxWidth; + this.relayout = true; + } + + public void forceEmoji() { + forceEmoji = true; + this.relayout = true; + requestLayout(); + } + + private Drawable getEmojiThumb(String emoji) { + Drawable drawable = Emoji.getEmojiBigDrawable(emoji); + if (drawable == null) { + return null; + } + return new Drawable() { + @Override + public void draw(@NonNull Canvas canvas) { + canvas.save(); + if (drawable.getBounds() != null) { + canvas.scale(1f / SCALE, 1f / SCALE, drawable.getBounds().centerX(), drawable.getBounds().centerY()); + } + drawable.draw(canvas); + canvas.restore(); + } + + @Override + public void setAlpha(int alpha) { + drawable.setAlpha(alpha); + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + drawable.setColorFilter(colorFilter); + } + + @Override + public void setBounds(@NonNull Rect bounds) { + drawable.setBounds(bounds); + } + + @Override + public void setBounds(int left, int top, int right, int bottom) { + drawable.setBounds(left, top, right, bottom); + } + + @Override + public int getOpacity() { + return drawable.getOpacity(); + } + }; + } + + public void setCountryCodeEmoji(int currentAccount, String emoji) { + if (TextUtils.isEmpty(emoji)) { + hasFlag = false; + flagImageReceiver.clearImage(); + } else { + hasFlag = true; + flagDocument = null; +// TLRPC.TL_inputStickerSetShortName inputStickerSetShortName = new TLRPC.TL_inputStickerSetShortName(); +// inputStickerSetShortName.short_name = "RestrictedEmoji"; +// TLRPC.TL_messages_stickerSet instantSet = MediaDataController.getInstance(currentAccount).getStickerSet(inputStickerSetShortName, 0, false, set -> { +// flagDocument = findDocument(set, emoji); +// if (flagDocument == null) { + TLRPC.TL_inputStickerSetShortName inputStickerSetShortName2 = new TLRPC.TL_inputStickerSetShortName(); + inputStickerSetShortName2.short_name = "StaticEmoji"; + MediaDataController.getInstance(currentAccount).getStickerSet(inputStickerSetShortName2, 0, false, set2 -> { + flagDocument = findDocument(set2, emoji); + flagImageReceiver.setImage( + ImageLocation.getForDocument(flagDocument), "80_80", + getEmojiThumb(emoji), + null, null, 0 + ); + }); +// return; +// } +// flagImageReceiver.setImage( +// ImageLocation.getForDocument(flagDocument), "80_80", +// getEmojiThumb(emoji), +// null, null, 0 +// ); +// }); +// flagDocument = findDocument(instantSet, emoji); + flagImageReceiver.setImage( + ImageLocation.getForDocument(flagDocument), "80_80", + getEmojiThumb(emoji), + null, null, 0 + ); + } + this.relayout = true; + requestLayout(); + } + + private TLRPC.Document findDocument(TLRPC.TL_messages_stickerSet set, String emoji) { + if (set == null || set.packs == null || set.documents == null) { + return null; + } + for (int i = 0; i < set.packs.size(); ++i) { + TLRPC.TL_stickerPack pack = set.packs.get(i); + if (pack.emoticon.contains(emoji) && !pack.documents.isEmpty()) { + long documentId = pack.documents.get(0); + for (int j = 0; j < set.documents.size(); ++j) { + if (set.documents.get(j).id == documentId) { + return set.documents.get(j); + } + } + } + } + return null; + } + + public TLRPC.Document getCountryCodeEmojiDocument() { + return flagDocument; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + flagImageReceiver.onAttachedToWindow(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + flagImageReceiver.onDetachedFromWindow(); + } + + public void setText(String text) { + this.text = text; + this.relayout = true; + requestLayout(); + } + + public String getText() { + return text; + } + + public void setType(int type, int color) { + if (type == 0) { + outlinePaint.setColor(color); + final int textColor = AndroidUtilities.computePerceivedBrightness(color) >= .721f ? Color.BLACK : Color.WHITE; + textPaint.setColor(textColor); + icon.setColorFilter(new PorterDuffColorFilter(textColor, PorterDuff.Mode.SRC_IN)); + } else if (type == 1) { + outlinePaint.setColor(0xFF000000); + textPaint.setColor(0xFFFFFFFF); + icon.setColorFilter(new PorterDuffColorFilter(0xFFFFFFFF, PorterDuff.Mode.SRC_IN)); + } else if (type == 2) { + outlinePaint.setColor(0x4C000000); + textPaint.setColor(0xFFFFFFFF); + icon.setColorFilter(null); + } else { + outlinePaint.setColor(0xFFFFFFFF); + textPaint.setColor(0xFF000000); + icon.setColorFilter(null); + } + invalidate(); + } + + private float w, h; + + private void setupLayout() { + if (!relayout) { + return; + } + + float textWidth = textPaint.measureText(text); + float maxWidth = this.maxWidth - padx - padx - (padding.left + (hasFlag || forceEmoji ? flagIconPadding : 0) + iconSize + iconPadding + padding.right) * density; + textScale = Math.min(1, maxWidth / textWidth); + if (textScale < .4f) { + layout = new StaticLayout(text, textPaint, HintView2.cutInFancyHalf(text, textPaint), Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false); + } else { + layout = new StaticLayout(text, textPaint, (int) Math.ceil(textWidth), Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false); + } + + layoutWidth = 0; + layoutLeft = Float.MAX_VALUE; + for (int i = 0; i < layout.getLineCount(); ++i) { + layoutWidth = Math.max(layoutWidth, layout.getLineWidth(i)); + layoutLeft = Math.min(layoutLeft, layout.getLineLeft(i)); + } + if (layout.getLineCount() > 2) { + textScale = .3f; + } else { + textScale = Math.min(1, maxWidth / layoutWidth); + } + + w = (padding.left + (hasFlag || forceEmoji ? flagIconPadding : 0) + iconSize + iconPadding + padding.right) * density + layoutWidth * textScale; + h = (padding.top + padding.bottom) * density + Math.max(iconSize * density, layout.getHeight() * textScale); + + relayout = false; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setupLayout(); + setMeasuredDimension(padx + (int) Math.round(w) + padx, pady + (int) Math.round(h) + pady); + } + + private final RectF bounds = new RectF(); + private final Path path = new Path(); + + @Override + protected void dispatchDraw(Canvas canvas) { + setupLayout(); + if (layout == null) { + return; + } + + bounds.set(padx, pady, padx + w, pady + h); + canvas.drawRoundRect(bounds, .2f * h, .2f * h, outlinePaint); + + if (hasFlag) { + flagImageReceiver.setImageCoords( + padx + (padding.left + flagIconPadding) * density, pady + (h - iconSize * density) / 2, + iconSize * density, iconSize * density + ); + canvas.save(); + canvas.scale(SCALE, SCALE, flagImageReceiver.getCenterX(), flagImageReceiver.getCenterY()); + flagImageReceiver.draw(canvas); + canvas.restore(); + } else if (forceEmoji) { + + } else { + icon.setBounds( + padx + (int) (padding.left * density), + pady + (int) ((h - iconSize * density) / 2), + padx + (int) ((padding.left + iconSize) * density), + pady + (int) ((h + iconSize * density) / 2) + ); + icon.draw(canvas); + } + + canvas.save(); + canvas.translate(padx + (padding.left + (hasFlag || forceEmoji ? flagIconPadding : 0) + iconSize + iconPadding) * density, pady + h / 2f); + canvas.scale(textScale, textScale); + canvas.translate(-layoutLeft, -layout.getHeight() / 2f); + layout.draw(canvas); + canvas.restore(); + } + + public void getEmojiBounds(RectF b) { + b.set( + padx + (padding.left + flagIconPadding) * density, pady + (h - iconSize * density) / 2, + padx + (padding.left + flagIconPadding + iconSize) * density, pady + (h + iconSize * density) / 2 + ); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LocationView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LocationView.java new file mode 100644 index 00000000000..1ba9b4e531e --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LocationView.java @@ -0,0 +1,288 @@ +package org.telegram.ui.Components.Paint.Views; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.PorterDuffXfermode; +import android.graphics.Typeface; +import android.graphics.Xfermode; +import android.graphics.drawable.Drawable; +import android.graphics.text.LineBreaker; +import android.os.Build; +import android.text.Editable; +import android.text.Layout; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextPaint; +import android.text.TextWatcher; +import android.text.style.DynamicDrawableSpan; +import android.text.style.ImageSpan; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; + +import androidx.core.graphics.ColorUtils; + +import com.googlecode.mp4parser.authoring.Edit; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Emoji; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.VideoEditedInfo; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AnimatedEmojiSpan; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Paint.PaintTypeface; +import org.telegram.ui.Components.Paint.Swatch; +import org.telegram.ui.Components.Point; +import org.telegram.ui.Components.Rect; + +public class LocationView extends EntityView { + + public final LocationMarker marker; + private int currentColor; + private int currentType; + + public TLRPC.MessageMedia location; + public TLRPC.MediaArea mediaArea; + + @Override + protected float getStickyPaddingLeft() { + return marker.padx; + } + + @Override + protected float getStickyPaddingTop() { + return marker.pady; + } + + @Override + protected float getStickyPaddingRight() { + return marker.padx; + } + + @Override + protected float getStickyPaddingBottom() { + return marker.pady; + } + + private static String deg(double deg) { + String s = ""; + + deg = Math.abs(deg); + + double p = Math.floor(deg); + s += (int) p + "°"; + deg -= p; + + p = Math.floor(deg * 60); + s += (p <= 0 ? "0" : "") + (p < 10 ? "0" : "") + (int) p + "'"; + deg = Math.floor(p); + + p = Math.floor(deg * 60); + s += (p <= 0 ? "0" : "") + (p < 10 ? "0" : "") + (int) p + "\""; + + return s; + } + + public static String geo(double Lat, double Long) { + return deg(Lat) + (Lat > 0 ? "N" : "S") + " " + deg(Long) + (Long > 0 ? "E" : "W"); + } + + public LocationView(Context context, Point position, int currentAccount, TLRPC.MessageMedia location, TLRPC.MediaArea mediaArea, float density, int maxWidth, int type, int color) { + super(context, position); + + marker = new LocationMarker(context, density); + marker.setMaxWidth(maxWidth); + setLocation(currentAccount, location, mediaArea); + marker.setType(currentType = type, currentColor = color); + addView(marker, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP)); + + setClipChildren(false); + setClipToPadding(false); + + updatePosition(); + } + + public void setLocation(int currentAccount, TLRPC.MessageMedia location, TLRPC.MediaArea area) { + this.location = location; + this.mediaArea = area; + + String countryCodeEmoji = null; + String title; + if (location instanceof TLRPC.TL_messageMediaGeo) { + title = geo(location.geo.lat, location.geo._long); + } else if (location instanceof TLRPC.TL_messageMediaVenue) { + title = location.title.toUpperCase(); + countryCodeEmoji = ((TLRPC.TL_messageMediaVenue) location).emoji; + } else { + title = ""; + } + marker.setCountryCodeEmoji(currentAccount, countryCodeEmoji); + marker.setText(title); + + updateSelectionView(); + } + + public void setMaxWidth(int maxWidth) { + marker.setMaxWidth(maxWidth); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + updatePosition(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + updatePosition(); + } + + public void setType(int type) { + marker.setType(currentType = type, currentColor); + } + + public void setType(int type, int color) { + marker.setType(currentType = type, currentColor = color); + } + + public void setColor(int color) { + setType(currentType, color); + } + + public int getColor() { + return currentColor; + } + + public int getType() { + return currentType; + } + + @Override + protected float getMaxScale() { + return 1.5f; + } + + @Override + protected Rect getSelectionBounds() { + ViewGroup parentView = (ViewGroup) getParent(); + if (parentView == null) { + return new Rect(); + } + float scale = parentView.getScaleX(); + float width = getMeasuredWidth() * getScale() + AndroidUtilities.dp(64) / scale; + float height = getMeasuredHeight() * getScale() + AndroidUtilities.dp(64) / scale; + float left = (getPositionX() - width / 2.0f) * scale; + float right = left + width * scale; + return new Rect(left, (getPositionY() - height / 2f) * scale, right - left, height * scale); + } + + protected TextViewSelectionView createSelectionView() { + return new TextViewSelectionView(getContext()); + } + + public class TextViewSelectionView extends SelectionView { + + private final Paint clearPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + public TextViewSelectionView(Context context) { + super(context); + clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + } + + @Override + protected int pointInsideHandle(float x, float y) { + float thickness = AndroidUtilities.dp(1.0f); + float radius = AndroidUtilities.dp(19.5f); + + float inset = radius + thickness; + float width = getMeasuredWidth() - inset * 2; + float height = getMeasuredHeight() - inset * 2; + + float middle = inset + height / 2.0f; + + if (x > inset - radius && y > middle - radius && x < inset + radius && y < middle + radius) { + return SELECTION_LEFT_HANDLE; + } else if (x > inset + width - radius && y > middle - radius && x < inset + width + radius && y < middle + radius) { + return SELECTION_RIGHT_HANDLE; + } + + if (x > inset && x < width && y > inset && y < height) { + return 0; + } + + return 0; + } + + private Path path = new Path(); + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + int count = canvas.getSaveCount(); + + float alpha = getShowAlpha(); + if (alpha <= 0) { + return; + } else if (alpha < 1) { + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), (int) (0xFF * alpha), Canvas.ALL_SAVE_FLAG); + } + + float thickness = AndroidUtilities.dp(2.0f); + float radius = AndroidUtilities.dpf2(5.66f); + + float inset = radius + thickness + AndroidUtilities.dp(15); + + float width = getMeasuredWidth() - inset * 2; + float height = getMeasuredHeight() - inset * 2; + + AndroidUtilities.rectTmp.set(inset, inset, inset + width, inset + height); + + float R = AndroidUtilities.dp(12); + float rx = Math.min(R, width / 2f), ry = Math.min(R, height / 2f); + + path.rewind(); + AndroidUtilities.rectTmp.set(inset, inset, inset + rx * 2, inset + ry * 2); + path.arcTo(AndroidUtilities.rectTmp, 180, 90); + AndroidUtilities.rectTmp.set(inset + width - rx * 2, inset, inset + width, inset + ry * 2); + path.arcTo(AndroidUtilities.rectTmp, 270, 90); + canvas.drawPath(path, paint); + + path.rewind(); + AndroidUtilities.rectTmp.set(inset, inset + height - ry * 2, inset + rx * 2, inset + height); + path.arcTo(AndroidUtilities.rectTmp, 180, -90); + AndroidUtilities.rectTmp.set(inset + width - rx * 2, inset + height - ry * 2, inset + width, inset + height); + path.arcTo(AndroidUtilities.rectTmp, 90, -90); + canvas.drawPath(path, paint); + + canvas.drawCircle(inset, inset + height / 2.0f, radius, dotStrokePaint); + canvas.drawCircle(inset, inset + height / 2.0f, radius - AndroidUtilities.dp(1) + 1, dotPaint); + + canvas.drawCircle(inset + width, inset + height / 2.0f, radius, dotStrokePaint); + canvas.drawCircle(inset + width, inset + height / 2.0f, radius - AndroidUtilities.dp(1) + 1, dotPaint); + + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), 0xFF, Canvas.ALL_SAVE_FLAG); + + canvas.drawLine(inset, inset + ry, inset, inset + height - ry, paint); + canvas.drawLine(inset + width, inset + ry, inset + width, inset + height - ry, paint); + canvas.drawCircle(inset + width, inset + height / 2.0f, radius + AndroidUtilities.dp(1) - 1, clearPaint); + canvas.drawCircle(inset, inset + height / 2.0f, radius + AndroidUtilities.dp(1) - 1, clearPaint); + + canvas.restoreToCount(count); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/PhotoView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/PhotoView.java index 255cee5abf1..f096b18d407 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/PhotoView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/PhotoView.java @@ -12,9 +12,11 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.MediaController; +import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.AnimatedFloat; @@ -39,6 +41,7 @@ protected void onDraw(Canvas canvas) { } } + private TLObject object; private String path; private int anchor = -1; private boolean mirrored = false; @@ -71,6 +74,33 @@ public PhotoView(Context context, Point position, float angle, float scale, Size updatePosition(); } + public PhotoView(Context context, Point position, float angle, float scale, Size baseSize, TLObject obj) { + super(context, position); + setRotation(angle); + setScale(scale); + + this.object = obj; + this.baseSize = baseSize; + + containerView = new FrameLayoutDrawer(context); + addView(containerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + mirrorT = new AnimatedFloat(containerView, 0, 500, CubicBezierInterpolator.EASE_OUT_QUINT); + + centerImage.setAspectFit(true); + centerImage.setInvalidateAll(true); + centerImage.setParentView(containerView); + centerImage.setRoundRadius(AndroidUtilities.dp(12)); + final int side = Math.round(Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * .8f / AndroidUtilities.density); + if (object instanceof TLRPC.Photo) { + TLRPC.Photo photo = (TLRPC.Photo) object; + TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, 1000); + TLRPC.PhotoSize thumbPhotoSize = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, 90); + centerImage.setImage(ImageLocation.getForPhoto(photoSize, photo), side + "_" + side, ImageLocation.getForPhoto(thumbPhotoSize, photo), side + "_" + side, (String) null, null, 1); + } + updatePosition(); + } + @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); @@ -162,7 +192,13 @@ protected SelectionView createSelectionView() { return new PhotoViewSelectionView(getContext()); } - public String getPath() { + public String getPath(int currentAccount) { + if (object instanceof TLRPC.Photo) { + TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(((TLRPC.Photo) object).sizes, 1000); + try { + return FileLoader.getInstance(currentAccount).getPathToAttach(photoSize, true).getAbsolutePath(); + } catch (Exception ignore) {} + } return path; } @@ -209,6 +245,15 @@ protected int pointInsideHandle(float x, float y) { protected void onDraw(Canvas canvas) { super.onDraw(canvas); + int count = canvas.getSaveCount(); + + float alpha = getShowAlpha(); + if (alpha <= 0) { + return; + } else if (alpha < 1) { + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), (int) (0xFF * alpha), Canvas.ALL_SAVE_FLAG); + } + float thickness = AndroidUtilities.dp(2.0f); float radius = AndroidUtilities.dpf2(5.66f); @@ -249,7 +294,7 @@ protected void onDraw(Canvas canvas) { canvas.drawCircle(inset + width, inset + height / 2.0f, radius + AndroidUtilities.dp(1) - 1, clearPaint); canvas.drawCircle(inset, inset + height / 2.0f, radius + AndroidUtilities.dp(1) - 1, clearPaint); - canvas.restore(); + canvas.restoreToCount(count); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/StickerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/StickerView.java index cfd89f716e0..5b24da7d9cb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/StickerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/StickerView.java @@ -236,6 +236,15 @@ protected int pointInsideHandle(float x, float y) { protected void onDraw(Canvas canvas) { super.onDraw(canvas); + int count = canvas.getSaveCount(); + + float alpha = getShowAlpha(); + if (alpha <= 0) { + return; + } else if (alpha < 1) { + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), (int) (0xFF * alpha), Canvas.ALL_SAVE_FLAG); + } + float thickness = AndroidUtilities.dp(1.0f); float radius = AndroidUtilities.dpf2(5.66f); @@ -251,6 +260,8 @@ protected void onDraw(Canvas canvas) { canvas.drawCircle(inset + mainRadius * 2, inset + mainRadius, radius, dotStrokePaint); canvas.drawCircle(inset + mainRadius * 2, inset + mainRadius, radius - AndroidUtilities.dp(1), dotPaint); + + canvas.restoreToCount(count); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/TextPaintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/TextPaintView.java index b708b6615ca..b3ea8ed9d0c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/TextPaintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/TextPaintView.java @@ -8,7 +8,6 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Typeface; -import android.graphics.Xfermode; import android.graphics.text.LineBreaker; import android.os.Build; import android.text.Editable; @@ -22,16 +21,11 @@ import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; -import androidx.core.graphics.ColorUtils; - -import com.googlecode.mp4parser.authoring.Edit; - import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.Emoji; import org.telegram.messenger.LocaleController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; -import org.telegram.messenger.VideoEditedInfo; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.LayoutHelper; @@ -142,6 +136,26 @@ public void afterTextChanged(Editable s) { }); } + @Override + protected float getStickyPaddingLeft() { + return editText.framePadding == null ? 0 : editText.framePadding.left; + } + + @Override + protected float getStickyPaddingRight() { + return editText.framePadding == null ? 0 : editText.framePadding.right; + } + + @Override + protected float getStickyPaddingTop() { + return editText.framePadding == null ? 0 : editText.framePadding.top; + } + + @Override + protected float getStickyPaddingBottom() { + return editText.framePadding == null ? 0 : editText.framePadding.bottom; + } + private void updateHint() { if (editText.getText().length() <= 0) { editText.setHint(LocaleController.getString(R.string.TextPlaceholder)); @@ -412,6 +426,15 @@ protected int pointInsideHandle(float x, float y) { protected void onDraw(Canvas canvas) { super.onDraw(canvas); + int count = canvas.getSaveCount(); + + float alpha = getShowAlpha(); + if (alpha <= 0) { + return; + } else if (alpha < 1) { + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), (int) (0xFF * alpha), Canvas.ALL_SAVE_FLAG); + } + float thickness = AndroidUtilities.dp(2.0f); float radius = AndroidUtilities.dpf2(5.66f); @@ -452,7 +475,7 @@ protected void onDraw(Canvas canvas) { canvas.drawCircle(inset + width, inset + height / 2.0f, radius + AndroidUtilities.dp(1) - 1, clearPaint); canvas.drawCircle(inset, inset + height / 2.0f, radius + AndroidUtilities.dp(1) - 1, clearPaint); - canvas.restore(); + canvas.restoreToCount(count); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java index e9b833dee95..1615d3bb7f8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java @@ -828,13 +828,12 @@ public boolean onEntityLongClicked(EntityView entityView) { } @Override - public float[] getTransformedTouch(MotionEvent e, float x, float y) { + public void getTransformedTouch(float x, float y, float[] output) { float x2 = (x - AndroidUtilities.displaySize.x / 2); float y2 = (y - AndroidUtilities.displaySize.y / 2); float rotation = (float) Math.toRadians(-entitiesView.getRotation()); - temp[0] = (float) (x2 * Math.cos(rotation) - y2 * Math.sin(rotation)) + AndroidUtilities.displaySize.x / 2; - temp[1] = (float) (x2 * Math.sin(rotation) + y2 * Math.cos(rotation)) + AndroidUtilities.displaySize.y / 2; - return temp; + output[0] = (float) (x2 * Math.cos(rotation) - y2 * Math.sin(rotation)) + AndroidUtilities.displaySize.x / 2; + output[1] = (float) (x2 * Math.sin(rotation) + y2 * Math.cos(rotation)) + AndroidUtilities.displaySize.y / 2; } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/BaseListPageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/BaseListPageView.java new file mode 100644 index 00000000000..408a0e8cf8b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/BaseListPageView.java @@ -0,0 +1,62 @@ +package org.telegram.ui.Components.Premium; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.widget.FrameLayout; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.UserConfig; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RecyclerListView; + +public abstract class BaseListPageView extends FrameLayout implements PagerHeaderView { + + final Theme.ResourcesProvider resourcesProvider; + final RecyclerListView recyclerListView; + final LinearLayoutManager layoutManager; + RecyclerView.Adapter adapter; + + public BaseListPageView(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context); + this.resourcesProvider = resourcesProvider; + recyclerListView = new RecyclerListView(context, resourcesProvider); + recyclerListView.setNestedScrollingEnabled(true); + // recyclerListView.setOverScrollMode(OVER_SCROLL_NEVER); + adapter = createAdapter(); + recyclerListView.setAdapter(adapter); + recyclerListView.setLayoutManager(layoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); + recyclerListView.setClipToPadding(false); + addView(recyclerListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } + + public abstract RecyclerView.Adapter createAdapter(); + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + + Paint dividerPaint = Theme.getThemePaint(Theme.key_paint_divider, resourcesProvider); + if (dividerPaint == null) { + dividerPaint = Theme.dividerPaint; + } + canvas.drawLine(0, getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight() - 1, dividerPaint); + } + + @Override + public void setOffset(float translationX) { + float progress = Math.abs(translationX / getMeasuredWidth()); + if (progress == 1f) { + if (recyclerListView.findViewHolderForAdapterPosition(0) == null || recyclerListView.findViewHolderForAdapterPosition(0).itemView.getTop() != recyclerListView.getPaddingTop()) { + recyclerListView.scrollToPosition(0); + } + } + } + + public void setTopOffset(int topOffset) { + recyclerListView.setPadding(0, topOffset, 0, 0); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubleLimitsPageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubleLimitsPageView.java index a645375e8af..0e216d8a520 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubleLimitsPageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubleLimitsPageView.java @@ -1,31 +1,25 @@ package org.telegram.ui.Components.Premium; import android.content.Context; -import android.graphics.Canvas; -import android.widget.FrameLayout; -import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.UserConfig; import org.telegram.ui.ActionBar.Theme; -import org.telegram.ui.Components.LayoutHelper; -import org.telegram.ui.Components.RecyclerListView; -public class DoubleLimitsPageView extends FrameLayout implements PagerHeaderView { +public class DoubleLimitsPageView extends BaseListPageView { - final RecyclerListView recyclerListView; - final LinearLayoutManager layoutManager; DoubledLimitsBottomSheet.Adapter adapter; - public DoubleLimitsPageView(Context context) { - super(context); - recyclerListView = new RecyclerListView(context); - adapter = new DoubledLimitsBottomSheet.Adapter(UserConfig.selectedAccount, true); - recyclerListView.setAdapter(adapter); - recyclerListView.setLayoutManager(layoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); - recyclerListView.setClipToPadding(false); + public DoubleLimitsPageView(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context, resourcesProvider); + } + + @Override + public RecyclerView.Adapter createAdapter() { + adapter = new DoubledLimitsBottomSheet.Adapter(UserConfig.selectedAccount, true, resourcesProvider); adapter.containerView = this; - addView(recyclerListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + return adapter; } @Override @@ -33,25 +27,4 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); adapter.measureGradient(getContext(), getMeasuredWidth(), getMeasuredHeight()); } - - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - canvas.drawLine(0, getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight() - 1, Theme.dividerPaint); - } - - @Override - public void setOffset(float translationX) { - float progress = Math.abs(translationX / getMeasuredWidth()); - if (progress == 1f) { - if (recyclerListView.findViewHolderForAdapterPosition(0) == null || recyclerListView.findViewHolderForAdapterPosition(0).itemView.getTop() != recyclerListView.getPaddingTop()) { - recyclerListView.scrollToPosition(0); - } - } - - } - - public void setTopOffset(int topOffset) { - recyclerListView.setPadding(0, topOffset, 0, 0); - } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java index 49a0447e760..a3ad0a45e22 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java @@ -55,7 +55,7 @@ public DoubledLimitsBottomSheet(BaseFragment fragment, int currentAccount) { } public DoubledLimitsBottomSheet(BaseFragment fragment, int currentAccount, PremiumPreviewFragment.SubscriptionTier subscriptionTier) { - super(fragment, false, false); + super(fragment, false, false, false, fragment == null ? null : fragment.getResourceProvider()); this.selectedTier = subscriptionTier; this.baseFragment = fragment; @@ -66,7 +66,7 @@ public DoubledLimitsBottomSheet(BaseFragment fragment, int currentAccount, Premi titleView.setText(LocaleController.getString("DoubledLimits", R.string.DoubledLimits)); titleView.setGravity(Gravity.CENTER); titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); - titleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + titleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); titleLayout.addView(titleView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); @@ -82,7 +82,7 @@ protected void onDraw(Canvas canvas) { canvas.drawRect(0, 0, getMeasuredWidth(), 1, Theme.dividerPaint); } }; - divider.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground)); + divider.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); containerView.addView(divider, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 72, Gravity.BOTTOM, 0, 0, 0, 0)); premiumButtonView = new PremiumButtonView(getContext(), true); @@ -156,7 +156,7 @@ protected CharSequence getTitle() { @Override protected RecyclerListView.SelectionAdapter createAdapter() { - adapter = new Adapter(currentAccount, false); + adapter = new Adapter(currentAccount, false, resourcesProvider); adapter.containerView = containerView; return adapter; } @@ -199,7 +199,7 @@ private static class LimitCell extends LinearLayout { TextView subtitle; LimitPreviewView previewView; - public LimitCell(@NonNull Context context) { + public LimitCell(@NonNull Context context, Theme.ResourcesProvider resourcesProvider) { super(context); setOrientation(VERTICAL); setPadding(AndroidUtilities.dp(6), 0, AndroidUtilities.dp(6), 0); @@ -207,15 +207,15 @@ public LimitCell(@NonNull Context context) { title = new TextView(context); title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); title.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - title.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + title.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); addView(title, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 16, 0, 16, 0)); subtitle = new TextView(context); - subtitle.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText)); + subtitle.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider)); subtitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); addView(subtitle, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 16, 1, 16, 0)); - previewView = new LimitPreviewView(context, 0, 10, 20); + previewView = new LimitPreviewView(context, 0, 10, 20, resourcesProvider); addView(previewView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 0, 8, 0, 21)); } @@ -247,6 +247,8 @@ private Limit(String title, String subtitle, int defaultLimit, int premiumLimit) public static class Adapter extends RecyclerListView.SelectionAdapter { + private final Theme.ResourcesProvider resourcesProvider; + int rowCount; int headerRow; int limitsStartRow; @@ -261,9 +263,11 @@ public static class Adapter extends RecyclerListView.SelectionAdapter { ViewGroup containerView; boolean drawHeader; - public Adapter(int currentAccount, boolean drawHeader) { + public Adapter(int currentAccount, boolean drawHeader, Theme.ResourcesProvider resourcesProvider) { this.drawHeader = drawHeader; - gradientTools = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4); + this.resourcesProvider = resourcesProvider; + + gradientTools = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4, -1, resourcesProvider); gradientTools.x1 = 0; gradientTools.y1 = 0; gradientTools.x2 = 0; @@ -341,7 +345,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int switch (viewType) { default: case 0: - LimitCell limitCell = new LimitCell(context); + LimitCell limitCell = new LimitCell(context, resourcesProvider); limitCell.previewView.setParentViewForGradien(containerView); limitCell.previewView.setStaticGradinet(gradientTools); view = limitCell; @@ -365,7 +369,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { titleView.setText(LocaleController.getString("DoubledLimits", R.string.DoubledLimits)); titleView.setGravity(Gravity.CENTER); titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); - titleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + titleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); linearLayout.addView(titleView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); @@ -411,7 +415,7 @@ public int getItemViewType(int position) { public void measureGradient(Context context, int w, int h) { int yOffset = 0; - LimitCell dummyCell = new LimitCell(context); + LimitCell dummyCell = new LimitCell(context, resourcesProvider); for (int i = 0; i < limits.size(); i++) { dummyCell.setData(limits.get(i)); dummyCell.measure(View.MeasureSpec.makeMeasureSpec(w, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(h, View.MeasureSpec.AT_MOST)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java index 07620e16e18..3d78fc3b193 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java @@ -1,5 +1,7 @@ package org.telegram.ui.Components.Premium; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -48,6 +50,7 @@ public class LimitPreviewView extends LinearLayout { boolean inc; float progress; + int width1; int icon; @@ -59,15 +62,15 @@ public class LimitPreviewView extends LinearLayout { int gradientYOffset; boolean wasHaptic; boolean animationCanPlay = true; - LinearLayout limitsContainer; + FrameLayout limitsContainer; private boolean premiumLocked; - public LimitPreviewView(@NonNull Context context, int icon, int currentValue, int premiumLimit) { - this(context, icon, currentValue, premiumLimit, .5f); + public LimitPreviewView(@NonNull Context context, int icon, int currentValue, int premiumLimit, Theme.ResourcesProvider resourcesProvider) { + this(context, icon, currentValue, premiumLimit, .5f, resourcesProvider); } @SuppressLint("SetTextI18n") - public LimitPreviewView(@NonNull Context context, int icon, int currentValue, int premiumLimit, float inputPercent) { + public LimitPreviewView(@NonNull Context context, int icon, int currentValue, int premiumLimit, float inputPercent, Theme.ResourcesProvider resourcesProvider) { super(context); final float percent = MathUtils.clamp(inputPercent, 0.1f, 0.9f); this.icon = icon; @@ -75,26 +78,71 @@ public LimitPreviewView(@NonNull Context context, int icon, int currentValue, in setClipChildren(false); setClipToPadding(false); if (icon != 0) { - setPadding(0, AndroidUtilities.dp(16), 0, 0); + setPadding(0, dp(16), 0, 0); limitIcon = new CounterView(context); setIconValue(currentValue); - limitIcon.setPadding(AndroidUtilities.dp(24), AndroidUtilities.dp(6), AndroidUtilities.dp(24), AndroidUtilities.dp(14)); + limitIcon.setPadding(dp(24), dp(6), dp(24), dp(14)); addView(limitIcon, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, Gravity.LEFT)); } - limitsContainer = new LinearLayout(context) { + + final FrameLayout defaultLayout = new FrameLayout(context); + + final TextView defaultText = new TextView(context); + defaultText.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + defaultText.setText(LocaleController.getString("LimitFree", R.string.LimitFree)); + defaultText.setGravity(Gravity.CENTER_VERTICAL); + defaultText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + + defaultCount = new TextView(context); + defaultCount.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + defaultCount.setText(String.format("%d", premiumLimit)); + defaultCount.setGravity(Gravity.CENTER_VERTICAL); + defaultCount.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + + if (LocaleController.isRTL) { + defaultLayout.addView(defaultText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 30, Gravity.RIGHT, 12, 0, 12, 0)); + defaultLayout.addView(defaultCount, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 30, Gravity.LEFT, 12, 0, 12, 0)); + } else { + defaultLayout.addView(defaultText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 30, Gravity.LEFT, 12, 0, 12, 0)); + defaultLayout.addView(defaultCount, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 30, Gravity.RIGHT, 12, 0, 12, 0)); + } + + final FrameLayout premiumLayout = new FrameLayout(context); + + final TextView premiumText = new TextView(context); + premiumText.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + premiumText.setText(LocaleController.getString("LimitPremium", R.string.LimitPremium)); + premiumText.setGravity(Gravity.CENTER_VERTICAL); + premiumText.setTextColor(Color.WHITE); + + premiumCount = new TextView(context); + premiumCount.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + premiumCount.setText(String.format("%d", premiumLimit)); + premiumCount.setGravity(Gravity.CENTER_VERTICAL); + premiumCount.setTextColor(Color.WHITE); + + if (LocaleController.isRTL) { + premiumLayout.addView(premiumText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 30, Gravity.RIGHT, 12, 0, 12, 0)); + premiumLayout.addView(premiumCount, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 30, Gravity.LEFT, 12, 0, 12, 0)); + } else { + premiumLayout.addView(premiumText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 30, Gravity.LEFT, 12, 0, 12, 0)); + premiumLayout.addView(premiumCount, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 30, Gravity.RIGHT, 12, 0, 12, 0)); + } + + limitsContainer = new FrameLayout(context) { Paint grayPaint = new Paint(); @Override protected void dispatchDraw(Canvas canvas) { - grayPaint.setColor(Theme.getColor(Theme.key_windowBackgroundGray)); + grayPaint.setColor(Theme.getColor(Theme.key_windowBackgroundGray, resourcesProvider)); AndroidUtilities.rectTmp.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); - canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(6), AndroidUtilities.dp(6), grayPaint); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(6), dp(6), grayPaint); canvas.save(); - canvas.clipRect(getMeasuredWidth() * percent, 0, getMeasuredWidth(), getMeasuredHeight()); + canvas.clipRect(width1, 0, getMeasuredWidth(), getMeasuredHeight()); Paint paint = PremiumGradient.getInstance().getMainGradientPaint(); if (parentVideForGradient != null) { View parent = parentVideForGradient; @@ -114,71 +162,60 @@ protected void dispatchDraw(Canvas canvas) { } else { PremiumGradient.getInstance().updateMainGradientMatrix(0, 0, LimitPreviewView.this.getMeasuredWidth(), LimitPreviewView.this.getMeasuredHeight(), getGlobalXOffset() - getLeft(), -getTop()); } - canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(6), AndroidUtilities.dp(6), paint); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(6), dp(6), paint); canvas.restore(); if (staticGradient == null) { invalidate(); } super.dispatchDraw(canvas); } - }; - limitsContainer.setOrientation(LinearLayout.HORIZONTAL); - - FrameLayout limitLayout = new FrameLayout(context); - - TextView freeTextView = new TextView(context); - freeTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - freeTextView.setText(LocaleController.getString("LimitFree", R.string.LimitFree)); - freeTextView.setGravity(Gravity.CENTER_VERTICAL); - freeTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); - freeTextView.setPadding(AndroidUtilities.dp(12), 0, 0, 0); - - defaultCount = new TextView(context); - defaultCount.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - defaultCount.setText(String.format("%d", premiumLimit)); - defaultCount.setGravity(Gravity.CENTER_VERTICAL); - defaultCount.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); - if (percent > .3f) { - if (LocaleController.isRTL) { - limitLayout.addView(freeTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 30, Gravity.RIGHT, 36, 0, 12, 0)); - limitLayout.addView(defaultCount, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 30, Gravity.LEFT, 12, 0, 0, 0)); - } else { - limitLayout.addView(freeTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 30, Gravity.LEFT, 0, 0, 36, 0)); - limitLayout.addView(defaultCount, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 30, Gravity.RIGHT, 0, 0, 12, 0)); + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (getChildCount() == 2) { + final int width = MeasureSpec.getSize(widthMeasureSpec); + final int height = MeasureSpec.getSize(heightMeasureSpec); + defaultLayout.measure( + MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) + ); + final int minWidth1 = Math.max(defaultLayout.getMeasuredWidth(), dp(24) + defaultText.getMeasuredWidth() + (defaultCount.getVisibility() == View.VISIBLE ? dp(24) + defaultCount.getMeasuredWidth() : 0)); + premiumLayout.measure( + MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) + ); + final int minWidth2 = Math.max(premiumLayout.getMeasuredWidth(), dp(24) + premiumText.getMeasuredWidth() + (premiumCount.getVisibility() == View.VISIBLE ? dp(24) + premiumCount.getMeasuredWidth() : 0)); + width1 = (int) Utilities.clamp(width * percent, width - minWidth2, minWidth1); + defaultLayout.measure( + MeasureSpec.makeMeasureSpec(width1, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) + ); + premiumLayout.measure( + MeasureSpec.makeMeasureSpec(width - width1, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) + ); + setMeasuredDimension(width, height); + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } } - } - - limitsContainer.addView(limitLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 30, 2f * (1f - percent))); - - FrameLayout limitLayout2 = new FrameLayout(context); - TextView limitTextView = new TextView(context); - limitTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - limitTextView.setText(LocaleController.getString("LimitPremium", R.string.LimitPremium)); - limitTextView.setGravity(Gravity.CENTER_VERTICAL); - limitTextView.setTextColor(Color.WHITE); - limitTextView.setPadding(AndroidUtilities.dp(12), 0, 0, 0); - - premiumCount = new TextView(context); - premiumCount.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - premiumCount.setText(String.format("%d", premiumLimit)); - premiumCount.setGravity(Gravity.CENTER_VERTICAL); - premiumCount.setTextColor(Color.WHITE); - - if (percent < .7f) { - if (LocaleController.isRTL) { - limitLayout2.addView(limitTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 30, Gravity.RIGHT, 36, 0, 12, 0)); - limitLayout2.addView(premiumCount, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 30, Gravity.LEFT, 12, 0, 0, 0)); - } else { - limitLayout2.addView(limitTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 30, Gravity.LEFT, 0, 0, 36, 0)); - limitLayout2.addView(premiumCount, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 30, Gravity.RIGHT, 0, 0, 12, 0)); + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + if (getChildCount() == 2) { + View child1 = getChildAt(0); + View child2 = getChildAt(1); + final int w = child1.getMeasuredWidth(); + child1.layout(0, 0, w, b - t); + child2.layout(w, 0, r - l, b - t); + } else { + super.onLayout(changed, l, t, r, b); + } } - } - - limitsContainer.addView(limitLayout2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 30, 2f * percent)); - - addView(limitsContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 14, icon == 0 ? 0 : 12, 14, 0)); + }; + limitsContainer.addView(defaultLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 30)); + limitsContainer.addView(premiumLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 30)); + addView(limitsContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 30, 0, 0, 14, icon == 0 ? 0 : 12, 14, 0)); } public void setIconValue(int currentValue) { @@ -215,9 +252,9 @@ protected void dispatchDraw(Canvas canvas) { protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if (!wasAnimation && limitIcon != null && animationCanPlay && !premiumLocked) { - int padding = AndroidUtilities.dp(14); + int padding = dp(14); float fromX = 0; - float toX = padding + (getMeasuredWidth() - padding * 2) * position - limitIcon.getMeasuredWidth() / 2f; + float toX = padding + Math.max(width1, (getMeasuredWidth() - padding * 2) * position) - limitIcon.getMeasuredWidth() / 2f; float fromProgressCenter = 0.5f; float toProgressCenter = 0.5f; if (toX > getMeasuredWidth() - padding - limitIcon.getMeasuredWidth()) { @@ -263,7 +300,7 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { wasAnimation = true; } else if (premiumLocked) { - int padding = AndroidUtilities.dp(14); + int padding = dp(14); float toX = padding + (getMeasuredWidth() - padding * 2) * 0.5f - limitIcon.getMeasuredWidth() / 2f; if (!wasAnimation && animationCanPlay) { wasAnimation = true; @@ -325,14 +362,14 @@ public void startDelayedAnimation() { public void setPremiumLocked() { limitsContainer.setVisibility(View.GONE); - limitIcon.setPadding(AndroidUtilities.dp(24), AndroidUtilities.dp(3), AndroidUtilities.dp(24), AndroidUtilities.dp(3)); + limitIcon.setPadding(dp(24), dp(3), dp(24), dp(3)); premiumLocked = true; } private class CounterView extends View { Path path = new Path(); - PathEffect pathEffect = new CornerPathEffect(AndroidUtilities.dp(6)); + PathEffect pathEffect = new CornerPathEffect(dp(6)); TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); StaticLayout textLayout; @@ -349,44 +386,44 @@ private class CounterView extends View { public CounterView(Context context) { super(context); textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - textPaint.setTextSize(AndroidUtilities.dp(22)); + textPaint.setTextSize(dp(22)); textPaint.setColor(Color.WHITE); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { textWidth = textPaint.measureText(text, 0, text.length()); - textLayout = new StaticLayout(text, textPaint, (int) textWidth + AndroidUtilities.dp(12), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - setMeasuredDimension((int) (textWidth + getPaddingRight() + getPaddingLeft()), AndroidUtilities.dp(44) + AndroidUtilities.dp(8)); + textLayout = new StaticLayout(text, textPaint, (int) textWidth + dp(12), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + setMeasuredDimension((int) (textWidth + getPaddingRight() + getPaddingLeft()), dp(44) + dp(8)); updatePath(); } private void updatePath() { - int h = getMeasuredHeight() - AndroidUtilities.dp(8); + int h = getMeasuredHeight() - dp(8); float widthHalf = getMeasuredWidth() * arrowCenter; - float x2 = Utilities.clamp(widthHalf + AndroidUtilities.dp(8), getMeasuredWidth(), 0); - float x3 = Utilities.clamp(widthHalf + AndroidUtilities.dp(10), getMeasuredWidth(), 0); + float x2 = Utilities.clamp(widthHalf + dp(8), getMeasuredWidth(), 0); + float x3 = Utilities.clamp(widthHalf + dp(10), getMeasuredWidth(), 0); path.rewind(); - path.moveTo(widthHalf - AndroidUtilities.dp(24), h - h / 2f - AndroidUtilities.dp(2)); - path.lineTo(widthHalf - AndroidUtilities.dp(24), h); - path.lineTo(widthHalf - AndroidUtilities.dp(8), h); - path.lineTo(widthHalf, h + AndroidUtilities.dp(8)); + path.moveTo(widthHalf - dp(24), h - h / 2f - dp(2)); + path.lineTo(widthHalf - dp(24), h); + path.lineTo(widthHalf - dp(8), h); + path.lineTo(widthHalf, h + dp(8)); if (arrowCenter < 0.7f) { path.lineTo(x2, h); } path.lineTo(x3, h); - path.lineTo(x3, h - h / 2f - AndroidUtilities.dp(2)); + path.lineTo(x3, h - h / 2f - dp(2)); path.close(); } @Override protected void onDraw(Canvas canvas) { - int h = getMeasuredHeight() - AndroidUtilities.dp(8); + int h = getMeasuredHeight() - dp(8); if (premiumLocked) { h = getMeasuredHeight(); PremiumGradient.getInstance().updateMainGradientMatrix(0, 0, LimitPreviewView.this.getMeasuredWidth(), LimitPreviewView.this.getMeasuredHeight(), getGlobalXOffset() - getX(), -getTop()); - AndroidUtilities.rectTmp.set(0, AndroidUtilities.dp(3), getMeasuredWidth(), h - AndroidUtilities.dp(3)); + AndroidUtilities.rectTmp.set(0, dp(3), getMeasuredWidth(), h - dp(3)); canvas.drawRoundRect(AndroidUtilities.rectTmp, h / 2f, h / 2f, PremiumGradient.getInstance().getPremiumLocakedPaint()); } else { if (invalidatePath) { @@ -413,7 +450,7 @@ protected void onDraw(Canvas canvas) { } } else { canvas.save(); - canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight() - AndroidUtilities.dp(8)); + canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight() - dp(8)); if (animatedStableLayout != null) { canvas.save(); canvas.translate(x, y); @@ -485,7 +522,7 @@ void createAnimationLayouts() { spannableStringBuilder.setSpan(new EmptyStubSpan(), i, i + 1, 0); } } - animatedStableLayout = new StaticLayout(spannableStringBuilder, textPaint, (int) textWidth + AndroidUtilities.dp(12), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + animatedStableLayout = new StaticLayout(spannableStringBuilder, textPaint, (int) textWidth + dp(12), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); for (int i = 0; i < animatedLayouts.size(); i++) { animationInProgress = true; AnimatedLayout layout = animatedLayouts.get(i); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java index 1f03b36ff28..2a080128fab 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java @@ -41,6 +41,7 @@ import org.telegram.ui.Components.RecyclerItemsEnterAnimator; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.PremiumPreviewFragment; +import org.telegram.ui.Stories.StoriesController; import java.util.ArrayList; import java.util.HashSet; @@ -63,6 +64,10 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { public static final int TYPE_FOLDER_INVITES = 12; public static final int TYPE_SHARED_FOLDERS = 13; + public static final int TYPE_STORIES_COUNT = 14; + public static final int TYPE_STORIES_WEEK = 15; + public static final int TYPE_STORIES_MONTH = 16; + private boolean canSendLink; public static String limitTypeToServerString(int type) { @@ -127,11 +132,11 @@ public static String limitTypeToServerString(int type) { public LimitReachedBottomSheet(BaseFragment fragment, Context context, int type, int currentAccount) { super(fragment, false, hasFixedSize(type)); - fixNavigationBar(); - parentFragment = fragment; + fixNavigationBar(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); + this.parentFragment = fragment; + this.currentAccount = currentAccount; this.type = type; updateTitle(); - this.currentAccount = currentAccount; updateRows(); if (type == TYPE_PUBLIC_LINKS) { loadAdminedChannels(); @@ -158,7 +163,7 @@ protected void onDraw(Canvas canvas) { } } }; - divider.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground)); + divider.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); containerView.addView(divider, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 72, Gravity.BOTTOM, 0, 0, 0, 0)); } containerView.addView(premiumButtonView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM, 16, 0, 16, 12)); @@ -302,7 +307,7 @@ private void leaveFromSelectedGroups() { for (Object obj : selectedChats) { chats.add((TLRPC.Chat) obj); } - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + AlertDialog.Builder builder = new AlertDialog.Builder(getContext(), resourcesProvider); builder.setTitle(LocaleController.formatPluralString("LeaveCommunities", chats.size())); if (chats.size() == 1) { TLRPC.Chat channel = chats.get(0); @@ -323,7 +328,7 @@ private void leaveFromSelectedGroups() { alertDialog.show(); TextView button = (TextView) alertDialog.getButton(DialogInterface.BUTTON_POSITIVE); if (button != null) { - button.setTextColor(Theme.getColor(Theme.key_text_RedBold)); + button.setTextColor(Theme.getColor(Theme.key_text_RedBold, resourcesProvider)); } } @@ -355,7 +360,7 @@ private void updateButton() { } private static boolean hasFixedSize(int type) { - if (type == TYPE_PIN_DIALOGS || type == TYPE_FOLDERS || type == TYPE_CHATS_IN_FOLDER || type == TYPE_LARGE_FILE || type == TYPE_ACCOUNTS || type == TYPE_FOLDER_INVITES || type == TYPE_SHARED_FOLDERS) { + if (type == TYPE_PIN_DIALOGS || type == TYPE_FOLDERS || type == TYPE_CHATS_IN_FOLDER || type == TYPE_LARGE_FILE || type == TYPE_ACCOUNTS || type == TYPE_FOLDER_INVITES || type == TYPE_SHARED_FOLDERS || type == TYPE_STORIES_COUNT || type == TYPE_STORIES_WEEK || type == TYPE_STORIES_MONTH) { return true; } return false; @@ -402,7 +407,7 @@ public void onClick(View v) { }, true, 9); break; case 2: - view = new ShadowSectionCell(context, 12, Theme.getColor(Theme.key_windowBackgroundGray)); + view = new ShadowSectionCell(context, 12, Theme.getColor(Theme.key_windowBackgroundGray, resourcesProvider)); break; case 3: view = new HeaderCell(context); @@ -574,7 +579,7 @@ public HeaderView(Context context) { int defaultLimit = limitParams.defaultLimit; int premiumLimit = limitParams.premiumLimit; int currentValue = LimitReachedBottomSheet.this.currentValue; - float position = 0.5f; + float percent = .5f, position = .5f; if (type == TYPE_FOLDERS) { currentValue = MessagesController.getInstance(currentAccount).dialogFilters.size() - 1; @@ -612,7 +617,9 @@ public HeaderView(Context context) { } } - limitPreviewView = new LimitPreviewView(context, icon, currentValue, premiumLimit, position); + percent = defaultLimit / (float) premiumLimit; + + limitPreviewView = new LimitPreviewView(context, icon, currentValue, premiumLimit, percent, resourcesProvider); limitPreviewView.setBagePosition(position); limitPreviewView.setType(type); limitPreviewView.defaultCount.setVisibility(View.GONE); @@ -651,14 +658,14 @@ public HeaderView(Context context) { title.setText(LocaleController.getString("LimitReached", R.string.LimitReached)); } title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); - title.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + title.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); addView(title, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, premiumLocked ? 8 : 22, 0, 10)); TextView description = new TextView(context); description.setText(AndroidUtilities.replaceTags(descriptionStr)); description.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); description.setGravity(Gravity.CENTER_HORIZONTAL); - description.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + description.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); addView(description, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, 24, 0, 24, 24)); updatePremiumButtonText(); @@ -737,6 +744,27 @@ private static LimitParams getLimitParams(int type, int currentAccount) { limitParams.descriptionStr = LocaleController.formatString("LimitReachedAccounts", R.string.LimitReachedAccounts, limitParams.defaultLimit, limitParams.premiumLimit); limitParams.descriptionStrPremium = ""; limitParams.descriptionStrLocked = ""; + } else if (type == TYPE_STORIES_COUNT) { + limitParams.defaultLimit = MessagesController.getInstance(currentAccount).storyExpiringLimitDefault; + limitParams.premiumLimit = MessagesController.getInstance(currentAccount).storyExpiringLimitPremium; + limitParams.icon = R.drawable.msg_limit_stories; + limitParams.descriptionStr = LocaleController.formatString("LimitReachedStoriesCount", R.string.LimitReachedStoriesCount, limitParams.defaultLimit, limitParams.premiumLimit); + limitParams.descriptionStrPremium = LocaleController.formatString("LimitReachedStoriesCountPremium", R.string.LimitReachedStoriesCountPremium, limitParams.premiumLimit); + limitParams.descriptionStrLocked = LocaleController.formatString("LimitReachedStoriesCountPremium", R.string.LimitReachedStoriesCountPremium, limitParams.defaultLimit); + } else if (type == TYPE_STORIES_WEEK) { + limitParams.defaultLimit = MessagesController.getInstance(currentAccount).storiesSentWeeklyLimitDefault; + limitParams.premiumLimit = MessagesController.getInstance(currentAccount).storiesSentWeeklyLimitPremium; + limitParams.icon = R.drawable.msg_limit_stories; + limitParams.descriptionStr = LocaleController.formatString("LimitReachedStoriesWeekly", R.string.LimitReachedStoriesWeekly, limitParams.defaultLimit, limitParams.premiumLimit); + limitParams.descriptionStrPremium = LocaleController.formatString("LimitReachedStoriesWeeklyPremium", R.string.LimitReachedStoriesWeeklyPremium, limitParams.premiumLimit); + limitParams.descriptionStrLocked = LocaleController.formatString("LimitReachedStoriesWeeklyPremium", R.string.LimitReachedStoriesWeeklyPremium, limitParams.defaultLimit); + } else if (type == TYPE_STORIES_MONTH) { + limitParams.defaultLimit = MessagesController.getInstance(currentAccount).storiesSentMonthlyLimitDefault; + limitParams.premiumLimit = MessagesController.getInstance(currentAccount).storiesSentMonthlyLimitPremium; + limitParams.icon = R.drawable.msg_limit_stories; + limitParams.descriptionStr = LocaleController.formatString("LimitReachedStoriesMonthly", R.string.LimitReachedStoriesMonthly, limitParams.defaultLimit, limitParams.premiumLimit); + limitParams.descriptionStrPremium = LocaleController.formatString("LimitReachedStoriesMonthlyPremium", R.string.LimitReachedStoriesMonthlyPremium, limitParams.premiumLimit); + limitParams.descriptionStrLocked = LocaleController.formatString("LimitReachedStoriesMonthlyPremium", R.string.LimitReachedStoriesMonthlyPremium, limitParams.defaultLimit); } return limitParams; } @@ -817,7 +845,7 @@ private void revokeSelectedLinks() { } private void revokeLinks(ArrayList channels) { - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + AlertDialog.Builder builder = new AlertDialog.Builder(getContext(), resourcesProvider); builder.setTitle(LocaleController.formatPluralString("RevokeLinks", channels.size())); if (channels.size() == 1) { TLRPC.Chat channel = channels.get(0); @@ -852,7 +880,7 @@ private void revokeLinks(ArrayList channels) { alertDialog.show(); TextView button = (TextView) alertDialog.getButton(DialogInterface.BUTTON_POSITIVE); if (button != null) { - button.setTextColor(Theme.getColor(Theme.key_text_RedBold)); + button.setTextColor(Theme.getColor(Theme.key_text_RedBold, resourcesProvider)); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumAppIconsPreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumAppIconsPreviewView.java index 9b8a2c30aed..100f97be3dd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumAppIconsPreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumAppIconsPreviewView.java @@ -21,13 +21,17 @@ import java.util.List; public class PremiumAppIconsPreviewView extends FrameLayout implements PagerHeaderView { + + private final Theme.ResourcesProvider resourcesProvider; private List icons = new ArrayList<>(); private AdaptiveIconImageView topIcon, bottomLeftIcon, bottomRightIcon; boolean isEmpty; - public PremiumAppIconsPreviewView(Context context) { + public PremiumAppIconsPreviewView(Context context, Theme.ResourcesProvider resourcesProvider) { super(context); + this.resourcesProvider = resourcesProvider; + for (LauncherIconController.LauncherIcon icon : LauncherIconController.LauncherIcon.values()) { if (icon.premium) { icons.add(icon); @@ -137,6 +141,7 @@ public AdaptiveIconImageView(Context ctx, int i) { } if (i == 0) { drawable.type = StarParticlesView.TYPE_APP_ICON_STAR_PREMIUM; } + drawable.resourcesProvider = resourcesProvider; drawable.colorKey = Theme.key_premiumStartSmallStarsColor2; drawable.init(); paint.setColor(Color.WHITE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumButtonView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumButtonView.java index 9358c9a92cb..b40fb5905eb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumButtonView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumButtonView.java @@ -54,6 +54,7 @@ public class PremiumButtonView extends FrameLayout { private boolean isFlickerDisabled; CounterView counterView; + public boolean drawGradient = true; public PremiumButtonView(@NonNull Context context, boolean createOverlayTextView) { this(context, AndroidUtilities.dp(8), createOverlayTextView); @@ -144,8 +145,13 @@ protected void dispatchDraw(Canvas canvas) { inc = true; } } - PremiumGradient.getInstance().updateMainGradientMatrix(0, 0, getMeasuredWidth(), getMeasuredHeight(), -getMeasuredWidth() * 0.1f * progress, 0); - canvas.drawRoundRect(AndroidUtilities.rectTmp, radius, radius, PremiumGradient.getInstance().getMainGradientPaint()); + if (drawGradient) { + PremiumGradient.getInstance().updateMainGradientMatrix(0, 0, getMeasuredWidth(), getMeasuredHeight(), -getMeasuredWidth() * 0.1f * progress, 0); + canvas.drawRoundRect(AndroidUtilities.rectTmp, radius, radius, PremiumGradient.getInstance().getMainGradientPaint()); + } else { + paintOverlayPaint.setAlpha(255); + canvas.drawRoundRect(AndroidUtilities.rectTmp, radius, radius, paintOverlayPaint); + } invalidate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java index be6e31978e4..e2957c303d9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java @@ -6,6 +6,7 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Path; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.util.TypedValue; @@ -55,6 +56,7 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati float containerViewsProgress; float progressToFullscreenView; + float progressToGradient; boolean containerViewsForward; ViewPager viewPager; FrameLayout content; @@ -68,6 +70,10 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati private final boolean onlySelectedType; private boolean forceAbout; + int selectedPosition; + int toPosition; + float progress; + private PremiumPreviewFragment.SubscriptionTier selectedTier; private int gradientAlpha = 255; int topGlobalOffset; @@ -87,14 +93,14 @@ public PremiumFeatureBottomSheet(BaseFragment fragment, Context context, int cur } public PremiumFeatureBottomSheet(BaseFragment fragment, Context context, int currentAccount, int startType, boolean onlySelectedType, PremiumPreviewFragment.SubscriptionTier subscriptionTier) { - super(context, false); + super(context, false, getResourceProvider(fragment)); this.baseFragment = fragment; if (fragment == null) { throw new RuntimeException("fragmnet can't be null"); } selectedTier = subscriptionTier; - fixNavigationBar(); + fixNavigationBar(getThemedColor(Theme.key_dialogBackground)); this.startType = startType; this.onlySelectedType = onlySelectedType; @@ -115,27 +121,22 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { PremiumPreviewFragment.fillPremiumFeaturesList(premiumFeatures, currentAccount); - int selectedPosition = 0; + int selectedPositionLocal = 0; for (int i = 0; i < premiumFeatures.size(); i++) { -// if (premiumFeatures.get(i).type == PremiumPreviewFragment.PREMIUM_FEATURE_LIMITS) { -// premiumFeatures.remove(i); -// i--; -// continue; -// } if (premiumFeatures.get(i).type == startType) { - selectedPosition = i; + selectedPositionLocal = i; break; } } if (onlySelectedType) { - PremiumPreviewFragment.PremiumFeatureData selectedFeature = premiumFeatures.get(selectedPosition); + PremiumPreviewFragment.PremiumFeatureData selectedFeature = premiumFeatures.get(selectedPositionLocal); premiumFeatures.clear(); premiumFeatures.add(selectedFeature); - selectedPosition = 0; + selectedPositionLocal = 0; } - PremiumPreviewFragment.PremiumFeatureData featureData = premiumFeatures.get(selectedPosition); + PremiumPreviewFragment.PremiumFeatureData featureData = premiumFeatures.get(selectedPositionLocal); setApplyTopPadding(false); setApplyBottomPadding(false); @@ -233,17 +234,13 @@ public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { } }; viewPager.setAdapter(pagerAdapter); - viewPager.setCurrentItem(selectedPosition); + viewPager.setCurrentItem(selectedPosition = selectedPositionLocal); frameLayout.addView(viewPager, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 100, 0, 0, 18, 0, 0)); frameLayout.addView(closeLayout, LayoutHelper.createFrame(52, 52, Gravity.RIGHT | Gravity.TOP, 0, 24, 0, 0)); BottomPagesView bottomPages = new BottomPagesView(getContext(), viewPager, premiumFeatures.size()); viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { - int selectedPosition; - int toPosition; - float progress; - @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { bottomPages.setPageOffset(position, positionOffset); @@ -255,6 +252,13 @@ public void onPageScrolled(int position, float positionOffset, int positionOffse @Override public void onPageSelected(int i) { + if (premiumFeatures.get(i).type == PremiumPreviewFragment.PREMIUM_FEATURE_LIMITS) { + actionBar.setTitle(LocaleController.getString("DoubledLimits", R.string.DoubledLimits)); + actionBar.requestLayout(); + } else if (premiumFeatures.get(i).type == PremiumPreviewFragment.PREMIUM_FEATURE_STORIES) { + actionBar.setTitle(LocaleController.getString("UpgradedStories", R.string.UpgradedStories)); + actionBar.requestLayout(); + } checkPage(); } @@ -280,13 +284,19 @@ private void checkPage() { } containerViewsProgress = progress; containerViewsForward = toPosition > selectedPosition; - if (selectedPosition >= 0 && selectedPosition < premiumFeatures.size() && premiumFeatures.get(selectedPosition).type == PremiumPreviewFragment.PREMIUM_FEATURE_LIMITS) { - progressToFullscreenView = 1f - progress; - } else if (toPosition >= 0 && toPosition < premiumFeatures.size() && premiumFeatures.get(toPosition).type == PremiumPreviewFragment.PREMIUM_FEATURE_LIMITS) { - progressToFullscreenView = progress; + boolean selectedFullscreen = selectedPosition >= 0 && selectedPosition < premiumFeatures.size() && isFullscreenType(premiumFeatures.get(selectedPosition).type); + boolean nextFullscreen = toPosition >= 0 && toPosition < premiumFeatures.size() && isFullscreenType(premiumFeatures.get(toPosition).type); + if (selectedFullscreen && nextFullscreen) { + progressToGradient = 1f; + progressToFullscreenView = progress == 0 ? 1f : progress; + } else if (selectedFullscreen) { + progressToGradient = progressToFullscreenView = 1f - progress; + } else if (nextFullscreen) { + progressToGradient = progressToFullscreenView = progress; } else { - progressToFullscreenView = 0; + progressToGradient = progressToFullscreenView = 0; } + int localGradientAlpha = (int) (255 * (1f - progressToFullscreenView)); if (localGradientAlpha != gradientAlpha) { gradientAlpha = localGradientAlpha; @@ -401,11 +411,16 @@ protected void dispatchDraw(Canvas canvas) { } } + Path path = new Path(); + @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { if (child == scrollView) { canvas.save(); - canvas.clipRect(0, topCurrentOffset + AndroidUtilities.dp(2), getMeasuredWidth(), getMeasuredHeight()); + path.rewind(); + AndroidUtilities.rectTmp.set(0, topCurrentOffset + AndroidUtilities.dp(18), getMeasuredWidth(), getMeasuredHeight()); + path.addRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(18), AndroidUtilities.dp(18), Path.Direction.CW); + canvas.clipPath(path); super.drawChild(canvas, child, drawingTime); canvas.restore(); return true; @@ -426,6 +441,20 @@ public boolean dispatchTouchEvent(MotionEvent event) { containerView.setPadding(backgroundPaddingLeft, backgroundPaddingTop - 1, backgroundPaddingLeft, 0); } + private static Theme.ResourcesProvider getResourceProvider(BaseFragment fragment) { + if (fragment != null) { + if (fragment.storyViewer != null && fragment.storyViewer.isShown()) { + return fragment.storyViewer.getResourceProvider(); + } + return fragment.getResourceProvider(); + } + return null; + } + + private boolean isFullscreenType(int type) { + return type == PremiumPreviewFragment.PREMIUM_FEATURE_LIMITS || type == PremiumPreviewFragment.PREMIUM_FEATURE_STORIES; + } + public PremiumFeatureBottomSheet setForceAbout() { this.forceAbout = true; premiumButtonView.clearOverlayText(); @@ -486,8 +515,8 @@ public void setTag(Object tag) { actionBar.setItemsColor(getThemedColor(Theme.key_actionBarActionModeDefaultIcon), false); actionBar.setCastShadows(true); + actionBar.setExtraHeight(AndroidUtilities.dp(2)); actionBar.setBackButtonImage(R.drawable.ic_ab_back); - actionBar.setTitle(LocaleController.getString("DoubledLimits", R.string.DoubledLimits)); actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { @@ -496,8 +525,17 @@ public void onItemClick(int id) { } } }); - containerView.addView(actionBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, -backgroundPaddingTop, 0, 0)); + containerView.addView(actionBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 0, 0, 0)); + ((FrameLayout.LayoutParams) actionBar.getLayoutParams()).topMargin = -backgroundPaddingTop - AndroidUtilities.dp(2); AndroidUtilities.updateViewVisibilityAnimated(actionBar, false, 1f, false); + + if (premiumFeatures.get(selectedPosition).type == PremiumPreviewFragment.PREMIUM_FEATURE_STORIES) { + actionBar.setTitle(LocaleController.getString("UpgradedStories", R.string.UpgradedStories)); + actionBar.requestLayout(); + } else { + actionBar.setTitle(LocaleController.getString("DoubledLimits", R.string.DoubledLimits)); + actionBar.requestLayout(); + } } @Override @@ -543,7 +581,7 @@ public ViewPage(Context context, int p) { title = new TextView(context); title.setGravity(Gravity.CENTER_HORIZONTAL); - title.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + title.setTextColor(getThemedColor(Theme.key_dialogTextBlack)); title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); title.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); @@ -552,7 +590,7 @@ public ViewPage(Context context, int p) { description = new TextView(context); description.setGravity(Gravity.CENTER_HORIZONTAL); description.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - description.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + description.setTextColor(getThemedColor(Theme.key_dialogTextBlack)); if (!onlySelectedType) { description.setLines(2); } @@ -563,8 +601,8 @@ public ViewPage(Context context, int p) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { title.setVisibility(View.VISIBLE); - if (topView instanceof DoubleLimitsPageView) { - ((DoubleLimitsPageView) topView).setTopOffset(topGlobalOffset); + if (topView instanceof BaseListPageView) { + ((BaseListPageView) topView).setTopOffset(topGlobalOffset); } topView.getLayoutParams().height = contentHeight; description.setVisibility(isPortrait ? View.VISIBLE : View.GONE); @@ -590,12 +628,12 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { if (child == topView) { - if (child instanceof DoubleLimitsPageView) { + if (child instanceof BaseListPageView) { setTranslationY(0); } else { setTranslationY(topGlobalOffset); } - if (child instanceof CarouselView || child instanceof DoubleLimitsPageView) { + if (child instanceof CarouselView || child instanceof BaseListPageView) { return super.drawChild(canvas, child, drawingTime); } canvas.save(); @@ -609,7 +647,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { } void setFeatureDate(PremiumPreviewFragment.PremiumFeatureData featureData) { - if (featureData.type == PremiumPreviewFragment.PREMIUM_FEATURE_LIMITS) { + if (featureData.type == PremiumPreviewFragment.PREMIUM_FEATURE_LIMITS || featureData.type == PremiumPreviewFragment.PREMIUM_FEATURE_STORIES) { title.setText(""); description.setText(""); topViewOnFullHeight = true; @@ -650,16 +688,29 @@ void setFeatureDate(PremiumPreviewFragment.PremiumFeatureData featureData) { View getViewForPosition(Context context, int position) { PremiumPreviewFragment.PremiumFeatureData featureData = premiumFeatures.get(position); if (featureData.type == PremiumPreviewFragment.PREMIUM_FEATURE_LIMITS) { - DoubleLimitsPageView doubleLimitsPagerView = new DoubleLimitsPageView(context); + DoubleLimitsPageView doubleLimitsPagerView = new DoubleLimitsPageView(context, resourcesProvider); doubleLimitsPagerView.recyclerListView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); + containerView.invalidate(); checkTopOffset(); } }); return doubleLimitsPagerView; } + if (featureData.type == PremiumPreviewFragment.PREMIUM_FEATURE_STORIES) { + StoriesPageView storiesPageView = new StoriesPageView(context, resourcesProvider); + storiesPageView.recyclerListView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + containerView.invalidate(); + checkTopOffset(); + } + }); + return storiesPageView; + } if (featureData.type == PremiumPreviewFragment.PREMIUM_FEATURE_STICKERS) { PremiumStickersPreviewRecycler recyclerListView = new PremiumStickersPreviewRecycler(context, currentAccount) { @Override @@ -670,9 +721,9 @@ public void setOffset(float v) { }; return recyclerListView; } else if (featureData.type == PremiumPreviewFragment.PREMIUM_FEATURE_APPLICATION_ICONS) { - return new PremiumAppIconsPreviewView(context); + return new PremiumAppIconsPreviewView(context, resourcesProvider); } - VideoScreenPreview preview = new VideoScreenPreview(context, svgIcon, currentAccount, featureData.type); + VideoScreenPreview preview = new VideoScreenPreview(context, svgIcon, currentAccount, featureData.type, resourcesProvider); return preview; } @@ -709,35 +760,51 @@ public void onAnimationEnd(Animator animation) { } void checkTopOffset() { - int viewOffset = -1; + int selectedViewOffset = -1; + int toViewOffset = -1; for (int i = 0; i < viewPager.getChildCount(); i++) { - if (((ViewPage) viewPager.getChildAt(i)).topView instanceof DoubleLimitsPageView) { - DoubleLimitsPageView doubleLimitsPagerView = (DoubleLimitsPageView) ((ViewPage) viewPager.getChildAt(i)).topView; + ViewPage viewPage = (ViewPage) viewPager.getChildAt(i); + if (viewPage.position == selectedPosition && viewPage.topView instanceof BaseListPageView) { + BaseListPageView doubleLimitsPagerView = (BaseListPageView) viewPage.topView; View view = doubleLimitsPagerView.layoutManager.findViewByPosition(0); if (view == null) { - viewOffset = 0; + selectedViewOffset = 0; } else { - viewOffset = view.getTop(); - if (viewOffset < 0) { - viewOffset = 0; + selectedViewOffset = view.getTop(); + if (selectedViewOffset < 0) { + selectedViewOffset = 0; + } + } + } + if (viewPage.position == toPosition && viewPage.topView instanceof BaseListPageView) { + BaseListPageView doubleLimitsPagerView = (BaseListPageView) viewPage.topView; + View view = doubleLimitsPagerView.layoutManager.findViewByPosition(0); + if (view == null) { + toViewOffset = 0; + } else { + toViewOffset = view.getTop(); + if (toViewOffset < 0) { + toViewOffset = 0; } } - break; } } - int localOffset; - if (viewOffset >= 0) { - localOffset = (int) (viewOffset * progressToFullscreenView + topGlobalOffset * (1f - progressToFullscreenView)); - } else { - localOffset = topGlobalOffset; + int localOffset = topGlobalOffset; + if (selectedViewOffset >= 0 ) { + float progressLocal = 1f - progress; + localOffset = Math.min(localOffset, (int) (selectedViewOffset * progressLocal + topGlobalOffset * (1f - progressLocal))); + } + if (toViewOffset >= 0) { + float progressLocal = progress; + localOffset = Math.min(localOffset, (int) (toViewOffset * progressLocal + topGlobalOffset * (1f - progressLocal))); } - closeLayout.setAlpha(1f - progressToFullscreenView); + closeLayout.setAlpha(1f - progressToGradient); if (progressToFullscreenView == 1) { closeLayout.setVisibility(View.INVISIBLE); } else { closeLayout.setVisibility(View.VISIBLE); } - content.setTranslationX(content.getMeasuredWidth() * progressToFullscreenView); + content.setTranslationX(content.getMeasuredWidth() * progressToGradient); if (localOffset != topCurrentOffset) { topCurrentOffset = localOffset; for (int i = 0; i < viewPager.getChildCount(); i++) { @@ -763,6 +830,17 @@ private void updateStatusBar() { } private boolean isLightStatusBar() { - return ColorUtils.calculateLuminance(Theme.getColor(Theme.key_dialogBackground)) > 0.7f; + return ColorUtils.calculateLuminance(getThemedColor(Theme.key_dialogBackground)) > 0.7f; + } + + @Override + protected boolean canDismissWithSwipe() { + for (int i = 0; i < viewPager.getChildCount(); i++) { + ViewPage viewPage = (ViewPage) viewPager.getChildAt(i); + if (viewPage.position == selectedPosition && viewPage.topView instanceof BaseListPageView) { + return !((BaseListPageView) viewPage.topView).recyclerListView.canScrollVertically(-1); + } + } + return true; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumGradient.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumGradient.java index 77a305ed454..280572241dd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumGradient.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumGradient.java @@ -147,6 +147,8 @@ public Paint getMainGradientPaint() { //help with update colors and position public static class PremiumGradientTools { + private final Theme.ResourcesProvider resourcesProvider; + public float cx = 0.5f; public float cy = 0.5f; Shader shader; @@ -168,6 +170,11 @@ public PremiumGradientTools(int colorKey1, int colorKey2, int colorKey3, int col } public PremiumGradientTools(int colorKey1, int colorKey2, int colorKey3, int colorKey4, int colorKey5) { + this(colorKey1, colorKey2, colorKey3, colorKey4, -1, null); + } + + public PremiumGradientTools(int colorKey1, int colorKey2, int colorKey3, int colorKey4, int colorKey5, Theme.ResourcesProvider resourcesProvider) { + this.resourcesProvider = resourcesProvider; this.colorKey1 = colorKey1; this.colorKey2 = colorKey2; this.colorKey3 = colorKey3; @@ -201,11 +208,11 @@ public void gradientMatrix(int x, int y, int x1, int y1, float xOffset, float yO } private void chekColors() { - int c1 = Theme.getColor(colorKey1); - int c2 = Theme.getColor(colorKey2); - int c3 = colorKey3 < 0 ? 0 : Theme.getColor(colorKey3); - int c4 = colorKey4 < 0 ? 0 : Theme.getColor(colorKey4); - int c5 = colorKey5 < 0 ? 0 : Theme.getColor(colorKey5); + int c1 = Theme.getColor(colorKey1, resourcesProvider); + int c2 = Theme.getColor(colorKey2, resourcesProvider); + int c3 = colorKey3 < 0 ? 0 : Theme.getColor(colorKey3, resourcesProvider); + int c4 = colorKey4 < 0 ? 0 : Theme.getColor(colorKey4, resourcesProvider); + int c5 = colorKey5 < 0 ? 0 : Theme.getColor(colorKey5, resourcesProvider); if (colors[0] != c1 || colors[1] != c2 || colors[2] != c3 || colors[3] != c4 || colors[4] != c5) { colors[0] = c1; colors[1] = c2; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StarParticlesView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StarParticlesView.java index c00068da427..80e4d070d6c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StarParticlesView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StarParticlesView.java @@ -141,6 +141,7 @@ public static class Drawable { public boolean forceMaxAlpha = false; public boolean roundEffect = true; public int type = -1; + public Theme.ResourcesProvider resourcesProvider; public int colorKey = Theme.key_premiumStartSmallStarsColor; public boolean svg; @@ -172,7 +173,7 @@ public void init() { } public void updateColors() { - int c = Theme.getColor(colorKey); + int c = Theme.getColor(colorKey, resourcesProvider); if (lastColor != c) { lastColor = c; generateBitmaps(); @@ -203,7 +204,7 @@ private void generateBitmaps() { } else { res = R.raw.premium_object_settings; } - stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey), 30)); + stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 30)); svg = true; continue; } else if (type == PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_EMOJI || type == PremiumPreviewFragment.PREMIUM_FEATURE_REACTIONS) { @@ -215,7 +216,7 @@ private void generateBitmaps() { } else { res = R.raw.premium_object_like; } - stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey), 30)); + stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 30)); svg = true; continue; } else if (type == PremiumPreviewFragment.PREMIUM_FEATURE_ADS) { @@ -227,7 +228,7 @@ private void generateBitmaps() { } else { res = R.raw.premium_object_noads; } - stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey), 30)); + stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 30)); svg = true; continue; } else if (type == PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_AVATARS) { @@ -239,15 +240,15 @@ private void generateBitmaps() { } else { res = R.raw.premium_object_user; } - stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey), 30)); + stars[i] = SvgHelper.getBitmap(res, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 30)); svg = true; continue; } else if (type == TYPE_APP_ICON_REACT) { - stars[i] = SvgHelper.getBitmap(R.raw.premium_object_fire, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey), 30)); + stars[i] = SvgHelper.getBitmap(R.raw.premium_object_fire, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 30)); svg = true; continue; } else if (type == TYPE_APP_ICON_STAR_PREMIUM) { - stars[i] = SvgHelper.getBitmap(R.raw.premium_object_star2, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey), 30)); + stars[i] = SvgHelper.getBitmap(R.raw.premium_object_star2, size, size, ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 30)); svg = true; continue; } @@ -259,7 +260,7 @@ private void generateBitmaps() { if (type == PremiumPreviewFragment.PREMIUM_FEATURE_PROFILE_BADGE && (i == 1 || i == 2)) { android.graphics.drawable.Drawable drawable = ContextCompat.getDrawable(ApplicationLoader.applicationContext, R.drawable.msg_premium_liststar); - drawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(colorKey), PorterDuff.Mode.MULTIPLY)); + drawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(colorKey, resourcesProvider), PorterDuff.Mode.MULTIPLY)); drawable.setBounds(0, 0, size, size); drawable.draw(canvas); continue; @@ -301,9 +302,9 @@ private void generateBitmaps() { paint1.setAlpha(255); } else { if (type == 100) { - paint.setColor(ColorUtils.setAlphaComponent(Theme.getColor(colorKey), 200)); + paint.setColor(ColorUtils.setAlphaComponent(Theme.getColor(colorKey, resourcesProvider), 200)); } else { - paint.setColor(Theme.getColor(colorKey)); + paint.setColor(Theme.getColor(colorKey, resourcesProvider)); } if (roundEffect) { paint.setPathEffect(new CornerPathEffect(AndroidUtilities.dpf2(size1 / 5f))); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StoriesPageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StoriesPageView.java new file mode 100644 index 00000000000..d728c621c52 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/StoriesPageView.java @@ -0,0 +1,265 @@ +package org.telegram.ui.Components.Premium; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.Shader; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.FixedHeightEmptyCell; +import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.GradientTools; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.PremiumPreviewFragment; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Locale; + +public class StoriesPageView extends BaseListPageView { + + RecyclerListView.SelectionAdapter adapter; + private final static int VIEW_TYPE_HEADER = 0; + private final static int VIEW_TYPE_ITEM = 1; + private final static int VIEW_TYPE_EMPTY = 2; + + ArrayList items = new ArrayList<>(); + Bitmap bitmap; + + public StoriesPageView(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context, resourcesProvider); + ArrayList itemsTmp = new ArrayList<>(); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_order, + LocaleController.getString("PremiumStoriesPriority", R.string.PremiumStoriesPriority), + LocaleController.getString("PremiumStoriesPriorityDescription", R.string.PremiumStoriesPriorityDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_PRIORITY_ORDER + )); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_stealth, + LocaleController.getString("PremiumStoriesStealth", R.string.PremiumStoriesStealth), + LocaleController.getString("PremiumStoriesStealthDescription", R.string.PremiumStoriesStealthDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_STEALTH_MODE + )); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_views, + LocaleController.getString("PremiumStoriesViews", R.string.PremiumStoriesViews), + LocaleController.getString("PremiumStoriesViewsDescription", R.string.PremiumStoriesViewsDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_VIEWS_HISTORY + )); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_timer, + LocaleController.getString("PremiumStoriesExpiration", R.string.PremiumStoriesExpiration), + LocaleController.getString("PremiumStoriesExpirationDescription", R.string.PremiumStoriesExpirationDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_EXPIRATION_DURATION + )); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_save, + LocaleController.getString("PremiumStoriesSaveToGallery", R.string.PremiumStoriesSaveToGallery), + LocaleController.getString("PremiumStoriesSaveToGalleryDescription", R.string.PremiumStoriesSaveToGalleryDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_SAVE_TO_GALLERY + )); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_caption, + LocaleController.getString("PremiumStoriesCaption", R.string.PremiumStoriesCaption), + LocaleController.getString("PremiumStoriesCaptionDescription", R.string.PremiumStoriesCaptionDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_CAPTION + )); + itemsTmp.add(new Item(VIEW_TYPE_ITEM, R.drawable.msg_stories_link, + LocaleController.getString("PremiumStoriesFormatting", R.string.PremiumStoriesFormatting), + LocaleController.getString("PremiumStoriesFormattingDescription", R.string.PremiumStoriesFormattingDescription), + PremiumPreviewFragment.PREMIUM_FEATURE_STORIES_LINKS_AND_FORMATTING + )); + + MessagesController messagesController = MessagesController.getInstance(UserConfig.selectedAccount); + Collections.sort(itemsTmp, (o1, o2) -> { + int type1 = messagesController.premiumFeaturesTypesToPosition.get(o1.order, Integer.MAX_VALUE); + int type2 = messagesController.premiumFeaturesTypesToPosition.get(o2.order, Integer.MAX_VALUE); + return type1 - type2; + }); + + items.add(new Item(VIEW_TYPE_HEADER)); + items.addAll(itemsTmp); + items.add(new Item(VIEW_TYPE_EMPTY)); + bitmap = Bitmap.createBitmap(items.size(), 1, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + Paint paint = new Paint(); + paint.setShader(new LinearGradient(0, 0, bitmap.getWidth(), 0, new int[] { + Theme.getColor(Theme.key_premiumGradient1), + Theme.getColor(Theme.key_premiumGradient2), + Theme.getColor(Theme.key_premiumGradient3), + Theme.getColor(Theme.key_premiumGradient4) + }, null, Shader.TileMode.CLAMP)); + canvas.drawRect(0, 0, bitmap.getWidth(), bitmap.getHeight(), paint); + } + + @Override + public RecyclerView.Adapter createAdapter() { + adapter = new RecyclerListView.SelectionAdapter() { + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return false; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + if (viewType == VIEW_TYPE_HEADER) { + view = new HeaderView(getContext()); + } else if (viewType == VIEW_TYPE_EMPTY) { + view = new FixedHeightEmptyCell(getContext(), 16); + } else { + view = new ItemCell(getContext()); + } + view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if (items.get(position).viewType == VIEW_TYPE_ITEM) { + ItemCell cell = (ItemCell) holder.itemView; + cell.imageView.setColorFilter(new PorterDuffColorFilter(bitmap.getPixel(position, 0), PorterDuff.Mode.MULTIPLY)); + cell.imageView.setImageDrawable(ContextCompat.getDrawable(getContext(), items.get(position).iconRes)); + cell.textView.setText(items.get(position).text); + cell.description.setText(items.get(position).description); + } + } + + @Override + public int getItemViewType(int position) { + return items.get(position).viewType; + } + + @Override + public int getItemCount() { + return items.size(); + } + }; + return adapter; + } + + private class Item { + final int viewType; + int iconRes; + String text; + String description; + int order; + + private Item(int viewType) { + this.viewType = viewType; + } + + public Item(int viewType, int iconRes, String text, String description, int order) { + this.viewType = viewType; + this.iconRes = iconRes; + this.text = text; + this.description = description; + this.order = order; + } + } + + private class HeaderView extends FrameLayout { + + BackupImageView imageView; + GradientTools gradientTools = new GradientTools(); + + public HeaderView(Context context) { + super(context); + imageView = new BackupImageView(context); + imageView.setRoundRadius((int) (AndroidUtilities.dp(65) / 2f)); + addView(imageView, LayoutHelper.createFrame(65, 65, Gravity.CENTER_HORIZONTAL, 0, 32, 0, 0)); + + TLRPC.User user = UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(); + AvatarDrawable avatarDrawable = new AvatarDrawable(); + avatarDrawable.setInfo(user); + imageView.getImageReceiver().setForUserOrChat(user, avatarDrawable); + + TextView textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + textView.setText(LocaleController.getString("UpgradedStories", R.string.UpgradedStories)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 111, 0, 0)); + + gradientTools.isLinear = true; + gradientTools.isDiagonal = true; + gradientTools.setColors( + Theme.getColor(Theme.key_premiumGradient2), + Theme.getColor(Theme.key_premiumGradient1) + ); + gradientTools.paint.setStyle(Paint.Style.STROKE); + gradientTools.paint.setStrokeCap(Paint.Cap.ROUND); + gradientTools.paint.setStrokeWidth(AndroidUtilities.dpf2(3.3f)); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + imageView.getHitRect(AndroidUtilities.rectTmp2); + AndroidUtilities.rectTmp.set(AndroidUtilities.rectTmp2); + AndroidUtilities.rectTmp.inset(-AndroidUtilities.dp(5), -AndroidUtilities.dp(5)); + gradientTools.setBounds(AndroidUtilities.rectTmp); + int storiesCount = 7; + float step = 360 / (float) storiesCount; + int gapLen = 5; + for (int i = 0; i < storiesCount; i++) { + float startAngle = step * i - 90; + float endAngle = startAngle + step; + startAngle += gapLen; + endAngle -= gapLen; + canvas.drawArc(AndroidUtilities.rectTmp, startAngle, (endAngle - startAngle), false, gradientTools.paint); + } + super.dispatchDraw(canvas); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(150), MeasureSpec.EXACTLY)); + } + } + + private class ItemCell extends FrameLayout { + + TextView textView; + TextView description; + ImageView imageView; + + public ItemCell(Context context) { + super(context); + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + addView(imageView, LayoutHelper.createFrame(28, 28, 0, 25, 12, 16, 0)); + + textView = new TextView(context); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 68, 8, 16, 0)); + + description = new TextView(context); + description.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider)); + description.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + addView(description, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 68, 28, 16, 8)); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java index 9f0ffc17c4e..a514de45584 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java @@ -112,14 +112,14 @@ private void checkVideo() { private TLRPC.Document document; - public VideoScreenPreview(Context context, SvgHelper.SvgDrawable svgDrawable, int currentAccount, int type) { + public VideoScreenPreview(Context context, SvgHelper.SvgDrawable svgDrawable, int currentAccount, int type, Theme.ResourcesProvider resourcesProvider) { super(context); this.currentAccount = currentAccount; this.type = type; this.svgIcon = svgDrawable; phoneFrame1.setColor(Color.BLACK); - phoneFrame2.setColor(ColorUtils.blendARGB(Theme.getColor(Theme.key_premiumGradient2), Color.BLACK, 0.5f)); + phoneFrame2.setColor(ColorUtils.blendARGB(Theme.getColor(Theme.key_premiumGradient2, resourcesProvider), Color.BLACK, 0.5f)); imageReceiver.setLayerNum(Integer.MAX_VALUE); setVideo(); @@ -147,6 +147,7 @@ public VideoScreenPreview(Context context, SvgHelper.SvgDrawable svgDrawable, in } starDrawable.k1 = starDrawable.k2 = starDrawable.k3 = 0.98f; starDrawable.speedScale = 4; + starDrawable.resourcesProvider = resourcesProvider; starDrawable.colorKey = Theme.key_premiumStartSmallStarsColor2; starDrawable.init(); } else if (type == PremiumPreviewFragment.PREMIUM_FEATURE_DOWNLOAD_SPEED) { @@ -163,6 +164,7 @@ public VideoScreenPreview(Context context, SvgHelper.SvgDrawable svgDrawable, in particlesCount = 400; } starDrawable = new StarParticlesView.Drawable(particlesCount); + starDrawable.resourcesProvider = resourcesProvider; starDrawable.colorKey = Theme.key_premiumStartSmallStarsColor2; starDrawable.size1 = 8; starDrawable.size1 = 6; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ProxyDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ProxyDrawable.java index b488aec41f4..6b553b78a48 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ProxyDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ProxyDrawable.java @@ -34,8 +34,8 @@ public class ProxyDrawable extends Drawable { public ProxyDrawable(Context context) { super(); - emptyDrawable = context.getResources().getDrawable(R.drawable.msg2_proxy_off); - fullDrawable = context.getResources().getDrawable(R.drawable.msg2_proxy_on); + emptyDrawable = context.getResources().getDrawable(R.drawable.msg2_proxy_off).mutate(); + fullDrawable = context.getResources().getDrawable(R.drawable.msg2_proxy_on).mutate(); outerPaint.setStyle(Paint.Style.STROKE); outerPaint.setStrokeWidth(AndroidUtilities.dp(1.66f)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/AnimatedEmojiEffect.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/AnimatedEmojiEffect.java index 8378ae45163..8437bcbbab4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/AnimatedEmojiEffect.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/AnimatedEmojiEffect.java @@ -87,7 +87,8 @@ public void draw(Canvas canvas) { effectImageReceiver.draw(canvas); } - + canvas.save(); + canvas.translate(bounds.left, bounds.top); for (int i = 0; i < particles.size(); i++) { particles.get(i).draw(canvas); if (particles.get(i).progress >= 1f) { @@ -95,6 +96,7 @@ public void draw(Canvas canvas) { i--; } } + canvas.restore(); if (parentView != null) { parentView.invalidate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java index e52e253b2f7..f17ccc7f5a9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java @@ -1,12 +1,14 @@ package org.telegram.ui.Components.Reactions; import static org.telegram.ui.Components.ReactionsContainerLayout.TYPE_STORY; +import static org.telegram.ui.Components.ReactionsContainerLayout.TYPE_STORY_LIKES; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Path; @@ -21,6 +23,7 @@ import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.View; +import android.view.ViewGroup; import android.view.ViewOutlineProvider; import android.view.WindowManager; import android.view.animation.OvershootInterpolator; @@ -28,6 +31,7 @@ import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; +import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AnimationNotificationsLocker; @@ -64,7 +68,8 @@ public class CustomEmojiReactionsWindow { ContainerView containerView; WindowManager windowManager; - FrameLayout windowView; + public FrameLayout windowView; + boolean attachToParent; float fromRadius; RectF fromRect = new RectF(); @@ -143,12 +148,18 @@ protected void onDetachedFromWindow() { super.onDetachedFromWindow(); Bulletin.removeDelegate(this); } + + @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + } }; windowView.setOnClickListener(v -> { if (enterTransitionFinished) { dismiss(); } }); + attachToParent = type == TYPE_STORY_LIKES; // sizeNotifierFrameLayout.setFitsSystemWindows(true); @@ -167,7 +178,9 @@ public boolean prevWindowKeyboardVisible() { protected void onInputFocus() { if (!wasFocused) { wasFocused = true; - windowManager.updateViewLayout(windowView, createLayoutParams(true)); + if (!attachToParent) { + windowManager.updateViewLayout(windowView, createLayoutParams(true)); + } if (baseFragment instanceof ChatActivity) { ((ChatActivity) baseFragment).needEnterText(); } @@ -251,10 +264,14 @@ public void onRecentCleared() { reactionsContainerLayout.getDelegate().drawRoundRect(canvas, AndroidUtilities.rectTmp, 0, containerView.getX() + x, containerView.getY() - AndroidUtilities.statusBarHeight + y); }); } - WindowManager.LayoutParams lp = createLayoutParams(false); - - windowManager = AndroidUtilities.findActivity(context).getWindowManager(); - windowManager.addView(windowView, lp); + if (attachToParent) { + ViewGroup group = (ViewGroup) reactionsContainerLayout.getParent(); + group.addView(windowView); + } else { + WindowManager.LayoutParams lp = createLayoutParams(false); + windowManager = AndroidUtilities.findActivity(context).getWindowManager(); + windowManager.addView(windowView, lp); + } this.reactionsContainerLayout = reactionsContainerLayout; reactionsContainerLayout.setOnSwitchedToLoopView(() -> containerView.invalidate()); //fixed emoji freeze @@ -274,7 +291,7 @@ private void updateWindowPosition() { } float y = yTranslation; int bottomOffset = AndroidUtilities.dp(32); - if (type == TYPE_STORY) { + if (type == TYPE_STORY || type == TYPE_STORY_LIKES) { bottomOffset = AndroidUtilities.dp(24); } if (y + containerView.getMeasuredHeight() > windowView.getMeasuredHeight() - keyboardHeight - bottomOffset) { @@ -335,6 +352,8 @@ private void createTransition(boolean enter) { if (type == TYPE_STORY) { containerView.setTranslationX((windowView.getMeasuredWidth() - containerView.getMeasuredWidth()) / 2f - AndroidUtilities.dp(16)); + } else if (type == TYPE_STORY_LIKES) { + containerView.setTranslationX(location[0] - windowLocation[0] - AndroidUtilities.dp(18)); } else { containerView.setTranslationX(location[0] - windowLocation[0] - AndroidUtilities.dp(2)); } @@ -587,10 +606,14 @@ public void removeView() { if (windowView.getParent() == null) { return; } - try { - windowManager.removeView(windowView); - } catch (Exception e) { + if (attachToParent) { + AndroidUtilities.removeFromParent(windowView); + } else { + try { + windowManager.removeView(windowView); + } catch (Exception e) { + } } if (onDismiss != null) { onDismiss.run(); @@ -682,7 +705,11 @@ public ContainerView(@NonNull Context context) { shadow = ContextCompat.getDrawable(context, R.drawable.reactions_bubble_shadow).mutate(); shadowPad.left = shadowPad.top = shadowPad.right = shadowPad.bottom = AndroidUtilities.dp(7); shadow.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_messagePanelShadow, resourcesProvider), PorterDuff.Mode.MULTIPLY)); - backgroundPaint.setColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground, resourcesProvider)); + if (type == TYPE_STORY_LIKES) { + backgroundPaint.setColor(ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.13f)); + } else { + backgroundPaint.setColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground, resourcesProvider)); + } } @Override @@ -696,7 +723,7 @@ public void invalidate() { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int size; - if (type == TYPE_STORY) { + if (type == TYPE_STORY || type == TYPE_STORY_LIKES) { size = reactionsContainerLayout.getMeasuredWidth(); } else { size = Math.min(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)); @@ -860,6 +887,7 @@ protected void dispatchDraw(Canvas canvas) { holderView.drawSelected = false; if (fromRoundRadiusLb != 0 || toRoundRadiusLb != 0) { ImageReceiver imageReceiver = holderView.loopImageView.getImageReceiver(); + holderView.checkPlayLoopImage(); if (holderView.loopImageView.animatedEmojiDrawable != null && holderView.loopImageView.animatedEmojiDrawable.getImageReceiver() != null) { imageReceiver = holderView.loopImageView.animatedEmojiDrawable.getImageReceiver(); } @@ -890,6 +918,7 @@ protected void dispatchDraw(Canvas canvas) { holderView.enterImageView.draw(canvas); holderView.enterImageView.getImageReceiver().setAlpha(oldAlpha); } else { + holderView.checkPlayLoopImage(); ImageReceiver imageReceiver = holderView.loopImageView.getImageReceiver(); if (holderView.loopImageView.animatedEmojiDrawable != null && holderView.loopImageView.animatedEmojiDrawable.getImageReceiver() != null) { imageReceiver = holderView.loopImageView.animatedEmojiDrawable.getImageReceiver(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java index 6345b698a2f..406dfebd112 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java @@ -19,6 +19,7 @@ import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.provider.Settings; +import android.util.Log; import android.util.Property; import android.view.Gravity; import android.view.HapticFeedbackConstants; @@ -92,6 +93,7 @@ public void set(ReactionsContainerLayout object, Float value) { public final static int TYPE_DEFAULT = 0; public final static int TYPE_STORY = 1; + public static final int TYPE_STORY_LIKES = 2; private final static int ALPHA_DURATION = 150; private final static float SIDE_SCALE = 0.6f; @@ -336,7 +338,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int customEmojiReactionsIconView = new InternalImageView(context); customEmojiReactionsIconView.setImageResource(R.drawable.msg_reactions_expand); customEmojiReactionsIconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - if (type == TYPE_STORY) { + if (type == TYPE_STORY || type == TYPE_STORY_LIKES) { customEmojiReactionsIconView.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY)); } else { customEmojiReactionsIconView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogBackground), PorterDuff.Mode.MULTIPLY)); @@ -492,7 +494,11 @@ public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull R nextRecentReaction.getLayoutParams().width = size - AndroidUtilities.dp(12); nextRecentReaction.getLayoutParams().height = size; - bgPaint.setColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground, resourcesProvider)); + if (type == TYPE_STORY_LIKES) { + bgPaint.setColor(ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.13f)); + } else { + bgPaint.setColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground, resourcesProvider)); + } MediaDataController.getInstance(currentAccount).preloadDefaultReactions(); } @@ -795,7 +801,7 @@ protected void dispatchDraw(Canvas canvas) { nextRecentReaction.setScaleX(scale); nextRecentReaction.setScaleY(scale); float additionalOffset = 0; - if (type != TYPE_STORY) { + if (type != TYPE_STORY && type != TYPE_STORY_LIKES) { additionalOffset = - AndroidUtilities.dp(20); } else { additionalOffset = - AndroidUtilities.dp(8); @@ -859,11 +865,12 @@ private void drawBubbles(Canvas canvas, float br, float cPr, float sr, int alpha if (type == TYPE_STORY) { return; } + float bigCy; canvas.save(); canvas.clipRect(0, AndroidUtilities.lerp(rect.bottom, 0, CubicBezierInterpolator.DEFAULT.getInterpolation(flipVerticalProgress)) - (int) Math.ceil(rect.height() / 2f * (1f - transitionProgress)), getMeasuredWidth(), AndroidUtilities.lerp(getMeasuredHeight() + AndroidUtilities.dp(8), getPaddingTop() - expandSize(), CubicBezierInterpolator.DEFAULT.getInterpolation(flipVerticalProgress))); float cx = LocaleController.isRTL || mirrorX ? bigCircleOffset : getWidth() - bigCircleOffset; float cy = getHeight() - getPaddingBottom() + expandSize(); - cy = AndroidUtilities.lerp(cy, getPaddingTop() - expandSize(), CubicBezierInterpolator.DEFAULT.getInterpolation(flipVerticalProgress)); + bigCy = cy = AndroidUtilities.lerp(cy, getPaddingTop() - expandSize(), CubicBezierInterpolator.DEFAULT.getInterpolation(flipVerticalProgress)); int sPad = AndroidUtilities.dp(3); shadow.setAlpha(alpha); bgPaint.setAlpha(alpha); @@ -1058,6 +1065,14 @@ public void setMessage(MessageObject message, TLRPC.ChatFull chatFull) { } } + public void setStoryItem(TLRPC.StoryItem storyItem) { + selectedReactions.clear(); + if (storyItem != null && storyItem.sent_reaction != null) { + selectedReactions.add(ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(storyItem.sent_reaction)); + } + listAdapter.notifyDataSetChanged(); + } + private void filterReactions(List visibleReactions) { HashSet set = new HashSet<>(); for (int i = 0; i < visibleReactions.size(); i++) { @@ -1275,8 +1290,10 @@ public void setFragment(BaseFragment lastFragment) { } public void reset() { + isHiddenNextReaction = true; pressedReactionPosition = 0; pressedProgress = 0; + pullingLeftOffset = 0; pressedReaction = null; clicked = false; AndroidUtilities.forEachViews(recyclerListView, view -> { @@ -1284,12 +1301,20 @@ public void reset() { ReactionHolderView reactionHolderView = (ReactionHolderView) view; reactionHolderView.pressed = false; reactionHolderView.loopImageView.setAlpha(1f); - reactionHolderView.loopImageView.setScaleX(1f); - reactionHolderView.loopImageView.setScaleY(1f); + if (skipEnterAnimation) { + reactionHolderView.loopImageView.setScaleX(1f); + reactionHolderView.loopImageView.setScaleY(1f); + } else { + reactionHolderView.resetAnimation(); + } } }); + lastVisibleViews.clear(); recyclerListView.invalidate(); + if (customReactionsContainer != null) { + customReactionsContainer.invalidate(); + } invalidate(); } @@ -1448,18 +1473,8 @@ public void invalidate(int l, int t, int r, int b) { @Override protected void onDraw(Canvas canvas) { - ImageReceiver imageReceiver = animatedEmojiDrawable != null ? animatedEmojiDrawable.getImageReceiver() : this.imageReceiver; - if (imageReceiver != null && imageReceiver.getLottieAnimation() != null) { - if (reactionsWindow != null || pressed) { - imageReceiver.getLottieAnimation().start(); - } else { - if (imageReceiver.getLottieAnimation().getCurrentFrame() <= 2) { - imageReceiver.getLottieAnimation().stop(); - } - } - } + checkPlayLoopImage(); super.onDraw(canvas); - } @Override @@ -1530,10 +1545,11 @@ public void invalidate() { private void setReaction(ReactionsLayoutInBubble.VisibleReaction react, int position) { if (currentReaction != null && currentReaction.equals(react)) { + this.position = position; + selected = selectedReactions.contains(react); updateImage(react); return; } - this.position = position; resetAnimation(); currentReaction = react; selected = selectedReactions.contains(react); @@ -1556,7 +1572,7 @@ private void setReaction(ReactionsLayoutInBubble.VisibleReaction react, int posi loopImageView.setAnimatedEmojiDrawable(loopDrawable); } setFocusable(true); - shouldSwitchToLoopView = hasEnterAnimation && !allReactionsIsDefault; + shouldSwitchToLoopView = hasEnterAnimation;// && !allReactionsIsDefault; if (!hasEnterAnimation) { enterImageView.setVisibility(View.GONE); loopImageView.setVisibility(View.VISIBLE); @@ -1754,6 +1770,19 @@ protected void dispatchDraw(Canvas canvas) { } super.dispatchDraw(canvas); } + + public void checkPlayLoopImage() { + ImageReceiver imageReceiver = loopImageView.animatedEmojiDrawable != null ? loopImageView.animatedEmojiDrawable.getImageReceiver() : loopImageView.imageReceiver; + if (imageReceiver != null && imageReceiver.getLottieAnimation() != null) { + if (reactionsWindow != null || pressed) { + imageReceiver.getLottieAnimation().start(); + } else { + if (imageReceiver.getLottieAnimation().getCurrentFrame() <= 2) { + imageReceiver.getLottieAnimation().stop(); + } + } + } + } } private void cancelPressed() { @@ -1788,7 +1817,9 @@ public void onAnimationEnd(Animator animation) { public interface ReactionsContainerDelegate { void onReactionClicked(View view, ReactionsLayoutInBubble.VisibleReaction visibleReaction, boolean longpress, boolean addToRecent); - void hideMenu(); + default void hideMenu() { + + } default void drawRoundRect(Canvas canvas, RectF rect, float radius, float offsetX, float offsetY) { @@ -1913,7 +1944,7 @@ public CustomReactionsContainer(Context context) { @Override protected void dispatchDraw(Canvas canvas) { int color; - if (type == TYPE_STORY) { + if (type == TYPE_STORY || type == TYPE_STORY_LIKES) { color = ColorUtils.setAlphaComponent(Color.WHITE, 30); } else { color = ColorUtils.blendARGB(Theme.getColor(Theme.key_actionBarDefaultSubmenuItemIcon, resourcesProvider), Theme.getColor(Theme.key_dialogBackground, resourcesProvider), 0.7f); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReplaceableIconDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReplaceableIconDrawable.java index 3601c851017..f6199deca44 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReplaceableIconDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReplaceableIconDrawable.java @@ -30,6 +30,7 @@ public class ReplaceableIconDrawable extends Drawable implements Animator.Animat private ValueAnimator animation; private float progress = 1f; ArrayList parentViews = new ArrayList<>(); + public boolean exactlyBounds; public ReplaceableIconDrawable(Context context) { this.context = context; @@ -99,7 +100,13 @@ protected void onBoundsChange(Rect bounds) { } private void updateBounds(Drawable d, Rect bounds) { - if (d == null) return; + if (d == null) { + return; + } + if (exactlyBounds) { + d.setBounds(bounds); + return; + } int left; int right; int bottom; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchField.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchField.java index 91ab540a9c3..ce9ecf2d9f9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchField.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchField.java @@ -32,6 +32,9 @@ public class SearchField extends FrameLayout { private final Theme.ResourcesProvider resourcesProvider; public SearchField(Context context, boolean supportRtl, Theme.ResourcesProvider resourcesProvider) { + this(context, supportRtl, 14, resourcesProvider); + } + public SearchField(Context context, boolean supportRtl, float horizontalMargin, Theme.ResourcesProvider resourcesProvider) { super(context); this.resourcesProvider = resourcesProvider; @@ -40,9 +43,9 @@ public SearchField(Context context, boolean supportRtl, Theme.ResourcesProvider searchBackground = new View(context); searchBackground.setBackgroundDrawable(Theme.createRoundRectDrawable(AndroidUtilities.dp(18), getThemedColor(Theme.key_dialogSearchBackground))); if (supportRtl) { - lp = LayoutHelper.createFrameRelatively(LayoutHelper.MATCH_PARENT, 36, Gravity.START | Gravity.TOP, 14, 11, 14, 0); + lp = LayoutHelper.createFrameRelatively(LayoutHelper.MATCH_PARENT, 36, Gravity.START | Gravity.TOP, horizontalMargin, 11, horizontalMargin, 0); } else { - lp = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.LEFT | Gravity.TOP, 14, 11, 14, 0); + lp = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.LEFT | Gravity.TOP, horizontalMargin, 11, horizontalMargin, 0); } addView(searchBackground, lp); @@ -51,9 +54,9 @@ public SearchField(Context context, boolean supportRtl, Theme.ResourcesProvider searchIconImageView.setImageResource(R.drawable.smiles_inputsearch); searchIconImageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_dialogSearchIcon), PorterDuff.Mode.MULTIPLY)); if (supportRtl) { - lp = LayoutHelper.createFrameRelatively(36, 36, Gravity.START | Gravity.TOP, 16, 11, 0, 0); + lp = LayoutHelper.createFrameRelatively(36, 36, Gravity.START | Gravity.TOP, horizontalMargin + 2, 11, 0, 0); } else { - lp = LayoutHelper.createFrame(36, 36, Gravity.LEFT | Gravity.TOP, 16, 11, 0, 0); + lp = LayoutHelper.createFrame(36, 36, Gravity.LEFT | Gravity.TOP, horizontalMargin + 2, 11, 0, 0); } addView(searchIconImageView, lp); @@ -70,9 +73,9 @@ protected int getCurrentColor() { clearSearchImageView.setScaleY(0.1f); clearSearchImageView.setAlpha(0.0f); if (supportRtl) { - lp = LayoutHelper.createFrameRelatively(36, 36, Gravity.END | Gravity.TOP, 14, 11, 14, 0); + lp = LayoutHelper.createFrameRelatively(36, 36, Gravity.END | Gravity.TOP, horizontalMargin, 11, horizontalMargin, 0); } else { - lp = LayoutHelper.createFrame(36, 36, Gravity.RIGHT | Gravity.TOP, 14, 11, 14, 0); + lp = LayoutHelper.createFrame(36, 36, Gravity.RIGHT | Gravity.TOP, horizontalMargin, 11, horizontalMargin, 0); } addView(clearSearchImageView, lp); clearSearchImageView.setOnClickListener(v -> { @@ -112,9 +115,9 @@ public boolean onTouchEvent(MotionEvent event) { searchEditText.setCursorSize(AndroidUtilities.dp(20)); searchEditText.setCursorWidth(1.5f); if (supportRtl) { - lp = LayoutHelper.createFrameRelatively(LayoutHelper.MATCH_PARENT, 40, Gravity.START | Gravity.TOP, 16 + 38, 9, 16 + 30, 0); + lp = LayoutHelper.createFrameRelatively(LayoutHelper.MATCH_PARENT, 40, Gravity.START | Gravity.TOP, horizontalMargin + 2 + 38, 9, horizontalMargin + 2 + 30, 0); } else { - lp = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 40, Gravity.LEFT | Gravity.TOP, 16 + 38, 9, 16 + 30, 0); + lp = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 40, Gravity.LEFT | Gravity.TOP, horizontalMargin + 2 + 38, 9, horizontalMargin + 2 + 30, 0); } addView(searchEditText, lp); searchEditText.addTextChangedListener(new TextWatcher() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java index b6f0d6e23a8..a3a4259ca1b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java @@ -59,6 +59,8 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.google.android.exoplayer2.util.Log; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AnimationNotificationsLocker; import org.telegram.messenger.ApplicationLoader; @@ -4792,7 +4794,7 @@ private void updateTabs(boolean animated) { animated = false; } int changed = 0; - if ((DialogObject.isUserDialog(dialog_id) && !DialogObject.isEncryptedDialog(dialog_id) && (userInfo != null && userInfo.stories_pinned_available || isStoriesView())) != scrollSlidingTextTabStrip.hasTab(TAB_STORIES)) { + if ((DialogObject.isUserDialog(dialog_id) && !DialogObject.isEncryptedDialog(dialog_id) && (userInfo != null && userInfo.stories_pinned_available || isStoriesView()) && includeStories()) != scrollSlidingTextTabStrip.hasTab(TAB_STORIES)) { changed++; } if (!isStoriesView()) { @@ -5385,7 +5387,11 @@ private void onItemClick(int index, View view, MessageObject message, int a, int } } else if (selectedMode == TAB_STORIES || selectedMode == TAB_ARCHIVED_STORIES) { StoriesController.StoriesList storiesList = (selectedMode == TAB_STORIES ? storiesAdapter : archivedStoriesAdapter).storiesList; - profileActivity.getOrCreateStoryViewer().open(getContext(), message.getId(), storiesList, StoriesListPlaceProvider.of(mediaPages[a].listView)); + profileActivity.getOrCreateStoryViewer().open(getContext(), message.getId(), storiesList, StoriesListPlaceProvider.of(mediaPages[a].listView).with(forward -> { + if (forward) { + storiesList.load(false, 30); + } + })); } } updateForwardItem(); @@ -6795,7 +6801,7 @@ private StoriesAdapter(Context context, boolean isArchive, StoriesController.Sto } private void checkColumns() { - if ((!storiesColumnsCountSet || allowStoriesSingleColumn && storiesList.getCount() > 1) && storiesList.getCount() > 0 && !isStoriesView()) { + if (!isArchive && (!storiesColumnsCountSet || allowStoriesSingleColumn && storiesList.getCount() > 1) && storiesList.getCount() > 0 && !isStoriesView()) { if (storiesList.getCount() < 5) { mediaColumnsCount[1] = storiesList.getCount(); if (mediaPages != null && mediaPages[0] != null && mediaPages[1] != null && mediaPages[0].listView != null && mediaPages[1].listView != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerEmptyView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerEmptyView.java index 49b113f0ac1..e4a3553d9ff 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerEmptyView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerEmptyView.java @@ -1,28 +1,36 @@ package org.telegram.ui.Components; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.content.Context; +import android.text.TextUtils; import android.util.Log; import android.util.TypedValue; import android.view.Gravity; +import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.DocumentObject; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.LiteMode; +import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; import org.telegram.messenger.SvgHelper; import org.telegram.messenger.UserConfig; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.LaunchActivity; public class StickerEmptyView extends FrameLayout implements NotificationCenter.NotificationCenterDelegate { @@ -36,7 +44,7 @@ public class StickerEmptyView extends FrameLayout implements NotificationCenter. public BackupImageView stickerView; private RadialProgressView progressBar; public final TextView title; - public final TextView subtitle; + public final LinkSpanDrawable.LinksTextView subtitle; private boolean progressShowing; private final Theme.ResourcesProvider resourcesProvider; @@ -103,9 +111,10 @@ public void setVisibility(int visibility) { title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); title.setGravity(Gravity.CENTER); - subtitle = new TextView(context); + subtitle = new LinkSpanDrawable.LinksTextView(context); subtitle.setTag(Theme.key_windowBackgroundWhiteGrayText); subtitle.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText)); + subtitle.setLinkTextColor(getThemedColor(Theme.key_windowBackgroundWhiteLinkText)); subtitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); subtitle.setGravity(Gravity.CENTER); @@ -123,6 +132,37 @@ public void setVisibility(int visibility) { } } + public void createButtonLayout(CharSequence sting, Runnable action) { + ((LinearLayout.LayoutParams) subtitle.getLayoutParams()).topMargin = AndroidUtilities.dp(12); + TextView buttonTextView = new TextView(getContext()); + buttonTextView.setText(sting); + buttonTextView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText, resourcesProvider)); + buttonTextView.setPadding(AndroidUtilities.dp(45), AndroidUtilities.dp(12), AndroidUtilities.dp(45), AndroidUtilities.dp(12)); + buttonTextView.setGravity(Gravity.CENTER); + buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + + FrameLayout buttonLayout = new FrameLayout(getContext()) { + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + getParent().requestDisallowInterceptTouchEvent(true); + return true; + } + }; + buttonLayout.setOnClickListener(v -> { + AndroidUtilities.runOnUIThread(action, 100); + }); + buttonLayout.setBackground( + Theme.createSimpleSelectorRoundRectDrawable(dp(8), + Theme.getColor(Theme.key_featuredStickers_addButton, resourcesProvider), + ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_featuredStickers_buttonText, resourcesProvider), 30)) + ); + ScaleStateListAnimator.apply(buttonLayout, 0.05f, 1.5f); + buttonLayout.addView(buttonTextView); + linearLayout.setClipChildren(false); + linearLayout.addView(buttonLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 28, 0, 4)); + } + private int lastH; @Override @@ -382,4 +422,37 @@ public void setStickerType(int stickerType) { setSticker(); } } + + public void setSubtitle(CharSequence text) { + int whitespaceCount = getWhitespaceCount(text); + if (whitespaceCount > 4 && text.length() > 20) { + int closestToCenterWhitespace = -1; + int closestValue = 0; + int centerIndex = text.length() >> 1; + for (int i = 0; i < text.length(); i++) { + if (Character.isWhitespace(text.charAt(i))) { + int value = Math.abs(centerIndex - i); + if (closestToCenterWhitespace == -1 || value < closestValue) { + closestValue = value; + closestToCenterWhitespace = i; + } + } + } + if (closestToCenterWhitespace > 0) { + text = text.subSequence(0, closestToCenterWhitespace) + "\n" + text.subSequence(closestToCenterWhitespace + 1, text.length()); + } + } + subtitle.setText(text); + } + + private int getWhitespaceCount(CharSequence text) { + int count = 0; + for (int i = 0; i < text.length(); i++) { + if (Character.isWhitespace(text.charAt(i))) { + count++; + } + } + return count; + } + } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TextViewSwitcher.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TextViewSwitcher.java index 5f353705747..1099aa2c98b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TextViewSwitcher.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TextViewSwitcher.java @@ -18,14 +18,20 @@ public void setText(CharSequence text) { } public void setText(CharSequence text, boolean animated) { - if (!TextUtils.equals(text, getCurrentView().getText())) { + setText(text, animated, false); + } + + public boolean setText(CharSequence text, boolean animated, boolean forceUpdate) { + if (forceUpdate || !TextUtils.equals(text, getCurrentView().getText())) { if (animated) { getNextView().setText(text); showNext(); + return true; } else { getCurrentView().setText(text); } } + return false; } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ViewPagerFixed.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ViewPagerFixed.java index 56bf41362f1..24cdb5ced0f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ViewPagerFixed.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ViewPagerFixed.java @@ -56,7 +56,7 @@ public class ViewPagerFixed extends FrameLayout { private Theme.ResourcesProvider resourcesProvider; - int currentPosition; + public int currentPosition; int nextPosition; protected View[] viewPages; private int[] viewTypes; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/WallpaperUpdater.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/WallpaperUpdater.java index 4d4881a84db..835bfb47c22 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/WallpaperUpdater.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/WallpaperUpdater.java @@ -110,10 +110,18 @@ public void showAlert(final boolean fromTheme) { public void openGallery() { if (parentFragment != null) { - if (Build.VERSION.SDK_INT >= 23 && parentFragment.getParentActivity() != null) { - if (parentFragment.getParentActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - parentFragment.getParentActivity().requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE); - return; + final Activity activity = parentFragment.getParentActivity(); + if (activity != null) { + if (Build.VERSION.SDK_INT >= 33) { + if (activity.checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) { + activity.requestPermissions(new String[]{Manifest.permission.READ_MEDIA_IMAGES}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE); + return; + } + } else if (Build.VERSION.SDK_INT >= 23) { + if (activity.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + activity.requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, BasePermissionsActivity.REQUEST_CODE_EXTERNAL_STORAGE); + return; + } } } PhotoAlbumPickerActivity fragment = new PhotoAlbumPickerActivity(PhotoAlbumPickerActivity.SELECT_TYPE_WALLPAPER, false, false, null); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilersClickDetector.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilersClickDetector.java index 9d9919bf454..0cc802b0492 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilersClickDetector.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilersClickDetector.java @@ -12,6 +12,8 @@ public class SpoilersClickDetector { private GestureDetectorCompat gestureDetector; private boolean trackingTap; + private int horizontalPadding; + private int verticalPadding; public SpoilersClickDetector(View v, List spoilers, OnSpoilerClickedListener clickedListener) { this(v, spoilers, true, clickedListener); @@ -27,6 +29,8 @@ public boolean onDown(MotionEvent e) { x -= v.getPaddingLeft(); y -= v.getPaddingTop(); } + x -= horizontalPadding; + y -= verticalPadding; for (SpoilerEffect eff : spoilers) { if (eff.getBounds().contains(x, y)) { trackingTap = true; @@ -48,6 +52,8 @@ public boolean onSingleTapUp(MotionEvent e) { x -= v.getPaddingLeft(); y -= v.getPaddingTop(); } + x -= horizontalPadding; + y -= verticalPadding; for (SpoilerEffect eff : spoilers) { if (eff.getBounds().contains(x, y)) { clickedListener.onSpoilerClicked(eff, x, y); @@ -64,6 +70,11 @@ public boolean onTouchEvent(MotionEvent ev) { return gestureDetector.onTouchEvent(ev); } + public void setAdditionalOffsets(int horizontalPadding, int verticalPadding) { + this.horizontalPadding = horizontalPadding; + this.verticalPadding = verticalPadding; + } + public interface OnSpoilerClickedListener { void onSpoilerClicked(SpoilerEffect spoiler, float x, float y); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContentPreviewViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/ContentPreviewViewer.java index db22d390c54..2a8dce96827 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContentPreviewViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContentPreviewViewer.java @@ -139,6 +139,10 @@ default boolean needRemoveFromRecent(TLRPC.Document document) { return false; } default void removeFromRecent(TLRPC.Document document) {} + + default boolean isPhotoEditor() { + return false; + } } public final static int CONTENT_TYPE_NONE = -1; @@ -162,6 +166,7 @@ default void removeFromRecent(TLRPC.Document document) {} ActionBarPopupWindow popupWindow; private ActionBarPopupWindow visibleMenu; private ContentPreviewViewerDelegate delegate; + private boolean isPhotoEditor; private boolean isRecentSticker; @@ -193,7 +198,7 @@ default void removeFromRecent(TLRPC.Document document) {} private Runnable showSheetRunnable = new Runnable() { @Override public void run() { - if (parentActivity == null) { + if (parentActivity == null || isPhotoEditor) { return; } closeOnDismiss = true; @@ -704,6 +709,9 @@ public void reset() { public boolean onTouch(MotionEvent event, final RecyclerListView listView, final int height, final Object listener, ContentPreviewViewerDelegate contentPreviewViewerDelegate, Theme.ResourcesProvider resourcesProvider) { delegate = contentPreviewViewerDelegate; + if (delegate != null) { + isPhotoEditor = delegate.isPhotoEditor(); + } if (delegate != null && !delegate.can()) { return false; } @@ -733,7 +741,7 @@ public boolean onTouch(MotionEvent event, final RecyclerListView listView, final } else if (event.getAction() != MotionEvent.ACTION_DOWN) { if (isVisible) { if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (currentContentType == CONTENT_TYPE_GIF) { + if (currentContentType == CONTENT_TYPE_GIF && !isPhotoEditor) { if (!menuVisible && showProgress == 1.0f) { if (lastTouchY == -10000) { lastTouchY = event.getY(); @@ -833,7 +841,7 @@ public boolean onTouch(MotionEvent event, final RecyclerListView listView, final } else if (currentPreviewCell instanceof ContextLinkCell) { ContextLinkCell contextLinkCell = (ContextLinkCell) currentPreviewCell; open(contextLinkCell.getDocument(), null, null, delegate != null ? delegate.getQuery(true) : null, contextLinkCell.getBotInlineResult(), contentType, false, contextLinkCell.getBotInlineResult() != null ? contextLinkCell.getInlineBot() : contextLinkCell.getParentObject(), resourcesProvider); - if (contentType != CONTENT_TYPE_GIF) { + if (contentType != CONTENT_TYPE_GIF || isPhotoEditor) { contextLinkCell.setScaled(true); } } else if (currentPreviewCell instanceof EmojiPacksAlert.EmojiImageView) { @@ -907,6 +915,9 @@ protected void runSmoothHaptic() { public boolean onInterceptTouchEvent(MotionEvent event, final RecyclerListView listView, final int height, ContentPreviewViewerDelegate contentPreviewViewerDelegate, Theme.ResourcesProvider resourcesProvider) { delegate = contentPreviewViewerDelegate; + if (delegate != null) { + isPhotoEditor = delegate.isPhotoEditor(); + } if (delegate != null && !delegate.can()) { return false; } @@ -998,7 +1009,7 @@ public boolean onInterceptTouchEvent(MotionEvent event, final RecyclerListView l ContextLinkCell contextLinkCell = (ContextLinkCell) currentPreviewCell; open(contextLinkCell.getDocument(), null, null, delegate != null ? delegate.getQuery(true) : null, contextLinkCell.getBotInlineResult(), contentTypeFinal, false, contextLinkCell.getBotInlineResult() != null ? contextLinkCell.getInlineBot() : contextLinkCell.getParentObject(), resourcesProvider); opened = true; - if (contentTypeFinal != CONTENT_TYPE_GIF) { + if (contentTypeFinal != CONTENT_TYPE_GIF || isPhotoEditor) { contextLinkCell.setScaled(true); } } else if (currentPreviewCell instanceof EmojiPacksAlert.EmojiImageView) { @@ -1050,6 +1061,9 @@ public boolean onInterceptTouchEvent(MotionEvent event, final RecyclerListView l public void setDelegate(ContentPreviewViewerDelegate contentPreviewViewerDelegate) { delegate = contentPreviewViewerDelegate; + if (delegate != null) { + isPhotoEditor = delegate.isPhotoEditor(); + } } public void setParentActivity(Activity activity) { @@ -1431,7 +1445,7 @@ private void onDraw(Canvas canvas) { centerImage.draw(canvas); } - if (currentContentType == CONTENT_TYPE_GIF && slideUpDrawable != null) { + if (currentContentType == CONTENT_TYPE_GIF && !isPhotoEditor && slideUpDrawable != null) { int w = slideUpDrawable.getIntrinsicWidth(); int h = slideUpDrawable.getIntrinsicHeight(); int y = (int) (centerImage.getDrawRegion().top - AndroidUtilities.dp(17 + 6 * (currentMoveY / (float) AndroidUtilities.dp(60)))); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index 63ca8d76cf2..53669f0bbc2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -208,6 +208,7 @@ import org.telegram.ui.Stories.DialogStoriesCell; import org.telegram.ui.Stories.StoriesController; import org.telegram.ui.Stories.StoriesListPlaceProvider; +import org.telegram.ui.Stories.StoriesUtilities; import org.telegram.ui.Stories.UserListPoller; import org.telegram.ui.Stories.recorder.HintView2; import org.telegram.ui.Stories.recorder.StoryRecorder; @@ -247,6 +248,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. private boolean fixScrollYAfterArchiveOpened; private Bulletin storiesBulletin; private float storiesOverscroll; + private boolean storiesOverscrollCalled; private boolean wasDrawn; public MessagesStorage.TopicKey getOpenedDialogId() { @@ -349,7 +351,6 @@ public void updateList(boolean animated) { private ActionBarMenuItem doneItem; private ProxyDrawable proxyDrawable; private HintView2 storyHint; - private HintView2 manyStoriesHint; private RLottieImageView floatingButton; private FrameLayout floatingButtonContainer; private RLottieImageView floatingButton2; @@ -439,6 +440,7 @@ public void updateList(boolean animated) { private FragmentContextView fragmentLocationContextView; private FragmentContextView fragmentContextView; private DialogsHintCell dialogsHintCell; + private boolean dialogsHintCellVisible; private Long cacheSize, deviceSize; private ArrayList frozenDialogsList; @@ -1541,11 +1543,11 @@ private void updateStoriesViewAlpha(float alpha) { float pHalf = Utilities.clamp(p / 0.5f, 1f, 0f); dialogStoriesCell.setClipTop(0); if (!hasStories && animateToHasStories) { - dialogStoriesCell.setTranslationY(-AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP)); + dialogStoriesCell.setTranslationY(-AndroidUtilities.dp(DialogStoriesCell.HEIGHT_IN_DP) - AndroidUtilities.dp(8)); dialogStoriesCell.setProgressToCollapse(1f); containersAlpha = 1f - progressToDialogStoriesCell; } else { - dialogStoriesCell.setTranslationY(scrollYOffset + storiesYOffset + storiesOverscroll / 2f); + dialogStoriesCell.setTranslationY(scrollYOffset + storiesYOffset + storiesOverscroll / 2f - AndroidUtilities.dp(8)); dialogStoriesCell.setProgressToCollapse(p, !rightSlidingDialogContainer.hasFragment()); if (!animateToHasStories) { containersAlpha = 1f - progressToDialogStoriesCell; @@ -4370,20 +4372,10 @@ public void getOutline(View view, Outline outline) { storyHint.hide(); } - final int limit = getUserConfig().isPremium() ? - getMessagesController().storyExpiringLimitPremium : - getMessagesController().storyExpiringLimitDefault; - if (getMessagesController().getStoriesController().getMyStoriesCount() >= limit) { - CharSequence text = AndroidUtilities.replaceTags(LocaleController.formatPluralString("StoriesTooMuch", limit)); - manyStoriesHint.setMaxWidthPx(HintView2.cutInFancyHalf(text, manyStoriesHint.getTextPaint())); - manyStoriesHint.setText(text); - if (manyStoriesHint.shown()) { - BotWebViewVibrationEffect.APP_ERROR.vibrate(); - } - manyStoriesHint.show(); + final StoriesController.StoryLimit storyLimit = MessagesController.getInstance(currentAccount).getStoriesController().checkStoryLimit(); + if (storyLimit != null) { + showDialog(new LimitReachedBottomSheet(this, getContext(), storyLimit.getLimitReachedType(), currentAccount)); return; - } else if (manyStoriesHint != null) { - manyStoriesHint.show(); } StoryRecorder.getInstance(getParentActivity(), currentAccount) @@ -4433,15 +4425,6 @@ public StoryRecorder.SourceView getView() { contentView.addView(storyHint, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 160, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0, 80, 0)); showStoryHint = true; } - manyStoriesHint = new HintView2(context, HintView2.DIRECTION_RIGHT) - .setRounding(8) - .setDuration(5000) - .setCloseButton(false) - .setMultilineText(true) - .setJoint(1, -40) - .setBgColor(getThemedColor(Theme.key_undo_background)); - manyStoriesHint.setPadding(0, 0, AndroidUtilities.dp(24), 0); - contentView.addView(manyStoriesHint, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 200, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0, 56, 0)); } floatingButton = new RLottieImageView(context); @@ -4798,7 +4781,7 @@ public void onUserLongPressed(View view, long dialogId) { } filterOptions.add(R.drawable.msg_stories_add, LocaleController.getString("AddStory", R.string.AddStory), Theme.key_actionBarDefaultSubmenuItemIcon, Theme.key_actionBarDefaultSubmenuItem, () -> { dialogStoriesCell.openStoryRecorder(); - }, null); + }); filterOptions.add(R.drawable.msg_stories_archive, LocaleController.getString("ArchivedStories", R.string.ArchivedStories), Theme.key_actionBarDefaultSubmenuItemIcon, Theme.key_actionBarDefaultSubmenuItem, () -> { Bundle args = new Bundle(); args.putLong("dialog_id", UserConfig.getInstance(currentAccount).getClientUserId()); @@ -4806,64 +4789,65 @@ public void onUserLongPressed(View view, long dialogId) { args.putInt("start_from", SharedMediaLayout.TAB_ARCHIVED_STORIES); MediaActivity mediaActivity = new MediaActivity(args, null); presentFragment(mediaActivity); - }, null); + }); filterOptions.add(R.drawable.msg_stories_saved, LocaleController.getString("SavedStories", R.string.SavedStories), Theme.key_actionBarDefaultSubmenuItemIcon, Theme.key_actionBarDefaultSubmenuItem, () -> { Bundle args = new Bundle(); args.putLong("dialog_id", UserConfig.getInstance(currentAccount).getClientUserId()); args.putInt("type", MediaActivity.TYPE_STORIES); presentFragment(new MediaActivity(args, null)); - }, null); + }); } else { final String key = NotificationsController.getSharedPrefKey(dialogId, 0); boolean muted = !NotificationsCustomSettingsActivity.areStoriesNotMuted(currentAccount, dialogId); filterOptions - .add(R.drawable.msg_discussion, LocaleController.getString("SendMessage", R.string.SendMessage), () -> { - presentFragment(ChatActivity.of(dialogId)); - }) - .add(R.drawable.msg_openprofile, LocaleController.getString("OpenProfile", R.string.OpenProfile), Theme.key_actionBarDefaultSubmenuItemIcon, Theme.key_actionBarDefaultSubmenuItem, () -> { - presentFragment(ProfileActivity.of(dialogId)); - }, null) - .addIf(!muted, R.drawable.msg_mute, LocaleController.getString("NotificationsStoryMute2", R.string.NotificationsStoryMute2), () -> { - MessagesController.getNotificationsSettings(currentAccount).edit().putBoolean("stories_" + key, false).apply(); - getNotificationsController().updateServerNotificationsSettings(dialogId, 0); - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); - String name = user == null ? "" : user.first_name.trim(); - int index = name.indexOf(" "); - if (index > 0) { - name = name.substring(0, index); - } - BulletinFactory.of(DialogsActivity.this).createUsersBulletin(Arrays.asList(user), AndroidUtilities.replaceTags(LocaleController.formatString("NotificationsStoryMutedHint", R.string.NotificationsStoryMutedHint, name))).show(); - }, subItem -> { - subItem.setMultiline(false); - }) - .addIf(muted, R.drawable.msg_unmute, LocaleController.getString("NotificationsStoryUnmute2", R.string.NotificationsStoryUnmute2), () -> { - MessagesController.getNotificationsSettings(currentAccount).edit().putBoolean("stories_" + key, true).apply(); - getNotificationsController().updateServerNotificationsSettings(dialogId, 0); - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); - String name = user == null ? "" : user.first_name.trim(); - int index = name.indexOf(" "); - if (index > 0) { - name = name.substring(0, index); - } - BulletinFactory.of(DialogsActivity.this).createUsersBulletin(Arrays.asList(user), AndroidUtilities.replaceTags(LocaleController.formatString("NotificationsStoryUnmutedHint", R.string.NotificationsStoryUnmutedHint, name))).show(); - }, subItem -> { - subItem.setMultiline(false); - }) - .addIf(!isArchive(), R.drawable.msg_archive, LocaleController.getString("ArchivePeerStories", R.string.ArchivePeerStories), () -> { - toggleArciveForStory(dialogId); - }, subItem -> { - subItem.setMultiline(false); - }) - .addIf(isArchive(), R.drawable.msg_unarchive, LocaleController.getString("UnarchiveStories", R.string.UnarchiveStories), () -> { - toggleArciveForStory(dialogId); - }, subItem -> { - subItem.setMultiline(false); - }); + .add(R.drawable.msg_discussion, LocaleController.getString("SendMessage", R.string.SendMessage), () -> { + presentFragment(ChatActivity.of(dialogId)); + }) + .add(R.drawable.msg_openprofile, LocaleController.getString("OpenProfile", R.string.OpenProfile), Theme.key_actionBarDefaultSubmenuItemIcon, Theme.key_actionBarDefaultSubmenuItem, () -> { + presentFragment(ProfileActivity.of(dialogId)); + }) + .addIf(!muted, R.drawable.msg_mute, LocaleController.getString("NotificationsStoryMute2", R.string.NotificationsStoryMute2), () -> { + MessagesController.getNotificationsSettings(currentAccount).edit().putBoolean("stories_" + key, false).apply(); + getNotificationsController().updateServerNotificationsSettings(dialogId, 0); + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + String name = user == null ? "" : user.first_name.trim(); + int index = name.indexOf(" "); + if (index > 0) { + name = name.substring(0, index); + } + BulletinFactory.of(DialogsActivity.this).createUsersBulletin(Arrays.asList(user), AndroidUtilities.replaceTags(LocaleController.formatString("NotificationsStoryMutedHint", R.string.NotificationsStoryMutedHint, name))).show(); + }).makeMultiline(false) + .addIf(muted, R.drawable.msg_unmute, LocaleController.getString("NotificationsStoryUnmute2", R.string.NotificationsStoryUnmute2), () -> { + MessagesController.getNotificationsSettings(currentAccount).edit().putBoolean("stories_" + key, true).apply(); + getNotificationsController().updateServerNotificationsSettings(dialogId, 0); + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + String name = user == null ? "" : user.first_name.trim(); + int index = name.indexOf(" "); + if (index > 0) { + name = name.substring(0, index); + } + BulletinFactory.of(DialogsActivity.this).createUsersBulletin(Arrays.asList(user), AndroidUtilities.replaceTags(LocaleController.formatString("NotificationsStoryUnmutedHint", R.string.NotificationsStoryUnmutedHint, name))).show(); + }).makeMultiline(false) + .addIf(!isArchive(), R.drawable.msg_archive, LocaleController.getString("ArchivePeerStories", R.string.ArchivePeerStories), () -> { + toggleArciveForStory(dialogId); + }).makeMultiline(false) + .addIf(isArchive(), R.drawable.msg_unarchive, LocaleController.getString("UnarchiveStories", R.string.UnarchiveStories), () -> { + toggleArciveForStory(dialogId); + }).makeMultiline(false); } filterOptions.setGravity(Gravity.LEFT) .translate(AndroidUtilities.dp(-8), AndroidUtilities.dp(-10)) .show(); } + + @Override + public void onMiniListClicked() { + if (hasOnlySlefStories && getStoriesController().hasOnlySelfStories()) { + dialogStoriesCell.openSelfStories(); + } else { + scrollToTop(true, true); + } + } }; dialogStoriesCell.setActionBar(actionBar); dialogStoriesCell.allowGlobalUpdates = false; @@ -4871,7 +4855,6 @@ public void onUserLongPressed(View view, long dialogId) { animateToHasStories = false; hasOnlySlefStories = false; hasStories = false; - contentView.addView(dialogStoriesCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, DialogStoriesCell.HEIGHT_IN_DP)); if (!onlySelect || initialDialogsType == DIALOGS_TYPE_FORWARD) { final FrameLayout.LayoutParams layoutParams = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT); if (inPreviewMode && Build.VERSION.SDK_INT >= 21) { @@ -5218,6 +5201,7 @@ void setOpenProgress(float progress) { }; rightSlidingDialogContainer.setOpenProgress(0f); contentView.addView(rightSlidingDialogContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + contentView.addView(dialogStoriesCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, DialogStoriesCell.HEIGHT_IN_DP)); updateStoriesVisibility(false); return fragmentView; } @@ -5227,11 +5211,15 @@ private void setStoriesOvercroll(ViewPage viewPage, float storiesOverscroll) { return; } this.storiesOverscroll = storiesOverscroll; + if (this.storiesOverscroll == 0) { + storiesOverscrollCalled = false; + } dialogStoriesCell.setOverscoll(storiesOverscroll); viewPage.listView.setViewsOffset(storiesOverscroll); viewPage.listView.setOverScrollMode(storiesOverscroll != 0 ? RecyclerView.OVER_SCROLL_NEVER : RecyclerView.OVER_SCROLL_ALWAYS); fragmentView.invalidate(); - if (storiesOverscroll > AndroidUtilities.dp(90)) { + if (storiesOverscroll > AndroidUtilities.dp(90) && !storiesOverscrollCalled) { + storiesOverscrollCalled = true; getOrCreateStoryViewer().doOnAnimationReady(() -> { fragmentView.dispatchTouchEvent(AndroidUtilities.emptyMotionEvent()); }); @@ -5254,9 +5242,9 @@ private void toggleArciveForStory(long dialogId) { }; CharSequence str; if (isArchive()) { - str = AndroidUtilities.replaceTags(LocaleController.formatString("StoriesMovedToDialogs", R.string.StoriesMovedToDialogs, ContactsController.formatName(user.first_name, null, 10))); + str = AndroidUtilities.replaceTags(LocaleController.formatString("StoriesMovedToDialogs", R.string.StoriesMovedToDialogs, ContactsController.formatName(user.first_name, null, 15))); } else { - str = AndroidUtilities.replaceTags(LocaleController.formatString("StoriesMovedToContacts", R.string.StoriesMovedToContacts, ContactsController.formatName(user.first_name, null, 10))); + str = AndroidUtilities.replaceTags(LocaleController.formatString("StoriesMovedToContacts", R.string.StoriesMovedToContacts, ContactsController.formatName(user.first_name, null, 15))); } storiesBulletin = BulletinFactory.global().createUsersBulletin( Arrays.asList(user), @@ -5454,6 +5442,7 @@ private void updateDialogsHint() { return; } if (isPremiumRestoreHintVisible()) { + dialogsHintCellVisible = true; dialogsHintCell.setVisibility(View.VISIBLE); dialogsHintCell.setOnClickListener(v -> { presentFragment(new PremiumPreviewFragment("dialogs_hint").setSelectAnnualByDefault()); @@ -5472,8 +5461,12 @@ private void updateDialogsHint() { LocaleController.getString(R.string.RestorePremiumHintMessage) ); } else if (isPremiumHintVisible()) { + dialogsHintCellVisible = true; dialogsHintCell.setVisibility(View.VISIBLE); dialogsHintCell.setOnClickListener(v -> { + if (dialogStoriesCell.getAlpha() == 0) { + return; + } presentFragment(new PremiumPreviewFragment("dialogs_hint").setSelectAnnualByDefault()); AndroidUtilities.runOnUIThread(() -> { MessagesController.getInstance(currentAccount).removeSuggestion(0, isPremiumHintUpgrade ? "PREMIUM_UPGRADE" : "PREMIUM_ANNUAL"); @@ -5490,6 +5483,7 @@ private void updateDialogsHint() { LocaleController.getString(isPremiumHintUpgrade ? R.string.UpgradePremiumMessage : R.string.SaveOnAnnualPremiumMessage) ); } else if (isCacheHintVisible()) { + dialogsHintCellVisible = true; dialogsHintCell.setVisibility(View.VISIBLE); dialogsHintCell.setOnClickListener(v -> { presentFragment(new CacheControlActivity()); @@ -5508,6 +5502,7 @@ private void updateDialogsHint() { LocaleController.getString(R.string.ClearStorageHintMessage) ); } else { + dialogsHintCellVisible = false; dialogsHintCell.setVisibility(View.GONE); } } @@ -6427,11 +6422,21 @@ public void onResume() { checkPermission = false; boolean hasNotContactsPermission = activity.checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED; boolean hasNotStoragePermission = (Build.VERSION.SDK_INT <= 28 || BuildVars.NO_SCOPED_STORAGE) && activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED; + boolean hasNotNotificationsPermission = Build.VERSION.SDK_INT >= 33 && activity.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED; AndroidUtilities.runOnUIThread(() -> { afterSignup = false; - if (hasNotContactsPermission || hasNotStoragePermission) { + if (hasNotNotificationsPermission || hasNotContactsPermission || hasNotStoragePermission) { askingForPermissions = true; - if (hasNotContactsPermission && askAboutContacts && getUserConfig().syncContacts && activity.shouldShowRequestPermissionRationale(Manifest.permission.READ_CONTACTS)) { + if (hasNotNotificationsPermission && NotificationPermissionDialog.shouldAsk(activity)) { + NotificationPermissionDialog sheet = new NotificationPermissionDialog(activity, granted -> { + if (granted) { + activity.requestPermissions(new String[] { Manifest.permission.POST_NOTIFICATIONS }, 1); + } + }); + if (showDialog(sheet) == null) { + sheet.show(); + } + } else if (hasNotContactsPermission && askAboutContacts && getUserConfig().syncContacts && activity.shouldShowRequestPermissionRationale(Manifest.permission.READ_CONTACTS)) { AlertDialog.Builder builder = AlertsCreator.createContactsPermissionDialog(activity, param -> { askAboutContacts = param != 0; MessagesController.getGlobalNotificationsSettings().edit().putBoolean("askAboutContacts", askAboutContacts).apply(); @@ -6447,7 +6452,7 @@ public void onResume() { askForPermissons(true); } } - }, afterSignup && hasNotContactsPermission ? 4000 : 0); + }, afterSignup && (hasNotContactsPermission || hasNotNotificationsPermission) ? 4000 : 0); } } else if (!onlySelect && XiaomiUtilities.isMIUI() && Build.VERSION.SDK_INT >= 19 && !XiaomiUtilities.isCustomPermissionGranted(XiaomiUtilities.OP_SHOW_WHEN_LOCKED)) { if (getParentActivity() == null) { @@ -6639,6 +6644,7 @@ public void onBecomeFullyHidden() { if (undoView[0] != null) { undoView[0].hide(true, 0); } + super.onBecomeFullyHidden(); } @Override @@ -7144,6 +7150,13 @@ public void setSearchAnimationProgress(float progress, boolean full) { } if (dialogsHintCell != null) { dialogsHintCell.setAlpha(1f - progress); + if (dialogsHintCellVisible) { + if (dialogsHintCell.getAlpha() == 0) { + dialogsHintCell.setVisibility(View.INVISIBLE); + } else { + dialogsHintCell.setVisibility(View.VISIBLE); + } + } } final boolean budget = SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW || !LiteMode.isEnabled(LiteMode.FLAG_CHAT_SCALE); if (full) { @@ -8037,9 +8050,6 @@ private void updateFloatingButtonOffset() { if (storyHint != null) { storyHint.setTranslationY(floatingButtonContainer.getTranslationY()); } - if (manyStoriesHint != null) { - manyStoriesHint.setTranslationY(floatingButtonContainer.getTranslationY()); - } } if (floatingButton2Container != null) { floatingButton2Container.setTranslationY(floatingButtonTranslation - floatingButtonPanOffset - Math.max(additionalFloatingTranslation, additionalFloatingTranslation2) * (1f - floatingButtonHideProgress) + AndroidUtilities.dp(44) * floatingButtonHideProgress); @@ -8196,6 +8206,10 @@ private void hideActionMode(boolean animateCheck) { } if (actionBarColorAnimator != null) { actionBarColorAnimator.cancel(); + actionBarColorAnimator = null; + } + if (progressToActionMode == 0) { + return; } float translateListHeight = 0; if (hasStories) { @@ -9556,6 +9570,17 @@ private void askForPermissons(boolean alert) { return; } ArrayList permissons = new ArrayList<>(); + if (Build.VERSION.SDK_INT >= 33 && NotificationPermissionDialog.shouldAsk(activity)) { + if (alert) { + showDialog(new NotificationPermissionDialog(activity, granted -> { + if (granted) { + activity.requestPermissions(new String[] { Manifest.permission.POST_NOTIFICATIONS }, 1); + } + })); + return; + } + permissons.add(Manifest.permission.POST_NOTIFICATIONS); + } if (getUserConfig().syncContacts && askAboutContacts && activity.checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { if (alert) { AlertDialog.Builder builder = AlertsCreator.createContactsPermissionDialog(activity, param -> { @@ -9570,7 +9595,12 @@ private void askForPermissons(boolean alert) { permissons.add(Manifest.permission.WRITE_CONTACTS); permissons.add(Manifest.permission.GET_ACCOUNTS); } - if ((Build.VERSION.SDK_INT <= 28 || BuildVars.NO_SCOPED_STORAGE) && activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + if (Build.VERSION.SDK_INT >= 33) { + permissons.add(Manifest.permission.READ_MEDIA_IMAGES); + permissons.add(Manifest.permission.READ_MEDIA_VIDEO); + permissons.add(Manifest.permission.READ_MEDIA_AUDIO); + permissons.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); + } else if ((Build.VERSION.SDK_INT <= 28 || BuildVars.NO_SCOPED_STORAGE) && activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { permissons.add(Manifest.permission.READ_EXTERNAL_STORAGE); permissons.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); } @@ -9625,6 +9655,13 @@ public void onRequestPermissionsResultFragment(int requestCode, String[] permiss continue; } switch (permissions[a]) { + case Manifest.permission.POST_NOTIFICATIONS: + if (grantResults[a] == PackageManager.PERMISSION_GRANTED) { + NotificationsController.getInstance(currentAccount).showNotifications(); + } else { + NotificationPermissionDialog.askLater(); + } + break; case Manifest.permission.READ_CONTACTS: if (grantResults[a] == PackageManager.PERMISSION_GRANTED) { AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.forceImportContactsStart)); @@ -10452,9 +10489,6 @@ private void hideFloatingButton(boolean hide) { if (storyHint != null) { storyHint.hide(); } - if (manyStoriesHint != null) { - manyStoriesHint.hide(); - } } } @@ -11498,6 +11532,13 @@ public ArrayList getThemeDescriptions() { arrayList.add(new ThemeDescription(null, 0, null, null, null, null, Theme.key_voipgroup_overlayAlertMutedByAdmin)); arrayList.add(new ThemeDescription(null, 0, null, null, null, null, Theme.key_voipgroup_overlayAlertMutedByAdmin2)); + arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_stories_circle_dialog1)); + arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_stories_circle_dialog2)); + arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_stories_circle_closeFriends1)); + arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_stories_circle_closeFriends2)); + arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_stories_circle1)); + arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_stories_circle2)); + if (filtersView != null) { arrayList.addAll(filtersView.getThemeDescriptions()); filtersView.updateColors(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DownloadProgressIcon.java b/TMessagesProj/src/main/java/org/telegram/ui/DownloadProgressIcon.java index e7ac9b0d8ff..f67c7331fd2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DownloadProgressIcon.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DownloadProgressIcon.java @@ -7,6 +7,8 @@ import android.graphics.PorterDuffColorFilter; import android.view.View; +import com.google.android.exoplayer2.util.Log; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.DownloadController; import org.telegram.messenger.FileLoader; @@ -37,10 +39,13 @@ public class DownloadProgressIcon extends View implements NotificationCenter.Not boolean showCompletedIcon; boolean hasUnviewedDownloads; int currentColor; + private boolean wasDrawn; public DownloadProgressIcon(int currentAccount, Context context) { super(context); this.currentAccount = currentAccount; + downloadImageReceiver.ignoreNotifications = true; + downloadCompleteImageReceiver.ignoreNotifications = true; downloadDrawable = new RLottieDrawable(R.raw.download_progress, "download_progress", AndroidUtilities.dp(28), AndroidUtilities.dp(28), true, null); downloadDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_actionBarDefaultIcon), PorterDuff.Mode.MULTIPLY)); @@ -120,6 +125,9 @@ protected void onDraw(Canvas canvas) { } } canvas.restore(); + if (getAlpha() != 0) { + wasDrawn = true; + } } @Override @@ -160,13 +168,15 @@ private void updateDownloadingListeners() { currentListeners.add(progressObserver); } } - if (currentListeners.size() == 0 && (getVisibility() != View.VISIBLE || getAlpha() != 1f)) { + if (currentListeners.size() == 0 && !wasDrawn) { if (DownloadController.getInstance(currentAccount).hasUnviewedDownloads()) { progress = 1f; currentProgress = 1f; + showCompletedIcon = true; } else { progress = 0; currentProgress = 0; + showCompletedIcon = false; } } } @@ -247,4 +257,19 @@ public int getObserverTag() { } } + @Override + public void setAlpha(float alpha) { + if (alpha == 0) { + wasDrawn = false; + } + super.setAlpha(alpha); + } + + @Override + public void setVisibility(int visibility) { + if (visibility != View.VISIBLE) { + wasDrawn = false; + } + super.setVisibility(visibility); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/FilterCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/FilterCreateActivity.java index 88e4c3f9f1f..560082161d1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/FilterCreateActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/FilterCreateActivity.java @@ -1974,6 +1974,7 @@ public static class NewSpan extends ReplacementSpan { float width, height; private boolean outline; + private int color; public NewSpan(boolean outline) { this.outline = outline; @@ -1994,6 +1995,10 @@ public NewSpan(boolean outline) { } } + public void setColor(int color) { + this.color = color; + } + public StaticLayout makeLayout() { if (layout == null) { layout = new StaticLayout("NEW"/*LocaleController.getString("New", R.string.New)*/, textPaint, AndroidUtilities.displaySize.x, Layout.Alignment.ALIGN_NORMAL, 1, 0, false); @@ -2013,7 +2018,10 @@ public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float _x, int top, int _y, int bottom, @NonNull Paint paint) { makeLayout(); - int color = paint.getColor(); + int color = this.color; + if (color == 0) { + color = paint.getColor(); + } bgPaint.setColor(color); if (outline) { textPaint.setColor(color); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index 01cd22e1619..507282c5348 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -84,6 +84,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.google.android.gms.common.api.Status; +import com.google.common.primitives.Longs; import com.google.firebase.appindexing.Action; import com.google.firebase.appindexing.FirebaseUserActions; import com.google.firebase.appindexing.builders.AssistActionBuilder; @@ -7249,7 +7250,7 @@ public boolean needPresentFragment(INavigationLayout layout, INavigationLayout.N } } else { boolean allow = true; // TODO: Make it a flag inside fragment itself, maybe BaseFragment#isDrawerOpenAllowed()? - if (fragment instanceof LoginActivity || fragment instanceof IntroActivity || fragment instanceof ProxyListActivity) { + if (fragment instanceof LoginActivity || fragment instanceof IntroActivity || fragment instanceof ProxyListActivity || fragment instanceof ProxySettingsActivity) { if (mainFragmentsStack.size() == 0 || mainFragmentsStack.get(0) instanceof IntroActivity || mainFragmentsStack.get(0) instanceof LoginActivity) { allow = false; } @@ -7266,7 +7267,7 @@ public boolean needPresentFragment(INavigationLayout layout, INavigationLayout.N @Override public boolean needAddFragmentToStack(BaseFragment fragment, INavigationLayout layout) { if (AndroidUtilities.isTablet()) { - drawerLayoutContainer.setAllowOpenDrawer(!(fragment instanceof LoginActivity || fragment instanceof IntroActivity || fragment instanceof CountrySelectActivity || fragment instanceof ProxyListActivity) && layersActionBarLayout.getView().getVisibility() != View.VISIBLE, true); + drawerLayoutContainer.setAllowOpenDrawer(!(fragment instanceof LoginActivity || fragment instanceof IntroActivity || fragment instanceof CountrySelectActivity || fragment instanceof ProxyListActivity || fragment instanceof ProxySettingsActivity) && layersActionBarLayout.getView().getVisibility() != View.VISIBLE, true); if (fragment instanceof DialogsActivity) { DialogsActivity dialogsActivity = (DialogsActivity) fragment; if (dialogsActivity.isMainDialogList() && layout != actionBarLayout) { @@ -7332,7 +7333,7 @@ public boolean needAddFragmentToStack(BaseFragment fragment, INavigationLayout l } } else { boolean allow = true; - if (fragment instanceof LoginActivity || fragment instanceof IntroActivity || fragment instanceof ProxyListActivity) { + if (fragment instanceof LoginActivity || fragment instanceof IntroActivity || fragment instanceof ProxyListActivity || fragment instanceof ProxySettingsActivity) { if (mainFragmentsStack.size() == 0 || mainFragmentsStack.get(0) instanceof IntroActivity) { allow = false; } @@ -7460,59 +7461,71 @@ private void openStories(long[] dialogIds, boolean requestWhenNeeded) { break; } } - NotificationsController.getInstance(currentAccount).processIgnoreStories(); - List fragments = actionBarLayout.getFragmentStack(); - DialogsActivity dialogsActivity = null; - for (int i = fragments.size() - 1; i >= 0; --i) { - BaseFragment fragment = fragments.get(i); - if (fragment instanceof DialogsActivity && (!((DialogsActivity) fragment).isArchive() || onlyArchived) && ((DialogsActivity) fragment).getType() == DialogsActivity.DIALOGS_TYPE_DEFAULT) { - dialogsActivity = (DialogsActivity) fragment; - break; - } else { - fragment.removeSelfFromStack(true); - } - } - if (dialogsActivity != null) { - if (drawerLayoutContainer != null) { - drawerLayoutContainer.closeDrawer(true); - } - if (onlyArchived) { - MessagesController.getInstance(dialogsActivity.getCurrentAccount()).getStoriesController().loadHiddenStories(); - } else { - MessagesController.getInstance(dialogsActivity.getCurrentAccount()).getStoriesController().loadStories(); - } - if (dialogsActivity.rightSlidingDialogContainer.hasFragment()) { - dialogsActivity.rightSlidingDialogContainer.finishPreview(); - } - if (onlyArchived && !dialogsActivity.isArchive()) { - Bundle args = new Bundle(); - args.putInt("folderId", 1); - presentFragment(dialogsActivity = new DialogsActivity(args)); - } - final DialogsActivity dialogsActivity1 = dialogsActivity; - dialogsActivity1.scrollToTop(false, false); - AndroidUtilities.runOnUIThread(() -> { - dialogsActivity1.scrollToTop(true, true); - }, 500); - return; - } +// NotificationsController.getInstance(currentAccount).processIgnoreStories(); +// List fragments = actionBarLayout.getFragmentStack(); +// DialogsActivity dialogsActivity = null; +// for (int i = fragments.size() - 1; i >= 0; --i) { +// BaseFragment fragment = fragments.get(i); +// if (fragment instanceof DialogsActivity && (!((DialogsActivity) fragment).isArchive() || onlyArchived) && ((DialogsActivity) fragment).getType() == DialogsActivity.DIALOGS_TYPE_DEFAULT) { +// dialogsActivity = (DialogsActivity) fragment; +// break; +// } else { +// fragment.removeSelfFromStack(true); +// } +// } +// if (dialogsActivity != null) { +// if (drawerLayoutContainer != null) { +// drawerLayoutContainer.closeDrawer(true); +// } +// if (onlyArchived) { +// MessagesController.getInstance(dialogsActivity.getCurrentAccount()).getStoriesController().loadHiddenStories(); +// } else { +// MessagesController.getInstance(dialogsActivity.getCurrentAccount()).getStoriesController().loadStories(); +// } +// if (dialogsActivity.rightSlidingDialogContainer.hasFragment()) { +// dialogsActivity.rightSlidingDialogContainer.finishPreview(); +// } +// if (onlyArchived && !dialogsActivity.isArchive()) { +// Bundle args = new Bundle(); +// args.putInt("folderId", 1); +// presentFragment(dialogsActivity = new DialogsActivity(args)); +// } +// final DialogsActivity dialogsActivity1 = dialogsActivity; +// dialogsActivity1.scrollToTop(false, false); +// AndroidUtilities.runOnUIThread(() -> { +// dialogsActivity1.scrollToTop(true, true); +// }, 500); +// return; +// } BaseFragment lastFragment = getLastFragment(); if (lastFragment == null) { return; } StoriesController storiesController = MessagesController.getInstance(currentAccount).getStoriesController(); - ArrayList stories = new ArrayList<>(storiesController.getDialogListStories()); - stories.addAll(storiesController.getHiddenList()); + ArrayList stories = new ArrayList<>(onlyArchived ? storiesController.getHiddenList() : storiesController.getDialogListStories()); ArrayList peerIds = new ArrayList<>(); ArrayList toLoadPeerIds = new ArrayList<>(); - if (requestWhenNeeded) { + final long[] finalDialogIds; + if (!onlyArchived) { + ArrayList dids = new ArrayList<>(); for (int i = 0; i < dialogIds.length; ++i) { - toLoadPeerIds.add(dialogIds[i]); + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogIds[i]); + if (user == null || !user.stories_hidden) { + dids.add(dialogIds[i]); + } } + finalDialogIds = Longs.toArray(dids); } else { - for (int i = 0; i < dialogIds.length; ++i) { - peerIds.add(dialogIds[i]); + finalDialogIds = dialogIds; + } + if (requestWhenNeeded) { + for (int i = 0; i < finalDialogIds.length; ++i) { + toLoadPeerIds.add(finalDialogIds[i]); + } + } else { + for (int i = 0; i < finalDialogIds.length; ++i) { + peerIds.add(finalDialogIds[i]); } } if (!toLoadPeerIds.isEmpty() && requestWhenNeeded) { @@ -7522,7 +7535,7 @@ private void openStories(long[] dialogIds, boolean requestWhenNeeded) { loaded[0]--; if (loaded[0] == 0) { NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesUpdated); - openStories(dialogIds, false); + openStories(finalDialogIds, false); } }; for (int i = 0; i < toLoadPeerIds.size(); ++i) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java index a613d6b221b..c629419dc1b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java @@ -58,6 +58,7 @@ import android.widget.TextView; import androidx.collection.LongSparseArray; +import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -306,7 +307,7 @@ public void addInfoView(IMapsProvider.IMarker marker) { lastPressedMarkerView = new FrameLayout(context); lastPressedMarkerView.setBackgroundResource(R.drawable.venue_tooltip); - lastPressedMarkerView.getBackground().setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogBackground), PorterDuff.Mode.MULTIPLY)); + lastPressedMarkerView.getBackground().setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_dialogBackground), PorterDuff.Mode.MULTIPLY)); frameLayout.addView(lastPressedMarkerView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 71)); lastPressedMarkerView.setAlpha(0.0f); lastPressedMarkerView.setOnClickListener(v -> { @@ -326,7 +327,7 @@ public void addInfoView(IMapsProvider.IMarker marker) { nameTextView.setMaxLines(1); nameTextView.setEllipsize(TextUtils.TruncateAt.END); nameTextView.setSingleLine(true); - nameTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + nameTextView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); nameTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); nameTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); lastPressedMarkerView.addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 18, 10, 18, 0)); @@ -336,7 +337,7 @@ public void addInfoView(IMapsProvider.IMarker marker) { addressTextView.setMaxLines(1); addressTextView.setEllipsize(TextUtils.TruncateAt.END); addressTextView.setSingleLine(true); - addressTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText3)); + addressTextView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText3)); addressTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); lastPressedMarkerView.addView(addressTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 18, 32, 18, 0)); @@ -426,6 +427,11 @@ public LocationActivity(int type) { AndroidUtilities.fixGoogleMapsBug(); } + private boolean initialMaxZoom; + public void setInitialMaxZoom(boolean initialMaxZoom) { + this.initialMaxZoom = initialMaxZoom; + } + @Override public boolean onFragmentCreate() { super.onFragmentCreate(); @@ -494,6 +500,11 @@ private UndoView getUndoView() { return undoView[0]; } + private boolean isSharingAllowed = true; + public void setSharingAllowed(boolean allowed) { + isSharingAllowed = allowed; + } + @Override public boolean isSwipeBackEnabled(MotionEvent event) { return false; @@ -521,10 +532,10 @@ public View createView(Context context) { } locationDenied = Build.VERSION.SDK_INT >= 23 && getParentActivity() != null && getParentActivity().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED; - actionBar.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground)); - actionBar.setTitleColor(Theme.getColor(Theme.key_dialogTextBlack)); - actionBar.setItemsColor(Theme.getColor(Theme.key_dialogTextBlack), false); - actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_dialogButtonSelector), false); + actionBar.setBackgroundColor(getThemedColor(Theme.key_dialogBackground)); + actionBar.setTitleColor(getThemedColor(Theme.key_dialogTextBlack)); + actionBar.setItemsColor(getThemedColor(Theme.key_dialogTextBlack), false); + actionBar.setItemsBackgroundColor(getThemedColor(Theme.key_dialogButtonSelector), false); actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setAllowOverlayTitle(true); if (AndroidUtilities.isTablet()) { @@ -559,7 +570,7 @@ public void onItemClick(int id) { } else if (messageObject != null) { if (messageObject.isLiveLocation()) { actionBar.setTitle(LocaleController.getString("AttachLiveLocation", R.string.AttachLiveLocation)); - otherItem = menu.addItem(0, R.drawable.ic_ab_other); + otherItem = menu.addItem(0, R.drawable.ic_ab_other, getResourceProvider()); otherItem.addSubItem(get_directions, R.drawable.navigate, LocaleController.getString("GetDirections", R.string.GetDirections)); } else { if (messageObject.messageOwner.media.title != null && messageObject.messageOwner.media.title.length() > 0) { @@ -567,9 +578,9 @@ public void onItemClick(int id) { } else { actionBar.setTitle(LocaleController.getString("ChatLocation", R.string.ChatLocation)); } - otherItem = menu.addItem(0, R.drawable.ic_ab_other); + otherItem = menu.addItem(0, R.drawable.ic_ab_other, getResourceProvider()); otherItem.addSubItem(open_in, R.drawable.msg_openin, LocaleController.getString("OpenInExternalApp", R.string.OpenInExternalApp)); - if (!getLocationController().isSharingLocation(dialogId)) { + if (!getLocationController().isSharingLocation(dialogId) && isSharingAllowed) { otherItem.addSubItem(share_live_location, R.drawable.msg_location, LocaleController.getString("SendLiveLocationMenu", R.string.SendLiveLocationMenu)); } otherItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); @@ -580,7 +591,7 @@ public void onItemClick(int id) { if (locationType != LOCATION_TYPE_GROUP) { overlayView = new MapOverlayView(context); - searchItem = menu.addItem(0, R.drawable.ic_ab_search).setIsSearchField(true).setActionBarMenuItemSearchListener(new ActionBarMenuItem.ActionBarMenuItemSearchListener() { + searchItem = menu.addItem(0, R.drawable.ic_ab_search, getResourceProvider()).setIsSearchField(true).setActionBarMenuItemSearchListener(new ActionBarMenuItem.ActionBarMenuItemSearchListener() { @Override public void onSearchExpand() { searching = true; @@ -630,9 +641,9 @@ public void onTextChanged(EditText editText) { searchItem.setSearchFieldHint(LocaleController.getString("Search", R.string.Search)); searchItem.setContentDescription(LocaleController.getString("Search", R.string.Search)); EditTextBoldCursor editText = searchItem.getSearchField(); - editText.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - editText.setCursorColor(Theme.getColor(Theme.key_dialogTextBlack)); - editText.setHintTextColor(Theme.getColor(Theme.key_chat_messagePanelHint)); + editText.setTextColor(getThemedColor(Theme.key_dialogTextBlack)); + editText.setCursorColor(getThemedColor(Theme.key_dialogTextBlack)); + editText.setHintTextColor(getThemedColor(Theme.key_chat_messagePanelHint)); } } @@ -661,10 +672,10 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { } }; FrameLayout frameLayout = (FrameLayout) fragmentView; - fragmentView.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground)); + fragmentView.setBackgroundColor(getThemedColor(Theme.key_dialogBackground)); shadowDrawable = context.getResources().getDrawable(R.drawable.sheet_shadow_round).mutate(); - shadowDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogBackground), PorterDuff.Mode.MULTIPLY)); + shadowDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_dialogBackground), PorterDuff.Mode.MULTIPLY)); Rect padding = new Rect(); shadowDrawable.getPadding(padding); @@ -685,12 +696,12 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } } }; - mapViewClip.setBackgroundDrawable(new MapPlaceholderDrawable()); + mapViewClip.setBackgroundDrawable(new MapPlaceholderDrawable(isActiveThemeDark())); if (messageObject == null && (locationType == LOCATION_TYPE_SEND || locationType == LOCATION_TYPE_SEND_WITH_LIVE)) { searchAreaButton = new SearchButton(context); searchAreaButton.setTranslationX(-AndroidUtilities.dp(80)); - Drawable drawable = Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(40), Theme.getColor(Theme.key_location_actionBackground), Theme.getColor(Theme.key_location_actionPressedBackground)); + Drawable drawable = Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(40), getThemedColor(Theme.key_location_actionBackground), getThemedColor(Theme.key_location_actionPressedBackground)); if (Build.VERSION.SDK_INT < 21) { Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.places_btn).mutate(); shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.MULTIPLY)); @@ -711,7 +722,7 @@ public void getOutline(View view, Outline outline) { }); } searchAreaButton.setBackgroundDrawable(drawable); - searchAreaButton.setTextColor(Theme.getColor(Theme.key_location_actionActiveIcon)); + searchAreaButton.setTextColor(getThemedColor(Theme.key_location_actionActiveIcon)); searchAreaButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); searchAreaButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); searchAreaButton.setText(LocaleController.getString("PlacesInThisArea", R.string.PlacesInThisArea)); @@ -726,16 +737,16 @@ public void getOutline(View view, Outline outline) { }); } - mapTypeButton = new ActionBarMenuItem(context, null, 0, Theme.getColor(Theme.key_location_actionIcon)); + mapTypeButton = new ActionBarMenuItem(context, null, 0, getThemedColor(Theme.key_location_actionIcon), getResourceProvider()); mapTypeButton.setClickable(true); mapTypeButton.setSubMenuOpenSide(2); mapTypeButton.setAdditionalXOffset(AndroidUtilities.dp(10)); mapTypeButton.setAdditionalYOffset(-AndroidUtilities.dp(10)); - mapTypeButton.addSubItem(map_list_menu_map, R.drawable.msg_map, LocaleController.getString("Map", R.string.Map)); - mapTypeButton.addSubItem(map_list_menu_satellite, R.drawable.msg_satellite, LocaleController.getString("Satellite", R.string.Satellite)); - mapTypeButton.addSubItem(map_list_menu_hybrid, R.drawable.msg_hybrid, LocaleController.getString("Hybrid", R.string.Hybrid)); + mapTypeButton.addSubItem(map_list_menu_map, R.drawable.msg_map, LocaleController.getString("Map", R.string.Map), getResourceProvider()); + mapTypeButton.addSubItem(map_list_menu_satellite, R.drawable.msg_satellite, LocaleController.getString("Satellite", R.string.Satellite), getResourceProvider()); + mapTypeButton.addSubItem(map_list_menu_hybrid, R.drawable.msg_hybrid, LocaleController.getString("Hybrid", R.string.Hybrid), getResourceProvider()); mapTypeButton.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); - Drawable drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(40), Theme.getColor(Theme.key_location_actionBackground), Theme.getColor(Theme.key_location_actionPressedBackground)); + Drawable drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(40), getThemedColor(Theme.key_location_actionBackground), getThemedColor(Theme.key_location_actionPressedBackground)); if (Build.VERSION.SDK_INT < 21) { Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.floating_shadow_profile).mutate(); shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.MULTIPLY)); @@ -773,7 +784,7 @@ public void getOutline(View view, Outline outline) { }); locationButton = new ImageView(context); - drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(40), Theme.getColor(Theme.key_location_actionBackground), Theme.getColor(Theme.key_location_actionPressedBackground)); + drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(40), getThemedColor(Theme.key_location_actionBackground), getThemedColor(Theme.key_location_actionPressedBackground)); if (Build.VERSION.SDK_INT < 21) { Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.floating_shadow_profile).mutate(); shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.MULTIPLY)); @@ -796,7 +807,7 @@ public void getOutline(View view, Outline outline) { locationButton.setBackgroundDrawable(drawable); locationButton.setImageResource(R.drawable.msg_current_location); locationButton.setScaleType(ImageView.ScaleType.CENTER); - locationButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_location_actionActiveIcon), PorterDuff.Mode.MULTIPLY)); + locationButton.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_location_actionActiveIcon), PorterDuff.Mode.MULTIPLY)); locationButton.setTag(Theme.key_location_actionActiveIcon); locationButton.setContentDescription(LocaleController.getString("AccDescrMyLocation", R.string.AccDescrMyLocation)); FrameLayout.LayoutParams layoutParams1 = LayoutHelper.createFrame(Build.VERSION.SDK_INT >= 21 ? 40 : 44, Build.VERSION.SDK_INT >= 21 ? 40 : 44, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 12, 12); @@ -821,7 +832,7 @@ public void getOutline(View view, Outline outline) { } } else { if (myLocation != null && map != null) { - locationButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_location_actionActiveIcon), PorterDuff.Mode.MULTIPLY)); + locationButton.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_location_actionActiveIcon), PorterDuff.Mode.MULTIPLY)); locationButton.setTag(Theme.key_location_actionActiveIcon); adapter.setCustomLocation(null); userLocationMoved = false; @@ -840,7 +851,7 @@ public void getOutline(View view, Outline outline) { }); proximityButton = new ImageView(context); - drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(40), Theme.getColor(Theme.key_location_actionBackground), Theme.getColor(Theme.key_location_actionPressedBackground)); + drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(40), getThemedColor(Theme.key_location_actionBackground), getThemedColor(Theme.key_location_actionPressedBackground)); if (Build.VERSION.SDK_INT < 21) { Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.floating_shadow_profile).mutate(); shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.MULTIPLY)); @@ -860,7 +871,7 @@ public void getOutline(View view, Outline outline) { } }); } - proximityButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_location_actionIcon), PorterDuff.Mode.MULTIPLY)); + proximityButton.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_location_actionIcon), PorterDuff.Mode.MULTIPLY)); proximityButton.setBackgroundDrawable(drawable); proximityButton.setScaleType(ImageView.ScaleType.CENTER); proximityButton.setContentDescription(LocaleController.getString("AccDescrLocationNotify", R.string.AccDescrLocationNotify)); @@ -935,11 +946,11 @@ public void getOutline(View view, Outline outline) { emptyImageView = new ImageView(context); emptyImageView.setImageResource(R.drawable.location_empty); - emptyImageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogEmptyImage), PorterDuff.Mode.MULTIPLY)); + emptyImageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_dialogEmptyImage), PorterDuff.Mode.MULTIPLY)); emptyView.addView(emptyImageView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); emptyTitleTextView = new TextView(context); - emptyTitleTextView.setTextColor(Theme.getColor(Theme.key_dialogEmptyText)); + emptyTitleTextView.setTextColor(getThemedColor(Theme.key_dialogEmptyText)); emptyTitleTextView.setGravity(Gravity.CENTER); emptyTitleTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); emptyTitleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 17); @@ -947,14 +958,14 @@ public void getOutline(View view, Outline outline) { emptyView.addView(emptyTitleTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 11, 0, 0)); emptySubtitleTextView = new TextView(context); - emptySubtitleTextView.setTextColor(Theme.getColor(Theme.key_dialogEmptyText)); + emptySubtitleTextView.setTextColor(getThemedColor(Theme.key_dialogEmptyText)); emptySubtitleTextView.setGravity(Gravity.CENTER); emptySubtitleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); emptySubtitleTextView.setPadding(AndroidUtilities.dp(40), 0, AndroidUtilities.dp(40), 0); emptyView.addView(emptySubtitleTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 6, 0, 0)); listView = new RecyclerListView(context); - listView.setAdapter(adapter = new LocationActivityAdapter(context, locationType, dialogId, false, null) { + listView.setAdapter(adapter = new LocationActivityAdapter(context, locationType, dialogId, false, getResourceProvider(), false) { @Override protected void onDirectionClick() { openDirections(null); @@ -983,7 +994,7 @@ public void setLiveLocations(ArrayList liveLocations) { super.setLiveLocations(liveLocations); } }); - adapter.setMyLocationDenied(locationDenied); + adapter.setMyLocationDenied(locationDenied, false); adapter.setUpdateRunnable(() -> updateClipView(false)); listView.setVerticalScrollBarEnabled(false); listView.setLayoutManager(layoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); @@ -1141,6 +1152,7 @@ public void dismiss() { frameLayout.addView(mapViewClip, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); mapView = ApplicationLoader.getMapsProvider().onCreateMapView(context); + mapView.getView().setAlpha(0f); mapView.setOnDispatchTouchEventInterceptor((ev, origMethod) -> { MotionEvent eventToRecycle = null; if (yOffset != 0) { @@ -1176,7 +1188,7 @@ public void dismiss() { } if (ev.getAction() == MotionEvent.ACTION_MOVE) { if (!userLocationMoved) { - locationButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_location_actionIcon), PorterDuff.Mode.MULTIPLY)); + locationButton.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_location_actionIcon), PorterDuff.Mode.MULTIPLY)); locationButton.setTag(Theme.key_location_actionIcon); userLocationMoved = true; } @@ -1211,9 +1223,10 @@ public void dismiss() { ApplicationLoader.getMapsProvider().initializeMaps(ApplicationLoader.applicationContext); mapView.getMapAsync(map1 -> { this.map = map1; - if (isActiveThemeDark()) { + int themeResId = getMapThemeResId(); + if (themeResId != 0) { currentMapStyleDark = true; - IMapsProvider.IMapStyleOptions style = ApplicationLoader.getMapsProvider().loadRawResourceStyle(ApplicationLoader.applicationContext, R.raw.mapstyle_night); + IMapsProvider.IMapStyleOptions style = ApplicationLoader.getMapsProvider().loadRawResourceStyle(ApplicationLoader.applicationContext, themeResId); this.map.setMapStyle(style); } this.map.setPadding(AndroidUtilities.dp(70), 0, AndroidUtilities.dp(70), AndroidUtilities.dp(10)); @@ -1255,7 +1268,7 @@ public void dismiss() { searchListView = new RecyclerListView(context); searchListView.setVisibility(View.GONE); searchListView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); - searchAdapter = new LocationActivitySearchAdapter(context) { + searchAdapter = new LocationActivitySearchAdapter(context, getResourceProvider(), false) { @Override public void notifyDataSetChanged() { if (searchItem != null) { @@ -1328,7 +1341,7 @@ protected void onDraw(Canvas canvas) { int w = AndroidUtilities.dp(36); int y = padding.top + AndroidUtilities.dp(10); rect.set((getMeasuredWidth() - w) / 2, y, (getMeasuredWidth() + w) / 2, y + AndroidUtilities.dp(4)); - int color = Theme.getColor(Theme.key_sheet_scrollUp); + int color = getThemedColor(Theme.key_sheet_scrollUp); int alpha = Color.alpha(color); Theme.dialogs_onlineCirclePaint.setColor(color); canvas.drawRoundRect(rect, AndroidUtilities.dp(2), AndroidUtilities.dp(2), Theme.dialogs_onlineCirclePaint); @@ -1342,7 +1355,7 @@ protected void onDraw(Canvas canvas) { if (messageObject == null && chatLocation == null && initialLocation != null) { userLocationMoved = true; - locationButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_location_actionIcon), PorterDuff.Mode.MULTIPLY)); + locationButton.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_location_actionIcon), PorterDuff.Mode.MULTIPLY)); locationButton.setTag(Theme.key_location_actionIcon); } @@ -1353,14 +1366,29 @@ protected void onDraw(Canvas canvas) { } private boolean isActiveThemeDark() { - Theme.ThemeInfo info = Theme.getActiveTheme(); - if (info.isDark()) { - return true; + if (getResourceProvider() == null) { + Theme.ThemeInfo info = Theme.getActiveTheme(); + if (info.isDark()) { + return true; + } } - int color = Theme.getColor(Theme.key_windowBackgroundWhite); + int color = getThemedColor(Theme.key_windowBackgroundWhite); return AndroidUtilities.computePerceivedBrightness(color) < 0.721f; } + private int getMapThemeResId() { + int color = getThemedColor(Theme.key_windowBackgroundWhite); + if (AndroidUtilities.computePerceivedBrightness(color) < 0.721f) { +// if (Color.blue(color) - 3 > Color.red(color) && Color.blue(color) - 3 > Color.green(color)) { +// return R.raw.mapstyle_night; +// } else { +// return R.raw.mapstyle_dark; +// } + return R.raw.mapstyle_night; + } + return 0; + } + private void openDirections(LiveLocation location) { double daddrLat, daddrLong; if (location != null && location.object != null) { @@ -1769,14 +1797,17 @@ private void onMapInit() { return; } + mapView.getView().animate().alpha(1).setStartDelay(200).setDuration(100).start(); + + final float zoom = initialMaxZoom ? map.getMinZoomLevel() + 4 : map.getMaxZoomLevel() - 4; if (chatLocation != null) { LiveLocation liveLocation = addUserMarker(chatLocation); - map.moveCamera(ApplicationLoader.getMapsProvider().newCameraUpdateLatLngZoom(liveLocation.marker.getPosition(), map.getMaxZoomLevel() - 4)); + map.moveCamera(ApplicationLoader.getMapsProvider().newCameraUpdateLatLngZoom(liveLocation.marker.getPosition(), zoom)); } else if (messageObject != null) { if (messageObject.isLiveLocation()) { LiveLocation liveLocation = addUserMarker(messageObject.messageOwner); if (!getRecentLocations()) { - map.moveCamera(ApplicationLoader.getMapsProvider().newCameraUpdateLatLngZoom(liveLocation.marker.getPosition(), map.getMaxZoomLevel() - 4)); + map.moveCamera(ApplicationLoader.getMapsProvider().newCameraUpdateLatLngZoom(liveLocation.marker.getPosition(), zoom)); } } else { IMapsProvider.LatLng latLng = new IMapsProvider.LatLng(userLocation.getLatitude(), userLocation.getLongitude()); @@ -1785,7 +1816,7 @@ private void onMapInit() { } catch (Exception e) { FileLog.e(e); } - IMapsProvider.ICameraUpdate position = ApplicationLoader.getMapsProvider().newCameraUpdateLatLngZoom(latLng, map.getMaxZoomLevel() - 4); + IMapsProvider.ICameraUpdate position = ApplicationLoader.getMapsProvider().newCameraUpdateLatLngZoom(latLng, zoom); map.moveCamera(position); firstFocus = false; getRecentLocations(); @@ -1794,9 +1825,10 @@ private void onMapInit() { userLocation = new Location("network"); if (initialLocation != null) { IMapsProvider.LatLng latLng = new IMapsProvider.LatLng(initialLocation.geo_point.lat, initialLocation.geo_point._long); - map.moveCamera(ApplicationLoader.getMapsProvider().newCameraUpdateLatLngZoom(latLng, map.getMaxZoomLevel() - 4)); + map.moveCamera(ApplicationLoader.getMapsProvider().newCameraUpdateLatLngZoom(latLng, zoom)); userLocation.setLatitude(initialLocation.geo_point.lat); userLocation.setLongitude(initialLocation.geo_point._long); + userLocation.setAccuracy(initialLocation.geo_point.accuracy_radius); adapter.setCustomLocation(userLocation); } else { userLocation.setLatitude(20.659322); @@ -1847,7 +1879,7 @@ private void onMapInit() { } markerImageView.setVisibility(View.INVISIBLE); if (!userLocationMoved) { - locationButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_location_actionIcon), PorterDuff.Mode.MULTIPLY)); + locationButton.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_location_actionIcon), PorterDuff.Mode.MULTIPLY)); locationButton.setTag(Theme.key_location_actionIcon); userLocationMoved = true; } @@ -1855,7 +1887,7 @@ private void onMapInit() { LiveLocation loc = markers.get(i); if (loc != null && loc.marker == marker) { selectedMarkerId = loc.id; - map.animateCamera(ApplicationLoader.getMapsProvider().newCameraUpdateLatLngZoom(loc.marker.getPosition(), map.getMaxZoomLevel() - 4)); + map.animateCamera(ApplicationLoader.getMapsProvider().newCameraUpdateLatLngZoom(loc.marker.getPosition(), zoom)); break; } } @@ -1890,7 +1922,7 @@ private boolean checkGpsEnabled() { LocationManager lm = (LocationManager) ApplicationLoader.applicationContext.getSystemService(Context.LOCATION_SERVICE); if (!lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTopAnimation(R.raw.permission_request_location, AlertsCreator.PERMISSIONS_REQUEST_TOP_ICON_SIZE, false, Theme.getColor(Theme.key_dialogTopBackground)); + builder.setTopAnimation(R.raw.permission_request_location, AlertsCreator.PERMISSIONS_REQUEST_TOP_ICON_SIZE, false, getThemedColor(Theme.key_dialogTopBackground)); builder.setMessage(LocaleController.getString("GpsDisabledAlertText", R.string.GpsDisabledAlertText)); builder.setPositiveButton(LocaleController.getString("ConnectingToProxyEnable", R.string.ConnectingToProxyEnable), (dialog, id) -> { if (getParentActivity() == null) { @@ -1948,7 +1980,7 @@ private void showPermissionAlert(boolean byButton) { return; } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTopAnimation(R.raw.permission_request_location, AlertsCreator.PERMISSIONS_REQUEST_TOP_ICON_SIZE, false, Theme.getColor(Theme.key_dialogTopBackground)); + builder.setTopAnimation(R.raw.permission_request_location, AlertsCreator.PERMISSIONS_REQUEST_TOP_ICON_SIZE, false, getThemedColor(Theme.key_dialogTopBackground)); if (byButton) { builder.setMessage(AndroidUtilities.replaceTags(LocaleController.getString("PermissionNoLocationNavigation", R.string.PermissionNoLocationNavigation))); } else { @@ -2464,7 +2496,7 @@ public void didReceivedNotification(int id, int account, Object... args) { } else if (id == NotificationCenter.locationPermissionGranted) { locationDenied = false; if (adapter != null) { - adapter.setMyLocationDenied(locationDenied); + adapter.setMyLocationDenied(locationDenied, false); } if (map != null) { try { @@ -2476,7 +2508,7 @@ public void didReceivedNotification(int id, int account, Object... args) { } else if (id == NotificationCenter.locationPermissionDenied) { locationDenied = true; if (adapter != null) { - adapter.setMyLocationDenied(locationDenied); + adapter.setMyLocationDenied(locationDenied, false); } } else if (id == NotificationCenter.liveLocationsChanged) { if (adapter != null) { @@ -2697,11 +2729,6 @@ public void onRequestPermissionsResultFragment(int requestCode, String[] permiss } } - @Override - public boolean hasForceLightStatusBar() { - return true; - } - @Override public void onLowMemory() { super.onLowMemory(); @@ -2729,19 +2756,20 @@ public ArrayList getThemeDescriptions() { ArrayList themeDescriptions = new ArrayList<>(); ThemeDescription.ThemeDescriptionDelegate cellDelegate = () -> { - mapTypeButton.setIconColor(Theme.getColor(Theme.key_location_actionIcon)); - mapTypeButton.redrawPopup(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground)); - mapTypeButton.setPopupItemsColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItemIcon), true); - mapTypeButton.setPopupItemsColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuItem), false); + mapTypeButton.setIconColor(getThemedColor(Theme.key_location_actionIcon)); + mapTypeButton.redrawPopup(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground)); + mapTypeButton.setPopupItemsColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItemIcon), true); + mapTypeButton.setPopupItemsColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem), false); - shadowDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogBackground), PorterDuff.Mode.MULTIPLY)); + shadowDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_dialogBackground), PorterDuff.Mode.MULTIPLY)); shadow.invalidate(); if (map != null) { - if (isActiveThemeDark()) { + int themeResId = getMapThemeResId(); + if (themeResId != 0) { if (!currentMapStyleDark) { currentMapStyleDark = true; - IMapsProvider.IMapStyleOptions style = ApplicationLoader.getMapsProvider().loadRawResourceStyle(ApplicationLoader.applicationContext, R.raw.mapstyle_night); + IMapsProvider.IMapStyleOptions style = ApplicationLoader.getMapsProvider().loadRawResourceStyle(ApplicationLoader.applicationContext, themeResId); map.setMapStyle(style); if (proximityCircle != null) { proximityCircle.setStrokeColor(0xffffffff); @@ -2871,4 +2899,9 @@ public ArrayList getThemeDescriptions() { return themeDescriptions; } + + @Override + public boolean isLightStatusBar() { + return ColorUtils.calculateLuminance(getThemedColor(Theme.key_windowBackgroundWhite)) > 0.7f; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java index 0863791713c..ea97ad406a1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java @@ -5783,7 +5783,12 @@ public void didReceivedNotification(int id, int account, Object... args) { .requestIdToken(BuildVars.GOOGLE_AUTH_CLIENT_ID) .requestEmail() .build()); - googleClient.signOut().addOnCompleteListener(command -> getParentActivity().startActivityForResult(googleClient.getSignInIntent(), BasePermissionsActivity.REQUEST_CODE_SIGN_IN_WITH_GOOGLE)); + googleClient.signOut().addOnCompleteListener(command -> { + if (getParentActivity() == null) { + return; + } + getParentActivity().startActivityForResult(googleClient.getSignInIntent(), BasePermissionsActivity.REQUEST_CODE_SIGN_IN_WITH_GOOGLE); + }); }); cantAccessEmailFrameLayout = new FrameLayout(context); @@ -5956,6 +5961,9 @@ private void requestEmailReset() { req.phone_number = requestPhone; req.phone_code_hash = phoneHash; getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (getParentActivity() == null) { + return; + } requestingEmailReset = false; if (response instanceof TLRPC.TL_auth_sentCode) { TLRPC.TL_auth_sentCode sentCode = (TLRPC.TL_auth_sentCode) response; @@ -8253,17 +8261,17 @@ private void updateProxyButton(boolean animated, boolean force) { currentConnectionState = state; SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); String proxyAddress = preferences.getString("proxy_ip", ""); - final boolean proxyEnabled = preferences.getBoolean("proxy_enabled", false); + final boolean proxyEnabled = preferences.getBoolean("proxy_enabled", false) && !TextUtils.isEmpty(proxyAddress); final boolean connected = currentConnectionState == ConnectionsManager.ConnectionStateConnected || currentConnectionState == ConnectionsManager.ConnectionStateUpdating; final boolean connecting = currentConnectionState == ConnectionsManager.ConnectionStateConnecting || currentConnectionState == ConnectionsManager.ConnectionStateWaitingForNetwork || currentConnectionState == ConnectionsManager.ConnectionStateConnectingToProxy; - final boolean show = (proxyEnabled && !TextUtils.isEmpty(proxyAddress)) || getMessagesController().blockedCountry && !SharedConfig.proxyList.isEmpty() || connecting; - if (show) { + if (proxyEnabled) { + proxyDrawable.setConnected(true, connected, animated); + showProxyButton(true, animated); + } else if (getMessagesController().blockedCountry && !SharedConfig.proxyList.isEmpty() || connecting) { + proxyDrawable.setConnected(true, connected, animated); showProxyButtonDelayed(); } else { - showProxyButton(show, animated); - } - if (show) { - proxyDrawable.setConnected(true, connected, animated); + showProxyButton(false, animated); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NotificationPermissionDialog.java b/TMessagesProj/src/main/java/org/telegram/ui/NotificationPermissionDialog.java new file mode 100644 index 00000000000..02a06dfbc4b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/NotificationPermissionDialog.java @@ -0,0 +1,320 @@ +package org.telegram.ui; + +import android.Manifest; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.app.Activity; +import android.content.Context; +import android.content.pm.PackageManager; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.animation.OvershootInterpolator; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +import org.telegram.messenger.AccountInstance; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.NotificationsController; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.AnimatedTextView; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RLottieImageView; + +import java.util.ArrayList; + +public class NotificationPermissionDialog extends BottomSheet implements NotificationCenter.NotificationCenterDelegate { + + private CounterView counterView; + private RLottieImageView rLottieImageView; + private Utilities.Callback whenGranted; + + public NotificationPermissionDialog(Context context, Utilities.Callback whenGranted) { + super(context, false); + this.whenGranted = whenGranted; + + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.VERTICAL); + + FrameLayout block = new FrameLayout(context); + rLottieImageView = new RLottieImageView(context); + rLottieImageView.setScaleType(ImageView.ScaleType.CENTER); + rLottieImageView.setAnimation(R.raw.silent_unmute, 46, 46); + rLottieImageView.playAnimation(); + rLottieImageView.setBackground(Theme.createCircleDrawable(AndroidUtilities.dp(72), Theme.getColor(Theme.key_featuredStickers_addButton))); + block.addView(rLottieImageView, LayoutHelper.createFrame(72, 72, Gravity.CENTER)); + block.addView(counterView = new CounterView(context), LayoutHelper.createFrame(64, 32, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 29, 16, 0, 0)); + counterView.setCount(0); + block.setOnClickListener(e -> { + if (!rLottieImageView.isPlaying()) { + rLottieImageView.setProgress(0); + rLottieImageView.playAnimation(); + } + }); + linearLayout.addView(block, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 110)); + + TextView textView = new TextView(context); + textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + textView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + textView.setGravity(Gravity.CENTER_HORIZONTAL); + textView.setText(LocaleController.getString("NotificationsPermissionAlertTitle")); + textView.setPadding(AndroidUtilities.dp(30), 0, AndroidUtilities.dp(30), 0); + linearLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + textView = new TextView(context); + textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setGravity(Gravity.CENTER_HORIZONTAL); + textView.setText(LocaleController.getString("NotificationsPermissionAlertSubtitle")); + textView.setPadding(AndroidUtilities.dp(30), AndroidUtilities.dp(10), AndroidUtilities.dp(30), AndroidUtilities.dp(21)); + linearLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + linearLayout.addView(new SectionView(context, R.drawable.msg_message_s, LocaleController.getString("NotificationsPermissionAlert1")), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + linearLayout.addView(new SectionView(context, R.drawable.msg_members_list2, LocaleController.getString("NotificationsPermissionAlert2")), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + linearLayout.addView(new SectionView(context, R.drawable.msg_customize_s, LocaleController.getString("NotificationsPermissionAlert3")), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + setCustomView(linearLayout); + fixNavigationBar(getThemedColor(Theme.key_dialogBackground)); + + textView = new TextView(context); + textView.setText(LocaleController.getString("NotificationsPermissionContinue")); + textView.setGravity(Gravity.CENTER); + textView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); + textView.setBackground(Theme.AdaptiveRipple.filledRect(Theme.getColor(Theme.key_featuredStickers_addButton), 8)); + textView.setOnClickListener(e -> { + if (this.whenGranted != null) { + this.whenGranted.run(true); + this.whenGranted = null; + } + dismiss(); + }); + linearLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, 14, 14, 14, 10)); + + for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; ++a) { + try { + NotificationCenter.getInstance(a).addObserver(this, NotificationCenter.updateInterfaces); + } catch (Exception ignore) {} + } + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.updateInterfaces) { + int flags = (int) args[0]; + if ((flags & MessagesController.UPDATE_MASK_READ_DIALOG_MESSAGE) >= 0) { + updateCounter(); + } + } + } + + public void updateCounter() { + int counter = 0; + for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; ++a) { + MessagesStorage messagesStorage = MessagesStorage.getInstance(a); + if (messagesStorage != null) { + counter += messagesStorage.getMainUnreadCount(); + } + } + if (counterView.setCount(counter)) { + if (!rLottieImageView.isPlaying()) { + rLottieImageView.setProgress(0); + rLottieImageView.playAnimation(); + } + } + } + + private boolean mayBeAccidentalDismiss; + private long showTime; + + @Override + public void show() { + super.show(); + showTime = System.currentTimeMillis(); + } + + @Override + protected void onDismissWithTouchOutside() { + mayBeAccidentalDismiss = (System.currentTimeMillis() - showTime) < 3000L; + super.onDismissWithTouchOutside(); + } + + @Override + public void dismiss() { + super.dismiss(); + if (whenGranted != null) { + whenGranted.run(false); + whenGranted = null; + if (!mayBeAccidentalDismiss) { + askLater(); + } + } + for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; ++a) { + try { + NotificationCenter.getInstance(a).removeObserver(this, NotificationCenter.updateInterfaces); + } catch (Exception ignore) {} + } + } + + private static class CounterView extends View { + private final Paint fillPaint = new Paint(Paint.ANTI_ALIAS_FLAG), strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final AnimatedFloat alpha = new AnimatedFloat(this, 0, 320, CubicBezierInterpolator.EASE_OUT_QUINT); + + AnimatedTextView.AnimatedTextDrawable textDrawable = new AnimatedTextView.AnimatedTextDrawable(false, true, true); + + public CounterView(Context context) { + super(context); + + fillPaint.setColor(Theme.getColor(Theme.key_featuredStickers_addButton)); + strokePaint.setColor(Theme.getColor(Theme.key_dialogBackground)); + strokePaint.setStyle(Paint.Style.STROKE); + strokePaint.setStrokeWidth(AndroidUtilities.dp(4)); + + textDrawable.setCallback(this); + textDrawable.setAnimationProperties(.35f, 0, 200, CubicBezierInterpolator.EASE_OUT_QUINT); + textDrawable.getPaint().setStyle(Paint.Style.FILL_AND_STROKE); + textDrawable.getPaint().setStrokeWidth(AndroidUtilities.dp(.24f)); + textDrawable.getPaint().setStrokeJoin(Paint.Join.ROUND); + textDrawable.setTextSize(AndroidUtilities.dp(13.3f)); + textDrawable.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); + textDrawable.setOverrideFullWidth(AndroidUtilities.dp(64)); + textDrawable.setGravity(Gravity.CENTER_HORIZONTAL); + } + + private int lastCount; + public boolean setCount(int count) { + if (lastCount != count) { + boolean more = lastCount < count; + lastCount = count; + textDrawable.setText(lastCount > 0 ? "" + lastCount : "", true); + if (more) { + animateBounce(); + } + return more; + } + return false; + } + + private float countScale = 1; + private ValueAnimator countAnimator; + private void animateBounce() { + if (countAnimator != null) { + countAnimator.cancel(); + countAnimator = null; + } + + countAnimator = ValueAnimator.ofFloat(0, 1); + countAnimator.addUpdateListener(anm -> { + countScale = Math.max(1, (float) anm.getAnimatedValue()); + invalidate(); + }); + countAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + countScale = 1; + invalidate(); + } + }); + countAnimator.setInterpolator(new OvershootInterpolator(2.0f)); + countAnimator.setDuration(200); + countAnimator.start(); + } + + @Override + protected void onDraw(Canvas canvas) { + float alpha = this.alpha.set(lastCount > 0 ? 1 : 0); + + canvas.save(); + canvas.scale(countScale * alpha, countScale * alpha, getWidth() / 2f, getHeight() / 2f); + + float w = textDrawable.getCurrentWidth() + AndroidUtilities.dpf2(12.66f), h = AndroidUtilities.dpf2(20.3f); + AndroidUtilities.rectTmp.set((getWidth() - w) / 2f, (getHeight() - h) / 2f, (getWidth() + w) / 2f, (getHeight() + h) / 2f); + + strokePaint.setAlpha((int) (0xFF * alpha)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(30), AndroidUtilities.dp(30), strokePaint); + fillPaint.setAlpha((int) (0xFF * alpha)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(30), AndroidUtilities.dp(30), fillPaint); + + canvas.save(); + canvas.translate(0, -AndroidUtilities.dp(1)); + textDrawable.setBounds(0, 0, getWidth(), getHeight()); + textDrawable.draw(canvas); + canvas.restore(); + + canvas.restore(); + } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == textDrawable || super.verifyDrawable(who); + } + } + + + private static class SectionView extends FrameLayout { + public SectionView(Context context, int resId, CharSequence text) { + super(context); + + setPadding(0, AndroidUtilities.dp(7), 0, AndroidUtilities.dp(7)); + + ImageView imageView = new ImageView(context); + imageView.setImageResource(resId); + imageView.setScaleType(ImageView.ScaleType.CENTER); + imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogTextBlack), PorterDuff.Mode.MULTIPLY)); + addView(imageView, LayoutHelper.createFrame(24, 24, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 0 : 22, 0, LocaleController.isRTL ? 22 : 0, 0)); + + TextView textView = new TextView(context); + textView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + textView.setText(text); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.FILL_HORIZONTAL, LocaleController.isRTL ? 0 : 61, 0, LocaleController.isRTL ? 61 : 0, 0)); + } + } + + public static boolean shouldAsk(Activity activity) { + if (activity == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.M || activity.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) { + return false; + } + long askAfter = MessagesController.getGlobalMainSettings().getLong("askNotificationsAfter", -1); + return askAfter != -2 && (askAfter < 0 || System.currentTimeMillis() >= askAfter); + } + + public static void askLater() { + long askAfter; + final long day = 1000L * 60L * 60L * 24L; + long nextDuration = MessagesController.getGlobalMainSettings().getLong("askNotificationsDuration", day); + askAfter = System.currentTimeMillis() + nextDuration; + if (nextDuration < day * 3) { + nextDuration = day * 3; + } else if (nextDuration < day * 7) { + nextDuration = day * 7; + } else { + nextDuration = day * 30; + } + MessagesController.getGlobalMainSettings().edit().putLong("askNotificationsAfter", askAfter).putLong("askNotificationsDuration", nextDuration).apply(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java index 1a8a5a4cdc4..9e8affb5671 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PaymentFormActivity.java @@ -3240,7 +3240,9 @@ public void onActivityResultFragment(int requestCode, int resultCode, Intent dat } showEditDoneProgress(true, false); setDonePressed(false); - googlePayButton.setClickable(true); + if (googlePayButton != null) { + googlePayButton.setClickable(true); + } }); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PeopleNearbyActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PeopleNearbyActivity.java index 15d072785a4..1bd4b12df29 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PeopleNearbyActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PeopleNearbyActivity.java @@ -709,7 +709,7 @@ public void onBecomeFullyHidden() { } @Override - public void onLocationAddressAvailable(String address, String displayAddress, Location location) { + public void onLocationAddressAvailable(String address, String displayAddress, TLRPC.TL_messageMediaVenue city, TLRPC.TL_messageMediaVenue street, Location location) { currentGroupCreateAddress = address; currentGroupCreateDisplayAddress = displayAddress; currentGroupCreateLocation = location; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index b3287f2f53d..b5db1275071 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -34,6 +34,7 @@ import android.graphics.Matrix; import android.graphics.Outline; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; @@ -61,6 +62,7 @@ import android.text.TextUtils; import android.text.style.ClickableSpan; import android.text.style.URLSpan; +import android.text.util.Linkify; import android.transition.ChangeBounds; import android.transition.Fade; import android.transition.Transition; @@ -68,6 +70,7 @@ import android.transition.TransitionSet; import android.transition.TransitionValues; import android.util.FloatProperty; +import android.util.Log; import android.util.Pair; import android.util.Property; import android.util.Range; @@ -153,6 +156,7 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.MessageCustomParamsHelper; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; @@ -161,6 +165,7 @@ import org.telegram.messenger.SecureDocument; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.TranslateController; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; @@ -215,6 +220,7 @@ import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LinkPath; import org.telegram.ui.Components.LinkSpanDrawable; +import org.telegram.ui.Components.LoadingDrawable; import org.telegram.ui.Components.MediaActivity; import org.telegram.ui.Components.NumberPicker; import org.telegram.ui.Components.OptionsSpeedIconDrawable; @@ -238,6 +244,7 @@ import org.telegram.ui.Components.StickersAlert; import org.telegram.ui.Components.TextViewSwitcher; import org.telegram.ui.Components.Tooltip; +import org.telegram.ui.Components.TranslateAlert2; import org.telegram.ui.Components.URLSpanReplacement; import org.telegram.ui.Components.URLSpanUserMentionPhotoViewer; import org.telegram.ui.Components.UndoView; @@ -249,6 +256,8 @@ import org.telegram.ui.Components.VideoTimelinePlayView; import org.telegram.ui.Components.ViewHelper; import org.telegram.ui.Components.spoilers.SpoilersTextView; +import org.telegram.ui.Stories.DarkThemeResourceProvider; +import org.telegram.ui.Stories.StoryCaptionView; import java.io.ByteArrayInputStream; import java.io.File; @@ -825,6 +834,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { private boolean dontChangeCaptionPosition; private boolean captionHwLayerEnabled; private ImageUpdater.AvatarFor setAvatarFor; + private boolean lastCaptionTranslating; private Paint bitmapPaint = new Paint(Paint.FILTER_BITMAP_FLAG); @@ -1032,7 +1042,7 @@ public int getClassGuid() { public void setCaption(CharSequence caption) { hasCaptionForAllMedia = true; captionForAllMedia = caption; - setCurrentCaption(null, caption, false); + setCurrentCaption(null, caption, false, false); updateCaptionTextForCurrentPhoto(null); } @@ -1628,6 +1638,8 @@ public void restore() { private boolean ignoreDidSetImage; private boolean dontAutoPlay; boolean fromCamera; + private boolean captionTranslated; + private String captionDetectedLanguage; private long avatarsDialogId; private boolean canEditAvatar; @@ -1753,6 +1765,8 @@ public interface PageBlocksAdapter { private final static int gallery_menu_share2 = 18; private final static int gallery_menu_speed = 19; private final static int gallery_menu_paint = 20; + private final static int gallery_menu_translate = 21; + private final static int gallery_menu_hide_translation = 22; private static DecelerateInterpolator decelerateInterpolator; private static Paint progressPaint; @@ -4412,6 +4426,9 @@ protected void onDetachedFromWindow() { @Override public boolean dispatchKeyEventPreIme(KeyEvent event) { if (event != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) { + if (textSelectionHelper.isInSelectionMode()) { + textSelectionHelper.clear(); + } if (captionEditText.isPopupShowing() || captionEditText.isKeyboardVisible()) { closeCaptionEnter(true); return false; @@ -4468,9 +4485,8 @@ public int getBottomOffset(int tag) { @Override public boolean dispatchTouchEvent(MotionEvent ev) { + textSelectionHelper.getOverlayView(getContext()).checkCancelAction(ev); if (textSelectionHelper.isInSelectionMode()) { - textSelectionHelper.getOverlayView(getContext()).checkCancelAction(ev); - if (textSelectionHelper.getOverlayView(getContext()).onTouchEvent(ev)) { return true; } @@ -5299,6 +5315,25 @@ public void dismiss() { thumb = null; } placeProvider.openPhotoForEdit(f.getAbsolutePath(), thumb, isVideo); + } else if (id == gallery_menu_translate) { + if (switchingToIndex < 0 || switchingToIndex >= imagesArr.size()) { + return; + } + MessageObject messageObject = imagesArr.get(switchingToIndex); + captionTranslated = true; + AndroidUtilities.runOnUIThread(() -> { + menuItem.hideSubItem(gallery_menu_translate); + menuItem.showSubItem(gallery_menu_hide_translation); + }, 32); + updateCaptionTranslated(); + MessagesController.getInstance(currentAccount).getTranslateController().translatePhoto(messageObject, PhotoViewer.this::updateCaptionTranslated); + } else if (id == gallery_menu_hide_translation) { + captionTranslated = false; + AndroidUtilities.runOnUIThread(() -> { + menuItem.showSubItem(gallery_menu_translate); + menuItem.hideSubItem(gallery_menu_hide_translation); + }, 32); + updateCaptionTranslated(); } } @@ -5379,9 +5414,13 @@ public void onSpeedSelected(float speed, boolean isFinal, boolean closeMenu) { menuItem.addSubItem(gallery_menu_save, R.drawable.msg_gallery, LocaleController.getString("SaveToGallery", R.string.SaveToGallery)).setColors(0xfffafafa, 0xfffafafa); //menuItem.addSubItem(gallery_menu_edit_avatar, R.drawable.photo_paint, LocaleController.getString("EditPhoto", R.string.EditPhoto)).setColors(0xfffafafa, 0xfffafafa); menuItem.addSubItem(gallery_menu_set_as_main, R.drawable.msg_openprofile, LocaleController.getString("SetAsMain", R.string.SetAsMain)).setColors(0xfffafafa, 0xfffafafa); + menuItem.addSubItem(gallery_menu_translate, R.drawable.msg_translate, LocaleController.getString(R.string.TranslateMessage)).setColors(0xfffafafa, 0xfffafafa); + menuItem.addSubItem(gallery_menu_hide_translation, R.drawable.msg_translate, LocaleController.getString(R.string.HideTranslation)).setColors(0xfffafafa, 0xfffafafa); menuItem.addSubItem(gallery_menu_delete, R.drawable.msg_delete, LocaleController.getString("Delete", R.string.Delete)).setColors(0xfffafafa, 0xfffafafa); menuItem.addSubItem(gallery_menu_cancel_loading, R.drawable.msg_cancel, LocaleController.getString("StopDownload", R.string.StopDownload)).setColors(0xfffafafa, 0xfffafafa); menuItem.redrawPopup(0xf9222222); + menuItem.hideSubItem(gallery_menu_translate); + menuItem.hideSubItem(gallery_menu_hide_translation); setMenuItemIcon(false, true); menuItem.setPopupItemsSelectorColor(0x0fffffff); @@ -5522,7 +5561,7 @@ public boolean validGroupId(long groupId) { } captionTextViewSwitcher = new CaptionTextViewSwitcher(containerView.getContext()); - captionTextViewSwitcher.setFactory(() -> createCaptionTextView()); + captionTextViewSwitcher.setFactory(() -> new CaptionTextView(activityContext)); captionTextViewSwitcher.setVisibility(View.INVISIBLE); setCaptionHwLayerEnabled(true); @@ -6026,7 +6065,8 @@ public void setAlpha(float alpha) { if (placeProvider != null && !placeProvider.allowSendingSubmenu()) { return false; } - if (parentChatActivity == null || parentChatActivity.isInScheduleMode()) { + boolean isStoryViewer = parentFragment != null && parentFragment.storyViewer != null && parentFragment.storyViewer.isShown(); + if (!isStoryViewer && (parentChatActivity == null || parentChatActivity.isInScheduleMode())) { return false; } if (captionEditText.getCaptionLimitOffset() < 0) { @@ -7056,7 +7096,13 @@ public void onContextClick(TLRPC.BotInlineResult result) { doneButtonFullWidth.setBackground(Theme.AdaptiveRipple.filledRect(getThemedColor(Theme.key_featuredStickers_addButton), 6)); doneButtonFullWidth.setTextColor(getThemedColor(Theme.key_featuredStickers_buttonText)); - textSelectionHelper = new TextSelectionHelper.SimpleTextSelectionHelper(null, resourcesProvider); + textSelectionHelper = new TextSelectionHelper.SimpleTextSelectionHelper(null, new DarkThemeResourceProvider()) { + @Override + public int getParentBottomPadding() { + return 0;//AndroidUtilities.dp(80); + } + }; + textSelectionHelper.allowScrollPrentRelative = true; textSelectionHelper.useMovingOffset = false; View overlay = textSelectionHelper.getOverlayView(windowView.getContext()); if (overlay != null) { @@ -7427,153 +7473,222 @@ public void onAnimationCancel(Animator animation) { }).start(); } - private TextView createCaptionTextView() { - SpoilersTextView textView = new SpoilersTextView(activityContext) { + private class CaptionTextView extends SpoilersTextView { + public CaptionTextView(Context context) { + super(context); + ViewHelper.setPadding(this, 16, 8, 16, 8); + setLinkTextColor(0xff79c4fc); + setTextColor(0xffffffff); + setHighlightColor(0x33ffffff); + setGravity(Gravity.CENTER_VERTICAL | LayoutHelper.getAbsoluteGravityStart()); + setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + setOnClickListener((v) -> { + if (!needCaptionLayout) { + captionScrollView.smoothScrollBy(0, AndroidUtilities.dp(64)); + return; + } + openCaptionEnter(); + }); + } - private LinkSpanDrawable pressedLink; - private LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(this); + private LinkSpanDrawable pressedLink; + private LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(this); - @Override - public boolean onTouchEvent(MotionEvent event) { - if (getLayout() == null) { - return false; - } - if (textSelectionHelper != null && getStaticTextLayout() != null) { - textSelectionHelper.setSelectabeleView(this); - textSelectionHelper.update(getPaddingLeft(), getPaddingTop()); - textSelectionHelper.onTouchEvent(event); - } - boolean linkResult = false; - if (event.getAction() == MotionEvent.ACTION_DOWN || pressedLink != null && event.getAction() == MotionEvent.ACTION_UP) { - int x = (int) (event.getX() - getPaddingLeft()); - int y = (int) (event.getY() - getPaddingTop()); - final int line = getLayout().getLineForVertical(y); - final int off = getLayout().getOffsetForHorizontal(line, x); - final float left = getLayout().getLineLeft(line); - - ClickableSpan touchLink = null; - if (left <= x && left + getLayout().getLineWidth(line) >= x && y >= 0 && y <= getLayout().getHeight()) { - Spannable buffer = new SpannableString(getText()); - ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); - if (link.length != 0) { - touchLink = link[0]; - if (event.getAction() == MotionEvent.ACTION_DOWN) { - linkResult = true; - links.clear(); - pressedLink = new LinkSpanDrawable<>(link[0], null, event.getX(), event.getY()); - pressedLink.setColor(0x6662a9e3); - links.addLink(pressedLink); - int start = buffer.getSpanStart(pressedLink.getSpan()); - int end = buffer.getSpanEnd(pressedLink.getSpan()); - LinkPath path = pressedLink.obtainNewPath(); - path.setCurrentLayout(getLayout(), start, getPaddingTop()); - getLayout().getSelectionPath(start, end, path); - - final LinkSpanDrawable savedPressedLink = pressedLink; - postDelayed(() -> { - if (savedPressedLink == pressedLink && pressedLink != null && pressedLink.getSpan() instanceof URLSpan) { - onLinkLongPress((URLSpan) pressedLink.getSpan(), this, () -> links.clear()); - pressedLink = null; - } - }, ViewConfiguration.getLongPressTimeout()); - } - } - } - if (event.getAction() == MotionEvent.ACTION_UP) { - links.clear(); - if (pressedLink != null && pressedLink.getSpan() == touchLink) { - onLinkClick(pressedLink.getSpan(), this); + @Override + public boolean onTouchEvent(MotionEvent event) { + if (getLayout() == null) { + return false; + } + if (textSelectionHelper != null && getStaticTextLayout() != null) { + textSelectionHelper.setSelectabeleView(this); + textSelectionHelper.setScrollingParent(captionScrollView); + textSelectionHelper.update(getPaddingLeft(), getPaddingTop()); + textSelectionHelper.onTouchEvent(event); + } + boolean linkResult = false; + if (event.getAction() == MotionEvent.ACTION_DOWN || pressedLink != null && event.getAction() == MotionEvent.ACTION_UP) { + int x = (int) (event.getX() - getPaddingLeft()); + int y = (int) (event.getY() - getPaddingTop()); + final int line = getLayout().getLineForVertical(y); + final int off = getLayout().getOffsetForHorizontal(line, x); + final float left = getLayout().getLineLeft(line); + + ClickableSpan touchLink = null; + if (left <= x && left + getLayout().getLineWidth(line) >= x && y >= 0 && y <= getLayout().getHeight()) { + Spannable buffer = new SpannableString(getText()); + ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); + if (link.length != 0) { + touchLink = link[0]; + if (event.getAction() == MotionEvent.ACTION_DOWN) { + linkResult = true; + links.clear(); + pressedLink = new LinkSpanDrawable<>(link[0], null, event.getX(), event.getY()); + pressedLink.setColor(0x6662a9e3); + links.addLink(pressedLink); + int start = buffer.getSpanStart(pressedLink.getSpan()); + int end = buffer.getSpanEnd(pressedLink.getSpan()); + LinkPath path = pressedLink.obtainNewPath(); + path.setCurrentLayout(getLayout(), start, getPaddingTop()); + getLayout().getSelectionPath(start, end, path); + + final LinkSpanDrawable savedPressedLink = pressedLink; + postDelayed(() -> { + if (savedPressedLink == pressedLink && pressedLink != null && pressedLink.getSpan() instanceof URLSpan) { + onLinkLongPress((URLSpan) pressedLink.getSpan(), this, () -> links.clear()); + pressedLink = null; + } + }, ViewConfiguration.getLongPressTimeout()); } - pressedLink = null; - linkResult = true; } - } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { + } + if (event.getAction() == MotionEvent.ACTION_UP) { links.clear(); + if (pressedLink != null && pressedLink.getSpan() == touchLink) { + onLinkClick(pressedLink.getSpan(), this); + } pressedLink = null; linkResult = true; } - - boolean b = linkResult || super.onTouchEvent(event); - return bottomTouchEnabled && b; + } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { + links.clear(); + pressedLink = null; + linkResult = true; } + boolean b = linkResult || super.onTouchEvent(event); + return bottomTouchEnabled && b; + } - @Override - public void setPressed(boolean pressed) { - final boolean needsRefresh = pressed != isPressed(); - super.setPressed(pressed); - if (needsRefresh) { - invalidate(); - } + @Override + public void setPressed(boolean pressed) { + final boolean needsRefresh = pressed != isPressed(); + super.setPressed(pressed); + if (needsRefresh) { + invalidate(); } + } - private Layout lastLayout; - - @Override - protected void onDraw(Canvas canvas) { - if (textSelectionHelper != null && textSelectionHelper.isInSelectionMode()) { - canvas.save(); - canvas.translate(getPaddingLeft(), getPaddingTop()); - if (textSelectionHelper != null && getStaticTextLayout() != null && textSelectionHelper.isCurrent(this)) { - textSelectionHelper.draw(canvas); - } - canvas.restore(); - } + private Layout lastLayout; + @Override + protected void onDraw(Canvas canvas) { + if (textSelectionHelper != null && textSelectionHelper.isInSelectionMode()) { canvas.save(); - canvas.translate(getPaddingLeft(), 0); - if (links.draw(canvas)) { - invalidate(); + canvas.translate(getPaddingLeft(), getPaddingTop()); + if (textSelectionHelper != null && getStaticTextLayout() != null && textSelectionHelper.isCurrent(this)) { + textSelectionHelper.draw(canvas); } canvas.restore(); - super.onDraw(canvas); - if (lastLayout != getLayout()) { - animatedEmojiDrawables = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, animatedEmojiDrawables, getLayout()); - lastLayout = getLayout(); - } } - private AnimatedEmojiSpan.EmojiGroupedSpans animatedEmojiDrawables; - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - AnimatedEmojiSpan.release(this, animatedEmojiDrawables); + canvas.save(); + canvas.translate(getPaddingLeft(), 0); + if (links.draw(canvas)) { + invalidate(); } - - @Override - protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { - super.onTextChanged(text, start, lengthBefore, lengthAfter); + canvas.restore(); + super.onDraw(canvas); + if (lastLayout != getLayout()) { animatedEmojiDrawables = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, animatedEmojiDrawables, getLayout()); + lastLayout = getLayout(); } + } - private final ColorFilter emojiTextColorFilter = new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN); + private AnimatedEmojiSpan.EmojiGroupedSpans animatedEmojiDrawables; - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); - canvas.save(); - canvas.translate(getPaddingLeft(), getPaddingTop()); - canvas.clipRect(0, getScrollY(), getWidth() - getPaddingRight(), getHeight() + getScrollY() - getPaddingBottom() * .75f); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, getLayout(), animatedEmojiDrawables, 0, null, 0, 0, 0, 1f); + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + AnimatedEmojiSpan.release(this, animatedEmojiDrawables); + } + + @Override + protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { + super.onTextChanged(text, start, lengthBefore, lengthAfter); + animatedEmojiDrawables = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, animatedEmojiDrawables, getLayout()); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (loading) { + checkLoadingPath(); + if (loadingDrawable == null) { + loadingDrawable = new LoadingDrawable(); + loadingDrawable.usePath(loadingPath); + loadingDrawable.setRadiiDp(4); + loadingDrawable.setColors( + Theme.multAlpha(Color.WHITE, .3f), + Theme.multAlpha(Color.WHITE, .1f), + Theme.multAlpha(Color.WHITE, .2f), + Theme.multAlpha(Color.WHITE, .7f) + ); + loadingDrawable.setCallback(CaptionTextView.this); + } + loadingDrawable.setBounds(0, 0, getWidth(), getHeight()); + loadingDrawable.draw(canvas); + } + if (loading) { + canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), 0xb2, Canvas.ALL_SAVE_FLAG); + } + super.dispatchDraw(canvas); + if (loading) { canvas.restore(); } - }; + canvas.save(); + canvas.translate(getPaddingLeft(), getPaddingTop()); + canvas.clipRect(0, getScrollY(), getWidth() - getPaddingRight(), getHeight() + getScrollY() - getPaddingBottom() * .75f); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, getLayout(), animatedEmojiDrawables, 0, null, 0, 0, 0, 1f); + canvas.restore(); + } - ViewHelper.setPadding(textView, 16, 8, 16, 8); - textView.setLinkTextColor(0xff79c4fc); - textView.setTextColor(0xffffffff); - textView.setHighlightColor(0x33ffffff); - textView.setGravity(Gravity.CENTER_VERTICAL | LayoutHelper.getAbsoluteGravityStart()); - textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - textView.setOnClickListener((v) -> { - if (!needCaptionLayout) { - captionScrollView.smoothScrollBy(0, AndroidUtilities.dp(64)); + public void setLoading(boolean loading) { + if (this.loading == loading) { return; } - openCaptionEnter(); - }); - return textView; + this.loading = loading; + invalidate(); + } + + private boolean loading; + private LoadingDrawable loadingDrawable; + + private Layout lastLoadingLayout; + private Path loadingPath; + private void checkLoadingPath() { + Layout layout = getLayout(); + if (loadingPath != null && lastLoadingLayout == layout) { + return; + } + if (loadingPath == null) { + loadingPath = new Path(); + } else { + loadingPath.rewind(); + } + if (layout != null) { + final float horizontalPadding = AndroidUtilities.dp(16); + final float verticalPadding = AndroidUtilities.dp(8); + float t = 0; + for (int i = 0; i < layout.getLineCount(); ++i) { + float l = layout.getLineLeft(i) - horizontalPadding / 3f; + float r = layout.getLineRight(i) + horizontalPadding / 3f; + if (i == 0) { + t = layout.getLineTop(i) - verticalPadding / 3f; + } + float b = layout.getLineBottom(i); + if (i >= layout.getLineCount() - 1) { + b += verticalPadding / 3f; + } + loadingPath.addRect(getPaddingLeft() + l, getPaddingTop() + t, getPaddingLeft() + r, getPaddingTop() + b, Path.Direction.CW); + t = b; + } + } + lastLoadingLayout = layout; + } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == loadingDrawable || super.verifyDrawable(who); + } } private int getLeftInset() { @@ -8428,7 +8543,7 @@ private void closeCaptionEnter(boolean apply) { if (placeProvider != null) { placeProvider.onApplyCaption(caption); } - setCurrentCaption(null, result[0], false); + setCurrentCaption(null, result[0], false, false); } captionEditText.setTag(null); if (isCurrentVideo && customTitle == null) { @@ -12100,6 +12215,7 @@ private void setIsAboutToSwitchToIndex(int index, boolean init, boolean animated boolean isVideo = false; CharSequence caption = null; + boolean captionTranslating = false; String newFileName = getFileName(index); MessageObject newMessageObject = null; @@ -12147,7 +12263,47 @@ private void setIsAboutToSwitchToIndex(int index, boolean init, boolean animated caption = MessageObject.getMedia(newMessageObject.messageOwner).description; allowShare = false; // captionTextViewSwitcher.setTranslationY(AndroidUtilities.dp(48)); + menuItem.hideSubItem(gallery_menu_translate); + menuItem.hideSubItem(gallery_menu_hide_translation); } else { + TranslateController translateController = MessagesController.getInstance(currentAccount).getTranslateController(); + if (wasIndex != switchingToIndex) { + captionTranslated = false; + captionDetectedLanguage = null; + } + if (translateController.isContextTranslateEnabled()) { + final MessageObject messageObject = newMessageObject; + translateController.detectPhotoLanguage(messageObject, lng -> { + if (index != switchingToIndex) { + return; + } + captionDetectedLanguage = lng; + if (translateController.isContextTranslateEnabled() && translateController.canTranslatePhoto(messageObject, captionDetectedLanguage)) { + if (captionTranslated) { + menuItem.showSubItem(gallery_menu_hide_translation); + menuItem.hideSubItem(gallery_menu_translate); + } else { + menuItem.showSubItem(gallery_menu_translate); + menuItem.hideSubItem(gallery_menu_hide_translation); + } + } else { + menuItem.hideSubItem(gallery_menu_translate); + menuItem.hideSubItem(gallery_menu_hide_translation); + } + }); + } + if (translateController.isContextTranslateEnabled() && translateController.canTranslatePhoto(newMessageObject, captionDetectedLanguage)) { + if (captionTranslated) { + menuItem.showSubItem(gallery_menu_hide_translation); + menuItem.hideSubItem(gallery_menu_translate); + } else { + menuItem.showSubItem(gallery_menu_translate); + menuItem.hideSubItem(gallery_menu_hide_translation); + } + } else { + menuItem.hideSubItem(gallery_menu_translate); + menuItem.hideSubItem(gallery_menu_hide_translation); + } allowShare = !noforwards; if (newMessageObject.isNewGif() && allowShare && !DialogObject.isEncryptedDialog(newMessageObject.getDialogId())) { menuItem.showSubItem(gallery_menu_savegif); @@ -12203,8 +12359,11 @@ private void setIsAboutToSwitchToIndex(int index, boolean init, boolean animated String restrictionReason = MessagesController.getRestrictionReason(newMessageObject.messageOwner.restriction_reason); if (!TextUtils.isEmpty(restrictionReason)) { caption = restrictionReason; + } else if (captionTranslated && newMessageObject.messageOwner != null && newMessageObject.messageOwner.translatedText != null && TextUtils.equals(newMessageObject.messageOwner.translatedToLanguage, TranslateAlert2.getToLanguage())) { + caption = postProcessTranslated(newMessageObject); } else { caption = newMessageObject.caption; + captionTranslating = captionTranslated; } } @@ -12320,6 +12479,8 @@ private void setIsAboutToSwitchToIndex(int index, boolean init, boolean animated allowShare = false; menuItem.showSubItem(gallery_menu_delete); menuItem.hideSubItem(gallery_menu_save); + menuItem.hideSubItem(gallery_menu_translate); + menuItem.hideSubItem(gallery_menu_hide_translation); if (countView != null) { countView.updateShow(secureDocuments.size() > 1, true); countView.set(switchingToIndex + 1, secureDocuments.size()); @@ -12331,6 +12492,8 @@ private void setIsAboutToSwitchToIndex(int index, boolean init, boolean animated if (index < 0 || index >= imagesArrLocations.size()) { return; } + menuItem.hideSubItem(gallery_menu_translate); + menuItem.hideSubItem(gallery_menu_hide_translation); if (canEditAvatar && !avatarsArr.isEmpty()) { menuItem.showSubItem(gallery_menu_edit_avatar); boolean currentSet = isCurrentAvatarSet(); @@ -12379,6 +12542,8 @@ private void setIsAboutToSwitchToIndex(int index, boolean init, boolean animated if (index < 0 || index >= imagesArrLocals.size()) { return; } + menuItem.hideSubItem(gallery_menu_translate); + menuItem.hideSubItem(gallery_menu_hide_translation); Object object = imagesArrLocals.get(index); int ttl = 0; boolean isFiltered = false; @@ -12585,6 +12750,8 @@ private void setIsAboutToSwitchToIndex(int index, boolean init, boolean animated if (switchingToIndex < 0 || switchingToIndex >= size) { return; } + menuItem.hideSubItem(gallery_menu_translate); + menuItem.hideSubItem(gallery_menu_hide_translation); allowShare = !MessagesController.getInstance(currentAccount).isChatNoForwards(-currentDialogId) && (currentMessageObject == null || !currentMessageObject.hasRevealedExtendedMedia()); TLRPC.PageBlock pageBlock = pageBlocksAdapter.get(switchingToIndex); caption = pageBlocksAdapter.getCaption(switchingToIndex); @@ -12638,6 +12805,9 @@ private void setIsAboutToSwitchToIndex(int index, boolean init, boolean animated } groupedPhotosListView.fillList(); pageBlocksAdapter.updateSlideshowCell(pageBlock); + } else { + menuItem.hideSubItem(gallery_menu_translate); + menuItem.hideSubItem(gallery_menu_hide_translation); } if (title != null) { if (animated) { @@ -12650,7 +12820,48 @@ private void setIsAboutToSwitchToIndex(int index, boolean init, boolean animated actionBarContainer.setTitle(title); } } - setCurrentCaption(newMessageObject, caption, animateCaption); + setCurrentCaption(newMessageObject, caption, captionTranslating, animateCaption); + } + + private void updateCaptionTranslated() { + if (!imagesArr.isEmpty()) { + if (switchingToIndex < 0 || switchingToIndex >= imagesArr.size()) { + return; + } + MessageObject messageObject = imagesArr.get(switchingToIndex); + if (messageObject == null) { + return; + } + if (captionTranslated && messageObject.messageOwner != null && messageObject.messageOwner.translatedText != null && TextUtils.equals(messageObject.messageOwner.translatedToLanguage, TranslateAlert2.getToLanguage())) { + setCurrentCaption(messageObject, postProcessTranslated(messageObject), false, true); + } else { + setCurrentCaption(messageObject, messageObject.caption, captionTranslated, true); + } + } + } + + private CharSequence postProcessTranslated(MessageObject messageObject) { + if (messageObject == null || messageObject.messageOwner == null) { + return ""; + } + CharSequence message = new SpannableStringBuilder(messageObject.messageOwner.translatedText.text); + message = Emoji.replaceEmoji(message, Theme.chat_msgTextPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); + message = MessageObject.replaceAnimatedEmoji(message, messageObject.messageOwner.translatedText.entities, Theme.chat_msgTextPaint.getFontMetricsInt(), false); + if (MessageObject.containsUrls(message)) { + try { + AndroidUtilities.addLinks((Spannable) message, Linkify.WEB_URLS | Linkify.PHONE_NUMBERS); + } catch (Exception e) { + FileLog.e(e); + } + } + MessageObject.addUrlsByPattern(messageObject.isOutOwner(), message, true, 0, 0, true); + MessageObject.addEntitiesToText(message, messageObject.messageOwner.translatedText.entities, messageObject.isOutOwner(), true, true, true); + if (messageObject.isVideo()) { + MessageObject.addUrlsByPattern(messageObject.isOutOwner(), message, true, 3, (int) messageObject.getDuration(), false); + } else if (messageObject.isMusic() || messageObject.isVoice()) { + MessageObject.addUrlsByPattern(messageObject.isOutOwner(), message, true, 4, (int) messageObject.getDuration(), false); + } + return message; } private void showVideoTimeline(boolean show, boolean animated) { @@ -13053,7 +13264,7 @@ private void resetIndexForDeferredImageLoading() { } } - private void setCurrentCaption(MessageObject messageObject, final CharSequence _caption, boolean animated) { + private void setCurrentCaption(MessageObject messageObject, final CharSequence _caption, boolean translating, boolean animated) { final CharSequence caption = AnimatedEmojiSpan.cloneSpans(_caption); if (needCaptionLayout) { if (captionTextViewSwitcher.getParent() != pickerView) { @@ -13243,10 +13454,13 @@ public void onAnimationEnd(Animator animation) { } } + boolean switchedToNext = false; if (!isCaptionEmpty) { Theme.createChatResources(null, true); CharSequence str; - if (messageObject != null && !messageObject.messageOwner.entities.isEmpty()) { + if (messageObject != null && captionTranslated && messageObject.messageOwner != null && messageObject.messageOwner.translatedText != null && TextUtils.equals(messageObject.messageOwner.translatedToLanguage, TranslateAlert2.getToLanguage())) { + str = caption; + } else if (messageObject != null && !messageObject.messageOwner.entities.isEmpty()) { Spannable spannableString = new SpannableString(caption); messageObject.addEntitiesToText(spannableString, true, false); if (messageObject.isVideo()) { @@ -13258,7 +13472,7 @@ public void onAnimationEnd(Animator animation) { } captionTextViewSwitcher.setTag(str); try { - captionTextViewSwitcher.setText(str, animated); + switchedToNext = captionTextViewSwitcher.setText(str, animated, lastCaptionTranslating != translating); if (captionScrollView != null) { captionScrollView.updateTopMargin(); } @@ -13282,6 +13496,10 @@ public void onAnimationEnd(Animator animation) { captionTextViewSwitcher.setTag(null); } } + if (captionTextViewSwitcher.getCurrentView() instanceof CaptionTextView) { + ((CaptionTextView) captionTextViewSwitcher.getCurrentView()).setLoading(translating); + } + lastCaptionTranslating = !isCaptionEmpty && translating; } private void setCaptionHwLayerEnabled(boolean enabled) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PremiumFeatureCell.java b/TMessagesProj/src/main/java/org/telegram/ui/PremiumFeatureCell.java index 54668ef93b7..4b93584b824 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PremiumFeatureCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PremiumFeatureCell.java @@ -9,14 +9,17 @@ import android.widget.LinearLayout; import android.widget.TextView; +import androidx.core.content.ContextCompat; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.LayoutHelper; public class PremiumFeatureCell extends FrameLayout { - private final TextView title; + private final SimpleTextView title; private final TextView description; public ImageView imageView; boolean drawDivider; @@ -28,9 +31,11 @@ public PremiumFeatureCell(Context context) { LinearLayout linearLayout = new LinearLayout(context); linearLayout.setOrientation(LinearLayout.VERTICAL); - title = new TextView(context); + setClipChildren(false); + linearLayout.setClipChildren(false); + title = new SimpleTextView(context); title.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + title.setTextSize(15); title.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); linearLayout.addView(title, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java index 7d3ffcc62f6..e86f2eb71f1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java @@ -23,6 +23,7 @@ import android.net.Uri; import android.os.Build; import android.text.SpannableString; +import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; import android.util.TypedValue; @@ -81,6 +82,7 @@ import org.telegram.ui.Components.Premium.PremiumNotAvailableBottomSheet; import org.telegram.ui.Components.Premium.PremiumTierCell; import org.telegram.ui.Components.Premium.StarParticlesView; +import org.telegram.ui.Components.Premium.StoriesPageView; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.SimpleThemeDescription; import org.telegram.ui.Components.TextStyleSpan; @@ -149,6 +151,15 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification public final static int PREMIUM_FEATURE_ANIMATED_EMOJI = 11; public final static int PREMIUM_FEATURE_EMOJI_STATUS = 12; public final static int PREMIUM_FEATURE_TRANSLATIONS = 13; + public final static int PREMIUM_FEATURE_STORIES = 14; + public final static int PREMIUM_FEATURE_STORIES_STEALTH_MODE = 15; + public final static int PREMIUM_FEATURE_STORIES_VIEWS_HISTORY = 16; + public final static int PREMIUM_FEATURE_STORIES_EXPIRATION_DURATION = 17; + public final static int PREMIUM_FEATURE_STORIES_SAVE_TO_GALLERY = 18; + public final static int PREMIUM_FEATURE_STORIES_LINKS_AND_FORMATTING = 19; + public static final int PREMIUM_FEATURE_STORIES_PRIORITY_ORDER = 20; + public static final int PREMIUM_FEATURE_STORIES_CAPTION = 21; + private int statusBarHeight; private int firstViewHeight; private boolean isDialogVisible; @@ -201,6 +212,22 @@ public static int serverStringToFeatureType(String s) { return PREMIUM_FEATURE_EMOJI_STATUS; case "translations": return PREMIUM_FEATURE_TRANSLATIONS; + case "stories": + return PREMIUM_FEATURE_STORIES; + case "stories__stealth_mode": + return PREMIUM_FEATURE_STORIES_STEALTH_MODE; + case "stories__permanent_views_history": + return PREMIUM_FEATURE_STORIES_VIEWS_HISTORY; + case "stories__expiration_durations": + return PREMIUM_FEATURE_STORIES_EXPIRATION_DURATION; + case "stories__save_stories_to_gallery": + return PREMIUM_FEATURE_STORIES_SAVE_TO_GALLERY; + case "stories__links_and_formatting": + return PREMIUM_FEATURE_STORIES_LINKS_AND_FORMATTING; + case "stories__priority_order": + return PREMIUM_FEATURE_STORIES_PRIORITY_ORDER; + case "stories__caption": + return PREMIUM_FEATURE_STORIES_CAPTION; } return -1; } @@ -235,6 +262,22 @@ public static String featureTypeToServerString(int type) { return "emoji_status"; case PREMIUM_FEATURE_TRANSLATIONS: return "translations"; + case PREMIUM_FEATURE_STORIES: + return "stories"; + case PREMIUM_FEATURE_STORIES_STEALTH_MODE: + return "stories__stealth_mode"; + case PREMIUM_FEATURE_STORIES_VIEWS_HISTORY: + return "stories__permanent_views_history"; + case PREMIUM_FEATURE_STORIES_EXPIRATION_DURATION: + return "stories__expiration_durations"; + case PREMIUM_FEATURE_STORIES_SAVE_TO_GALLERY: + return "stories__save_stories_to_gallery"; + case PREMIUM_FEATURE_STORIES_LINKS_AND_FORMATTING: + return "stories__links_and_formatting"; + case PREMIUM_FEATURE_STORIES_PRIORITY_ORDER: + return "stories__priority_order"; + case PREMIUM_FEATURE_STORIES_CAPTION: + return "stories__caption"; } return null; } @@ -594,6 +637,7 @@ public static void fillPremiumFeaturesList(ArrayList premium MessagesController messagesController = MessagesController.getInstance(currentAccount); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_LIMITS, R.drawable.msg_premium_limits, LocaleController.getString("PremiumPreviewLimits", R.string.PremiumPreviewLimits), LocaleController.formatString("PremiumPreviewLimitsDescription", R.string.PremiumPreviewLimitsDescription, messagesController.channelsLimitPremium, messagesController.dialogFiltersLimitPremium, messagesController.dialogFiltersPinnedLimitPremium, messagesController.publicLinksLimitPremium, 4))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_STORIES, R.drawable.msg_filled_stories, applyNewSpan(LocaleController.getString("PremiumPreviewStories", R.string.PremiumPreviewStories)), LocaleController.formatString("PremiumPreviewStoriesDescription", R.string.PremiumPreviewStoriesDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_UPLOAD_LIMIT, R.drawable.msg_premium_uploads, LocaleController.getString("PremiumPreviewUploads", R.string.PremiumPreviewUploads), LocaleController.getString("PremiumPreviewUploadsDescription", R.string.PremiumPreviewUploadsDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_DOWNLOAD_SPEED, R.drawable.msg_premium_speed, LocaleController.getString("PremiumPreviewDownloadSpeed", R.string.PremiumPreviewDownloadSpeed), LocaleController.getString("PremiumPreviewDownloadSpeedDescription", R.string.PremiumPreviewDownloadSpeedDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_VOICE_TO_TEXT, R.drawable.msg_premium_voice, LocaleController.getString("PremiumPreviewVoiceToText", R.string.PremiumPreviewVoiceToText), LocaleController.getString("PremiumPreviewVoiceToTextDescription", R.string.PremiumPreviewVoiceToTextDescription))); @@ -624,6 +668,15 @@ public static void fillPremiumFeaturesList(ArrayList premium }); } + private static CharSequence applyNewSpan(String str) { + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(str); + spannableStringBuilder.append(" d"); + FilterCreateActivity.NewSpan span = new FilterCreateActivity.NewSpan(false); + span.setColor(Theme.getColor(Theme.key_premiumGradient1)); + spannableStringBuilder.setSpan(span, spannableStringBuilder.length() - 1, spannableStringBuilder.length(), 0); + return spannableStringBuilder; + } + private void updateBackgroundImage() { if (contentView.getMeasuredWidth() == 0 || contentView.getMeasuredHeight() == 0) { return; @@ -669,6 +722,8 @@ public static void buyPremium(BaseFragment fragment, SubscriptionTier tier, Stri for (TLRPC.TL_premiumSubscriptionOption option : promo.period_options) { if (option.months == 1) { tier = new SubscriptionTier(option); + } else if (option.months == 12) { + tier = new SubscriptionTier(option); break; } } @@ -813,16 +868,28 @@ public static String getPremiumButtonText(int currentAccount, SubscriptionTier t if (BuildVars.useInvoiceBilling()) { TLRPC.TL_help_premiumPromo premiumPromo = MediaDataController.getInstance(currentAccount).getPremiumPromo(); if (premiumPromo != null) { - long amount = 0; - String currency = "USD"; + TLRPC.TL_premiumSubscriptionOption selectedOption = null; for (TLRPC.TL_premiumSubscriptionOption option : premiumPromo.period_options) { - if (option.months == 1) { - amount = option.amount; - currency = option.currency; + if (option.months == 12) { + selectedOption = option; + break; + } else if (selectedOption == null && option.months == 1) { + selectedOption = option; } } - return LocaleController.formatString(R.string.SubscribeToPremium, BillingController.getInstance().formatCurrency(amount, currency)); + if (selectedOption == null) { + return LocaleController.getString(R.string.SubscribeToPremiumNoPrice); + } + + final String price; + if (selectedOption.months == 12) { + price = BillingController.getInstance().formatCurrency(selectedOption.amount / 12, selectedOption.currency); + } else { + price = BillingController.getInstance().formatCurrency(selectedOption.amount, selectedOption.currency); + } + + return LocaleController.formatString(R.string.SubscribeToPremium, price); } return LocaleController.getString(R.string.SubscribeToPremiumNoPrice); @@ -836,6 +903,8 @@ public static String getPremiumButtonText(int currentAccount, SubscriptionTier t for (ProductDetails.PricingPhase phase : offerDetails.getPricingPhases().getPricingPhaseList()) { if (phase.getBillingPeriod().equals("P1M")) { // Once per month price = phase.getFormattedPrice(); + } else if (phase.getBillingPeriod().equals("P1Y")) { // Once per year + price = BillingController.getInstance().formatCurrency(phase.getPriceAmountMicros() / 12L, phase.getPriceCurrencyCode(), 6); break; } } @@ -851,8 +920,16 @@ public static String getPremiumButtonText(int currentAccount, SubscriptionTier t if (!BuildVars.useInvoiceBilling() && tier.getOfferDetails() == null) { return LocaleController.getString(R.string.Loading); } - return LocaleController.formatString(UserConfig.getInstance(currentAccount).isPremium() ? tier.getMonths() == 12 ? R.string.UpgradePremiumPerYear : R.string.UpgradePremiumPerMonth : - tier.getMonths() == 12 ? R.string.SubscribeToPremiumPerYear : R.string.SubscribeToPremium, tier.getMonths() == 12 ? tier.getFormattedPricePerYear() : tier.getFormattedPricePerMonth()); + final boolean isPremium = UserConfig.getInstance(currentAccount).isPremium(); + final boolean isYearTier = tier.getMonths() == 12; + final String price = isYearTier ? tier.getFormattedPricePerYear() : tier.getFormattedPricePerMonth(); + final int resId; + if (isPremium) { + resId = isYearTier ? R.string.UpgradePremiumPerYear : R.string.UpgradePremiumPerMonth; + } else { + resId = isYearTier ? R.string.SubscribeToPremiumPerYear : R.string.SubscribeToPremium; + } + return LocaleController.formatString(resId, price); } } @@ -1107,11 +1184,11 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { public static class PremiumFeatureData { public final int type; public final int icon; - public final String title; + public final CharSequence title; public final String description; public int yOffset; - public PremiumFeatureData(int type, int icon, String title, String description) { + public PremiumFeatureData(int type, int icon, CharSequence title, String description) { this.type = type; this.icon = icon; this.title = title; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index 6b1bfacb44f..7aa159917df 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -3441,7 +3441,7 @@ public boolean onItemClick(View view, int position) { getMessagesStorage().clearSentMedia(); SharedConfig.setNoSoundHintShowed(false); SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); - editor.remove("archivehint").remove("proximityhint").remove("archivehint_l").remove("speedhint").remove("gifhint").remove("reminderhint").remove("soundHint").remove("themehint").remove("bganimationhint").remove("filterhint").remove("n_0").remove("storyprvhint").remove("storyhint").remove("storyhint2").remove("storydualhint").remove("storysvddualhint").remove("stories_camera").remove("dualcam").remove("dualmatrix").remove("dual_available").remove("archivehint").commit(); + editor.remove("archivehint").remove("proximityhint").remove("archivehint_l").remove("speedhint").remove("gifhint").remove("reminderhint").remove("soundHint").remove("themehint").remove("bganimationhint").remove("filterhint").remove("n_0").remove("storyprvhint").remove("storyhint").remove("storyhint2").remove("storydualhint").remove("storysvddualhint").remove("stories_camera").remove("dualcam").remove("dualmatrix").remove("dual_available").remove("archivehint").remove("askNotificationsAfter").remove("askNotificationsDuration").commit(); MessagesController.getEmojiSettings(currentAccount).edit().remove("featured_hidden").remove("emoji_featured_hidden").commit(); SharedConfig.textSelectionHintShows = 0; SharedConfig.lockRecordAudioVideoHint = 0; @@ -3451,6 +3451,9 @@ public boolean onItemClick(View view, int position) { SharedConfig.emojiInteractionsHintCount = 3; SharedConfig.dayNightThemeSwitchHintCount = 3; SharedConfig.fastScrollHintCount = 3; + SharedConfig.stealthModeSendMessageConfirm = 2; + SharedConfig.updateStealthModeSendMessageConfirm(2); + SharedConfig.setStoriesReactionsLongPressHintUsed(false); ChatThemeController.getInstance(currentAccount).clearCache(); getNotificationCenter().postNotificationName(NotificationCenter.newSuggestionsAvailable); RestrictedLanguagesSelectActivity.cleanup(); @@ -3955,26 +3958,8 @@ protected void dispatchDraw(Canvas canvas) { } return; } - if (!AndroidUtilities.isTablet() && !isInLandscapeMode && avatarImage.getImageReceiver().hasNotThumb() && !AndroidUtilities.isAccessibilityScreenReaderEnabled()) { - openingAvatar = true; - allowPullingDown = true; - View child = null; - for (int i = 0; i < listView.getChildCount(); i++) { - if (listView.getChildAdapterPosition(listView.getChildAt(i)) == 0) { - child = listView.getChildAt(i); - break; - } - } - if (child != null) { - RecyclerView.ViewHolder holder = listView.findContainingViewHolder(child); - if (holder != null) { - Integer offset = positionToOffset.get(holder.getAdapterPosition()); - if (offset != null) { - listView.smoothScrollBy(0, -(offset + (listView.getPaddingTop() - child.getTop() - actionBar.getMeasuredHeight())), CubicBezierInterpolator.EASE_OUT_QUINT); - return; - } - } - } + if (expandAvatar()) { + return; } openAvatar(); }); @@ -4165,12 +4150,12 @@ protected TextView createTextView() { storyView = new ProfileStoriesView(context, currentAccount, userId, avatarContainer, avatarImage, resourcesProvider) { @Override protected void onTap(StoryViewer.PlaceProvider provider) { - if (getMessagesController().getStoriesController().getStories(userId) != null) { + if (getMessagesController().getStoriesController().hasStories(userId)) { getOrCreateStoryViewer().open(context, userId, provider); - } else if (userInfo != null && userInfo.stories != null && userId != getUserConfig().clientUserId) { + } else if (userInfo != null && userInfo.stories != null && !userInfo.stories.stories.isEmpty() && userId != getUserConfig().clientUserId) { getOrCreateStoryViewer().open(context, userInfo.stories, provider); } else { - getOrCreateStoryViewer().open(context, userId, provider); + expandAvatar(); } } }; @@ -4366,6 +4351,31 @@ public void onZoomStarted(MessageObject messageObject) { return fragmentView; } + private boolean expandAvatar() { + if (!AndroidUtilities.isTablet() && !isInLandscapeMode && avatarImage.getImageReceiver().hasNotThumb() && !AndroidUtilities.isAccessibilityScreenReaderEnabled()) { + openingAvatar = true; + allowPullingDown = true; + View child = null; + for (int i = 0; i < listView.getChildCount(); i++) { + if (listView.getChildAdapterPosition(listView.getChildAt(i)) == 0) { + child = listView.getChildAt(i); + break; + } + } + if (child != null) { + RecyclerView.ViewHolder holder = listView.findContainingViewHolder(child); + if (holder != null) { + Integer offset = positionToOffset.get(holder.getAdapterPosition()); + if (offset != null) { + listView.smoothScrollBy(0, -(offset + (listView.getPaddingTop() - child.getTop() - actionBar.getMeasuredHeight())), CubicBezierInterpolator.EASE_OUT_QUINT); + return true; + } + } + } + } + return false; + } + private void setAvatarExpandProgress(float animatedFracture) { final int newTop = ActionBar.getCurrentActionBarHeight() + (actionBar.getOccupyStatusBar() ? AndroidUtilities.statusBarHeight : 0); final float value = currentExpandAnimatorValue = AndroidUtilities.lerp(expandAnimatorValues, currentExpanAnimatorFracture = animatedFracture); @@ -5521,7 +5531,7 @@ private void openAddMember() { fragment.setDelegate((users, fwdCount) -> { HashSet currentParticipants = new HashSet<>(); ArrayList addedUsers = new ArrayList<>(); - if (chatInfo.participants.participants != null) { + if (chatInfo != null && chatInfo.participants != null && chatInfo.participants.participants != null) { for (int i = 0; i < chatInfo.participants.participants.size(); i++) { currentParticipants.add(chatInfo.participants.participants.get(i).user_id); } @@ -6564,6 +6574,7 @@ public void onBecomeFullyHidden() { if (undoView != null) { undoView.hide(true, 0); } + super.onBecomeFullyHidden(); } public void setPlayProfileAnimation(int type) { @@ -7218,7 +7229,7 @@ private void updateRowsIds() { sendLastLogsRow = rowCount++; clearLogsRow = rowCount++; } - if (BuildVars.DEBUG_PRIVATE_VERSION) { + if (BuildVars.DEBUG_VERSION) { switchBackendRow = rowCount++; } versionRow = rowCount++; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/RecyclerListViewScroller.java b/TMessagesProj/src/main/java/org/telegram/ui/RecyclerListViewScroller.java index cad97efbff1..0546d80ad41 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/RecyclerListViewScroller.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/RecyclerListViewScroller.java @@ -3,6 +3,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; +import android.view.animation.Interpolator; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.RecyclerListView; @@ -19,6 +20,10 @@ public RecyclerListViewScroller(RecyclerListView recyclerListView) { } public void smoothScrollBy(int dy) { + smoothScrollBy(dy, 200, CubicBezierInterpolator.DEFAULT); + } + + public void smoothScrollBy(int dy, long duration, Interpolator interpolator) { if (valueAnimator != null) { valueAnimator.removeAllListeners(); valueAnimator.cancel(); @@ -37,8 +42,8 @@ public void onAnimationEnd(Animator animation) { valueAnimator = null; } }); - valueAnimator.setDuration(200); - valueAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + valueAnimator.setDuration(duration); + valueAnimator.setInterpolator(interpolator); valueAnimator.start(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java b/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java index 32e7c5c856d..25df3ba9dbe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java @@ -1924,10 +1924,10 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi } imageView.setDrawable(drawable); - if (!UserConfig.getInstance(currentAccount).isPremium() && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_TOPIC_ICON) { - imageView.createPremiumLockView(); - imageView.premiumLockIconView.setVisibility(View.VISIBLE); - } +// if (!UserConfig.getInstance(currentAccount).isPremium() && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_TOPIC_ICON) { +// imageView.createPremiumLockView(); +// imageView.premiumLockIconView.setVisibility(View.VISIBLE); +// } } } else if (holder.getItemViewType() == VIEW_TYPE_EMOJI) { ImageViewEmoji imageView = (ImageViewEmoji) holder.itemView; @@ -2231,10 +2231,10 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi } imageView.setDrawable(drawable); - if (!UserConfig.getInstance(currentAccount).isPremium() && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_TOPIC_ICON) { - imageView.createPremiumLockView(); - imageView.premiumLockIconView.setVisibility(View.VISIBLE); - } +// if (!UserConfig.getInstance(currentAccount).isPremium() && type != TYPE_AVATAR_CONSTRUCTOR && type != TYPE_TOPIC_ICON) { +// imageView.createPremiumLockView(); +// imageView.premiumLockIconView.setVisibility(View.VISIBLE); +// } } } else if (viewType == VIEW_TYPE_EXPAND) { EmojiPackExpand button = (EmojiPackExpand) holder.itemView; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java index 823c631a8e2..1c8b6a302b4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java @@ -314,7 +314,7 @@ public void onItemClick(int id) { @Override protected void dispatchDraw(Canvas canvas) { if (actionBar.isActionModeShowed()) { - drawSectionBackground(canvas, stickersHeaderRow, stickersEndRow, getThemedColor(Theme.key_windowBackgroundWhite)); + drawSectionBackground(canvas, stickersHeaderRow, stickersEndRow - 1, getThemedColor(Theme.key_windowBackgroundWhite)); } super.dispatchDraw(canvas); } @@ -329,6 +329,7 @@ protected void onMoveAnimationUpdate(RecyclerView.ViewHolder holder) { } }; itemAnimator.setMoveDuration(350); + itemAnimator.setSupportsChangeAnimations(false); itemAnimator.setMoveInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); listView.setItemAnimator(itemAnimator); layoutManager = new LinearLayoutManager(context) { @@ -346,8 +347,6 @@ protected void calculateExtraLayoutSpace(@NonNull RecyclerView.State state, @Non listView.setLayoutManager(layoutManager); itemTouchHelper = new ItemTouchHelper(new TouchHelperCallback()); itemTouchHelper.attachToRecyclerView(listView); - itemAnimator = (DefaultItemAnimator) listView.getItemAnimator(); - itemAnimator.setSupportsChangeAnimations(false); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); listView.setAdapter(listAdapter); @@ -653,7 +652,6 @@ public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { loopRow = -1; loopInfoRow = -1; - archivedRow = -1; if (currentType == MediaDataController.TYPE_IMAGE) { featuredRow = rowCount++; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/DarkThemeResourceProvider.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/DarkThemeResourceProvider.java index 593170db347..8feb636adfc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/DarkThemeResourceProvider.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/DarkThemeResourceProvider.java @@ -39,6 +39,7 @@ public DarkThemeResourceProvider() { sparseIntArray.put(Theme.key_dialogSearchBackground, ColorUtils.setAlphaComponent(Color.WHITE, 17)); sparseIntArray.put(Theme.key_actionBarDefaultSubmenuItem, Color.WHITE); sparseIntArray.put(Theme.key_actionBarDefaultSubmenuItemIcon, Color.WHITE); + sparseIntArray.put(Theme.key_text_RedRegular, -1152913); sparseIntArray.put(Theme.key_listSelector, 234881023); sparseIntArray.put(Theme.key_dialogButtonSelector, 436207615); sparseIntArray.put(Theme.key_chat_emojiPanelTrendingTitle, Color.WHITE); @@ -80,6 +81,7 @@ public DarkThemeResourceProvider() { sparseIntArray.put(Theme.key_chat_messagePanelIcons, Color.WHITE); sparseIntArray.put(Theme.key_chat_messagePanelBackground, ColorUtils.setAlphaComponent(Color.BLACK, 122)); sparseIntArray.put(Theme.key_dialogBackground, 0xFF1F1F1F); + sparseIntArray.put(Theme.key_dialogBackgroundGray, 0xff000000); sparseIntArray.put(Theme.key_dialog_inlineProgressBackground, -15393241); sparseIntArray.put(Theme.key_windowBackgroundWhite, -15198183); sparseIntArray.put(Theme.key_windowBackgroundWhiteBlackText, Color.WHITE); @@ -98,7 +100,8 @@ public DarkThemeResourceProvider() { sparseIntArray.put(Theme.key_dialogFloatingIcon, 0xffffffff); sparseIntArray.put(Theme.key_graySection, 0xFF292929); sparseIntArray.put(Theme.key_graySectionText, -8158332); - sparseIntArray.put(Theme.key_windowBackgroundGray, 0xFF1F1F1F); + // sparseIntArray.put(Theme.key_windowBackgroundGray, 0xFF1F1F1F); + sparseIntArray.put(Theme.key_windowBackgroundGray, Color.BLACK); sparseIntArray.put(Theme.key_windowBackgroundWhiteBlueHeader, -9652488); sparseIntArray.put(Theme.key_windowBackgroundWhiteGrayText3, ColorUtils.blendARGB(Color.WHITE, Color.BLACK, 0.3f)); sparseIntArray.put(Theme.key_undo_background, 0xFF212426); @@ -132,13 +135,18 @@ public DarkThemeResourceProvider() { sparseIntArray.put(Theme.key_chat_messageLinkIn, 0xFF46A3EB); sparseIntArray.put(Theme.key_dialogTextGray2, -8553091); + sparseIntArray.put(Theme.key_location_actionIcon, -592138); + sparseIntArray.put(Theme.key_location_actionBackground, 0xFF1F1F1F); + sparseIntArray.put(Theme.key_location_actionPressedBackground, 0xFF3F3F3F); + sparseIntArray.put(Theme.key_location_actionActiveIcon, -8796932); + sparseIntArray.put(Theme.key_sheet_other, 1140850687); sparseIntArray.put(Theme.key_chat_outBubble, ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.4f)); sparseIntArray.put(Theme.key_chat_outBubbleGradient1, 0); sparseIntArray.put(Theme.key_chat_outBubbleGradient2, 0); sparseIntArray.put(Theme.key_chat_outBubbleGradient3, 0); - sparseIntArray.put(Theme.key_chat_textSelectBackground, ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.6f)); + sparseIntArray.put(Theme.key_chat_textSelectBackground, ColorUtils.setAlphaComponent(Color.WHITE, 75)); appendColors(); dividerPaint.setColor(getColor(Theme.key_divider)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java index b981564879a..e272d3c6739 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/DialogStoriesCell.java @@ -7,7 +7,6 @@ import android.content.Context; import android.content.res.Configuration; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; @@ -22,6 +21,7 @@ import android.text.style.ClickableSpan; import android.view.Gravity; import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.OvershootInterpolator; @@ -34,6 +34,8 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.google.android.exoplayer2.util.Log; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.Emoji; @@ -41,7 +43,6 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; -import org.telegram.messenger.NotificationsController; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; @@ -54,11 +55,13 @@ import org.telegram.ui.Components.AnimatedTextView; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.ButtonBounce; +import org.telegram.ui.Components.CanvasButton; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.EllipsizeSpanAnimator; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; +import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.RadialProgress; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.TypefaceSpan; @@ -76,6 +79,8 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter public final static int TYPE_DIALOGS = 0; public final static int TYPE_ARCHIVE= 1; private static final float COLLAPSED_DIS = 18; + private static final float ITEM_WIDTH = 70; + private static final int FAKE_TOP_PADDING = 4; private final int type; public final static int HEIGHT_IN_DP = 81; @@ -87,7 +92,6 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter public RadialProgress radialProgress; RecyclerListView listViewMini; - StoriesController storiesController; ArrayList oldItems = new ArrayList<>(); ArrayList oldMiniItems = new ArrayList<>(); @@ -98,6 +102,7 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter Paint grayPaint = new Paint(); Paint addCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG); Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + CanvasButton miniItemsClickArea = new CanvasButton(this); private HintView2 premiumHint; @@ -138,6 +143,7 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter private int overscrollSelectedPosition; private StoryCell overscrollSelectedView; private ActionBar actionBar; + private StoriesUtilities.EnsureStoryFileLoadedObject globalCancelable; public DialogStoriesCell(@NonNull Context context, BaseFragment fragment, int currentAccount, int type) { super(context); @@ -162,7 +168,21 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { } afterNextLayout.clear(); } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN && (collapsedProgress1 > 0.2f || DialogStoriesCell.this.getAlpha() == 0)) { + return false; + } + return super.dispatchTouchEvent(ev); + } }; + recyclerListView.setPadding(AndroidUtilities.dp(3), 0, AndroidUtilities.dp(3), 0); + recyclerListView.setClipToPadding(false); + recyclerListView.setClipChildren(false); + miniItemsClickArea.setDelegate(() -> { + onMiniListClicked(); + }); recyclerListView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { @@ -182,7 +202,7 @@ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { recyclerListView.setLayoutManager(layoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)); RecyclerListView.OnItemClickListener itemClickListener = (view, position) -> { StoryCell cell = (StoryCell) view; - openStoryForCell(cell); + openStoryForCell(cell, false); }; recyclerListView.setOnItemClickListener(itemClickListener); recyclerListView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { @@ -196,7 +216,7 @@ public boolean onItemClick(View view, int position) { }); recyclerListView.setAdapter(adapter); - addView(recyclerListView); + addView(recyclerListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, FAKE_TOP_PADDING, 0, 0)); titleView = new AnimatedTextView(getContext(), true, true, false); titleView.setGravity(Gravity.LEFT); @@ -249,6 +269,22 @@ public void onScrolled(int dx, int dy) { premiumHint.hide(); } } + + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + return false; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent e) { + return false; + } + + @Override + public boolean onTouchEvent(MotionEvent e) { + return false; + } }; listViewMini.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false)); listViewMini.addItemDecoration(new RecyclerView.ItemDecoration() { @@ -257,9 +293,9 @@ public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull R int p = parent.getChildLayoutPosition(view); outRect.setEmpty(); if (p == 1) { - outRect.left = -AndroidUtilities.dp(85) + AndroidUtilities.dp(25 + COLLAPSED_DIS - 14); + outRect.left = -AndroidUtilities.dp(85) + AndroidUtilities.dp(29 + COLLAPSED_DIS - 14); } else if (p == 2) { - outRect.left = -AndroidUtilities.dp(85) + AndroidUtilities.dp(25 + COLLAPSED_DIS - 14); + outRect.left = -AndroidUtilities.dp(85) + AndroidUtilities.dp(29 + COLLAPSED_DIS - 14); } } }); @@ -274,14 +310,18 @@ protected float animateByScale(View view) { listViewMini.setItemAnimator(miniItemAnimator); listViewMini.setAdapter(miniAdapter); listViewMini.setClipChildren(false); - addView(listViewMini); + addView(listViewMini, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, FAKE_TOP_PADDING, 0, 0)); setClipChildren(false); setClipToPadding(false); updateItems(false, false); } - private void openStoryForCell(StoryCell cell) { + public void onMiniListClicked() { + + } + + private void openStoryForCell(StoryCell cell, boolean overscroll) { if (cell == null) { return; } @@ -293,46 +333,86 @@ private void openStoryForCell(StoryCell cell) { } return; } - int position = cell.position; - long startFromDialogId = cell.dialogId; - ArrayList peerIds = new ArrayList<>(); - boolean allStoriesIsRead = true; if (!storiesController.hasStories(cell.dialogId)) { return; } - for (int i = 0; i < items.size(); i++) { - long dialogId = items.get(i).dialogId; - if (dialogId != UserConfig.getInstance(currentAccount).clientUserId && storiesController.hasUnreadStories(dialogId)) { - allStoriesIsRead = false; - break; - } + TLRPC.TL_userStories userStories = storiesController.getStories(cell.dialogId); + long startFromDialogId = cell.dialogId; + if (globalCancelable != null) { + globalCancelable.cancel(); + globalCancelable = null; } - if (cell.isSelf && (!allStoriesIsRead || items.size() == 1)) { - peerIds.add(cell.dialogId); - } else { - boolean isUnreadStory = !cell.isSelf && storiesController.hasUnreadStories(cell.dialogId); - if (isUnreadStory) { - for (int i = 0; i < items.size(); i++) { - long dialogId = items.get(i).dialogId; - if (!cell.isSelf && storiesController.hasUnreadStories(dialogId)) { - peerIds.add(dialogId); - } - if (dialogId == cell.dialogId) { - position = peerIds.size() - 1; - } + + Runnable runnable = () -> { + if (fragment == null || fragment.getParentActivity() == null) { + return; + } + int position = cell.position; + + ArrayList peerIds = new ArrayList<>(); + boolean allStoriesIsRead = true; + + for (int i = 0; i < items.size(); i++) { + long dialogId = items.get(i).dialogId; + if (dialogId != UserConfig.getInstance(currentAccount).clientUserId && storiesController.hasUnreadStories(dialogId)) { + allStoriesIsRead = false; + break; } + } + + boolean onlySelfStories = false; + boolean onlyUnreadStories = false; + if (cell.isSelf && (!allStoriesIsRead || items.size() == 1)) { + peerIds.add(cell.dialogId); + onlySelfStories = true; } else { - for (int i = 0; i < items.size(); i++) { - long dialogId = items.get(i).dialogId; - if (storiesController.hasStories(dialogId)) { - peerIds.add(items.get(i).dialogId); - } else if (i <= position) { - position--; + boolean isUnreadStory = !cell.isSelf && storiesController.hasUnreadStories(cell.dialogId); + if (isUnreadStory) { + onlyUnreadStories = true; + for (int i = 0; i < items.size(); i++) { + long dialogId = items.get(i).dialogId; + if (!cell.isSelf && storiesController.hasUnreadStories(dialogId)) { + peerIds.add(dialogId); + } + if (dialogId == cell.dialogId) { + position = peerIds.size() - 1; + } + } + } else { + for (int i = 0; i < items.size(); i++) { + long dialogId = items.get(i).dialogId; + if (storiesController.hasStories(dialogId)) { + peerIds.add(items.get(i).dialogId); + } else if (i <= position) { + position--; + } } } } + StoryViewer storyViewer = fragment.getOrCreateStoryViewer(); + storyViewer.doOnAnimationReady(() -> { + storiesController.setLoading(startFromDialogId, false); + }); + boolean finalOnlySelfStories = onlySelfStories; + storyViewer.open(getContext(), null, peerIds, position, null, null, StoriesListPlaceProvider.of(recyclerListView).with(forward -> { + if (finalOnlySelfStories) { + return; + } + if (forward) { + boolean hidden = type == TYPE_ARCHIVE; + storiesController.loadNextStories(hidden); + } + }).setPaginationParaments(type == TYPE_ARCHIVE, onlyUnreadStories, onlySelfStories), false); + }; + if (overscroll) { + runnable.run(); + } else { + globalCancelable = cell.cancellable = StoriesUtilities.ensureStoryFileLoaded(userStories, runnable); + if (globalCancelable != null) { + storiesController.setLoading(cell.dialogId, true); + } } - fragment.getOrCreateStoryViewer().open(getContext(), null, peerIds, position, null, null, StoriesListPlaceProvider.of(recyclerListView), false); + } private void checkLoadMore() { @@ -444,7 +524,7 @@ protected void dispatchDraw(Canvas canvas) { if (clipTop > 0) { canvas.clipRect(0, clipTop, getMeasuredWidth(), getMeasuredHeight()); } - float y = AndroidUtilities.lerp(0, getMeasuredHeight() - ActionBar.getCurrentActionBarHeight() - AndroidUtilities.dp(4), collapsedProgress1); + float y = AndroidUtilities.lerp(0, getMeasuredHeight() - ActionBar.getCurrentActionBarHeight() - AndroidUtilities.dp(4) - AndroidUtilities.dp(FAKE_TOP_PADDING), collapsedProgress1); recyclerListView.setTranslationY(y); listViewMini.setTranslationY(y); listViewMini.setTranslationX(AndroidUtilities.dp(68)); @@ -559,7 +639,7 @@ protected void dispatchDraw(Canvas canvas) { } } if (cell.drawInParent) { - float right = recyclerListView.getX() + cell.getX() + cell.getMeasuredWidth() / 2f + AndroidUtilities.dp(74) / 2f; + float right = recyclerListView.getX() + cell.getX() + cell.getMeasuredWidth() / 2f + AndroidUtilities.dp(ITEM_WIDTH) / 2f; if (lastViewRight == 0 || right > lastViewRight) { lastViewRight = right; } @@ -586,12 +666,12 @@ protected void dispatchDraw(Canvas canvas) { float progress = Math.min(collapsedProgress, collapsedProgress2); if (progress != 0) { float offset = (titleView.getMeasuredHeight() - titleView.getTextHeight()) / 2f; - titleView.setTranslationY(y + AndroidUtilities.dp(14) - offset); + titleView.setTranslationY(y + AndroidUtilities.dp(14) - offset + AndroidUtilities.dp(FAKE_TOP_PADDING)); int cellWidth = AndroidUtilities.dp(72); - lastViewRight += -cellWidth + getAvatarRight(cellWidth, collapsedProgress) + AndroidUtilities.dp(12); + lastViewRight += -cellWidth + AndroidUtilities.dp(6) + getAvatarRight(cellWidth, collapsedProgress) + AndroidUtilities.dp(12); // float toX = AndroidUtilities.dp(28) * Math.min(1, animateToCount) + AndroidUtilities.dp(14) * Math.max(0, animateToCount - 1); titleView.setTranslationX(lastViewRight); - titleView.getDrawable().setRightPadding(lastViewRight + actionBar.menu.getItemsMeasuredWidth() * progress); + titleView.getDrawable().setRightPadding(lastViewRight + actionBar.menu.getItemsMeasuredWidth(false) * progress); titleView.setAlpha(progress); titleView.setVisibility(View.VISIBLE); } else { @@ -625,24 +705,18 @@ protected void onDetachedFromWindow() { super.onDetachedFromWindow(); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storiesUpdated); ellipsizeSpanAnimator.onDetachedFromWindow(); + if (globalCancelable != null) { + globalCancelable.cancel(); + globalCancelable = null; + } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { titleView.setTextSize(AndroidUtilities.dp(!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 18 : 20)); - int fullWidth = items.size() * AndroidUtilities.dp(74); - int lastCellWidth = currentCellWidth; -// if (fullWidth < MeasureSpec.getSize(widthMeasureSpec)) { -// currentCellWidth = MeasureSpec.getSize(widthMeasureSpec) / items.size(); -// } else { - currentCellWidth = AndroidUtilities.dp(74); - // } -// if (currentCellWidth != lastCellWidth) { -// //adapter.notifyItemRangeChanged(0, items.size()); -// AndroidUtilities.forEachViews(recyclerListView, view -> view.forceLayout()); -// } + currentCellWidth = AndroidUtilities.dp(ITEM_WIDTH); AndroidUtilities.rectTmp.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(85), MeasureSpec.EXACTLY)); + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(85 + FAKE_TOP_PADDING), MeasureSpec.EXACTLY)); } @Override @@ -733,6 +807,7 @@ public void scrollToFirstCell() { } public void updateColors() { + StoriesUtilities.updateColors(); int color = getTextColor(); titleView.setTextColor(color); @@ -745,7 +820,6 @@ public void updateColors() { StoryCell cell = (StoryCell) view; cell.invalidate(); }); - } private int getTextColor() { @@ -801,6 +875,12 @@ public void onUserLongPressed(View view, long dialogId) { } public void openStoryRecorder() { + final StoriesController.StoryLimit storyLimit = MessagesController.getInstance(currentAccount).getStoriesController().checkStoryLimit(); + if (storyLimit != null) { + fragment.showDialog(new LimitReachedBottomSheet(fragment, getContext(), storyLimit.getLimitReachedType(), currentAccount)); + return; + } + StoryCell cell = null; for (int i = 0 ; i < recyclerListView.getChildCount(); i++) { StoryCell storyCell = (StoryCell) recyclerListView.getChildAt(i); @@ -876,16 +956,14 @@ public void setOverscoll(float storiesOverscroll) { invalidate(); recyclerListView.invalidate(); if (overscrollPrgoress != 0) { - recyclerListView.setClipChildren(false); ((ViewGroup) getParent()).setClipChildren(false); } else { - recyclerListView.setClipChildren(true); ((ViewGroup) getParent()).setClipChildren(true); } } public void openOverscrollSelectedStory() { - openStoryForCell(overscrollSelectedView); + openStoryForCell(overscrollSelectedView, true); performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); } @@ -984,6 +1062,7 @@ public class StoryCell extends FrameLayout { public int position; public boolean isLast; public boolean isFirst; + public StoriesUtilities.EnsureStoryFileLoadedObject cancellable; TLRPC.User user; TLRPC.Chat chat; @@ -1037,18 +1116,27 @@ private void createTextView() { textView.setGravity(Gravity.CENTER); textView.setTextSize(11); textView.setTextColor(getTextColor()); + NotificationCenter.listenEmojiLoading(textView); // textView.setEllipsize(TextUtils.TruncateAt.END); textView.setMaxLines(1); //textView.setSingleLine(true); - textViewContainer.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 2, 0, 2, 0)); + textViewContainer.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 1, 0, 1, 0)); avatarImage.setRoundRadius(AndroidUtilities.dp(48) / 2); crossfageToAvatarImage.setRoundRadius(AndroidUtilities.dp(48) / 2); } public void setDialogId(long dialogId) { boolean animated = this.dialogId == dialogId; + if (!animated) { + if (cancellable != null) { + storiesController.setLoading(this.dialogId, false); + cancellable.cancel(); + cancellable = null; + } + } this.dialogId = dialogId; + isSelf = dialogId == UserConfig.getInstance(currentAccount).getClientUserId(); TLObject object; if (dialogId > 0) { @@ -1149,7 +1237,7 @@ public void onAnimationEnd(Animator animation) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(mini ? AndroidUtilities.dp(74) : currentCellWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(HEIGHT_IN_DP), MeasureSpec.EXACTLY)); + super.onMeasure(MeasureSpec.makeMeasureSpec(mini ? AndroidUtilities.dp(ITEM_WIDTH) : currentCellWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(HEIGHT_IN_DP), MeasureSpec.EXACTLY)); } float getCy() { @@ -1395,7 +1483,7 @@ private float getArcProgress(float cx, float radius) { public void setPressed(boolean pressed) { super.setPressed(pressed); if (pressed && params.buttonBounce == null) { - params.buttonBounce = new ButtonBounce(this, 1.5f); + params.buttonBounce = new ButtonBounce(this, 1.5f, 5f); } if (params.buttonBounce != null) { params.buttonBounce.setPressed(pressed); @@ -1467,6 +1555,10 @@ protected void onDetachedFromWindow() { avatarImage.onDetachedFromWindow(); crossfageToAvatarImage.onDetachedFromWindow(); params.onDetachFromWindow(); + if (cancellable != null) { + cancellable.cancel(); + cancellable = null; + } } public void setProgressToCollapsed(float progressToCollapsed, float progressToCollapsed2, float overscrollProgress, boolean selectedForOverscroll) { @@ -1571,6 +1663,10 @@ private void updateCurrentState(int state) { recyclerListView.setVisibility(View.INVISIBLE); layoutManager.scrollToPositionWithOffset(0, 0); MessagesController.getInstance(currentAccount).getStoriesController().scheduleSort(); + if (globalCancelable != null) { + globalCancelable.cancel(); + globalCancelable = null; + } } invalidate(); } @@ -1591,7 +1687,7 @@ private void checkExpanded() { if (System.currentTimeMillis() < checkedStoryNotificationDeletion) { return; } - NotificationsController.getInstance(currentAccount).processIgnoreStories(); +// NotificationsController.getInstance(currentAccount).processIgnoreStories(); checkedStoryNotificationDeletion = System.currentTimeMillis() + 1000L * 60; } @@ -1616,7 +1712,7 @@ private HintView2 makePremiumHint() { .setMultilineText(true) .setTextAlign(Layout.Alignment.ALIGN_CENTER) .setJoint(0, 37 - 8); - Spannable text = AndroidUtilities.replaceSingleTag(LocaleController.getString("StoriesPremiumHint").replace('\n', ' '), Theme.key_undo_cancelColor, 0, () -> { + Spannable text = AndroidUtilities.replaceSingleTag(LocaleController.getString("StoriesPremiumHint2").replace('\n', ' '), Theme.key_undo_cancelColor, 0, () -> { if (premiumHint != null) { premiumHint.hide(); } @@ -1646,4 +1742,17 @@ public void showPremiumHint() { premiumHint.show(); } } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (currentState == COLLAPSED_STATE) { + int k = miniItems.size(); + int width = AndroidUtilities.dp(COLLAPSED_SIZE * k - COLLAPSED_DIS * Math.max(0, k - 1)); + miniItemsClickArea.setRect((int) listViewMini.getX(), (int) listViewMini.getY(), (int) (listViewMini.getX() + width), (int) (listViewMini.getY() + listViewMini.getHeight())); + if (miniItemsClickArea.checkTouchEvent(event)) { + return true; + } + } + return super.onTouchEvent(event); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java index c4ac21db8b6..609e5d462a1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java @@ -14,7 +14,10 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.ColorFilter; import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; @@ -51,6 +54,8 @@ import androidx.core.math.MathUtils; import androidx.recyclerview.widget.ChatListItemAnimator; +import com.google.android.exoplayer2.util.Log; + import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AnimationNotificationsLocker; @@ -107,10 +112,12 @@ import org.telegram.ui.Components.ChatActivityEnterView; import org.telegram.ui.Components.ChatAttachAlert; import org.telegram.ui.Components.ChatAttachAlertDocumentLayout; +import org.telegram.ui.Components.ColoredImageSpan; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.CustomPopupMenu; import org.telegram.ui.Components.DotDividerSpan; +import org.telegram.ui.Components.EditTextCaption; import org.telegram.ui.Components.EmojiPacksAlert; import org.telegram.ui.Components.HintView; import org.telegram.ui.Components.InstantCameraView; @@ -118,9 +125,11 @@ import org.telegram.ui.Components.LoadingDrawable; import org.telegram.ui.Components.MediaActivity; import org.telegram.ui.Components.MentionsContainerView; +import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.RadialProgress; +import org.telegram.ui.Components.Reactions.AnimatedEmojiEffect; import org.telegram.ui.Components.Reactions.ReactionsEffectOverlay; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; import org.telegram.ui.Components.ReactionsContainerLayout; @@ -128,6 +137,7 @@ import org.telegram.ui.Components.ShareAlert; import org.telegram.ui.Components.SizeNotifierFrameLayout; import org.telegram.ui.Components.TextStyleSpan; +import org.telegram.ui.Components.TranslateAlert2; import org.telegram.ui.Components.URLSpanMono; import org.telegram.ui.Components.URLSpanNoUnderline; import org.telegram.ui.Components.URLSpanReplacement; @@ -136,6 +146,7 @@ import org.telegram.ui.LaunchActivity; import org.telegram.ui.NotificationsCustomSettingsActivity; import org.telegram.ui.PinchToZoomHelper; +import org.telegram.ui.PremiumPreviewFragment; import org.telegram.ui.ProfileActivity; import org.telegram.ui.Stories.recorder.CaptionContainerView; import org.telegram.ui.Stories.recorder.HintView2; @@ -166,8 +177,11 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica private final Theme.ResourcesProvider resourcesProvider; // private final CloseFriendsBadge closeFriendsBadge; private final StoryPrivacyButton privacyButton; + private final FrameLayout likeButtonContainer; + private StoriesLikeButton storiesLikeButton; private HintView2 privacyHint; private HintView2 soundTooltip; + private HintView2 reactionsLongpressTooltip; private int reactionsContainerIndex; private final StoryViewer storyViewer; private final StoryCaptionView storyCaptionView; @@ -186,7 +200,9 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica private final ImageReceiver rightPreloadImageReceiver; private Runnable onImageReceiverThumbLoaded; - private ImageReceiver viewsThumbImageReceiver; + private StoryMediaAreasView storyAreasView; + + private SelfStoriesPreviewView.ImageHolder viewsThumbImageReceiver; private float viewsThumbAlpha; private final AvatarDrawable avatarDrawable; @@ -281,6 +297,22 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica boolean checkBlackoutMode; private boolean messageSent; private boolean isCaptionPartVisible; + private boolean stealthModeIsActive; + private ImageReceiver reactionEffectImageReceiver; + private AnimatedEmojiEffect emojiReactionEffect; + private ImageReceiver reactionMoveImageReceiver; + private AnimatedEmojiDrawable reactionMoveDrawable; + private boolean drawAnimatedEmojiAsMovingReaction; + private boolean drawReactionEffect; + private ReactionsContainerLayout likesReactionLayout; + private boolean likesReactionShowing; + private float likesReactionShowProgress; + private boolean movingReaction; + private float movingReactionProgress; + private int movingReactionFromX, movingReactionFromY, movingReactionFromSize; + private Runnable reactionsTooltipRunnable; + private float viewsThumbScale; + private float viewsThumbPivotY; public PeerStoriesView(@NonNull Context context, StoryViewer storyViewer, SharedResources sharedResources, Theme.ResourcesProvider resourcesProvider) { super(context); @@ -317,6 +349,16 @@ protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, b this.imageReceiver.ignoreNotifications = true; this.imageReceiver.setFileLoadingPriority(FileLoader.PRIORITY_LOW); + this.reactionEffectImageReceiver = new ImageReceiver(this); + this.reactionEffectImageReceiver.setAllowLoadingOnAttachedOnly(true); + this.reactionEffectImageReceiver.ignoreNotifications = true; + this.reactionEffectImageReceiver.setFileLoadingPriority(FileLoader.PRIORITY_HIGH); + + this.reactionMoveImageReceiver = new ImageReceiver(this); + this.reactionMoveImageReceiver.setAllowLoadingOnAttachedOnly(true); + this.reactionMoveImageReceiver.ignoreNotifications = true; + this.reactionMoveImageReceiver.setFileLoadingPriority(FileLoader.PRIORITY_HIGH); + this.leftPreloadImageReceiver = new ImageReceiver(); this.leftPreloadImageReceiver.setAllowLoadingOnAttachedOnly(true); this.leftPreloadImageReceiver.ignoreNotifications = true; @@ -338,6 +380,22 @@ protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, b this.resourcesProvider = resourcesProvider; setClipChildren(false); + storyAreasView = new StoryMediaAreasView(context, resourcesProvider) { + @Override + protected void onHintVisible(boolean hintVisible) { + if (delegate != null) { + delegate.setIsHintVisible(hintVisible); + } + } + + @Override + protected void presentFragment(BaseFragment fragment) { + if (storyViewer != null) { + storyViewer.presentFragment(fragment); + } + } + }; + storyContainer = new HwFrameLayout(context) { AnimatedFloat progressToAudio = new AnimatedFloat(this, 150, CubicBezierInterpolator.DEFAULT); @@ -407,7 +465,13 @@ protected void dispatchDraw(Canvas canvas) { loadingDrawableAlpha2.set(0, true); loadingDrawableAlpha.set(0, true); } - loadingDrawableAlpha2.set(!imageReceiver.hasNotThumb() && (playerSharedScope.renderView == null || !playerSharedScope.firstFrameRendered) && currentStory.uploadingStory == null ? 1f : 0f); + boolean storyDrawing; + if (currentStory.isVideo) { + storyDrawing = playerSharedScope.renderView != null && playerSharedScope.firstFrameRendered && !(playerSharedScope.player.progress == 0 && playerSharedScope.isBuffering()); + } else { + storyDrawing = imageReceiver.hasNotThumb(); + } + loadingDrawableAlpha2.set(!storyDrawing && currentStory.uploadingStory == null ? 1f : 0f); loadingDrawableAlpha.set(loadingDrawableAlpha2.get() == 1f ? 1f : 0); if (loadingDrawableAlpha.get() > 0) { @@ -503,10 +567,7 @@ protected void dispatchDraw(Canvas canvas) { } } if (viewsThumbAlpha != 0 && viewsThumbImageReceiver != null) { - viewsThumbImageReceiver.setImageCoords(0, 0, getMeasuredWidth(), getMeasuredHeight() + 1); - viewsThumbImageReceiver.setAlpha(viewsThumbAlpha); - viewsThumbImageReceiver.draw(canvas); - viewsThumbImageReceiver.setAlpha(1f); + viewsThumbImageReceiver.draw(canvas, viewsThumbAlpha, viewsThumbScale, 0, 0, getMeasuredWidth(), getMeasuredHeight() + 1); } progressToAudio.set(isRecording ? 1f : 0); @@ -551,12 +612,18 @@ private void drawLines(Canvas canvas) { if (playerSharedScope.player != null) { float p = playerSharedScope.player.getPlaybackProgress(videoDuration); timeProgress = Utilities.clamp(p, 1f, 0f); + if (playerSharedScope.firstFrameRendered && storyAreasView != null) { + storyAreasView.shine(); + } } invalidate(); } else if (!paused && isActive && !isUploading && !isEditing && imageReceiver.hasNotThumb()) { long currentTime = System.currentTimeMillis(); if (lastDrawTime != 0) { if (!isCaptionPartVisible) { + if (currentImageTime <= 0 && currentTime - lastDrawTime > 0 && storyAreasView != null) { + storyAreasView.shine(); + } currentImageTime += currentTime - lastDrawTime; } } @@ -658,6 +725,8 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // storyContainer.addView(surfaceView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); // storyContainer.setClipChildren(false); + storyContainer.addView(storyAreasView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + storyCaptionView = new StoryCaptionView(getContext(), storyViewer.resourcesProvider) { @Override public void onLinkClick(CharacterStyle span, View spoilersTextView) { @@ -794,6 +863,36 @@ public void onEmojiClick(AnimatedEmojiSpan span) { shareButton.setOnClickListener(v -> { shareStory(true); }); + ScaleStateListAnimator.apply(shareButton); + + likeButtonContainer = new FrameLayout(getContext()); + likeButtonContainer.setOnClickListener(v -> { + if (currentStory.storyItem != null && currentStory.storyItem.sent_reaction == null) { + applyMessageToChat(() -> { + likeStory(); + }); + } else { + likeStory(); + } + }); + likeButtonContainer.setOnLongClickListener(v -> { + if (reactionsTooltipRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(reactionsTooltipRunnable); + reactionsTooltipRunnable = null; + } + SharedConfig.setStoriesReactionsLongPressHintUsed(true); + if (reactionsLongpressTooltip != null) { + reactionsLongpressTooltip.hide(); + } + checkReactionsLayoutForLike(); + storyViewer.windowView.dispatchTouchEvent(AndroidUtilities.emptyMotionEvent()); + showLikesReaction(true); + return true; + }); + storiesLikeButton = new StoriesLikeButton(context, sharedResources); + storiesLikeButton.setPadding(padding, padding, padding, padding); + likeButtonContainer.addView(storiesLikeButton); + ScaleStateListAnimator.apply(likeButtonContainer, 0.3f, 5f); imageReceiver.setAllowLoadingOnAttachedOnly(true); imageReceiver.setParentView(storyContainer); @@ -828,7 +927,8 @@ public void onEmojiClick(AnimatedEmojiSpan span) { storyContainer.addView(headerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 17, 0, 0)); - addView(shareButton, LayoutHelper.createFrame(40, 40, Gravity.RIGHT, 10, 10, 10, 10)); + addView(shareButton, LayoutHelper.createFrame(40, 40, Gravity.RIGHT, 10, 10, 10 + 40, 10)); + addView(likeButtonContainer, LayoutHelper.createFrame(40, 40, Gravity.RIGHT, 10, 10, 10, 10)); optionsIconView = new ImageView(context); optionsIconView.setImageDrawable(sharedResources.optionsDrawable); @@ -840,6 +940,10 @@ public void onEmojiClick(AnimatedEmojiSpan span) { delegate.setPopupIsVisible(true); editStoryItem = null; final boolean[] popupStillVisible = new boolean[] { false }; + if (isSelf) { + MessagesController.getInstance(currentAccount).getStoriesController().loadBlocklistAtFirst(); + MessagesController.getInstance(currentAccount).getStoriesController().getDraftsController().load(); + } popupMenu = new CustomPopupMenu(getContext(), resourcesProvider, isSelf) { private boolean edit; @Override @@ -901,7 +1005,11 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay if (playerSharedScope != null && playerSharedScope.player != null) { time = playerSharedScope.player.currentPosition; } - editor.openEdit(StoryRecorder.SourceView.fromStoryViewer(storyViewer), StoryEntry.fromStoryItem(currentStory.getPath(), currentStory.storyItem), time, true); + StoryEntry entry = MessagesController.getInstance(currentAccount).getStoriesController().getDraftsController().getForEdit(currentStory.storyItem.dialogId, currentStory.storyItem); + if (entry == null || entry.file == null || !entry.file.exists()) { + entry = StoryEntry.fromStoryItem(currentStory.getPath(), currentStory.storyItem); + } + editor.openEdit(StoryRecorder.SourceView.fromStoryViewer(storyViewer), entry, time, true); editor.setOnPrepareCloseListener((t, close, sent) -> { final long start = System.currentTimeMillis(); if (playerSharedScope.player == null) { @@ -946,7 +1054,7 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay } final boolean pin = !storyItem.pinned; - ActionBarMenuItem.addItem(popupLayout, pin ? R.drawable.msg_save_story : R.drawable.msg_archive, pin ? LocaleController.getString("SaveToProfile", R.string.SaveToProfile) : LocaleController.getString("ArchiveStory"), false, resourcesProvider).setOnClickListener(v -> { + ActionBarMenuItem.addItem(popupLayout, pin ? R.drawable.msg_save_story : R.drawable.menu_unsave_story, pin ? LocaleController.getString("SaveToProfile", R.string.SaveToProfile) : LocaleController.getString("ArchiveStory"), false, resourcesProvider).setOnClickListener(v -> { ArrayList storyItems = new ArrayList<>(); storyItems.add(storyItem); MessagesController.getInstance(currentAccount).getStoriesController().updateStoriesPinned(storyItems, pin, success -> { @@ -971,7 +1079,9 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay }); } - if (allowShare) { + createStealthModeItem(popupLayout); + + if (allowShareLink) { ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_shareout, LocaleController.getString("BotShare", R.string.BotShare), false, resourcesProvider).setOnClickListener(v -> { shareStory(false); if (popupMenu != null) { @@ -1034,7 +1144,7 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay }); item.setMultiline(false); } - if (user.contact) { + if (user != null && user.contact) { if (!user.stories_hidden) { ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_archive, LocaleController.getString("ArchivePeerStories", R.string.ArchivePeerStories), false, resourcesProvider).setOnClickListener(v -> { toggleArchiveForStory(dialogId); @@ -1053,16 +1163,44 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay } } - if (!unsupported) { - if (UserObject.isService(dialogId) || allowShare) { + if (!unsupported && allowShare) { + if (UserConfig.getInstance(currentAccount).isPremium()) { ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_gallery, LocaleController.getString("SaveToGallery", R.string.SaveToGallery), false, resourcesProvider).setOnClickListener(v -> { saveToGallery(); if (popupMenu != null) { popupMenu.dismiss(); } }); + } else { + Drawable lockIcon = ContextCompat.getDrawable(context, R.drawable.msg_gallery_locked2); + lockIcon.setColorFilter(new PorterDuffColorFilter(ColorUtils.blendARGB(Color.WHITE, Color.BLACK, 0.5f), PorterDuff.Mode.MULTIPLY)); + CombinedDrawable combinedDrawable = new CombinedDrawable( + ContextCompat.getDrawable(context, R.drawable.msg_gallery_locked1), + lockIcon + ) { + @Override + public void setColorFilter(ColorFilter colorFilter) { + + } + }; + ActionBarMenuSubItem item = ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_gallery, LocaleController.getString("SaveToGallery", R.string.SaveToGallery), false, resourcesProvider); + item.setIcon(combinedDrawable); + item.setOnClickListener(v -> { + item.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + BulletinFactory bulletinFactory = BulletinFactory.global(); + if (bulletinFactory != null) { + bulletinFactory.createSimpleBulletin(R.raw.ic_save_to_gallery, AndroidUtilities.replaceSingleTag( + LocaleController.getString("SaveStoryToGalleryPremiumHint", R.string.SaveStoryToGalleryPremiumHint), + () -> { + PremiumFeatureBottomSheet sheet = new PremiumFeatureBottomSheet(storyViewer.fragment, PremiumPreviewFragment.PREMIUM_FEATURE_STORIES, false); + delegate.showDialog(sheet); + })).show(); + } + }); } } + + createStealthModeItem(popupLayout); if (allowShareLink) { ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_link, LocaleController.getString("CopyLink", R.string.CopyLink), false, resourcesProvider).setOnClickListener(v -> { AndroidUtilities.addToClipboard(currentStory.createLink()); @@ -1072,7 +1210,7 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay } }); } - if (allowShare) { + if (allowShareLink) { ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_shareout, LocaleController.getString("BotShare", R.string.BotShare), false, resourcesProvider).setOnClickListener(v -> { shareStory(false); if (popupMenu != null) { @@ -1081,6 +1219,45 @@ protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLay }); } + if (currentStory.storyItem != null) { + if (currentStory.storyItem.translated && TextUtils.equals(currentStory.storyItem.translatedLng, TranslateAlert2.getToLanguage())) { + ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_translate, LocaleController.getString("HideTranslation", R.string.HideTranslation), false, resourcesProvider).setOnClickListener(v -> { + currentStory.storyItem.translated = false; + MessagesController.getInstance(currentAccount).getStoriesController().getStoriesStorage().updateStoryItem(currentStory.storyItem.dialogId, currentStory.storyItem); + cancelTextSelection(); + updatePosition(); + if (popupMenu != null) { + popupMenu.dismiss(); + } + }); + } else if (MessagesController.getInstance(currentAccount).getTranslateController().canTranslateStory(currentStory.storyItem)) { + ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_translate, LocaleController.getString("TranslateMessage", R.string.TranslateMessage), false, resourcesProvider).setOnClickListener(v -> { + currentStory.storyItem.translated = true; + cancelTextSelection(); + if (delegate != null) { + delegate.setTranslating(true); + } + MessagesController.getInstance(currentAccount).getStoriesController().getStoriesStorage().updateStoryItem(currentStory.storyItem.dialogId, currentStory.storyItem); + final long start = System.currentTimeMillis(); + final Runnable finishTranslate = () -> { + if (delegate != null) { + delegate.setTranslating(false); + } + PeerStoriesView.this.updatePosition(); + checkBlackoutMode = true; + storyCaptionView.expand(true); + }; + MessagesController.getInstance(currentAccount).getTranslateController().translateStory(currentStory.storyItem, () -> AndroidUtilities.runOnUIThread(finishTranslate, Math.max(0, 500L - (System.currentTimeMillis() - start)))); + updatePosition(); + checkBlackoutMode = true; + storyCaptionView.expand(true); + if (popupMenu != null) { + popupMenu.dismiss(); + } + }); + } + } + if (!unsupported) { if (!UserObject.isService(dialogId)) { ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_report, LocaleController.getString("ReportChat", R.string.ReportChat), false, resourcesProvider).setOnClickListener(v -> { @@ -1239,6 +1416,133 @@ public void onStateChanged(boolean isSelected) { storyCaptionView.textSelectionHelper.setParentView(this); } + private void createStealthModeItem(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout) { + if (UserConfig.getInstance(currentAccount).isPremium()) { + ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_stories_stealth2, LocaleController.getString("StealthMode", R.string.StealthMode), false, resourcesProvider).setOnClickListener(v -> { + if (stealthModeIsActive) { + StealthModeAlert.showStealthModeEnabledBulletin(); + } else { + StealthModeAlert stealthModeAlert = new StealthModeAlert(getContext(), getY() + storyContainer.getY(), resourcesProvider); + delegate.showDialog(stealthModeAlert); + } + if (popupMenu != null) { + popupMenu.dismiss(); + } + }); + } else { + Drawable lockIcon2 = ContextCompat.getDrawable(getContext(), R.drawable.msg_gallery_locked2); + lockIcon2.setColorFilter(new PorterDuffColorFilter(ColorUtils.blendARGB(Color.WHITE, Color.BLACK, 0.5f), PorterDuff.Mode.MULTIPLY)); + CombinedDrawable combinedDrawable2 = new CombinedDrawable( + ContextCompat.getDrawable(getContext(), R.drawable.msg_stealth_locked), + lockIcon2 + ) { + @Override + public void setColorFilter(ColorFilter colorFilter) { + + } + }; + ActionBarMenuSubItem item2 = ActionBarMenuItem.addItem(popupLayout, R.drawable.msg_stories_stealth2, LocaleController.getString("StealthMode", R.string.StealthMode), false, resourcesProvider); + item2.setOnClickListener(v -> { + StealthModeAlert stealthModeAlert = new StealthModeAlert(getContext(), getY() + storyContainer.getY(), resourcesProvider); + delegate.showDialog(stealthModeAlert); + if (popupMenu != null) { + popupMenu.dismiss(); + } + }); + item2.setIcon(combinedDrawable2); + } + } + + private void showLikesReaction(boolean show) { + if (likesReactionShowing == show || currentStory.storyItem == null) { + return; + } + likesReactionShowing = show; + if (show) { + likesReactionLayout.setVisibility(View.VISIBLE); + } + likesReactionLayout.setStoryItem(currentStory.storyItem); + delegate.setIsLikesReaction(show); + if (show) { + ValueAnimator valueAnimator = ValueAnimator.ofFloat(likesReactionShowProgress, show ? 1f : 0f); + likesReactionLayout.setTransitionProgress(likesReactionShowProgress); + valueAnimator.addUpdateListener(animation -> { + likesReactionShowProgress = (float) animation.getAnimatedValue(); + likesReactionLayout.setTransitionProgress(likesReactionShowProgress); + }); + valueAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (!show) { + likesReactionLayout.setVisibility(View.GONE); + likesReactionLayout.reset(); + } + } + }); + valueAnimator.setDuration(200); + valueAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT); + valueAnimator.start(); + } else { + if (likesReactionLayout.getReactionsWindow() != null) { + likesReactionLayout.getReactionsWindow().dismissWithAlpha(); + } + likesReactionLayout.animate().alpha(0).setDuration(150).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + likesReactionShowProgress = 0; + likesReactionLayout.setAlpha(1f); + likesReactionLayout.setVisibility(View.GONE); + likesReactionLayout.reset(); + } + }).start(); + } + } + + private void likeStory() { + if (currentStory.storyItem == null) { + return; + } + if (currentStory.storyItem.sent_reaction == null) { + TLRPC.TL_availableReaction reaction = MediaDataController.getInstance(currentAccount).getReactionsMap().get("\u2764"); + if (reaction != null) { + drawAnimatedEmojiAsMovingReaction = false; + TLRPC.Document document = reaction.around_animation; + String filer = ReactionsEffectOverlay.getFilterForAroundAnimation(); + reactionEffectImageReceiver.setImage(ImageLocation.getForDocument(document), filer, null, null, null, 0); + if (reactionEffectImageReceiver.getLottieAnimation() != null) { + reactionEffectImageReceiver.getLottieAnimation().setCurrentFrame(0, false, true); + } + drawReactionEffect = true; + ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(reaction); + storiesController.setStoryReaction(dialogId, currentStory.storyItem, visibleReaction); + } + } else { + View oldLikeButton = storiesLikeButton; + oldLikeButton.animate().alpha(0).scaleX(0.8f).scaleY(0.8f).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + AndroidUtilities.removeFromParent(oldLikeButton); + } + }).setDuration(150).start(); + int padding = dp(8); + storiesLikeButton = new StoriesLikeButton(getContext(), sharedResources); + storiesLikeButton.setPadding(padding, padding, padding, padding); + storiesLikeButton.setAlpha(0); + storiesLikeButton.setScaleX(0.8f); + storiesLikeButton.setScaleY(0.8f); + storiesLikeButton.animate().alpha(1f).scaleX(1f).scaleY(1f).setDuration(150); + likeButtonContainer.addView(storiesLikeButton); + drawReactionEffect = false; + storiesController.setStoryReaction(dialogId, currentStory.storyItem, null); + } + if (currentStory.storyItem == null || currentStory.storyItem.sent_reaction == null) { + storiesLikeButton.setReaction(null); + } else { + storiesLikeButton.setReaction(ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(currentStory.storyItem.sent_reaction)); + performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + } + } + private ArrayList getAnimatedEmojiSets(StoryItemHolder storyHolder) { if (storyHolder != null) { if (storyHolder.storyItem != null && storyHolder.storyItem.entities != null && !storyHolder.storyItem.entities.isEmpty()) { @@ -1339,6 +1643,11 @@ public void appendColors() { int messageEditTextPredrawHeigth; int messageEditTextPredrawScrollY; + @Override + protected boolean showConfirmAlert(Runnable onConfirmed) { + return applyMessageToChat(onConfirmed); + } + public void checkAnimation() { int t = getBackgroundTop(); if (chatActivityEnterViewAnimateFromTop != 0 && t != chatActivityEnterViewAnimateFromTop) { @@ -1441,8 +1750,8 @@ public void extendActionMode(Menu menu) { ChatActivity.fillActionModeMenu(menu, null); } }; + chatActivityEnterView.getEditField().useAnimatedTextDrawable(); chatActivityEnterView.setOverrideKeyboardAnimation(true); - chatActivityEnterView.setOverrideHint(LocaleController.getString("ReplyPrivately", R.string.ReplyPrivately)); chatActivityEnterView.setClipChildren(false); chatActivityEnterView.setDelegate(new ChatActivityEnterView.ChatActivityEnterViewDelegate() { @Override @@ -1600,6 +1909,7 @@ public TLRPC.StoryItem getReplyToStory() { if (attachedToWindow) { chatActivityEnterView.onResume(); } + checkStealthMode(false); reactionsContainerIndex = getChildCount(); } @@ -1641,10 +1951,42 @@ public Paint.FontMetricsInt getFontMetrics() { public void addEmojiToRecent(String code) { chatActivityEnterView.addEmojiToRecent(code); } + + @Override + public void sendBotInlineResult(TLRPC.BotInlineResult result, boolean notify, int scheduleDate) { + long uid = mentionContainer.getAdapter().getContextBotId(); + HashMap params = new HashMap<>(); + params.put("id", result.id); + params.put("query_id", "" + result.query_id); + params.put("bot", "" + uid); + params.put("bot_name", mentionContainer.getAdapter().getContextBotName()); + SendMessagesHelper.prepareSendingBotContextResult(storyViewer.fragment, getAccountInstance(), result, params, dialogId, null, null, null, notify, scheduleDate); + chatActivityEnterView.setFieldText(""); + afterMessageSend(); + MediaDataController.getInstance(currentAccount).increaseInlineRaiting(uid); + } }); addView(mentionContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.BOTTOM)); } + private boolean applyMessageToChat(Runnable runnable) { + if (SharedConfig.stealthModeSendMessageConfirm > 0 && stealthModeIsActive) { + SharedConfig.stealthModeSendMessageConfirm--; + SharedConfig.updateStealthModeSendMessageConfirm(SharedConfig.stealthModeSendMessageConfirm); + AlertDialog alertDialog = new AlertDialog(getContext(), 0, resourcesProvider); + alertDialog.setTitle(LocaleController.getString("StealthModeConfirmTitle", R.string.StealthModeConfirmTitle)); + alertDialog.setMessage(LocaleController.getString("StealthModeConfirmMessage", R.string.StealthModeConfirmMessage)); + alertDialog.setPositiveButton(LocaleController.getString("Proceed", R.string.Proceed), (dialog, which) -> { + runnable.run(); + }); + alertDialog.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), (dialog, which) -> dialog.dismiss()); + alertDialog.show(); + } else { + runnable.run(); + } + return true; + } + private void saveToGallery() { if (currentStory.storyItem == null && currentStory.uploadingStory == null) { return; @@ -1770,8 +2112,8 @@ public void didPressedButton(int button, boolean arg, boolean notify, int schedu } SendMessagesHelper.prepareSendingMedia(getAccountInstance(), photos, dialogId, null, null, storyItem, button == 4 || forceDocument, arg, null, notify, scheduleDate, updateStickersOrder, null); } - afterMessageSend(); chatActivityEnterView.setFieldText(""); + afterMessageSend(); } // if (scheduleDate != 0) { // if (scheduledMessagesCount == -1) { @@ -1926,19 +2268,19 @@ public void run(TLObject response, TLRPC.TL_error error) { }); } - public void setDay(long dialogId, ArrayList day) { + public void setDay(long dialogId, ArrayList day, int selectedPosition) { this.dialogId = dialogId; this.day = day; - bindInternal(); + bindInternal(selectedPosition); } - public void setDialogId(long dialogId) { + public void setDialogId(long dialogId, int selectedPosition) { if (this.dialogId != dialogId) { currentStory.clear(); } this.dialogId = dialogId; this.day = null; - bindInternal(); + bindInternal(selectedPosition); if (storyViewer.overrideUserStories != null) { storiesController.loadSkippedStories(storyViewer.overrideUserStories, true); } else { @@ -1946,7 +2288,7 @@ public void setDialogId(long dialogId) { } } - private void bindInternal() { + private void bindInternal(int startFromPosition) { deletedPeer = false; forceUpdateOffsets = true; if (dialogId >= 0) { @@ -1987,7 +2329,10 @@ private void bindInternal() { TLRPC.ChatFull chatFull = MessagesController.getInstance(currentAccount).getChatFull(-dialogId); } updateStoryItems(); - selectedPosition = 0; + this.selectedPosition = startFromPosition; + if (this.selectedPosition < 0) { + this.selectedPosition = 0; + } currentImageTime = 0; switchEventSent = false; if (isSelf) { @@ -1996,25 +2341,27 @@ private void bindInternal() { if (chatActivityEnterView != null) { chatActivityEnterView.setVisibility(View.GONE); } - if (day != null) { - int index = day.indexOf(storyViewer.dayStoryId); - if (index < 0) { - if (!day.isEmpty()) { - if (storyViewer.dayStoryId > day.get(0)) { - index = 0; - } else if (storyViewer.dayStoryId < day.get(day.size() - 1)) { - index = day.size() - 1; + if (startFromPosition == -1) { + if (day != null) { + int index = day.indexOf(storyViewer.dayStoryId); + if (index < 0) { + if (!day.isEmpty()) { + if (storyViewer.dayStoryId > day.get(0)) { + index = 0; + } else if (storyViewer.dayStoryId < day.get(day.size() - 1)) { + index = day.size() - 1; + } } } - } - selectedPosition = Math.max(0, index); - } else if (!uploadingStories.isEmpty()) { - selectedPosition = storyItems.size(); - } else { - for (int i = 0; i < storyItems.size(); i++) { - if (storyItems.get(i).justUploaded || storyItems.get(i).id > storiesController.dialogIdToMaxReadId.get(dialogId)) { - selectedPosition = i; - break; + selectedPosition = Math.max(0, index); + } else if (!uploadingStories.isEmpty()) { + selectedPosition = storyItems.size(); + } else { + for (int i = 0; i < storyItems.size(); i++) { + if (storyItems.get(i).justUploaded || storyItems.get(i).id > storiesController.dialogIdToMaxReadId.get(dialogId)) { + selectedPosition = i; + break; + } } } } @@ -2025,7 +2372,9 @@ private void bindInternal() { if (chatActivityEnterView == null) { createEnterView(); } - updateSelectedPosition(); + if (startFromPosition == -1) { + updateSelectedPosition(); + } if (chatActivityEnterView != null) { chatActivityEnterView.setVisibility(View.VISIBLE); if (!TextUtils.isEmpty(chatActivityEnterView.getEditField().getText())) { @@ -2281,15 +2630,15 @@ public void onClick(DialogInterface dialog, int which) { } private void showUserViewsDialog() { - if (StoriesUtilities.hasExpiredViews(currentStory.storyItem)) { - performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); - BulletinFactory bulletinFactory = BulletinFactory.global(); - if (bulletinFactory != null) { - bulletinFactory.createErrorBulletin(AndroidUtilities.replaceTags(LocaleController.getString("ExpiredViewsStub", R.string.ExpiredViewsStub))).show(); - } - } else { +// if (StoriesUtilities.hasExpiredViews(currentStory.storyItem)) { +// performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); +// BulletinFactory bulletinFactory = BulletinFactory.global(); +// if (bulletinFactory != null) { +// bulletinFactory.createErrorBulletin(AndroidUtilities.replaceTags(LocaleController.getString("ExpiredViewsStub", R.string.ExpiredViewsStub))).show(); +// } +// } else { storyViewer.openViews(); - } + //} } @Override @@ -2301,7 +2650,52 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto @Override protected void dispatchDraw(Canvas canvas) { updateViewOffsets(); + if (reactionsLongpressTooltip != null && reactionsLongpressTooltip.shown() && likeButtonContainer.getVisibility() == View.VISIBLE && likeButtonContainer.getAlpha() == 1) { + reactionsLongpressTooltip.setTranslationY(-(getMeasuredHeight() - likeButtonContainer.getY()) - AndroidUtilities.dp(2)); + } super.dispatchDraw(canvas); + if (movingReaction) { + float cX = likeButtonContainer.getX() + likeButtonContainer.getMeasuredWidth() / 2f; + float cY = likeButtonContainer.getY() + likeButtonContainer.getMeasuredHeight() / 2f; + int size = AndroidUtilities.dp(24); + float finalX = AndroidUtilities.lerp(movingReactionFromX, cX - size / 2f, CubicBezierInterpolator.EASE_OUT.getInterpolation(movingReactionProgress)); + float finalY = AndroidUtilities.lerp(movingReactionFromY, cY - size / 2f, movingReactionProgress); + int finalSize = AndroidUtilities.lerp(movingReactionFromSize, size, movingReactionProgress); + if (drawAnimatedEmojiAsMovingReaction) { + if (reactionMoveDrawable != null) { + reactionMoveDrawable.setBounds((int) finalX, (int) finalY, (int) (finalX + finalSize), (int) (finalY + finalSize)); + reactionMoveDrawable.draw(canvas); + } + } else { + reactionMoveImageReceiver.setImageCoords(finalX, finalY, finalSize, finalSize); + reactionMoveImageReceiver.draw(canvas); + } + } + if (drawReactionEffect) { + float cX = likeButtonContainer.getX() + likeButtonContainer.getMeasuredWidth() / 2f; + float cY = likeButtonContainer.getY() + likeButtonContainer.getMeasuredHeight() / 2f; + int size = AndroidUtilities.dp(120); + if (!drawAnimatedEmojiAsMovingReaction) { + reactionEffectImageReceiver.setImageCoords(cX - size / 2f, cY - size / 2f, size, size); + reactionEffectImageReceiver.draw(canvas); + if (reactionEffectImageReceiver.getLottieAnimation() != null && reactionEffectImageReceiver.getLottieAnimation().isLastFrame()) { + drawReactionEffect = false; + } + } else { + if (emojiReactionEffect != null) { + //emojiReactionEffect.setBounds(0, 0, size, size); + emojiReactionEffect.setBounds((int) (cX - size / 2f), (int) (cY - size / 2f), (int) (cX + size / 2f), (int) (cY + size / 2f)); + emojiReactionEffect.draw(canvas); + if (emojiReactionEffect.done()) { + emojiReactionEffect.removeView(this); + emojiReactionEffect = null; + drawReactionEffect = false; + } + } else { + drawReactionEffect = false; + } + } + } if (chatActivityEnterView != null) { chatActivityEnterView.drawRecordedPannel(canvas); } @@ -2314,12 +2708,15 @@ protected void onAttachedToWindow() { imageReceiver.onAttachedToWindow(); rightPreloadImageReceiver.onAttachedToWindow(); leftPreloadImageReceiver.onAttachedToWindow(); + reactionEffectImageReceiver.onAttachedToWindow(); + reactionMoveImageReceiver.onAttachedToWindow(); if (chatActivityEnterView != null) { chatActivityEnterView.onResume(); } // sharedResources.muteDrawable.addView(muteIconView); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.storiesUpdated); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.storiesListUpdated); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.stealthModeChanged); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiLoaded); } @@ -2330,12 +2727,23 @@ protected void onDetachedFromWindow() { imageReceiver.onDetachedFromWindow(); rightPreloadImageReceiver.onDetachedFromWindow(); leftPreloadImageReceiver.onDetachedFromWindow(); + reactionEffectImageReceiver.onDetachedFromWindow(); + reactionMoveImageReceiver.onDetachedFromWindow(); if (chatActivityEnterView != null) { chatActivityEnterView.onPause(); } + if (reactionMoveDrawable != null) { + reactionMoveDrawable.removeView(PeerStoriesView.this); + reactionMoveDrawable = null; + } + if (emojiReactionEffect != null) { + emojiReactionEffect.removeView(PeerStoriesView.this); + emojiReactionEffect = null; + } //sharedResources.muteDrawable.removeView(muteIconView); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storiesUpdated); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storiesListUpdated); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.stealthModeChanged); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiLoaded); } @@ -2372,6 +2780,33 @@ public void didReceivedNotification(int id, int account, Object... args) { } } else if (id == NotificationCenter.emojiLoaded) { storyCaptionView.captionTextview.invalidate(); + } else if (id == NotificationCenter.stealthModeChanged) { + checkStealthMode(true); + } + } + + Runnable updateStealthModeTimer = () -> checkStealthMode(true); + + private void checkStealthMode(boolean animated) { + if (chatActivityEnterView == null || !isVisible || !attachedToWindow) { + return; + } + AndroidUtilities.cancelRunOnUIThread(updateStealthModeTimer); + TLRPC.TL_storiesStealthMode stealthMode = storiesController.getStealthMode(); + if (stealthMode != null && ConnectionsManager.getInstance(currentAccount).getCurrentTime() < stealthMode.active_until_date) { + stealthModeIsActive = true; + int time = stealthMode.active_until_date - ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + int minutes = time / 60; + int seconds = time % 60; + if (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) < AndroidUtilities.dp(200)) { + chatActivityEnterView.setOverrideHint(LocaleController.formatString("StealthModeActiveHintShort", R.string.StealthModeActiveHintShort, String.format(Locale.US, "%02d:%02d", minutes, seconds)), animated); + } else { + chatActivityEnterView.setOverrideHint(LocaleController.formatString("StealthModeActiveHint", R.string.StealthModeActiveHint, String.format(Locale.US, "%02d:%02d", minutes, seconds)), animated); + } + AndroidUtilities.runOnUIThread(updateStealthModeTimer, 1000); + } else { + stealthModeIsActive = false; + chatActivityEnterView.setOverrideHint(LocaleController.getString("ReplyPrivately", R.string.ReplyPrivately), animated); } } @@ -2419,6 +2854,7 @@ private void updatePosition(boolean preload) { imageReceiver.setImage(null, null, ImageLocation.getForPath(uploadingStory.path), filter, null, null, thumbDrawable, 0, null, null, 0); } currentStory.set(uploadingStory); + storyAreasView.set(null); allowShare = allowShareLink = false; } else { isUploading = false; @@ -2439,6 +2875,7 @@ private void updatePosition(boolean preload) { imageReceiver.setImage(null, null, ImageLocation.getForPath(editingStory.firstFramePath), filter, /*messageObject.strippedThumb*/null, 0, null, null, 0); } currentStory.set(editingStory); + storyAreasView.set(null); currentStory.editingSourceItem = storyItem; allowShare = allowShareLink = false; } else { @@ -2474,7 +2911,7 @@ private void updatePosition(boolean preload) { } } } else { - if (storyViewer.isSingleStory && storyViewer.transitionViewHolder.storyImage != null) { + if ((storyViewer.storiesList != null || storyViewer.isSingleStory) && storyViewer.transitionViewHolder != null && storyViewer.transitionViewHolder.storyImage != null && storyViewer.transitionViewHolder.storyId == storyItem.id) { thumbDrawable = storyViewer.transitionViewHolder.storyImage.getDrawable(); } storyItem.dialogId = dialogId; @@ -2484,7 +2921,7 @@ private void updatePosition(boolean preload) { thumbDrawable = ImageLoader.createStripedBitmap(storyItem.media.document.thumbs); } //imageReceiver.setImage(ImageLocation.getForDocument(size, storyItem.media.document), filter, null, null, thumbDrawable, 0, null, storyItem, 0); - imageReceiver.setImage(ImageLocation.getForDocument(storyItem.media.document), filter + "_pframe", ImageLocation.getForDocument(size, storyItem.media.document), filter, null, null, thumbDrawable, 0, null, storyItem, 0); + imageReceiver.setImage(null, null, ImageLocation.getForDocument(storyItem.media.document), filter + "_pframe", ImageLocation.getForDocument(size, storyItem.media.document), filter, thumbDrawable, 0, null, storyItem, 0); } else { TLRPC.Photo photo = storyItem.media != null ? storyItem.media.photo : null; if (photo != null && photo.sizes != null) { @@ -2504,6 +2941,7 @@ private void updatePosition(boolean preload) { } } storyItem.dialogId = dialogId; + storyAreasView.set(preload ? null : storyItem.media_areas); currentStory.set(storyItem); allowShare = allowShareLink = !unsupported && currentStory.storyItem != null && !(currentStory.storyItem instanceof TLRPC.TL_storyItemDeleted) && !(currentStory.storyItem instanceof TLRPC.TL_storyItemSkipped); if (allowShare) { @@ -2552,7 +2990,7 @@ private void updatePosition(boolean preload) { } else if (!animateSubtitle) { headerView.progressToUploading = 0; } - Bulletin.hideVisible(); + Bulletin.hideVisible(storyContainer); storyCaptionView.reset(); cancelWaiting(); } @@ -2584,22 +3022,16 @@ private void updatePosition(boolean preload) { soundTooltip.hide(false); } } - CharSequence caption = null; - if (currentStory.uploadingStory != null) { - caption = currentStory.uploadingStory.entry.caption; - caption = Emoji.replaceEmoji(caption, storyCaptionView.captionTextview.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); - SpannableStringBuilder spannableStringBuilder = SpannableStringBuilder.valueOf(caption); - MessageObject.addLinks(true, spannableStringBuilder); - } else if (currentStory.storyItem != null) { - caption = currentStory.storyItem.caption; - caption = Emoji.replaceEmoji(caption, storyCaptionView.captionTextview.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); - if (caption != null && currentStory.storyItem.entities != null) { - SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(currentStory.storyItem.caption); - spannableStringBuilder = SpannableStringBuilder.valueOf(MessageObject.replaceAnimatedEmoji(spannableStringBuilder, currentStory.storyItem.entities, storyCaptionView.captionTextview.getPaint().getFontMetricsInt(), false)); - SpannableStringBuilder.valueOf(Emoji.replaceEmoji(spannableStringBuilder, storyCaptionView.captionTextview.getPaint().getFontMetricsInt(), false)); - MessageObject.addLinks(true, spannableStringBuilder); - MessageObject.addEntitiesToText(spannableStringBuilder, currentStory.storyItem.entities, false, true, true, false); - caption = spannableStringBuilder; + if ( + oldStoryItem != currentStory.storyItem || + oldUploadingStory != currentStory.uploadingStory || + currentStory.captionTranslated != (currentStory.storyItem != null && currentStory.storyItem.translated && currentStory.storyItem.translatedText != null && TextUtils.equals(currentStory.storyItem.translatedLng, TranslateAlert2.getToLanguage())) + ) { + currentStory.updateCaption(); + } + if (currentStory.captionTranslated || oldStoryItem != currentStory.storyItem) { + if (delegate != null) { + delegate.setTranslating(false); } } @@ -2635,8 +3067,8 @@ private void updatePosition(boolean preload) { } } - if (caption != null && !unsupported) { - storyCaptionView.captionTextview.setText(caption); + if (currentStory.caption != null && !unsupported) { + storyCaptionView.captionTextview.setText(currentStory.caption, storyViewer.isTranslating &&!currentStory.captionTranslated && currentStory.storyItem != null && currentStory.storyItem.translated, oldStoryItem == currentStory.storyItem); storyCaptionView.setVisibility(View.VISIBLE); } else { if (isActive) { @@ -2650,6 +3082,8 @@ private void updatePosition(boolean preload) { delegate.onPeerSelected(dialogId, selectedPosition); } shareButton.setVisibility(allowShare ? View.VISIBLE : View.GONE); + likeButtonContainer.setVisibility(isSelf ? View.GONE : View.VISIBLE); + shareButton.setTranslationX(isSelf ? AndroidUtilities.dp(40) : 0); storyViewer.savedPositions.append(dialogId, position); @@ -2701,6 +3135,14 @@ private void updatePosition(boolean preload) { } editedPrivacy = false; privacyButton.setTranslationX(muteIconContainer.getVisibility() == View.VISIBLE ? -AndroidUtilities.dp(44) : 0); + if (storyChanged) { + drawReactionEffect = false; + if (currentStory.storyItem == null || currentStory.storyItem.sent_reaction == null) { + storiesLikeButton.setReaction(null); + } else { + storiesLikeButton.setReaction(ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(currentStory.storyItem.sent_reaction)); + } + } // final boolean closeFriends = currentStory.forCloseFriends(); // if (oldStoryItem != null && currentStory.storyItem != null && oldStoryItem.id == currentStory.storyItem.id) { @@ -2721,7 +3163,6 @@ private void updatePosition(boolean preload) { // closeFriendsBadge.setTranslationX(muteIconContainer.getVisibility() == View.VISIBLE ? -AndroidUtilities.dp(44) : 0); //sharedResources.muteDrawable.setIcon(storyViewer.soundEnabled() ? R.drawable.media_mute : R.drawable.media_unmute, false); sharedResources.setIconMuted(!storyViewer.soundEnabled(), false); - // sharedResources. if (isActive && currentStory.storyItem != null) { FileLog.d("StoryViewer displayed story dialogId=" + dialogId + " storyId=" + currentStory.storyItem.id); @@ -2730,18 +3171,44 @@ private void updatePosition(boolean preload) { SelfStoryViewsPage.preload(currentAccount, currentStory.storyItem); } headerView.titleView.setPadding(0, 0, storyViewer.storiesList != null && storyViewer.storiesList.getCount() != linesCount ? AndroidUtilities.dp(56) : 0, 0); + + MessagesController.getInstance(currentAccount).getTranslateController().detectStoryLanguage(currentStory.storyItem); + + if (!preload && !isSelf && reactionsTooltipRunnable == null && !SharedConfig.storyReactionsLongPressHint) { + AndroidUtilities.runOnUIThread(reactionsTooltipRunnable = () -> { + if (!storyViewer.isShown()) { + return; + } + reactionsTooltipRunnable = null; + if (reactionsLongpressTooltip == null) { + reactionsLongpressTooltip = new HintView2(getContext(), HintView2.DIRECTION_BOTTOM).setJoint(1, -AndroidUtilities.dp(8)); + reactionsLongpressTooltip.setBgColor(ColorUtils.setAlphaComponent(ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.13f), 240)); + reactionsLongpressTooltip.setBounce(false); + reactionsLongpressTooltip.setText(LocaleController.getString("ReactionLongTapHint", R.string.ReactionLongTapHint)); + reactionsLongpressTooltip.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); + addView(reactionsLongpressTooltip, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.FILL_HORIZONTAL | Gravity.TOP, 0, 0, 0, 0)); + } + reactionsLongpressTooltip.show(); + SharedConfig.setStoriesReactionsLongPressHintUsed(true); + }, 500); + } } private void createReplyDisabledView() { if (replyDisabledTextView != null) { return; } - replyDisabledTextView = new TextView(getContext()); + replyDisabledTextView = new TextView(getContext()) { + @Override + public void setTranslationY(float translationY) { + super.setTranslationY(translationY); + } + }; replyDisabledTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - replyDisabledTextView.setTextColor(ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.42f)); - replyDisabledTextView.setGravity(Gravity.LEFT); + replyDisabledTextView.setTextColor(ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.5f)); + replyDisabledTextView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); replyDisabledTextView.setText(LocaleController.getString("StoryReplyDisabled", R.string.StoryReplyDisabled)); - addView(replyDisabledTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL)); + addView(replyDisabledTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 40, Gravity.LEFT, 16, 0, 16, 0)); } ArrayList uriesToPrepare = new ArrayList<>(); @@ -2900,7 +3367,16 @@ private void updateUserViews() { avatarsCount++; } selfAvatarsView.commitTransition(false); - selfStatusView.setText(LocaleController.formatPluralStringComma("Views", storyItem.views.views_count)); + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(LocaleController.formatPluralStringComma("Views", storyItem.views.views_count)); + if (storyItem.views.reactions_count > 0) { + spannableStringBuilder.append(" d "); + ColoredImageSpan span = new ColoredImageSpan(R.drawable.mini_views_likes); + span.setOverrideColor(0xFFFF2E38); + span.setTopOffset(AndroidUtilities.dp(0.2f)); + spannableStringBuilder.setSpan(span, spannableStringBuilder.length() - 2, spannableStringBuilder.length() - 1, 0); + spannableStringBuilder.append(String.valueOf(storyItem.views.reactions_count)); + } + selfStatusView.setText(spannableStringBuilder); if (k == 0) { selfAvatarsView.setVisibility(View.GONE); selfStatusView.setTranslationX(AndroidUtilities.dp(16)); @@ -3055,6 +3531,21 @@ public int getSelectedPosition() { } public boolean closeKeyboardOrEmoji() { + if (likesReactionShowing) { + if (likesReactionLayout.getReactionsWindow() != null) { + if (realKeyboardHeight > 0) { + AndroidUtilities.hideKeyboard(likesReactionLayout.getReactionsWindow().windowView); + } else { + likesReactionLayout.getReactionsWindow().dismiss(); + } + return true; + } + showLikesReaction(false); + return true; + } + if (storyAreasView != null) { + storyAreasView.closeHint(); + } if (storyCaptionView.textSelectionHelper.isInSelectionMode()) { storyCaptionView.textSelectionHelper.clear(false); return true; @@ -3121,7 +3612,9 @@ public boolean findClickableView(ViewGroup container, float x, float y, boolean } } child.getHitRect(AndroidUtilities.rectTmp2); - if (keyboardVisible && child == chatActivityEnterView && y > AndroidUtilities.rectTmp2.top) { + if (child == storyAreasView && !storyAreasView.hasSelected() && (x < dp(60) || x > container.getMeasuredWidth() - dp(60))) { + + } else if (keyboardVisible && child == chatActivityEnterView && y > AndroidUtilities.rectTmp2.top) { return true; } else if (!swipeToDissmiss && AndroidUtilities.rectTmp2.contains((int) x, (int) y) && (((child.isClickable() || child == reactionsContainerLayout) && child.isEnabled()) || (chatActivityEnterView != null && child == chatActivityEnterView.getRecordCircle()))) { return true; @@ -3201,6 +3694,9 @@ public void reset() { if (reactionsContainerLayout != null) { reactionsContainerLayout.reset(); } + if (likesReactionLayout != null) { + likesReactionLayout.reset(); + } if (instantCameraView != null) { AndroidUtilities.removeFromParent(instantCameraView); instantCameraView.hideCamera(true); @@ -3299,9 +3795,17 @@ public void setLongpressed(boolean isLongpressed) { } } - public void showKeyboard() { - chatActivityEnterView.getEditField().requestFocus(); - AndroidUtilities.showKeyboard(chatActivityEnterView.getEditField()); + public boolean showKeyboard() { + if (chatActivityEnterView == null || replyDisabledTextView != null && replyDisabledTextView.getVisibility() == View.VISIBLE) { + return false; + } + EditTextCaption editText = chatActivityEnterView.getEditField(); + if (editText == null) { + return false; + } + editText.requestFocus(); + AndroidUtilities.showKeyboard(editText); + return true; } public void checkPinchToZoom(MotionEvent ev) { @@ -3316,6 +3820,7 @@ public void setIsVisible(boolean visible) { isVisible = visible; if (visible) { imageReceiver.setCurrentAlpha(1f); + checkStealthMode(false); } } @@ -3414,6 +3919,31 @@ public void cancelTextSelection() { } } + public boolean checkReactionEvent(MotionEvent ev) { + if (likesReactionLayout != null) { + View view = likesReactionLayout; + float xOffset = getX(); + float yOffset = getY() + ((View) getParent()).getY(); + if (likesReactionLayout.getReactionsWindow() != null && likesReactionLayout.getReactionsWindow().windowView != null) { + ev.offsetLocation(-xOffset, -yOffset - likesReactionLayout.getReactionsWindow().windowView.getTranslationY()); + likesReactionLayout.getReactionsWindow().windowView.dispatchTouchEvent(ev); + return true; + } + view.getHitRect(AndroidUtilities.rectTmp2); + + AndroidUtilities.rectTmp2.offset((int) xOffset, (int) yOffset); + if (ev.getAction() == MotionEvent.ACTION_DOWN && !AndroidUtilities.rectTmp2.contains((int) ev.getX(), (int) ev.getY())) { + showLikesReaction(false); + return true; + } else { + ev.offsetLocation(-AndroidUtilities.rectTmp2.left, -AndroidUtilities.rectTmp2.top); + view.dispatchTouchEvent(ev); + return true; + } + } + return false; + } + public static class PeerHeaderView extends FrameLayout { public BackupImageView backupImageView; @@ -3629,6 +4159,8 @@ public interface Delegate { void setPopupIsVisible(boolean b); + void setTranslating(boolean b); + void setBulletinIsVisible(boolean b); void setIsInPinchToZoom(boolean b); @@ -3640,6 +4172,8 @@ public interface Delegate { void setIsSwiping(boolean swiping); void setIsInSelectionMode(boolean selectionMode); + + void setIsLikesReaction(boolean show); } public class StoryItemHolder { @@ -3649,6 +4183,54 @@ public class StoryItemHolder { boolean skipped; private boolean isVideo; + public boolean captionTranslated; + public CharSequence caption; + + public void updateCaption() { + captionTranslated = false; + if (currentStory.uploadingStory != null) { + caption = currentStory.uploadingStory.entry.caption; + caption = Emoji.replaceEmoji(caption, storyCaptionView.captionTextview.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); + SpannableStringBuilder spannableStringBuilder = SpannableStringBuilder.valueOf(caption); + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + if (MessagesController.getInstance(currentAccount).storyEntitiesAllowed(user)) { + MessageObject.addLinks(true, spannableStringBuilder); + } + } else if (currentStory.storyItem != null) { + if (currentStory.storyItem.translated && currentStory.storyItem.translatedText != null && TextUtils.equals(currentStory.storyItem.translatedLng, TranslateAlert2.getToLanguage())) { + captionTranslated = true; + TLRPC.TL_textWithEntities text = currentStory.storyItem.translatedText; + caption = text.text; + caption = Emoji.replaceEmoji(caption, storyCaptionView.captionTextview.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); + if (caption != null && text.entities != null) { + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(text.text); + spannableStringBuilder = SpannableStringBuilder.valueOf(MessageObject.replaceAnimatedEmoji(spannableStringBuilder, text.entities, storyCaptionView.captionTextview.getPaint().getFontMetricsInt(), false)); + SpannableStringBuilder.valueOf(Emoji.replaceEmoji(spannableStringBuilder, storyCaptionView.captionTextview.getPaint().getFontMetricsInt(), false)); + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + if (MessagesController.getInstance(currentAccount).storyEntitiesAllowed(user)) { + MessageObject.addLinks(true, spannableStringBuilder); + MessageObject.addEntitiesToText(spannableStringBuilder, text.entities, false, true, true, false); + } + caption = spannableStringBuilder; + } + } else { + caption = currentStory.storyItem.caption; + caption = Emoji.replaceEmoji(caption, storyCaptionView.captionTextview.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); + if (caption != null && currentStory.storyItem.entities != null) { + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(currentStory.storyItem.caption); + spannableStringBuilder = SpannableStringBuilder.valueOf(MessageObject.replaceAnimatedEmoji(spannableStringBuilder, currentStory.storyItem.entities, storyCaptionView.captionTextview.getPaint().getFontMetricsInt(), false)); + SpannableStringBuilder.valueOf(Emoji.replaceEmoji(spannableStringBuilder, storyCaptionView.captionTextview.getPaint().getFontMetricsInt(), false)); + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); + if (MessagesController.getInstance(currentAccount).storyEntitiesAllowed(user)) { + MessageObject.addLinks(true, spannableStringBuilder); + MessageObject.addEntitiesToText(spannableStringBuilder, currentStory.storyItem.entities, false, true, true, false); + } + caption = spannableStringBuilder; + } + } + } + } + void set(TLRPC.StoryItem storyItem) { this.storyItem = storyItem; this.uploadingStory = null; @@ -3842,14 +4424,22 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { realKeyboardHeight = 0; } int keyboardHeight = realKeyboardHeight; - if (chatActivityEnterView != null && (chatActivityEnterView.isPopupShowing() || chatActivityEnterView.isWaitingForKeyboard())) { - if (chatActivityEnterView.getEmojiView().getMeasuredHeight() == 0) { - keyboardHeight = chatActivityEnterView.getEmojiPadding(); - } else if (chatActivityEnterView.isStickersExpanded()) { - chatActivityEnterView.checkStickresExpandHeight(); - keyboardHeight = chatActivityEnterView.getStickersExpandedHeight(); - } else { - keyboardHeight = chatActivityEnterView.getVisibleEmojiPadding(); + if (likesReactionLayout != null && likesReactionLayout.getReactionsWindow() != null && likesReactionLayout.getReactionsWindow().isShowing()) { + likesReactionLayout.getReactionsWindow().windowView.animate().translationY(-realKeyboardHeight) + .setDuration(AdjustPanLayoutHelper.keyboardDuration) + .setInterpolator(AdjustPanLayoutHelper.keyboardInterpolator) + .start(); + keyboardHeight = 0; + } else { + if (chatActivityEnterView != null && (chatActivityEnterView.isPopupShowing() || chatActivityEnterView.isWaitingForKeyboard())) { + if (chatActivityEnterView.getEmojiView().getMeasuredHeight() == 0) { + keyboardHeight = chatActivityEnterView.getEmojiPadding(); + } else if (chatActivityEnterView.isStickersExpanded()) { + chatActivityEnterView.checkStickresExpandHeight(); + keyboardHeight = chatActivityEnterView.getStickersExpandedHeight(); + } else { + keyboardHeight = chatActivityEnterView.getVisibleEmojiPadding(); + } } } boolean keyboardVisibleOld = keyboardVisible; @@ -3953,10 +4543,12 @@ public void onAnimationEnd(Animator animation) { if (replyDisabledTextView != null) { layoutParams = (LayoutParams) replyDisabledTextView.getLayoutParams(); - if (BIG_SCREEN) { - layoutParams.topMargin = top + viewPagerHeight + AndroidUtilities.dp(8) + AndroidUtilities.dp(24); + if (!BIG_SCREEN) { + replyDisabledTextView.setTextColor(ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.75f))); + layoutParams.topMargin = top + viewPagerHeight - AndroidUtilities.dp(12) - AndroidUtilities.dp(40); } else { - layoutParams.topMargin = top + viewPagerHeight - AndroidUtilities.dp(48) + AndroidUtilities.dp(24); + replyDisabledTextView.setTextColor(ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.5f)); + layoutParams.topMargin = top + viewPagerHeight + AndroidUtilities.dp(12); } } if (instantCameraView != null) { @@ -3970,11 +4562,13 @@ public void onAnimationEnd(Animator animation) { if (!BIG_SCREEN) { ((LayoutParams) shareButton.getLayoutParams()).topMargin = top + viewPagerHeight - AndroidUtilities.dp(12) - AndroidUtilities.dp(40); - int bottomPadding = isSelf ? AndroidUtilities.dp(40) : AndroidUtilities.dp(64); + ((LayoutParams) likeButtonContainer.getLayoutParams()).topMargin = top + viewPagerHeight - AndroidUtilities.dp(12) - AndroidUtilities.dp(40); + int bottomPadding = isSelf ? AndroidUtilities.dp(40) : AndroidUtilities.dp(56); ((LayoutParams) storyCaptionView.getLayoutParams()).bottomMargin = bottomPadding; storyCaptionView.blackoutBottomOffset = bottomPadding; } else { ((LayoutParams) shareButton.getLayoutParams()).topMargin = top + viewPagerHeight + AndroidUtilities.dp(12); + ((LayoutParams) likeButtonContainer.getLayoutParams()).topMargin = top + viewPagerHeight + AndroidUtilities.dp(12); ((LayoutParams) storyCaptionView.getLayoutParams()).bottomMargin = AndroidUtilities.dp(8); storyCaptionView.blackoutBottomOffset = AndroidUtilities.dp(8); } @@ -4059,7 +4653,6 @@ private void updateViewOffsets() { return; } - if (reactionsContainerLayout != null) { reactionsContainerLayout.setVisibility(progressToKeyboard > 0 ? View.VISIBLE : View.GONE); } @@ -4092,7 +4685,7 @@ private void updateViewOffsets() { } else if (child instanceof HintView) { HintView hintView = (HintView) child; hintView.updatePosition(); - } else if (child != instantCameraView && child != storyContainer && child != shareButton && child != mediaBanTooltip) { + } else if (child != instantCameraView && child != storyContainer && child != shareButton && child != mediaBanTooltip && child != likeButtonContainer && (likesReactionLayout == null || likesReactionLayout.getReactionsWindow() == null || child != likesReactionLayout.getReactionsWindow().windowView)) { float alpha; float translationY = -enterViewBottomOffset * (1f - progressToKeyboard) - animatingKeyboardHeight - AndroidUtilities.dp(8) * (1f - progressToKeyboard) - AndroidUtilities.dp(20) * storyViewer.swipeToReplyProgress; if (BIG_SCREEN) { @@ -4100,6 +4693,9 @@ private void updateViewOffsets() { } else { alpha = 1f * hideInterfaceAlpha; } + if (child == replyDisabledTextView) { + translationY = - AndroidUtilities.dp(20) * storyViewer.swipeToReplyProgress; + } if (child == mentionContainer) { translationY -= chatActivityEnterView.getMeasuredHeight() - chatActivityEnterView.getAnimatedTop(); alpha = progressToKeyboard; @@ -4107,7 +4703,11 @@ private void updateViewOffsets() { } if (child == reactionsContainerLayout) { float finalProgress = progressToKeyboard * (1f - progressToRecording.get()) * (1f - progressToStickerExpandedLocal) * (1f - progressToTextA.get()); - child.setAlpha(finalProgress * alpha * 1f); + float finalAlpha = finalProgress * alpha * 1f; + if (child.getAlpha() != 0 && finalAlpha == 0) { + reactionsContainerLayout.reset(); + } + child.setAlpha(finalAlpha); float s = 0.8f + 0.2f * finalProgress; child.setScaleX(s); child.setScaleY(s); @@ -4118,6 +4718,7 @@ private void updateViewOffsets() { } } shareButton.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal)); + likeButtonContainer.setAlpha(hideInterfaceAlpha * (1f - progressToDismissLocal)); for (int i = 0; i < storyContainer.getChildCount(); i++) { View child = storyContainer.getChildAt(i); @@ -4170,9 +4771,10 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { getMeasuredWidth() + AndroidUtilities.dp(20), getMeasuredHeight() ); + float rightOffset = (allowShare ? AndroidUtilities.dp(SHARE_BUTTON_OFFSET) : 0) + AndroidUtilities.dp(40); sharedResources.rect2.set(AndroidUtilities.dp(10), (chatActivityEnterView.getBottom() - AndroidUtilities.dp(48) + chatActivityEnterView.getTranslationY() + AndroidUtilities.dp(2)), - getMeasuredWidth() - AndroidUtilities.dp(10) - (allowShare ? AndroidUtilities.dp(SHARE_BUTTON_OFFSET) : 0), + getMeasuredWidth() - AndroidUtilities.dp(10) - rightOffset, (chatActivityEnterView.getY() + chatActivityEnterView.getMeasuredHeight() - AndroidUtilities.dp(2)) ); if (chatActivityEnterView.getMeasuredHeight() > AndroidUtilities.dp(50)) { @@ -4207,6 +4809,12 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { sharedResources.dimPaint.setAlpha((int) (125 * progressToKeyboard)); canvas.drawRect(0, 0, getMeasuredWidth(), chatActivityEnterView.getY() + chatActivityEnterView.getAnimatedTop(), sharedResources.dimPaint); } + } else if (child == likesReactionLayout && chatActivityEnterView != null) { + child.setTranslationY(-(likesReactionLayout.getMeasuredHeight() - likesReactionLayout.getPaddingBottom()) + likeButtonContainer.getY() - AndroidUtilities.dp(18)); +// if (progressToKeyboard > 0) { +// sharedResources.dimPaint.setAlpha((int) (125 * progressToKeyboard)); +// canvas.drawRect(0, 0, getMeasuredWidth(), chatActivityEnterView.getY() + chatActivityEnterView.getAnimatedTop(), sharedResources.dimPaint); +// } } return super.drawChild(canvas, child, drawingTime); } @@ -4319,7 +4927,6 @@ public boolean isBuffering() { void checkReactionsLayout() { if (reactionsContainerLayout == null) { - reactionsContainerLayout = new ReactionsContainerLayout(ReactionsContainerLayout.TYPE_STORY, LaunchActivity.getLastFragment(), getContext(), currentAccount, new WrappedResourceProvider(resourcesProvider) { @Override public void appendColors() { @@ -4331,6 +4938,15 @@ public void appendColors() { reactionsContainerLayout.setDelegate(new ReactionsContainerLayout.ReactionsContainerDelegate() { @Override public void onReactionClicked(View view, ReactionsLayoutInBubble.VisibleReaction visibleReaction, boolean longpress, boolean addToRecent) { + onReactionClickedInternal(view, visibleReaction, longpress, addToRecent, !longpress); + } + + void onReactionClickedInternal(View view, ReactionsLayoutInBubble.VisibleReaction visibleReaction, boolean longpress, boolean addToRecent, boolean allowConfirm) { + if (allowConfirm && applyMessageToChat(() -> { + onReactionClickedInternal(view, visibleReaction, longpress, addToRecent, false); + })) { + return; + } ReactionsEffectOverlay effectOverlay; if (longpress && visibleReaction.emojicon != null) { performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); @@ -4418,7 +5034,139 @@ public void onEmojiWindowDismissed() { reactionsContainerLayout.setFragment(LaunchActivity.getLastFragment()); } + void checkReactionsLayoutForLike() { + if (likesReactionLayout == null) { + likesReactionLayout = new ReactionsContainerLayout(ReactionsContainerLayout.TYPE_STORY_LIKES, LaunchActivity.getLastFragment(), getContext(), currentAccount, new WrappedResourceProvider(resourcesProvider) { + @Override + public void appendColors() { + sparseIntArray.put(Theme.key_chat_emojiPanelBackground, ColorUtils.setAlphaComponent(Color.WHITE, 30)); + } + }); + likesReactionLayout.setPadding(0, 0, 0, AndroidUtilities.dp(22)); + + addView(likesReactionLayout, reactionsContainerIndex, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 52 + 22, Gravity.TOP | Gravity.RIGHT, 0, 0, 12, 64)); + likesReactionLayout.setVisibility(View.GONE); + likesReactionLayout.setDelegate(new ReactionsContainerLayout.ReactionsContainerDelegate() { + @Override + public void onReactionClicked(View view, ReactionsLayoutInBubble.VisibleReaction visibleReaction, boolean longpress, boolean addToRecent) { + Runnable runnable = () -> { + movingReaction = true; + boolean[] effectStarted = {false}; + View oldLikeButton = storiesLikeButton; + oldLikeButton.animate().alpha(0).scaleX(0.8f).scaleY(0.8f).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + AndroidUtilities.removeFromParent(oldLikeButton); + } + }).setDuration(150).start(); + int padding = dp(8); + storiesLikeButton = new StoriesLikeButton(getContext(), sharedResources); + storiesLikeButton.setPadding(padding, padding, padding, padding); + likeButtonContainer.addView(storiesLikeButton); + + if (reactionMoveDrawable != null) { + reactionMoveDrawable.removeView(PeerStoriesView.this); + reactionMoveDrawable = null; + } + if (emojiReactionEffect != null) { + emojiReactionEffect.removeView(PeerStoriesView.this); + emojiReactionEffect = null; + } + drawAnimatedEmojiAsMovingReaction = false; + if (visibleReaction.documentId != 0) { + drawAnimatedEmojiAsMovingReaction = true; + reactionMoveDrawable = new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_KEYBOARD, currentAccount, visibleReaction.documentId); + reactionMoveDrawable.addView(PeerStoriesView.this); + } else if (visibleReaction.emojicon != null) { + TLRPC.TL_availableReaction availableReaction = MediaDataController.getInstance(currentAccount).getReactionsMap().get(visibleReaction.emojicon); + if (availableReaction != null) { + TLRPC.Document document = availableReaction.select_animation;//availableReaction.appear_animation; + reactionMoveImageReceiver.setImage(null, null, ImageLocation.getForDocument(document), "60_60", null, null, null, 0, null, null, 0); + document = availableReaction.around_animation; + String filer = ReactionsEffectOverlay.getFilterForAroundAnimation(); + reactionEffectImageReceiver.setImage(ImageLocation.getForDocument(document), filer, null, null, null, 0); + if (reactionEffectImageReceiver.getLottieAnimation() != null) { + reactionEffectImageReceiver.getLottieAnimation().setCurrentFrame(0, false, true); + } + } + } + storiesLikeButton.setReaction(visibleReaction); + if (visibleReaction.documentId != 0 && storiesLikeButton.emojiDrawable != null) { + emojiReactionEffect = AnimatedEmojiEffect.createFrom(storiesLikeButton.emojiDrawable, false, true); + emojiReactionEffect.setView(PeerStoriesView.this); + } + storiesController.setStoryReaction(dialogId, currentStory.storyItem, visibleReaction); + int[] childCoords = new int[2]; + view.getLocationInWindow(childCoords); + int[] parentCoords = new int[2]; + PeerStoriesView.this.getLocationInWindow(parentCoords); + movingReactionFromX = (int) childCoords[0] - parentCoords[0]; + movingReactionFromY = (int) childCoords[1] - parentCoords[1]; + movingReactionFromSize = view.getMeasuredHeight(); + + ValueAnimator animator = ValueAnimator.ofFloat(0, 1); + movingReactionProgress = 0; + PeerStoriesView.this.invalidate(); + StoriesLikeButton storiesLikeButtonFinal = storiesLikeButton; + storiesLikeButtonFinal.setAllowDrawReaction(false); + storiesLikeButtonFinal.prepareAnimateReaction(visibleReaction); + animator.addUpdateListener(animation -> { + movingReactionProgress = (float) animator.getAnimatedValue(); + PeerStoriesView.this.invalidate(); + if (movingReactionProgress > 0.8f && !effectStarted[0]) { + effectStarted[0] = true; + drawReactionEffect = true; + performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + } + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + movingReaction = false; + movingReactionProgress = 1f; + PeerStoriesView.this.invalidate(); + if (!effectStarted[0]) { + effectStarted[0] = true; + drawReactionEffect = true; + performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + } + storiesLikeButtonFinal.setAllowDrawReaction(true); + storiesLikeButtonFinal.animateVisibleReaction(); + + if (reactionMoveDrawable != null) { + reactionMoveDrawable.removeView(PeerStoriesView.this); + reactionMoveDrawable = null; + } + } + }); + animator.setDuration(220); + animator.start(); + showLikesReaction(false); + }; + if (!longpress) { + applyMessageToChat(runnable); + } else { + runnable.run(); + } + } + + @Override + public boolean needEnterText() { + delegate.requestAdjust(true); + return false; + } + }); + likesReactionLayout.setMessage(null, null); + } else { + likesReactionLayout.reset(); + } + likesReactionLayout.setFragment(LaunchActivity.getLastFragment()); + } + public boolean needEnterText() { + if (chatActivityEnterView == null) { + return false; + } boolean keyboardVisible = chatActivityEnterView.isKeyboardVisible(); if (keyboardVisible) { chatActivityEnterView.showEmojiView(); @@ -4430,9 +5178,17 @@ public boolean needEnterText() { return keyboardVisible; } - public void setViewsThumbImageReceiver(float alpha, ImageReceiver viewsThumbImageReceiver) { - this.viewsThumbImageReceiver = viewsThumbImageReceiver; + public void setViewsThumbImageReceiver(float alpha, float scale, float pivotY, SelfStoriesPreviewView.ImageHolder viewsThumbImageReceiver) { this.viewsThumbAlpha = alpha; + this.viewsThumbScale = 1f / scale; + this.viewsThumbPivotY = pivotY; + if (this.viewsThumbImageReceiver == viewsThumbImageReceiver) { + return; + } + this.viewsThumbImageReceiver = viewsThumbImageReceiver; + if (viewsThumbImageReceiver != null && viewsThumbImageReceiver.receiver.getBitmap() != null) { + imageReceiver.updateStaticDrawableThump(viewsThumbImageReceiver.receiver.getBitmap().copy(Bitmap.Config.ARGB_8888, false)); + } } public static class SharedResources { @@ -4450,6 +5206,8 @@ public static class SharedResources { private final RectF finalRect = new RectF(); private final Paint dimPaint = new Paint(); public Drawable shareDrawable; + public Drawable likeDrawable; + public Drawable likeDrawableFilled; public Drawable drawMoreDrawable; public Drawable optionsDrawable; public Drawable deleteDrawable; @@ -4460,6 +5218,9 @@ public static class SharedResources { SharedResources(Context context) { // drawMoreDrawable = ContextCompat.getDrawable(context, R.drawable.msg_draw_more); shareDrawable = ContextCompat.getDrawable(context, R.drawable.media_share); + likeDrawable = ContextCompat.getDrawable(context, R.drawable.media_like); + likeDrawableFilled = ContextCompat.getDrawable(context, R.drawable.media_like_active); + likeDrawableFilled.setColorFilter(new PorterDuffColorFilter(0xFFFF2E38, PorterDuff.Mode.MULTIPLY)); optionsDrawable = ContextCompat.getDrawable(context, R.drawable.media_more); deleteDrawable = ContextCompat.getDrawable(context, R.drawable.msg_delete); muteDrawable = new RLottieDrawable(R.raw.media_mute_unmute, "media_mute_unmute", AndroidUtilities.dp(28), AndroidUtilities.dp(28), true, null); @@ -4474,8 +5235,6 @@ public static class SharedResources { selectedBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG); selectedBarPaint.setColor(0xffffffff); - - int gradientColor = ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * 0.4f)); topOverlayGradient = ContextCompat.getDrawable(context, R.drawable.shadow_story_top); bottomOverlayGradient = ContextCompat.getDrawable(context, R.drawable.shadow_story_bottom);//new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[]{0, gradientColor}); @@ -4514,7 +5273,7 @@ private void editPrivacy(StoryPrivacyBottomSheet.StoryPrivacy currentPrivacy, TL delegate.showDialog(new StoryPrivacyBottomSheet(getContext(), storyItem.pinned ? Integer.MAX_VALUE : storyItem.expire_date - storyItem.date, resourcesProvider) .setValue(currentPrivacy) .enableSharing(false) - .allowSmallChats(false) +// .allowSmallChats(false) .isEdit(true) .whenSelectedRules((privacy, a, b, whenDone) -> { TLRPC.TL_stories_editStory editStory = new TLRPC.TL_stories_editStory(); @@ -4527,6 +5286,7 @@ private void editPrivacy(StoryPrivacyBottomSheet.StoryPrivacy currentPrivacy, TL } if (error == null || "STORY_NOT_MODIFIED".equals(error.text)) { + storyItem.parsedPrivacy = privacy; storyItem.privacy = privacy.toValue(); storyItem.close_friends = privacy.type == StoryPrivacyBottomSheet.TYPE_CLOSE_FRIENDS; storyItem.contacts = privacy.type == StoryPrivacyBottomSheet.TYPE_CONTACTS; @@ -4545,7 +5305,12 @@ private void editPrivacy(StoryPrivacyBottomSheet.StoryPrivacy currentPrivacy, TL BulletinFactory.of(storyContainer, resourcesProvider).createSimpleBulletin(R.raw.contact_check, LocaleController.formatPluralString("StorySharedToAllContactsExcluded", privacy.selectedUserIds.size())).show(); } } else if (privacy.type == StoryPrivacyBottomSheet.TYPE_SELECTED_CONTACTS) { - BulletinFactory.of(storyContainer, resourcesProvider).createSimpleBulletin(R.raw.contact_check, LocaleController.formatPluralString("StorySharedToContacts", privacy.selectedUserIds.size())).show(); + HashSet userIds = new HashSet<>(); + userIds.addAll(privacy.selectedUserIds); + for (ArrayList ids : privacy.selectedUserIdsByGroup.values()) { + userIds.addAll(ids); + } + BulletinFactory.of(storyContainer, resourcesProvider).createSimpleBulletin(R.raw.contact_check, LocaleController.formatPluralString("StorySharedToContacts", userIds.size())).show(); } } else { BulletinFactory.of(storyContainer, resourcesProvider).createSimpleBulletin(R.raw.error, LocaleController.getString("UnknownError", R.string.UnknownError)).show(); @@ -4634,4 +5399,8 @@ public void onAnimationEnd(Animator animation) { outAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); outAnimator.start(); } + + public int getListPosition() { + return listPosition; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoriesPreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoriesPreviewView.java index 9d6a54c7aa9..e8e3e2543f9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoriesPreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoriesPreviewView.java @@ -5,6 +5,15 @@ import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.drawable.GradientDrawable; +import android.text.Layout; +import android.text.SpannableStringBuilder; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; @@ -12,10 +21,16 @@ import android.widget.Scroller; import androidx.annotation.NonNull; +import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.ColoredImageSpan; import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.StaticLayoutEx; import java.util.ArrayList; @@ -41,6 +56,7 @@ public abstract class SelfStoriesPreviewView extends View { ArrayList imageReceiversTmp = new ArrayList<>(); ArrayList lastDrawnImageReceivers = new ArrayList<>(); + GradientDrawable gradientDrawable; GestureDetector gestureDetector = new GestureDetector(new GestureDetector.OnGestureListener() { @Override @@ -101,6 +117,7 @@ public boolean onFling(@NonNull MotionEvent e1, @NonNull MotionEvent e2, float v return false; } }); + private float textWidth; public void onCenteredImageTap() { @@ -111,6 +128,7 @@ public void onCenteredImageTap() { public SelfStoriesPreviewView(Context context) { super(context); scroller = new Scroller(context, new OvershootInterpolator()); + gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[]{Color.TRANSPARENT, ColorUtils.setAlphaComponent(Color.BLACK, 160)}); } @Override @@ -119,6 +137,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { childPadding = AndroidUtilities.dp(8); viewH = (int) (AndroidUtilities.dp(180) / 1.2f); viewW = (int) ((viewH / 16f) * 9f); + float textWidthLocal = viewW - AndroidUtilities.dp(8); topPadding = ((AndroidUtilities.dp(180) - viewH) / 2f) + AndroidUtilities.dp(20); updateScrollParams(); if (scrollToPositionInLayout >= 0 && getMeasuredWidth() > 0) { @@ -126,6 +145,12 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { scrollToPosition(scrollToPositionInLayout, false, false); scrollToPositionInLayout = -1; } + if (textWidth != textWidthLocal) { + textWidth = textWidthLocal; + for (int i = 0; i < lastDrawnImageReceivers.size(); i++) { + lastDrawnImageReceivers.get(i).onBind(lastDrawnImageReceivers.get(i).position); + } + } } private void updateScrollParams() { @@ -134,6 +159,7 @@ private void updateScrollParams() { } boolean checkScroll; + @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); @@ -142,8 +168,8 @@ protected void onDraw(Canvas canvas) { // if (Math.abs(scrollX - scroller.getCurrX()) < AndroidUtilities.dp(1)) { // scroller.abortAnimation(); // } else { - scrollX = scroller.getCurrX(); - // } + scrollX = scroller.getCurrX(); + // } invalidate(); checkScroll = true; } else if (checkScroll) { @@ -198,6 +224,18 @@ protected void onDraw(Canvas canvas) { } if (!(progressToOpen != 1f && i == lastClosestPosition)) { holder.receiver.draw(canvas); + if (holder.layout != null) { + float alpha = 0.7f + 0.3f * k;//k; + gradientDrawable.setAlpha((int) (255 * alpha)); + gradientDrawable.setBounds( + (int) holder.receiver.getImageX(), (int) (holder.receiver.getImageY2() - AndroidUtilities.dp(24)), (int) holder.receiver.getImageX2(), (int) holder.receiver.getImageY2() + 2); + gradientDrawable.draw(canvas); + canvas.save(); + canvas.translate(holder.receiver.getCenterX() - textWidth / 2f, holder.receiver.getImageY2() - AndroidUtilities.dp(8) - holder.layout.getHeight()); + holder.paint.setAlpha((int) (255 * alpha)); + holder.layout.draw(canvas); + canvas.restore(); + } } lastDrawnImageReceivers.add(holder); } @@ -238,6 +276,7 @@ private ImageHolder findOrCreateImageReceiver(int position, ArrayList 1) { + spannableStringBuilder = new SpannableStringBuilder(""); + formatCounterText(spannableStringBuilder, storyItem.storyItem.views, true); + layout = StaticLayoutEx.createStaticLayout(spannableStringBuilder, paint, (int) (textWidth + 1), Layout.Alignment.ALIGN_CENTER, 1.0f, 0f, false, null, Integer.MAX_VALUE, 2); + } + } } void onDetach() { receiver.onDetachedFromWindow(); } + + public void draw(Canvas canvas, float alpha, float scale, int x, int y, int width, int height) { + receiver.setImageCoords(x, y, width, height); + receiver.setAlpha(alpha); + receiver.draw(canvas); + receiver.setAlpha(1f); + if (layout != null) { + paint.setAlpha((int) (255 * alpha)); + gradientDrawable.setAlpha((int) (255 * alpha)); + gradientDrawable.setBounds( + (int) receiver.getImageX(), (int) (receiver.getImageY2() - AndroidUtilities.dp(24) * scale), (int) receiver.getImageX2(), (int) receiver.getImageY2() + 2); + gradientDrawable.draw(canvas); + canvas.save(); + canvas.scale(scale, scale, receiver.getCenterX(), receiver.getImageY2() - AndroidUtilities.dp(8) * scale); + canvas.translate(receiver.getCenterX() - textWidth / 2f, receiver.getImageY2() - AndroidUtilities.dp(8) * scale - layout.getHeight()); + layout.draw(canvas); + canvas.restore(); + } + } + } + + private void formatCounterText(SpannableStringBuilder spannableStringBuilder, TLRPC.StoryViews storyViews, boolean twoLines) { + int count = storyViews == null ? 0 : storyViews.views_count; + if (count > 0) { + spannableStringBuilder.append("d"); + spannableStringBuilder.setSpan(new ColoredImageSpan(R.drawable.msg_views), spannableStringBuilder.length() - 1, spannableStringBuilder.length(), 0); + spannableStringBuilder.append(" ").append( + AndroidUtilities.formatWholeNumber(count, 0) + ); + if (storyViews != null && storyViews.reactions_count > 0) { + spannableStringBuilder.append(twoLines ? "\n" : " "); + spannableStringBuilder.append("d"); + spannableStringBuilder.setSpan(new ColoredImageSpan(R.drawable.mini_like_filled), spannableStringBuilder.length() - 1, spannableStringBuilder.length(), 0); + spannableStringBuilder.append(" ").append( + AndroidUtilities.formatWholeNumber(storyViews.reactions_count, 0) + ); + } + } } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsPage.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsPage.java index a5d8290d59b..f060affe93e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsPage.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsPage.java @@ -1,68 +1,181 @@ package org.telegram.ui.Stories; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; +import android.text.Layout; +import android.text.SpannableStringBuilder; +import android.text.TextPaint; +import android.text.TextUtils; import android.util.TypedValue; +import android.view.Gravity; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.google.android.exoplayer2.util.Consumer; +import com.google.android.exoplayer2.util.Log; + import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BuildVars; +import org.telegram.messenger.ContactsController; +import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.ActionBarMenuSubItem; +import org.telegram.ui.ActionBar.ActionBarPopupWindow; +import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.FixedHeightEmptyCell; import org.telegram.ui.Cells.ReactedUserHolderView; +import org.telegram.ui.Components.AnimatedEmojiDrawable; +import org.telegram.ui.Components.Bulletin; +import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.CustomPopupMenu; +import org.telegram.ui.Components.EmojiPacksAlert; +import org.telegram.ui.Components.FillLastGridLayoutManager; +import org.telegram.ui.Components.FillLastLinearLayoutManager; import org.telegram.ui.Components.FlickerLoadingView; +import org.telegram.ui.Components.ItemOptions; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LinkSpanDrawable; +import org.telegram.ui.Components.MessageContainsEmojiButton; +import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; +import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; +import org.telegram.ui.Components.RecyclerAnimationScrollHelper; import org.telegram.ui.Components.RecyclerItemsEnterAnimator; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.ReplaceableIconDrawable; +import org.telegram.ui.Components.SearchField; import org.telegram.ui.Components.StickerEmptyView; import org.telegram.ui.LaunchActivity; +import org.telegram.ui.PremiumPreviewFragment; import org.telegram.ui.ProfileActivity; +import org.telegram.ui.RecyclerListViewScroller; +import org.telegram.ui.Stories.recorder.HintView2; +import org.telegram.ui.Stories.recorder.StoryPrivacyBottomSheet; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashSet; +import java.util.Objects; public class SelfStoryViewsPage extends FrameLayout implements NotificationCenter.NotificationCenterDelegate { - private final static int TOP_PADDING = 46; + private final View shadowView; + private final View shadowView2; + private final FrameLayout topViewsContainer; + private final RecyclerListViewScroller scroller; + private int TOP_PADDING = 96; private static final int FIRST_PADDING_ITEM = 0; private static final int USER_ITEM = 1; - private static final int LAST_ITEM = 2; private static final int BUTTON_PADDING = 3; private static final int FLICKER_LOADING_ITEM = 4; private static final int EMPTY_VIEW = 5; + private static final int EMPTY_VIEW_SEARCH = 7; + private static final int EMPTY_VIEW_NO_CONTACTS = 8; + private static final int FLICKER_LOADING_ITEM_FULL = 6; + private static final int LAST_PADDING_VIEW = 9; + private static final int EMPTY_VIEW_SERVER_CANT_RETURN = 10; + private static final int SUBSCRIBE_TO_PREMIUM_TEXT_HINT = 11; + private static final int SERVER_CANT_RETURN_TEXT_HINT = 12; + + private CustomPopupMenu popupMenu; private final TextView titleView; private int measuerdHeight; RecyclerListView recyclerListView; + RecyclerAnimationScrollHelper scrollHelper; Theme.ResourcesProvider resourcesProvider; int currentAccount; ListAdapter listAdapter; - public LinearLayoutManager layoutManager; + public FillLastLinearLayoutManager layoutManager; SelfStoryViewsView.StoryItemInternal storyItem; - ViewsModel model; + ViewsModel currentModel; + ViewsModel defaultModel; + ViewsModel filteredModel; private boolean isAttachedToWindow; RecyclerItemsEnterAnimator recyclerItemsEnterAnimator; + StoryViewer storyViewer; + SearchField searchField; + final FiltersState sharedFilterState; + Consumer onSharedStateChanged; + final FiltersState state = new FiltersState(); + HeaderView headerView; + boolean isSearchDebounce; + private boolean showSearch; + private boolean showReactionsSort; + private boolean showContactsFilter; + Drawable shadowDrawable; + private boolean checkAutoscroll; + private boolean showServerErrorText; + + private boolean isStoryShownToUser(TLRPC.TL_storyView view) { + if (MessagesController.getInstance(currentAccount).getStoriesController().isBlocked(view)) { + return false; + } + + if (MessagesController.getInstance(currentAccount).blockePeers.indexOfKey(view.user_id) >= 0) { + return false; + } + + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(view.user_id); + + if (storyItem != null) { + if (storyItem.storyItem != null) { + if (storyItem.storyItem.parsedPrivacy == null) { + storyItem.storyItem.parsedPrivacy = new StoryPrivacyBottomSheet.StoryPrivacy(currentAccount, storyItem.storyItem.privacy); + } + return storyItem.storyItem.parsedPrivacy.containsUser(user); + } else if (storyItem.uploadingStory != null && storyItem.uploadingStory.entry != null && storyItem.uploadingStory.entry.privacy != null) { + return storyItem.uploadingStory.entry.privacy.containsUser(user); + } + } + + return true; + } - public SelfStoryViewsPage(StoryViewer storyViewer, @NonNull Context context) { + public SelfStoryViewsPage(StoryViewer storyViewer, @NonNull Context context, FiltersState sharedFilterState, Consumer onSharedStateChanged) { super(context); + this.sharedFilterState = sharedFilterState; + //this.sharedFilterState = null; + this.onSharedStateChanged = onSharedStateChanged; this.resourcesProvider = storyViewer.resourcesProvider; + this.storyViewer = storyViewer; + + // state.set(sharedFilterState); currentAccount = storyViewer.currentAccount; titleView = new TextView(context); @@ -71,46 +184,292 @@ public SelfStoryViewsPage(StoryViewer storyViewer, @NonNull Context context) { titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); titleView.setPadding(AndroidUtilities.dp(21), AndroidUtilities.dp(6), AndroidUtilities.dp(21), AndroidUtilities.dp(8)); - recyclerListView = new RecyclerListView(context) { + headerView = new HeaderView(getContext()); + + recyclerListView = new RecyclerListViewInner(context, resourcesProvider) { + @Override protected void onMeasure(int widthSpec, int heightSpec) { measuerdHeight = MeasureSpec.getSize(heightSpec); super.onMeasure(widthSpec, heightSpec); } + + }; recyclerListView.setClipToPadding(false); recyclerItemsEnterAnimator = new RecyclerItemsEnterAnimator(recyclerListView, true); - recyclerListView.setLayoutManager(layoutManager = new LinearLayoutManager(context)); + recyclerListView.setLayoutManager(layoutManager = new FillLastLinearLayoutManager(context, 0, recyclerListView)); recyclerListView.setNestedScrollingEnabled(true); recyclerListView.setAdapter(listAdapter = new ListAdapter()); + scrollHelper = new RecyclerAnimationScrollHelper(recyclerListView, layoutManager); + scrollHelper.setScrollListener(new RecyclerAnimationScrollHelper.ScrollListener() { + @Override + public void onScroll() { + SelfStoryViewsPage.this.invalidate(); + } + }); addView(recyclerListView); - - + scroller = new RecyclerListViewScroller(recyclerListView); recyclerListView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { checkLoadMore(); + SelfStoryViewsPage.this.invalidate(); + } + + @Override + public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + if (newState == RecyclerListView.SCROLL_STATE_IDLE) { + checkAutoscroll = true; + invalidate(); + } + if (newState == RecyclerView.SCROLL_STATE_DRAGGING) { + checkAutoscroll = false; + scroller.cancel(); + AndroidUtilities.hideKeyboard(SelfStoryViewsPage.this); + } } }); recyclerListView.setOnItemClickListener((view, position) -> { + if (position < 0 || position >= listAdapter.items.size()) { + return; + } TLRPC.TL_storyView user = listAdapter.items.get(position).user; if (user != null) { storyViewer.presentFragment(ProfileActivity.of(user.user_id)); } }); + recyclerListView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { + @Override + public boolean onItemClick(View view, int position) { + if (!(view instanceof ReactedUserHolderView)) { + return false; + } + ReactedUserHolderView cell = (ReactedUserHolderView) view; + if (storyViewer == null || storyViewer.containerView == null) { + return false; + } + TLRPC.TL_storyView viewUser = listAdapter.items.get(position).user; + if (viewUser == null) { + return false; + } + + MessagesController messagesController = MessagesController.getInstance(currentAccount); + + TLRPC.User user = messagesController.getUser(viewUser.user_id); + if (user == null) { + return false; + } + + boolean isBlocked = messagesController.blockePeers.indexOfKey(user.id) >= 0; + boolean isContact = user != null && (user.contact || ContactsController.getInstance(currentAccount).contactsDict.get(user.id) != null); + boolean storiesShown = isStoryShownToUser(viewUser); + boolean storiesBlocked = messagesController.getStoriesController().isBlocked(viewUser); + + String firstName = TextUtils.isEmpty(user.first_name) ? (TextUtils.isEmpty(user.last_name) ? "" : user.last_name) : user.first_name; + int index; + if ((index = firstName.indexOf(" ")) > 2) { + firstName = firstName.substring(0, index); + } + final String firstNameFinal = firstName; + + ItemOptions itemOptions = ItemOptions.makeOptions(storyViewer.containerView, resourcesProvider, view) + .setGravity(Gravity.LEFT).ignoreX() + .setScrimViewBackground(new ColorDrawable(Theme.getColor(Theme.key_dialogBackground, resourcesProvider))) + .setDimAlpha(0x85) + .addIf(storiesShown && !storiesBlocked && !isBlocked, R.drawable.msg_stories_myhide, LocaleController.formatString(R.string.StoryHideFrom, firstNameFinal), () -> { + messagesController.getStoriesController().updateBlockUser(user.id, true); + BulletinFactory.of(SelfStoryViewsPage.this, resourcesProvider) + .createSimpleBulletin(R.raw.ic_ban, LocaleController.formatString(R.string.StoryHidFromToast, firstNameFinal)) + .show(); + cell.animateAlpha(isStoryShownToUser(viewUser) ? 1 : 0.5f, true); + }).makeMultiline(false).cutTextInFancyHalf() + .addIf(storiesBlocked && !isBlocked, R.drawable.msg_menu_stories, LocaleController.formatString(R.string.StoryShowBackTo, firstNameFinal), () -> { + messagesController.getStoriesController().updateBlockUser(user.id, false); + BulletinFactory.of(SelfStoryViewsPage.this, resourcesProvider) + .createSimpleBulletin(R.raw.contact_check, LocaleController.formatString(R.string.StoryShownBackToToast, firstNameFinal)) + .show(); + cell.animateAlpha(isStoryShownToUser(viewUser) ? 1 : 0.5f, true); + }).makeMultiline(false).cutTextInFancyHalf() +// .addIf(!isContact, R.drawable.msg_contact_add, LocaleController.getString(R.string.AddContact), () -> { +// messagesController.getStoriesController().updateBlockUser(user.id, false); +// ContactsController.getInstance(currentAccount).addContact(user, false); +// user.contact = true; +// BulletinFactory.of(SelfStoryViewsPage.this, resourcesProvider) +// .createSimpleBulletin(R.raw.contact_check, LocaleController.formatString(R.string.AddContactToast, firstNameFinal)) +// .show(); +// cell.animateAlpha(isStoryShownToUser(viewUser) ? 1 : 0.5f, true); +// }) + .addIf(!isContact && !isBlocked, R.drawable.msg_user_remove, LocaleController.getString(R.string.BlockUser), true, () -> { + messagesController.blockPeer(user.id); + BulletinFactory.of(SelfStoryViewsPage.this, resourcesProvider).createBanBulletin(true).show(); + cell.animateAlpha(isStoryShownToUser(viewUser) ? 1 : 0.5f, true); + }) + .addIf(!isContact && isBlocked, R.drawable.msg_block, LocaleController.getString(R.string.Unblock), () -> { + messagesController.getStoriesController().updateBlockUser(user.id, false); + messagesController.unblockPeer(user.id); + BulletinFactory.of(SelfStoryViewsPage.this, resourcesProvider).createBanBulletin(false).show(); + cell.animateAlpha(isStoryShownToUser(viewUser) ? 1 : 0.5f, true); + }) + .addIf(isContact, R.drawable.msg_user_remove, LocaleController.getString(R.string.StoryDeleteContact), true, () -> { + ArrayList users = new ArrayList<>(); + users.add(user); + ContactsController.getInstance(currentAccount).deleteContact(users, false); + BulletinFactory.of(SelfStoryViewsPage.this, resourcesProvider) + .createSimpleBulletin(R.raw.ic_ban, LocaleController.formatString(R.string.DeletedFromYourContacts, firstNameFinal)) + .show(); + cell.animateAlpha(isStoryShownToUser(viewUser) ? 1 : 0.5f, true); + }); + + if (viewUser.reaction instanceof TLRPC.TL_reactionCustomEmoji) { + TLRPC.TL_reactionCustomEmoji customEmoji = (TLRPC.TL_reactionCustomEmoji) viewUser.reaction; + TLRPC.InputStickerSet inputStickerSet = AnimatedEmojiDrawable.getDocumentFetcher(currentAccount).findStickerSet(customEmoji.document_id); + if (inputStickerSet != null) { + itemOptions.addGap(); + ArrayList arr = new ArrayList(); + arr.add(inputStickerSet); + MessageContainsEmojiButton button = new MessageContainsEmojiButton(currentAccount, getContext(), resourcesProvider, arr, MessageContainsEmojiButton.SINGLE_REACTION_TYPE); + button.setOnClickListener(v -> { + new EmojiPacksAlert(new BaseFragment() { + @Override + public int getCurrentAccount() { + return currentAccount; + } + + @Override + public Context getContext() { + return SelfStoryViewsPage.this.getContext(); + } + + @Override + public Theme.ResourcesProvider getResourceProvider() { + return resourcesProvider; + } + }, getContext(), resourcesProvider, arr).show(); + itemOptions.dismiss(); + }); + itemOptions.addView(button); + } + } + + itemOptions.show(); + + try { + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); + } catch (Exception ignore) { + } + + return true; + } + }); listAdapter.updateRows(); - View shadowView = new View(getContext()); - shadowView.setBackground(new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[]{ Theme.getColor(Theme.key_dialogBackground, resourcesProvider), Color.TRANSPARENT })); - addView(shadowView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 8, 0, 0, TOP_PADDING - 8, 0, 0)); + topViewsContainer = new FrameLayout(getContext()); + shadowView = new View(getContext()); + shadowView.setBackground(new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[]{Theme.getColor(Theme.key_dialogBackground, resourcesProvider), Color.TRANSPARENT})); + topViewsContainer.addView(shadowView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 8, 0, 0, TOP_PADDING - 8, 0, 0)); - View shadowView2 = new View(getContext()); + shadowView2 = new View(getContext()); shadowView2.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); - addView(shadowView2, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 10, 0, 0, TOP_PADDING - 17, 0, 0)); + topViewsContainer.addView(shadowView2, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 10, 0, 0, TOP_PADDING - 17, 0, 0)); + + topViewsContainer.addView(headerView); + topViewsContainer.addView(titleView); + searchField = new SearchField(getContext(), true, 13, resourcesProvider) { + Runnable runnable; + + @Override + public void onTextChange(String text) { + if (runnable != null) { + AndroidUtilities.cancelRunOnUIThread(runnable); + } + runnable = () -> { + runnable = null; + isSearchDebounce = false; + state.searchQuery = text.toLowerCase(); + reload(); + //layoutManager.scrollToPositionWithOffset(0, -recyclerListView.getPaddingTop()); + }; + if (!TextUtils.isEmpty(text)) { + AndroidUtilities.runOnUIThread(runnable, 300); + } else { + runnable.run(); + } + if (runnable != null && !isSearchDebounce) { + isSearchDebounce = true; + listAdapter.updateRows(); + layoutManager.scrollToPositionWithOffset(0, -recyclerListView.getPaddingTop()); + } + } + }; + searchField.setHint(LocaleController.getString("Search", R.string.Search)); + topViewsContainer.addView(searchField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 36, 0, 0)); + + addView(topViewsContainer); + } + + + @Override + protected void dispatchDraw(Canvas canvas) { + int minPosition = -1; + View minView = null; + for (int i = 0; i < recyclerListView.getChildCount(); i++) { + View child = recyclerListView.getChildAt(i); + int childPosition = recyclerListView.getChildLayoutPosition(child); + if (childPosition < minPosition || minPosition == -1) { + minPosition = childPosition; + minView = child; + } + } + int paddingTop; + if (minPosition == 0) { + paddingTop = (int) Math.max(0, minView.getY()); + } else if (minPosition > 0) { + paddingTop = 0; + } else { + paddingTop = recyclerListView.getPaddingTop(); + } + if (topViewsContainer.getTranslationY() != paddingTop) { + topViewsContainer.setTranslationY(paddingTop); + onTopOffsetChanged(paddingTop); + } + shadowDrawable.setBounds(-AndroidUtilities.dp(6), paddingTop, getMeasuredWidth() + AndroidUtilities.dp(6), getMeasuredHeight()); + shadowDrawable.draw(canvas); + if (checkAutoscroll) { + checkAutoscroll = false; + if (topViewsContainer.getTranslationY() != 0 && topViewsContainer.getTranslationY() != recyclerListView.getPaddingTop()) { + if (topViewsContainer.getTranslationY() > recyclerListView.getPaddingTop() / 2f) { + scroller.smoothScrollBy((int) -(recyclerListView.getPaddingTop() - topViewsContainer.getTranslationY())); + } else { + scroller.smoothScrollBy((int) topViewsContainer.getTranslationY()); + } + + } + } + super.dispatchDraw(canvas); + } + + public void onTopOffsetChanged(int paddingTop) { - addView(titleView); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (ev.getY() < topViewsContainer.getTranslationY()) { + return false; + } + return super.onInterceptTouchEvent(ev); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getY() < topViewsContainer.getTranslationY()) { + return false; + } + return super.onTouchEvent(event); } @Override @@ -126,33 +485,107 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { } private void checkLoadMore() { - if (model != null && layoutManager.findLastVisibleItemPosition() > listAdapter.getItemCount() - 10) { - model.loadNext(); + if (currentModel != null && layoutManager.findLastVisibleItemPosition() > listAdapter.getItemCount() - 10) { + currentModel.loadNext(); } } public void setStoryItem(SelfStoryViewsView.StoryItemInternal storyItem) { this.storyItem = storyItem; + updateViewsVisibility(); + updateViewState(false); + } + + private void updateViewsVisibility() { + this.showSearch = false; + this.showContactsFilter = false; + this.showReactionsSort = false; + boolean forceHideTitle = false; if (storyItem.storyItem != null) { TLRPC.StoryItem serverItem = storyItem.storyItem; - model = MessagesController.getInstance(currentAccount).storiesController.selfViewsModel.get(serverItem.id); + if (serverItem.views != null) { + showSearch = serverItem.views.views_count >= 15; + showReactionsSort = serverItem.views.reactions_count >= (BuildVars.DEBUG_PRIVATE_VERSION ? 5 : 10); + showContactsFilter = serverItem.views.views_count >= 20 && !serverItem.contacts && !serverItem.close_friends && !serverItem.selected_contacts; + } + defaultModel = MessagesController.getInstance(currentAccount).storiesController.selfViewsModel.get(serverItem.id); int totalCount = serverItem.views == null ? 0 : serverItem.views.views_count; - if (model == null || model.totalCount != totalCount) { - if (model != null) { - model.release(); + if (defaultModel == null || defaultModel.totalCount != totalCount) { + if (defaultModel != null) { + defaultModel.release(); } - model = new ViewsModel(currentAccount, serverItem); - model.loadNext(); - MessagesController.getInstance(currentAccount).storiesController.selfViewsModel.put(serverItem.id, model); + defaultModel = new ViewsModel(currentAccount, serverItem, true); + defaultModel.reloadIfNeed(state, showContactsFilter, showReactionsSort); + defaultModel.loadNext(); + MessagesController.getInstance(currentAccount).storiesController.selfViewsModel.put(serverItem.id, defaultModel); + } else { + defaultModel.reloadIfNeed(state, showContactsFilter, showReactionsSort); + } + if (currentModel != null) { + currentModel.removeListener(this); + } + currentModel = defaultModel; + if (currentModel != null && isAttachedToWindow) { + currentModel.addListener(this); } - if (serverItem.views == null || serverItem.views.views_count == 0) { - titleView.setText(LocaleController.getString("NobodyViewsTitle", R.string.NobodyViewsTitle)); + if ((currentModel.isExpiredViews && !UserConfig.getInstance(currentAccount).isPremium()) || (!currentModel.loading && !currentModel.hasNext && currentModel.views.isEmpty() && TextUtils.isEmpty(currentModel.state.searchQuery))) { + showSearch = false; + showReactionsSort = false; + showContactsFilter = false; + titleView.setText(LocaleController.getString("Viewers", R.string.Viewers)); + searchField.setVisibility(View.GONE); + headerView.setVisibility(View.GONE); + TOP_PADDING = 46; + } else if (serverItem.views == null || serverItem.views.views_count == 0) { + showSearch = false; + showReactionsSort = false; + showContactsFilter = false; + titleView.setText(LocaleController.getString("Viewers", R.string.Viewers)); + searchField.setVisibility(View.GONE); + headerView.setVisibility(View.GONE); + TOP_PADDING = 46; } else { - titleView.setText(LocaleController.formatPluralStringComma("Views", serverItem.views.views_count)); + headerView.setVisibility(View.VISIBLE); + if (currentModel.showReactionOnly) { + titleView.setText(LocaleController.formatPluralString("Likes", serverItem.views.reactions_count, serverItem.views.reactions_count)); + showSearch = false; + showReactionsSort = false; + showContactsFilter = false; + } else { + if (currentModel.views.size() < 20 && currentModel.views.size() < serverItem.views.views_count && !currentModel.loading && !currentModel.hasNext) { + showSearch = false; + showReactionsSort = false; + showContactsFilter = false; + showServerErrorText = true; + } else { + showSearch = serverItem.views.views_count >= 15; + showReactionsSort = serverItem.views.reactions_count >= (BuildVars.DEBUG_VERSION ? 5 : 10); + showContactsFilter = serverItem.views.views_count >= 20 && !serverItem.contacts && !serverItem.close_friends && !serverItem.selected_contacts; + } + titleView.setText(LocaleController.getString("Viewers", R.string.Viewers)); + } + searchField.setVisibility(showSearch ? View.VISIBLE : View.GONE); + TOP_PADDING = showSearch ? 96 : 46; + + // titleView.setText(LocaleController.formatPluralStringComma("Views", serverItem.views.views_count)); } } else { + TOP_PADDING = 46; titleView.setText(LocaleController.getString("UploadingStory", R.string.UploadingStory)); + searchField.setVisibility(View.GONE); + headerView.setVisibility(View.GONE); + } + headerView.buttonContainer.setVisibility(showReactionsSort ? View.VISIBLE : View.GONE); + headerView.allViewersView.setVisibility(showContactsFilter ? View.VISIBLE : View.GONE); + headerView.contactsViewersView.setVisibility(showContactsFilter ? View.VISIBLE : View.GONE); + if (!showContactsFilter && !forceHideTitle) { + titleView.setVisibility(View.VISIBLE); + } else { + titleView.setVisibility(View.GONE); } + + ((MarginLayoutParams) shadowView.getLayoutParams()).topMargin = AndroidUtilities.dp(TOP_PADDING - 8); + ((MarginLayoutParams) shadowView2.getLayoutParams()).topMargin = AndroidUtilities.dp(TOP_PADDING - 17); } public static void preload(int currentAccount, TLRPC.StoryItem storyItem) { @@ -165,7 +598,7 @@ public static void preload(int currentAccount, TLRPC.StoryItem storyItem) { if (model != null) { model.release(); } - model = new ViewsModel(currentAccount, storyItem); + model = new ViewsModel(currentAccount, storyItem, true); model.loadNext(); MessagesController.getInstance(currentAccount).storiesController.selfViewsModel.put(storyItem.id, model); } @@ -174,35 +607,49 @@ public static void preload(int currentAccount, TLRPC.StoryItem storyItem) { @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - if (model != null) { - model.addListener(this); - model.animateDateForUsers.clear(); + isAttachedToWindow = true; + if (currentModel != null) { + currentModel.addListener(this); + currentModel.animateDateForUsers.clear(); } listAdapter.updateRows(); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.storiesUpdated); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.storiesBlocklistUpdate); + Bulletin.addDelegate(this, new Bulletin.Delegate() { + @Override + public int getBottomOffset(int tag) { + return recyclerListView.getPaddingBottom(); + } + }); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - if (model != null) { - model.removeListener(this); + isAttachedToWindow = false; + if (currentModel != null) { + currentModel.removeListener(this); } NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storiesUpdated); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storiesBlocklistUpdate); + Bulletin.removeDelegate(this); } - public void onDataRecieved() { - NotificationCenter.getInstance(currentAccount).doOnIdle(() -> { + public void onDataRecieved(ViewsModel model) { + // NotificationCenter.getInstance(currentAccount).doOnIdle(() -> { int oldCount = listAdapter.getItemCount(); + if (TextUtils.isEmpty(state.searchQuery) && !state.contactsOnly) { + updateViewsVisibility(); + } listAdapter.updateRows(); recyclerItemsEnterAnimator.showItemsAnimated(oldCount); checkLoadMore(); - }); + // }); } public void setListBottomPadding(float bottomPadding) { if (bottomPadding != recyclerListView.getPaddingBottom()) { - recyclerListView.setPadding(0, 0, 0, (int) bottomPadding); + recyclerListView.setPadding(0, (int) bottomPadding, 0, 0); recyclerListView.requestLayout(); } } @@ -224,9 +671,53 @@ public void didReceivedNotification(int id, int account, Object... args) { } } } + } else if (id == NotificationCenter.storiesBlocklistUpdate) { + for (int i = 0; i < recyclerListView.getChildCount(); ++i) { + View child = recyclerListView.getChildAt(i); + if (child instanceof ReactedUserHolderView) { + int position = recyclerListView.getChildAdapterPosition(child); + if (position < 0 || position >= listAdapter.items.size()) { + continue; + } + ((ReactedUserHolderView) child).animateAlpha(isStoryShownToUser(listAdapter.items.get(position).user) ? 1 : .5f, true); + } + } } } + protected void updateSharedState() { +// if (sharedFilterState != null) { +// state.sortByReactions = sharedFilterState.sortByReactions; +// state.contactsOnly = sharedFilterState.contactsOnly; +// reload(); +// updateViewState(false); +// } + } + + public void setShadowDrawable(Drawable shadowDrawable) { + this.shadowDrawable = shadowDrawable; + } + + public void onKeyboardShown() { + recyclerListView.dispatchTouchEvent(AndroidUtilities.emptyMotionEvent()); + if (topViewsContainer.getTranslationY() != 0) { + scroller.smoothScrollBy((int) topViewsContainer.getTranslationY(), AdjustPanLayoutHelper.keyboardDuration, AdjustPanLayoutHelper.keyboardInterpolator); + } + } + + public boolean onBackPressed() { + if (Math.abs(topViewsContainer.getTranslationY() - recyclerListView.getPaddingTop()) > AndroidUtilities.dp(2)) { + recyclerListView.dispatchTouchEvent(AndroidUtilities.emptyMotionEvent()); + recyclerListView.smoothScrollToPosition(0); + return true; + } + return false; + } + + public float getTopOffset() { + return topViewsContainer.getTranslationY(); + } + private class ListAdapter extends RecyclerListView.SelectionAdapter { ArrayList items = new ArrayList<>(); @@ -263,27 +754,94 @@ public void openStory(long dialogId, Runnable onDone) { loadingView.showDate(false); view = loadingView; break; + case FLICKER_LOADING_ITEM_FULL: + loadingView = new FlickerLoadingView(getContext(), resourcesProvider); + loadingView.setIsSingleCell(true); + loadingView.setIgnoreHeightCheck(true); + loadingView.setItemsCount(20); + loadingView.setViewType(FlickerLoadingView.SOTRY_VIEWS_USER_TYPE); + loadingView.showDate(false); + view = loadingView; + break; + case SERVER_CANT_RETURN_TEXT_HINT: + case SUBSCRIBE_TO_PREMIUM_TEXT_HINT: + LinkSpanDrawable.LinksTextView textView = new LinkSpanDrawable.LinksTextView(getContext()); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider)); + textView.setLinkTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkText, resourcesProvider)); + int padding = AndroidUtilities.dp(16); + int paddingHorizontal = AndroidUtilities.dp(21); + textView.setPadding(paddingHorizontal, padding, paddingHorizontal, padding); + textView.setMaxLines(Integer.MAX_VALUE); + textView.setGravity(Gravity.CENTER); + textView.setDisablePaddingsOffsetY(true); + if (viewType == SUBSCRIBE_TO_PREMIUM_TEXT_HINT) { + textView.setText(AndroidUtilities.replaceSingleTag(LocaleController.getString("StoryViewsPremiumHint", R.string.StoryViewsPremiumHint), () -> { + showPremiumAlert(); + })); + } else { + textView.setText(LocaleController.getString("ServerErrorViewersFull", R.string.ServerErrorViewersFull)); + } + textView.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + view = textView; + break; default: - case LAST_ITEM: + case LAST_PADDING_VIEW: view = new View(getContext()) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int h = layoutManager.getLastItemHeight(); + if (h >= recyclerListView.getPaddingTop() && !showSearch) { + h = 0; + } + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY)); } }; break; + case EMPTY_VIEW_NO_CONTACTS: + case EMPTY_VIEW_SEARCH: case EMPTY_VIEW: - StickerEmptyView emptyView = new StickerEmptyView(getContext(), null, model.isExpiredViews ? StickerEmptyView.STICKER_TYPE_PRIVACY : StickerEmptyView.STICKER_TYPE_NO_CONTACTS, resourcesProvider) { + case EMPTY_VIEW_SERVER_CANT_RETURN: + int stickerType; + if (defaultModel.isExpiredViews) { + stickerType = StickerEmptyView.STICKER_TYPE_PRIVACY; + } else if (viewType == EMPTY_VIEW_SERVER_CANT_RETURN || viewType == EMPTY_VIEW_SEARCH || viewType == EMPTY_VIEW_NO_CONTACTS || viewType == EMPTY_VIEW) { + stickerType = StickerEmptyView.STICKER_TYPE_SEARCH; + } else { + stickerType = StickerEmptyView.STICKER_TYPE_NO_CONTACTS; + } + StickerEmptyView emptyView = new StickerEmptyView(getContext(), null, stickerType, resourcesProvider) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(measuerdHeight - recyclerListView.getPaddingBottom(), MeasureSpec.EXACTLY)); + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(measuerdHeight - recyclerListView.getPaddingTop() - AndroidUtilities.dp(TOP_PADDING), MeasureSpec.EXACTLY)); } }; - emptyView.title.setVisibility(View.GONE); - if (model.isExpiredViews) { - emptyView.subtitle.setText(AndroidUtilities.replaceTags(LocaleController.getString("ExpiredViewsStub", R.string.ExpiredViewsStub))); + if (viewType == EMPTY_VIEW_SEARCH) { + emptyView.title.setVisibility(View.GONE); + emptyView.setSubtitle(LocaleController.getString("NoResult", R.string.NoResult)); + } else if (viewType == EMPTY_VIEW_NO_CONTACTS) { + emptyView.title.setVisibility(View.GONE); + emptyView.setSubtitle(LocaleController.getString("NoContactsViewed", R.string.NoContactsViewed)); + } else if (viewType == EMPTY_VIEW_SERVER_CANT_RETURN) { + emptyView.title.setVisibility(View.VISIBLE); + emptyView.title.setText(LocaleController.getString("ServerErrorViewersTitle", R.string.ServerErrorViewersTitle)); + emptyView.setSubtitle(LocaleController.getString("ServerErrorViewers", R.string.ServerErrorViewers)); + } else if (defaultModel.isExpiredViews) { + emptyView.title.setVisibility(View.GONE); + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); + spannableStringBuilder.append(AndroidUtilities.replaceTags(LocaleController.getString("ExpiredViewsStub", R.string.ExpiredViewsStub))); + spannableStringBuilder.append("\n\n"); + spannableStringBuilder.append(AndroidUtilities.replaceSingleTag(LocaleController.getString("ExpiredViewsStubPremiumDescription", R.string.ExpiredViewsStubPremiumDescription), () -> { + showPremiumAlert(); + })); + emptyView.subtitle.setText(spannableStringBuilder); + emptyView.createButtonLayout(LocaleController.getString("LearnMore", R.string.LearnMore), () -> { + showPremiumAlert(); + }); } else { - emptyView.subtitle.setText(LocaleController.getString("NoViewsStub", R.string.NoViewsStub)); + emptyView.title.setVisibility(View.VISIBLE); + emptyView.title.setText(LocaleController.getString("NoViews", R.string.NoViews)); + emptyView.setSubtitle(LocaleController.getString("NoViewsStub", R.string.NoViewsStub)); } emptyView.showProgress(false, false); view = emptyView; @@ -298,9 +856,18 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi ReactedUserHolderView view = (ReactedUserHolderView) holder.itemView; TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(items.get(position).user.user_id); - boolean animated = model.animateDateForUsers.remove(items.get(position).user.user_id); - view.setUserReaction(user, null, null, items.get(position).user.date, true, animated); - // items.get(position + 1).viewType == USER_ITEM + boolean animated = defaultModel.animateDateForUsers.remove(items.get(position).user.user_id); + boolean like = false; + if (items.get(position).user.reaction != null) { + ReactionsLayoutInBubble.VisibleReaction visibleReaction = ReactionsLayoutInBubble.VisibleReaction.fromTLReaction(items.get(position).user.reaction); + if (visibleReaction != null && visibleReaction.emojicon != null && visibleReaction.emojicon.equals("\u2764")) { + like = true; + } + } + view.setUserReaction(user, null, like ? null : items.get(position).user.reaction, like, items.get(position).user.date, true, animated); + int nextItemType = position < items.size() - 1 ? items.get(position + 1).viewType : -1; + view.drawDivider = nextItemType == USER_ITEM || nextItemType == SUBSCRIBE_TO_PREMIUM_TEXT_HINT || nextItemType == SERVER_CANT_RETURN_TEXT_HINT; + view.animateAlpha(isStoryShownToUser(items.get(position).user) ? 1f : .5f, false); } } @@ -316,19 +883,44 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { public void updateRows() { items.clear(); - if (model != null && model.views.isEmpty() && (model.isExpiredViews || (!model.loading && !model.hasNext))) { - items.add(new Item(EMPTY_VIEW)); + ViewsModel model = currentModel; + if (isSearchDebounce) { + items.add(new Item(FIRST_PADDING_ITEM)); + items.add(new Item(FLICKER_LOADING_ITEM_FULL)); } else { items.add(new Item(FIRST_PADDING_ITEM)); - if (model != null) { - for (int i = 0; i < model.views.size(); i++) { - items.add(new Item(USER_ITEM, model.views.get(i))); + if (model != null && model.views.isEmpty() && (model.isExpiredViews || (!model.loading && !model.hasNext))) { + if (!TextUtils.isEmpty(model.state.searchQuery)) { + items.add(new Item(EMPTY_VIEW_SEARCH)); + } else if (model.isExpiredViews) { + items.add(new Item(EMPTY_VIEW)); + } else if (model.totalCount > 0 && model.state.contactsOnly) { + items.add(new Item(EMPTY_VIEW_NO_CONTACTS)); + } else if (model.totalCount > 0) { + items.add(new Item(EMPTY_VIEW_SERVER_CANT_RETURN)); + } else { + items.add(new Item(EMPTY_VIEW)); + } + } else { + if (model != null) { + for (int i = 0; i < model.views.size(); i++) { + items.add(new Item(USER_ITEM, model.views.get(i))); + } + } + if (model != null && (model.loading || model.hasNext)) { + if (model.views.isEmpty()) { + items.add(new Item(FLICKER_LOADING_ITEM_FULL)); + } else { + items.add(new Item(FLICKER_LOADING_ITEM)); + } + } else if (model != null && model.showReactionOnly) { + items.add(new Item(SUBSCRIBE_TO_PREMIUM_TEXT_HINT)); + } else if (model != null && model.views.size() < model.totalCount && TextUtils.isEmpty(model.state.searchQuery) && !model.state.contactsOnly) { + items.add(new Item(SERVER_CANT_RETURN_TEXT_HINT)); } - } - if (model != null && (model.loading || model.hasNext)) { - items.add(new Item(FLICKER_LOADING_ITEM)); } } + items.add(new Item(LAST_PADDING_VIEW)); notifyDataSetChanged(); } @@ -338,6 +930,11 @@ public int getItemViewType(int position) { } } + private void showPremiumAlert() { + PremiumFeatureBottomSheet sheet = new PremiumFeatureBottomSheet(storyViewer.fragment, PremiumPreviewFragment.PREMIUM_FEATURE_STORIES, false); + sheet.show(); + } + private class Item { final int viewType; TLRPC.TL_storyView user; @@ -359,27 +956,41 @@ public static class ViewsModel { int currentAccount; boolean loading; ArrayList views = new ArrayList<>(); + ArrayList originalViews = new ArrayList<>(); boolean isExpiredViews; + boolean showReactionOnly; boolean initial; boolean hasNext = true; - long offsetId; - int offsetDate; + String offset; int reqId = -1; HashSet animateDateForUsers = new HashSet<>(); + boolean useLocalFilters; ArrayList listeners = new ArrayList<>(); + FiltersState state = new FiltersState(); - public ViewsModel(int currentAccount, TLRPC.StoryItem storyItem) { + public ViewsModel(int currentAccount, TLRPC.StoryItem storyItem, boolean isDefault) { this.currentAccount = currentAccount; this.storyItem = storyItem; this.totalCount = storyItem.views == null ? 0 : storyItem.views.views_count; - isExpiredViews = StoriesUtilities.hasExpiredViews(storyItem); + if (totalCount < 200) { + useLocalFilters = true; + } + isExpiredViews = StoriesUtilities.hasExpiredViews(storyItem) && !UserConfig.getInstance(currentAccount).isPremium(); + if (isExpiredViews && storyItem.views != null && storyItem.views.reactions_count > 0) { + isExpiredViews = false; + showReactionOnly = true; + } if (!isExpiredViews) { initial = true; - if (storyItem.views != null) { + if (storyItem.views != null && isDefault) { for (int i = 0; i < storyItem.views.recent_viewers.size(); i++) { + long uid = storyItem.views.recent_viewers.get(i); + if (MessagesController.getInstance(currentAccount).getUser(uid) == null) { + continue; + } TLRPC.TL_storyView storyView = new TLRPC.TL_storyView(); - storyView.user_id = storyItem.views.recent_viewers.get(i); + storyView.user_id = uid; storyView.date = 0; views.add(storyView); } @@ -393,16 +1004,37 @@ public void loadNext() { } TLRPC.TL_stories_getStoryViewsList req = new TLRPC.TL_stories_getStoryViewsList(); req.id = storyItem.id; - req.limit = initial ? 20 : 100; - req.offset_id = offsetId; - req.offset_date = offsetDate; + if (useLocalFilters) { + req.q = ""; + req.just_contacts = false; + req.reactions_first = true; + } else { + req.q = state.searchQuery; + if (!TextUtils.isEmpty(req.q)) { + req.flags |= 2; + } + req.just_contacts = state.contactsOnly; + req.reactions_first = state.sortByReactions; + } + req.limit = (initial || views.size() < 20) ? 20 : 100; + req.offset = offset; + if (req.offset == null) { + req.offset = ""; + } loading = true; - reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + int[] localReqId = new int[1]; + FileLog.d("SelfStoryViewsPage load next " + storyItem.id + " " + initial + " offset=" + req.offset + " q" + req.q + " " + req.just_contacts + " " + req.reactions_first); + localReqId[0] = reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (localReqId[0] != reqId) { + FileLog.d("SelfStoryViewsPage " + storyItem.id + " localId != reqId"); + return; + } loading = false; reqId = -1; if (response != null) { TLRPC.TL_stories_storyViewsList res = (TLRPC.TL_stories_storyViewsList) response; + MessagesController.getInstance(currentAccount).getStoriesController().applyStoryViewsBlocked(res); MessagesController.getInstance(currentAccount).putUsers(res.users, false); if (initial) { initial = false; @@ -410,17 +1042,24 @@ public void loadNext() { animateDateForUsers.add(views.get(i).user_id); } views.clear(); + originalViews.clear(); + } + if (useLocalFilters) { + originalViews.addAll(res.views); + applyLocalFilter(); + } else { + views.addAll(res.views); } - views.addAll(res.views); if (!res.views.isEmpty()) { - TLRPC.TL_storyView last = res.views.get(res.views.size() - 1); - offsetDate = last.date; - offsetId = last.user_id; - hasNext = res.views.size() == req.limit; + hasNext = true; } else { hasNext = false; } + offset = res.next_offset; + if (TextUtils.isEmpty(offset)) { + hasNext = false; + } if (storyItem.views == null) { storyItem.views = new TLRPC.TL_storyViews(); @@ -435,11 +1074,49 @@ public void loadNext() { } else { hasNext = false; } + + FileLog.d("SelfStoryViewsPage " + storyItem.id + " response totalItems " + views.size() + " has next " + hasNext); for (int i = 0; i < listeners.size(); i++) { - listeners.get(i).onDataRecieved(); + listeners.get(i).onDataRecieved(this); + } + if (views.size() < 20 && hasNext) { + loadNext(); } })); + } + private void applyLocalFilter() { + views.clear(); + if (state.contactsOnly || !TextUtils.isEmpty(state.searchQuery)) { + String search1 = null; + String search2 = null; + if (!TextUtils.isEmpty(state.searchQuery)) { + search1 = state.searchQuery.trim().toLowerCase(); + search2 = LocaleController.getInstance().getTranslitString(search1); + } + for (int i = 0; i < originalViews.size(); i++) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(originalViews.get(i).user_id); + boolean canAdd = true; + if (state.contactsOnly && (user == null || !user.contact)) { + canAdd = false; + } + if (canAdd && search1 != null) { + String name = ContactsController.formatName(user.first_name, user.last_name).toLowerCase(); + String username = UserObject.getPublicUsername(user); + if (!(name.contains(search1) || name.contains(search2) || (username != null && (username.contains(search1) || username.contains(search2))))) { + canAdd = false; + } + } + if (canAdd) { + views.add(originalViews.get(i)); + } + } + } else { + views.addAll(originalViews); + } + if (!state.sortByReactions) { + Collections.sort(views, Comparator.comparingInt(o -> -o.date)); + } } public void addListener(SelfStoryViewsPage listener) { @@ -458,5 +1135,304 @@ public void release() { } reqId = -1; } + + public void reloadIfNeed(FiltersState state, boolean showContactsFilter, boolean showReactionsSort) { + FiltersState localState = new FiltersState(); + localState.set(state); + if (!showContactsFilter) { + localState.contactsOnly = false; + } + if (!showReactionsSort) { + localState.sortByReactions = true; + } + if (this.state.equals(localState)) { + return; + } + this.state.set(localState); + if (useLocalFilters) { + applyLocalFilter(); + for (int i = 0; i < listeners.size(); i++) { + listeners.get(i).onDataRecieved(this); + } + } else { + release(); + views.clear(); + initial = true; + loading = false; + hasNext = true; + offset = ""; + loadNext(); + } + } + } + + private class HeaderView extends FrameLayout { + + private final LinearLayout buttonContainer; + Paint selectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + TextView allViewersView; + TextView contactsViewersView; + + RectF animateFromRect = new RectF(); + float animateFromAlpha1; + float animateFromAlpha2; + + RectF rectF = new RectF(); + float animationProgress = 1f; + int selected; + boolean lastSortType; + ReplaceableIconDrawable replacableDrawable; + + public HeaderView(@NonNull Context context) { + super(context); + selectedPaint.setColor(Theme.getColor(Theme.key_listSelector, resourcesProvider)); + + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + + allViewersView = new TextView(context); + allViewersView.setText(LocaleController.getString("AllViewers", R.string.AllViewers)); + allViewersView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + allViewersView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + allViewersView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + allViewersView.setPadding(AndroidUtilities.dp(12), AndroidUtilities.dp(4), AndroidUtilities.dp(12), AndroidUtilities.dp(4)); + + contactsViewersView = new TextView(context); + contactsViewersView.setText(LocaleController.getString("Contacts", R.string.Contacts)); + contactsViewersView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack, resourcesProvider)); + contactsViewersView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + contactsViewersView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + contactsViewersView.setPadding(AndroidUtilities.dp(12), AndroidUtilities.dp(4), AndroidUtilities.dp(12), AndroidUtilities.dp(4)); + + linearLayout.setPadding(0, AndroidUtilities.dp(6), 0, AndroidUtilities.dp(6)); + linearLayout.addView(allViewersView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, 13, 0, 0, 0)); + linearLayout.addView(contactsViewersView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, 0, 0, 0, 0)); + + buttonContainer = new LinearLayout(getContext()); + buttonContainer.setPadding(AndroidUtilities.dp(6), 0, AndroidUtilities.dp(6), 0); + buttonContainer.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(26), Theme.getColor(Theme.key_listSelector, resourcesProvider))); + buttonContainer.setOrientation(LinearLayout.HORIZONTAL); + replacableDrawable = new ReplaceableIconDrawable(getContext()); + replacableDrawable.exactlyBounds = true; + lastSortType = true; + replacableDrawable.setIcon(R.drawable.menu_views_reactions3, false); + ImageView imageView = new ImageView(getContext()); + imageView.setScaleType(ImageView.ScaleType.FIT_XY); + imageView.setImageDrawable(replacableDrawable); + buttonContainer.addView(imageView, LayoutHelper.createLinear(26, 26)); + + ImageView arrowImage = new ImageView(getContext()); + arrowImage.setImageResource(R.drawable.arrow_more); + buttonContainer.addView(arrowImage, LayoutHelper.createLinear(16, 26)); + + addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); + addView(buttonContainer, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.RIGHT, 13, 6, 13, 6)); + + allViewersView.setOnClickListener(v -> { + if (!state.contactsOnly) { + return; + } + state.contactsOnly = false; + updateViewState(true); + reload(); + }); + contactsViewersView.setOnClickListener(v -> { + if (state.contactsOnly) { + return; + } + state.contactsOnly = true; + updateViewState(true); + reload(); + }); + buttonContainer.setOnClickListener(v -> { + popupMenu = new CustomPopupMenu(getContext(), resourcesProvider, false) { + @Override + protected void onCreate(ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout) { + popupLayout.setBackgroundColor(ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.18f)); + ActionBarMenuSubItem item = ActionBarMenuItem.addItem(popupLayout, state.sortByReactions ? R.drawable.menu_views_reactions2 : R.drawable.menu_views_reactions, LocaleController.getString("SortByReactions", R.string.SortByReactions), false, resourcesProvider); + if (!state.sortByReactions) { + item.setAlpha(0.5f); + } + item.setOnClickListener(v -> { + if (!state.sortByReactions) { + if (sharedFilterState != null) { + sharedFilterState.sortByReactions = state.sortByReactions = true; + } else { + state.sortByReactions = true; + } + updateViewState(true); + reload(); + onSharedStateChanged.accept(SelfStoryViewsPage.this); + } + if (popupMenu != null) { + popupMenu.dismiss(); + } + }); + + item = ActionBarMenuItem.addItem(popupLayout, !state.sortByReactions ? R.drawable.menu_views_recent2 : R.drawable.menu_views_recent, LocaleController.getString("SortByTime", R.string.SortByTime), false, resourcesProvider); + if (state.sortByReactions) { + item.setAlpha(0.5f); + } + item.setOnClickListener(v -> { + if (state.sortByReactions) { + if (sharedFilterState != null) { + sharedFilterState.sortByReactions = state.sortByReactions = false; + } else { + state.sortByReactions = false; + } + updateViewState(true); + reload(); + onSharedStateChanged.accept(SelfStoryViewsPage.this); + } + if (popupMenu != null) { + popupMenu.dismiss(); + } + }); + ActionBarPopupWindow.GapView gap = new ActionBarPopupWindow.GapView(getContext(), resourcesProvider, Theme.key_actionBarDefaultSubmenuSeparator); + gap.setTag(R.id.fit_width_tag, 1); + popupLayout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + ActionBarMenuItem.addText(popupLayout, LocaleController.getString("StoryViewsSortDescription", R.string.StoryViewsSortDescription), resourcesProvider); + } + + @Override + protected void onDismissed() { + + } + }; + popupMenu.show(buttonContainer, 0, -buttonContainer.getMeasuredHeight() - AndroidUtilities.dp(8)); + }); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (showContactsFilter) { + float allViewersAlpha, contactsAlpha; + if (selected == 0) { + allViewersView.getHitRect(AndroidUtilities.rectTmp2); + allViewersAlpha = 1f; + contactsAlpha = 0.5f; + } else { + contactsViewersView.getHitRect(AndroidUtilities.rectTmp2); + allViewersAlpha = 0.5f; + contactsAlpha = 1f; + } + rectF.set(AndroidUtilities.rectTmp2); + if (animationProgress != 1f) { + allViewersAlpha = AndroidUtilities.lerp(animateFromAlpha1, allViewersAlpha, animationProgress); + contactsAlpha = AndroidUtilities.lerp(animateFromAlpha2, contactsAlpha, animationProgress); + AndroidUtilities.lerp(animateFromRect, rectF, animationProgress, rectF); + } + allViewersView.setAlpha(allViewersAlpha); + contactsViewersView.setAlpha(contactsAlpha); + float r = rectF.height() / 2f; + canvas.drawRoundRect(rectF, r, r, selectedPaint); + } + super.dispatchDraw(canvas); + } + + ValueAnimator animator; + + public void setState(boolean contactsOnly, boolean animate) { + int localSelected = contactsOnly ? 1 : 0; + if (localSelected == selected && animate) { + return; + } + if (animator != null) { + animator.removeAllListeners(); + animator.cancel(); + } + selected = localSelected; + if (!animate) { + animationProgress = 1f; + invalidate(); + return; + } else { + animateFromRect.set(rectF); + animateFromAlpha1 = allViewersView.getAlpha(); + animateFromAlpha2 = contactsViewersView.getAlpha(); + animationProgress = 0; + invalidate(); + animator = ValueAnimator.ofFloat(0, 1f); + animator.addUpdateListener(animation -> { + animationProgress = (float) animator.getAnimatedValue(); + invalidate(); + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + animator = null; + animationProgress = 1f; + invalidate(); + } + }); + animator.setDuration(250); + animator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animator.start(); + } + } + } + + private void reload() { + if (currentModel != null) { + currentModel.removeListener(this); + } + currentModel = defaultModel; + if (currentModel == null) { + return; + } + currentModel.addListener(this); + currentModel.reloadIfNeed(state, showContactsFilter, showReactionsSort); + listAdapter.updateRows(); + layoutManager.scrollToPositionWithOffset(0, (int) (getTopOffset() - recyclerListView.getPaddingTop())); + } + + private void updateViewState(boolean animated) { + headerView.setState(state.contactsOnly, animated); + if (headerView.lastSortType != state.sortByReactions) { + headerView.lastSortType = state.sortByReactions; + headerView.replacableDrawable.setIcon(state.sortByReactions ? R.drawable.menu_views_reactions3 : R.drawable.menu_views_recent3, animated); + } + } + + public static class FiltersState { + boolean sortByReactions = true; + boolean contactsOnly; + String searchQuery; + + public boolean isDefault() { + return sortByReactions && !contactsOnly && TextUtils.isEmpty(searchQuery); + } + + public void set(FiltersState state) { + sortByReactions = state.sortByReactions; + contactsOnly = state.contactsOnly; + searchQuery = state.searchQuery; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + FiltersState that = (FiltersState) o; + boolean textIsEquals = (TextUtils.isEmpty(searchQuery) && TextUtils.isEmpty(that.searchQuery)) || Objects.equals(searchQuery, that.searchQuery); + return sortByReactions == that.sortByReactions && contactsOnly == that.contactsOnly && textIsEquals; + } + + @Override + public int hashCode() { + return Objects.hash(sortByReactions, contactsOnly, searchQuery); + } + } + + private class RecyclerListViewInner extends RecyclerListView implements StoriesListPlaceProvider.ClippedView { + public RecyclerListViewInner(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context, resourcesProvider); + } + + @Override + public void updateClip(int[] clip) { + clip[0] = AndroidUtilities.dp(TOP_PADDING); + clip[1] = getMeasuredHeight(); + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsView.java index e2d250eee8d..2f5f5e1f4a1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/SelfStoryViewsView.java @@ -1,7 +1,7 @@ package org.telegram.ui.Stories; +import android.animation.ValueAnimator; import android.content.Context; -import android.graphics.Canvas; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; @@ -19,11 +19,12 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.FileLog; -import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.LayoutHelper; @@ -45,10 +46,15 @@ public class SelfStoryViewsView extends FrameLayout { float selfStoriesViewsOffset; boolean listenPager; + int keyboardHeight; + int animatedKeyboardHeight; + ViewPagerInner viewPager; ArrayList storyItems = new ArrayList<>(); ArrayList itemViews = new ArrayList<>(); private int currentState; + SelfStoryViewsPage.FiltersState sharedFilterState = new SelfStoryViewsPage.FiltersState(); + float progressToKeyboard; public SelfStoryViewsView(@NonNull Context context, StoryViewer storyViewer) { super(context); @@ -76,6 +82,13 @@ public void onClosestPositionChanged(int lastClosestPosition) { viewPager.setCurrentItem(lastClosestPosition, false); } } + if (storyViewer.storiesList != null && storyViewer.placeProvider != null) { + if (lastClosestPosition < 10) { + storyViewer.placeProvider.loadNext(false); + } else if (lastClosestPosition >= storyItems.size() - 10) { + storyViewer.placeProvider.loadNext(true); + } + } } @Override @@ -89,7 +102,45 @@ public void onCenteredImageTap() { shadowDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogBackground, resourcesProvider), PorterDuff.Mode.MULTIPLY)); viewPagerContainer = new ContainerView(context); - viewPager = new ViewPagerInner(context); + viewPager = new ViewPagerInner(context) { + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (checkTopOffset(ev) && ev.getAction() == MotionEvent.ACTION_DOWN) { + return false; + } + return super.dispatchTouchEvent(ev); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (checkTopOffset(ev)) { + return false; + } + if (Math.abs(getCurrentTopOffset() - bottomPadding) > AndroidUtilities.dp(1)) { + return false; + } + return super.onInterceptTouchEvent(ev); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (checkTopOffset(ev)) { + return false; + } + if (Math.abs(getCurrentTopOffset() - bottomPadding) > AndroidUtilities.dp(1)) { + return false; + } + return super.onTouchEvent(ev); + } + + private boolean checkTopOffset(MotionEvent ev) { + if (ev.getY() < getCurrentTopOffset()) { + return true; + } + return false; + } + }; viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { @@ -117,6 +168,7 @@ public void onPageScrollStateChanged(int state) { } }); viewPager.setAdapter(pagerAdapter = new PagerAdapter() { + @Override public int getCount() { return storyItems.size(); @@ -125,14 +177,25 @@ public int getCount() { @NonNull @Override public Object instantiateItem(@NonNull ViewGroup container, int position) { - SelfStoryViewsPage item = new SelfStoryViewsPage(storyViewer, context) { + SelfStoryViewsPage item = new SelfStoryViewsPage(storyViewer, context, sharedFilterState, selfStoryViewsPage -> { + for (int i = 0; i < itemViews.size(); i++) { + if (selfStoryViewsPage != itemViews.get(i)) { + itemViews.get(i).updateSharedState(); + } + } + }) { @Override - protected void dispatchDraw(Canvas canvas) { - shadowDrawable.setBounds(-AndroidUtilities.dp(6), 0, getMeasuredWidth() + AndroidUtilities.dp(6), getMeasuredHeight()); - shadowDrawable.draw(canvas); - super.dispatchDraw(canvas); + public void onTopOffsetChanged(int paddingTop) { + super.onTopOffsetChanged(paddingTop); + if ((Integer) getTag() == viewPager.getCurrentItem()) { + float progress = Utilities.clamp( (paddingTop / bottomPadding), 1f, 0); + selfStoriesPreviewView.setAlpha(progress); + selfStoriesPreviewView.setTranslationY(-(bottomPadding - paddingTop) / 2f); + } } }; + item.setTag(position); + item.setShadowDrawable(shadowDrawable); item.setPadding(0, AndroidUtilities.dp(16), 0 , 0); item.setStoryItem(storyItems.get(position)); // bottomPadding = (selfStoriesPreviewView.getTop() + toHeight + AndroidUtilities.dp(24)); @@ -140,7 +203,6 @@ protected void dispatchDraw(Canvas canvas) { container.addView(item); - itemViews.add(item); return item; } @@ -185,6 +247,37 @@ public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { setVisibility(View.INVISIBLE); } + private float getCurrentTopOffset() { + float top = bottomPadding; + SelfStoryViewsPage page = getCurrentPage(); + if (page != null) { + top = page.getTopOffset(); + } + return top; + } + + public void setKeyboardHeight(int keyboardHeight) { + boolean keyboardVisible = this.keyboardHeight >= AndroidUtilities.dp(20); + boolean newKeyboardVisible = keyboardHeight >= AndroidUtilities.dp(20); + if (newKeyboardVisible != keyboardVisible) { + ValueAnimator keyboardAniamtor = ValueAnimator.ofFloat(progressToKeyboard, newKeyboardVisible ? 1f : 0); + keyboardAniamtor.addUpdateListener(animation -> { + progressToKeyboard = (float) animation.getAnimatedValue(); + updateTranslation(); + }); + keyboardAniamtor.setInterpolator(AdjustPanLayoutHelper.keyboardInterpolator); + keyboardAniamtor.setDuration(AdjustPanLayoutHelper.keyboardDuration); + keyboardAniamtor.start(); + } + this.keyboardHeight = keyboardHeight; + if (keyboardHeight > 0) { + SelfStoryViewsPage page = getCurrentPage(); + if (page != null) { + page.onKeyboardShown(); + } + } + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int topMargin = 0;//AndroidUtilities.dp(20); @@ -196,7 +289,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { layoutParams.topMargin = topMargin; toHeight = selfStoriesPreviewView.getFinalHeight(); toY = topMargin + AndroidUtilities.dp(20); - bottomPadding = (topMargin + AndroidUtilities.dp(20) + toHeight + AndroidUtilities.dp(24)); + layoutParams = (LayoutParams) viewPagerContainer.getLayoutParams(); + layoutParams.topMargin = AndroidUtilities.statusBarHeight; + bottomPadding = (topMargin + AndroidUtilities.dp(20) + toHeight + AndroidUtilities.dp(24)) -AndroidUtilities.statusBarHeight; maxSelfStoriesViewsOffset = height - bottomPadding; for (int i = 0; i < itemViews.size(); i++) { itemViews.get(i).setListBottomPadding(bottomPadding); @@ -204,22 +299,30 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } - public void setOffset(float selfStoriesViewsOffset) { if (this.selfStoriesViewsOffset == selfStoriesViewsOffset) { return; } this.selfStoriesViewsOffset = selfStoriesViewsOffset; - viewPagerContainer.setTranslationY(getMeasuredHeight() - selfStoriesViewsOffset); + updateTranslation(); float oldProgressToOpen = progressToOpen; progressToOpen = Utilities.clamp(selfStoriesViewsOffset / maxSelfStoriesViewsOffset, 1f, 0); float alpha = Utilities.clamp(progressToOpen / 0.5f, 1f, 0); - // selfStoriesPreviewView.setAlpha(alpha); final PeerStoriesView currentView = storyViewer.getCurrentPeerView(); if (oldProgressToOpen == 1f && progressToOpen != 1f) { - if (currentView != null) { - currentView.selectPosition(selfStoriesPreviewView.getClosestPosition()); + if (storyViewer.storiesList != null) { + MessageObject object = storyViewer.storiesList.messageObjects.get(selfStoriesPreviewView.getClosestPosition()); + long date = StoriesController.StoriesList.day(object); + if (storyViewer.transitionViewHolder.storyImage != null) { + storyViewer.transitionViewHolder.storyImage.setVisible(true, true); + storyViewer.transitionViewHolder.storyImage = null; + } + storyViewer.storiesViewPager.setCurrentDate(date, object.storyItem.id); + } else { + if (currentView != null) { + currentView.selectPosition(selfStoriesPreviewView.getClosestPosition()); + } } selfStoriesPreviewView.abortScroll(); } @@ -238,6 +341,10 @@ public void setOffset(float selfStoriesViewsOffset) { } } + private void updateTranslation() { + viewPagerContainer.setTranslationY(-bottomPadding + getMeasuredHeight() - selfStoriesViewsOffset); + } + public void setItems(ArrayList storyItems, int selectedPosition) { this.storyItems.clear(); for (int i = 0; i < storyItems.size(); i++) { @@ -254,11 +361,31 @@ public void setItems(ArrayList storyItems, int selectedPosition viewPager.setCurrentItem(selectedPosition); } - public ImageReceiver getCrossfadeToImage() { + public SelfStoriesPreviewView.ImageHolder getCrossfadeToImage() { return selfStoriesPreviewView.getCenteredImageReciever(); } - private class ContainerView extends FrameLayout implements NestedScrollingParent3{ + public boolean onBackPressed() { + if (keyboardHeight > 0) { + AndroidUtilities.hideKeyboard(this); + return true; + } + SelfStoryViewsPage page = getCurrentPage(); + if (page != null) { + return page.onBackPressed(); + } + return false; + } + + public TLRPC.StoryItem getSelectedStory() { + int p = selfStoriesPreviewView.getClosestPosition(); + if (p < 0 || p >= storyItems.size()) { + return null; + } + return storyItems.get(p).storyItem; + } + + private class ContainerView extends FrameLayout implements NestedScrollingParent3 { private final NestedScrollingParentHelper nestedScrollingParentHelper; @@ -269,6 +396,9 @@ public ContainerView(@NonNull Context context) { @Override public boolean onStartNestedScroll(@NonNull View child, @NonNull View target, int axes, int type) { + if (keyboardHeight > 0) { + return false; + } if (axes == ViewCompat.SCROLL_AXIS_VERTICAL) { return true; } @@ -292,6 +422,9 @@ public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, @Override public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type, @NonNull int[] consumed) { + if (keyboardHeight > 0) { + return; + } if (dyUnconsumed != 0 && dyConsumed == 0) { float currentTranslation = storyViewer.selfStoriesViewsOffset; currentTranslation += dyUnconsumed; @@ -306,7 +439,10 @@ public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, @Override public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) { - + //AndroidUtilities.hideKeyboard(this); + if (keyboardHeight > 0) { + return; + } float currentTranslation = storyViewer.selfStoriesViewsOffset; if (currentTranslation < maxSelfStoriesViewsOffset && dy > 0) { currentTranslation += dy; @@ -333,7 +469,7 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { gesturesEnabled = true; } - if (!gesturesEnabled) { + if (!gesturesEnabled || keyboardHeight > 0) { return false; } try { @@ -348,7 +484,7 @@ public boolean onTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { gesturesEnabled = true; } - if (!gesturesEnabled) { + if (!gesturesEnabled || keyboardHeight > 0) { return false; } return super.onTouchEvent(ev); @@ -368,5 +504,14 @@ public StoryItemInternal(StoriesController.UploadingStory uploadingStory) { } } + public SelfStoryViewsPage getCurrentPage() { + for (int i = 0; i < itemViews.size(); i++) { + if ((Integer)itemViews.get(i).getTag() == viewPager.getCurrentItem()) { + return itemViews.get(i); + } + } + return null; + } + } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StealthModeAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StealthModeAlert.java new file mode 100644 index 00000000000..576cbc8353a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StealthModeAlert.java @@ -0,0 +1,250 @@ +package org.telegram.ui.Stories; + +import android.content.Context; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.text.Layout; +import android.text.SpannableStringBuilder; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.HapticFeedbackConstants; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.core.graphics.ColorUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.ActionBar.SimpleTextView; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.Bulletin; +import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.ColoredImageSpan; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Premium.PremiumButtonView; +import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; +import org.telegram.ui.Components.ScaleStateListAnimator; +import org.telegram.ui.LaunchActivity; +import org.telegram.ui.PremiumPreviewFragment; +import org.telegram.ui.Stories.recorder.ButtonWithCounterView; + +import java.util.Locale; + +public class StealthModeAlert extends BottomSheet { + + private final PremiumButtonView button; + boolean stealthModeIsActive; + + public StealthModeAlert(Context context, float topOffset, Theme.ResourcesProvider resourcesProvider) { + super(context, false, resourcesProvider); + FrameLayout frameLayout = new FrameLayout(getContext()) { + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + Bulletin.addDelegate(container, new Bulletin.Delegate() { + @Override + public int getTopOffset(int tag) { + return (int) (topOffset + AndroidUtilities.dp(58)); + } + }); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + Bulletin.removeDelegate(container); + } + }; + + ImageView imageView = new ImageView(getContext()); + imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + imageView.setBackground(Theme.createCircleDrawable(AndroidUtilities.dp(80), Theme.getColor(Theme.key_featuredStickers_addButton))); + imageView.setImageResource(R.drawable.large_stealth); + frameLayout.addView(imageView, LayoutHelper.createFrame(80, 80, Gravity.CENTER_HORIZONTAL, 0, 18, 0, 0)); + + LinearLayout linearLayout = new LinearLayout(getContext()); + linearLayout.setOrientation(LinearLayout.VERTICAL); + frameLayout.addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 116, 0, 0)); + + TextView title = new TextView(getContext()); + title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + title.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + title.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + title.setText(LocaleController.getString("StealthMode", R.string.StealthMode)); + linearLayout.addView(title, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL)); + + SimpleTextView subtitle = new SimpleTextView(getContext()); + subtitle.setTextSize(14); + subtitle.setAlignment(Layout.Alignment.ALIGN_CENTER); + subtitle.setMaxLines(100); + subtitle.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider)); + if (UserConfig.getInstance(currentAccount).isPremium()) { + subtitle.setText(LocaleController.getString("StealthModeHint", R.string.StealthModeHint)); + } else { + subtitle.setText(LocaleController.getString("StealthModePremiumHint", R.string.StealthModePremiumHint)); + } + linearLayout.addView(subtitle, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 36, 10, 36, 0)); + + ItemCell itemCell = new ItemCell(getContext()); + itemCell.imageView.setImageResource(R.drawable.msg_stealth_5min); + itemCell.textView.setText(LocaleController.getString("HideRecentViews", R.string.HideRecentViews)); + itemCell.description.setText(LocaleController.getString("HideRecentViewsDescription", R.string.HideRecentViewsDescription)); + + linearLayout.addView(itemCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT,0, 0, 20, 0, 0)); + + + ItemCell itemCell2 = new ItemCell(getContext()); + itemCell2.imageView.setImageResource(R.drawable.msg_stealth_25min); + itemCell2.textView.setText(LocaleController.getString("HideNextViews", R.string.HideNextViews)); + itemCell2.description.setText(LocaleController.getString("HideNextViewsDescription", R.string.HideNextViewsDescription)); + + linearLayout.addView(itemCell2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT,0, 0, 10, 0, 0)); + + button = new PremiumButtonView(context, AndroidUtilities.dp(8), true); + button.drawGradient = false; + button.overlayTextView.getDrawable().setSplitByWords(false); + button.setIcon(R.raw.unlock_icon); + ScaleStateListAnimator.apply(button); + TLRPC.User user = UserConfig.getInstance(currentAccount).getCurrentUser(); + if (!user.premium) { + button.setIcon(R.raw.unlock_icon); + button.setButton(LocaleController.getString("UnlockStealthMode", R.string.UnlockStealthMode), v -> { + dismiss(); + BaseFragment baseFragment = LaunchActivity.getLastFragment(); + if (baseFragment != null) { + PremiumFeatureBottomSheet sheet = new PremiumFeatureBottomSheet(baseFragment, PremiumPreviewFragment.PREMIUM_FEATURE_STORIES, false); + baseFragment.showDialog(sheet); + } + }); + } else { + updateButton(false); + } + linearLayout.addView(button, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM, 14, 24, 14, 16)); + + + setCustomView(frameLayout); + + button.setOnClickListener(v -> { + if (!user.premium) { + dismiss(); + BaseFragment baseFragment = LaunchActivity.getLastFragment(); + if (baseFragment != null) { + PremiumFeatureBottomSheet sheet = new PremiumFeatureBottomSheet(baseFragment, PremiumPreviewFragment.PREMIUM_FEATURE_STORIES, false); + baseFragment.showDialog(sheet); + } + } else { + if (stealthModeIsActive) { + dismiss(); + return; + } + StoriesController storiesController = MessagesController.getInstance(currentAccount).getStoriesController(); + TLRPC.TL_storiesStealthMode stealthMode = storiesController.getStealthMode(); + if (stealthMode == null || ConnectionsManager.getInstance(currentAccount).getCurrentTime() > stealthMode.cooldown_until_date) { + TLRPC.TL_stories_activateStealthMode req = new TLRPC.TL_stories_activateStealthMode(); + req.future = true; + req.past = true; + stealthMode = new TLRPC.TL_storiesStealthMode(); + stealthMode.flags |= 1 + 2; + stealthMode.cooldown_until_date = ConnectionsManager.getInstance(currentAccount).getCurrentTime() +MessagesController.getInstance(currentAccount).stealthModeCooldown; + stealthMode.active_until_date = ConnectionsManager.getInstance(currentAccount).getCurrentTime() + MessagesController.getInstance(currentAccount).stealthModeFuture; + storiesController.setStealthMode(stealthMode); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + + })); + containerView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); + dismiss(); + showStealthModeEnabledBulletin(); + } else if (stealthModeIsActive) { + dismiss(); + } else { + BulletinFactory factory = BulletinFactory.of(container, resourcesProvider); + if (factory != null) { + factory.createErrorBulletin( + AndroidUtilities.replaceTags(LocaleController.getString("StealthModeCooldownHint", R.string.StealthModeCooldownHint)) + ).show(true); + } + } + } + }); + } + + public static void showStealthModeEnabledBulletin() { + BaseFragment fragment = LaunchActivity.getLastFragment(); + BulletinFactory factory; + if (fragment.storyViewer != null) { + factory = BulletinFactory.of(fragment.storyViewer.windowView, fragment.storyViewer.getResourceProvider()); + } else { + factory = BulletinFactory.global(); + } + if (factory != null) { + factory.createSimpleLargeBulletin(R.drawable.msg_stories_stealth2, + LocaleController.getString("StealthModeOn", R.string.StealthModeOn), + LocaleController.getString("StealthModeOnHint", R.string.StealthModeOnHint) + ).show(); + } + } + + Runnable updateButtonRunnuble = () -> { + if (isShowing()) { + updateButton(true); + } + }; + + private void updateButton(boolean animated) { + StoriesController storiesController = MessagesController.getInstance(currentAccount).getStoriesController(); + TLRPC.TL_storiesStealthMode stealthMode = storiesController.getStealthMode(); + if (stealthMode != null && ConnectionsManager.getInstance(currentAccount).getCurrentTime() < stealthMode.active_until_date) { + stealthModeIsActive = true; + button.setOverlayText(LocaleController.getString("StealthModeIsActive", R.string.StealthModeIsActive), true, animated); + button.overlayTextView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); + } else if (stealthMode == null || ConnectionsManager.getInstance(currentAccount).getCurrentTime() > stealthMode.cooldown_until_date) { + button.setOverlayText(LocaleController.getString("EnableStealthMode", R.string.EnableStealthMode), true, animated); + button.overlayTextView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); + } else { + long timeLeft = stealthMode.cooldown_until_date - ConnectionsManager.getInstance(currentAccount).getCurrentTime(); + int s = (int) ((timeLeft) % 60); + int m = (int) ((timeLeft / 60) % 60); + int h = (int) ((timeLeft / 60 / 60)); + String time = String.format(Locale.ENGLISH, "%02d", h) + String.format(Locale.ENGLISH, ":%02d", m) + String.format(Locale.ENGLISH, ":%02d", s); + button.setOverlayText(LocaleController.formatString("AvailableIn", R.string.AvailableIn, time), true, animated); + button.overlayTextView.setTextColor(ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_featuredStickers_buttonText), 125)); + AndroidUtilities.cancelRunOnUIThread(updateButtonRunnuble); + AndroidUtilities.runOnUIThread(updateButtonRunnuble, 1000); + } + } + + private class ItemCell extends FrameLayout { + + TextView textView; + TextView description; + ImageView imageView; + + public ItemCell(Context context) { + super(context); + imageView = new ImageView(context); + imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_featuredStickers_addButton), PorterDuff.Mode.MULTIPLY)); + addView(imageView, LayoutHelper.createFrame(28, 28, 0, 25, 12, 16, 0)); + + textView = new TextView(context); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 68, 8, 16, 0)); + + description = new TextView(context); + description.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider)); + description.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + addView(description, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 68, 28, 16, 8)); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java index ae830706e07..11e61e9654a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesController.java @@ -3,6 +3,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.text.TextUtils; +import android.util.Log; import android.util.SparseArray; import android.webkit.MimeTypeMap; @@ -18,6 +19,7 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BuildVars; +import org.telegram.messenger.DialogObject; import org.telegram.messenger.DownloadController; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; @@ -40,9 +42,13 @@ import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.NativeByteBuffer; import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.SerializedData; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.EmojiThemes; import org.telegram.ui.Components.Bulletin; +import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; +import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; import org.telegram.ui.Stories.recorder.DraftsController; import org.telegram.ui.Stories.recorder.StoryEntry; import org.telegram.ui.Stories.recorder.StoryPrivacyBottomSheet; @@ -61,6 +67,7 @@ import java.util.List; import java.util.Locale; import java.util.Objects; +import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; @@ -108,6 +115,7 @@ public class StoriesController { private String stateHidden; private boolean hasMoreHidden = true; private boolean firstLoad = true; + private TLRPC.TL_storiesStealthMode stealthMode; public StoriesController(int currentAccount) { this.currentAccount = currentAccount; @@ -118,6 +126,7 @@ public StoriesController(int currentAccount) { totalStoriesCountHidden = mainSettings.getInt("total_stores_hidden", 0); totalStoriesCount = mainSettings.getInt("total_stores", 0); storiesReadLoaded = mainSettings.getBoolean("read_loaded", false); + stealthMode = readStealthMode(mainSettings.getString("stories_stealth_mode", null)); pollingViewsForSelfStoriesRequester = new ViewsForSelfStoriesRequester(this, currentAccount); storiesStorage.getMaxReadIds(longSparseIntArray -> dialogIdToMaxReadId = longSparseIntArray); @@ -130,6 +139,32 @@ public StoriesController(int currentAccount) { draftsController = new DraftsController(currentAccount); } + private TLRPC.TL_storiesStealthMode readStealthMode(String string) { + if (string == null) { + return null; + } + SerializedData serializedData = new SerializedData(Utilities.hexToBytes(string)); + try { + TLRPC.TL_storiesStealthMode storiesStealthMode = TLRPC.TL_storiesStealthMode.TLdeserialize(serializedData, serializedData.readInt32(true), true); + + return storiesStealthMode; + } catch (Throwable e) { + FileLog.e(e); + } + return null; + } + + private void writeStealthMode(TLRPC.TL_storiesStealthMode mode) { + SharedPreferences.Editor editor = MessagesController.getInstance(currentAccount).getMainSettings().edit(); + if (mode == null) { + editor.remove("stories_stealth_mode").apply(); + return; + } + SerializedData data = new SerializedData(mode.getObjectSize()); + mode.serializeToStream(data); + editor.putString("stories_stealth_mode", Utilities.bytesToHex(data.toByteArray())).apply(); + } + public void loadAllStories() { if (!firstLoad) { loadStories(); @@ -164,7 +199,7 @@ private void fixDeletedAndNonContactsStories(ArrayList lis for (int k = 0; k < list.size(); k++) { TLRPC.TL_userStories userStories = list.get(k); TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(userStories.user_id); - if (user != null && !user.contact) { + if (user != null && !isContactOrService(user)) { list.remove(k); k--; } @@ -308,6 +343,7 @@ private void loadFromServer(boolean hidden) { FileLog.d("StoriesController loaded stories from server state=" + req.state + " more=" + req.next + " " + response); if (response instanceof TLRPC.TL_stories_allStories) { TLRPC.TL_stories_allStories storiesResponse = (TLRPC.TL_stories_allStories) response; + MessagesStorage.getInstance(currentAccount).putUsersAndChats(storiesResponse.users, null, true, true); if (!hidden) { this.totalStoriesCount = ((TLRPC.TL_stories_allStories) response).count; this.hasMore = ((TLRPC.TL_stories_allStories) response).has_more; @@ -355,7 +391,7 @@ private void processAllStoriesResponse(TLRPC.TL_stories_allStories storiesRespon } FileLog.d("StoriesController processAllStoriesResponse " + storiesResponse.user_stories.size() + " " + fromCache + " " + hidden); - MessagesController.getInstance(currentAccount).putUsers(storiesResponse.users, false); + MessagesController.getInstance(currentAccount).putUsers(storiesResponse.users, fromCache); for (int i = 0; i < storiesResponse.user_stories.size(); i++) { TLRPC.TL_userStories userStories = storiesResponse.user_stories.get(i); @@ -539,6 +575,7 @@ private void applyNewStories(TLRPC.TL_userStories stories) { preloadUserStories(stories); } } + FileLog.d("StoriesController applyNewStories " + stories.user_id); updateStoriesInLists(stories.user_id, stories.stories); } @@ -576,7 +613,7 @@ public void processUpdate(TLRPC.TL_updateStory updateStory) { return; } TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(updateStory.user_id); - if (user != null && (user.contact || user.self)) { + if (user != null && (isContactOrService(user) || user.self)) { storiesStorage.processUpdate(updateStory); } AndroidUtilities.runOnUIThread(() -> { @@ -627,7 +664,7 @@ public void processUpdate(TLRPC.TL_updateStory updateStory) { FileLog.d("StoriesController can't add new story isExpired"); return; } - if (user == null || (!user.self && !user.contact)) { + if (user == null || (!user.self && !isContactOrService(user))) { FileLog.d("StoriesController can't add new story user is not contact"); return; } @@ -659,7 +696,7 @@ public void processUpdate(TLRPC.TL_updateStory updateStory) { FileLog.d("StoriesController can't add user " + updateStory.user_id + " with new story isExpired"); return; } - if (user == null || (!user.self && !user.contact)) { + if (user == null || (!user.self && !isContactOrService(user))) { FileLog.d("StoriesController can't add user cause is not contact"); return; } @@ -684,6 +721,10 @@ public void processUpdate(TLRPC.TL_updateStory updateStory) { }); } + private boolean isContactOrService(TLRPC.User user) { + return user != null && (user.contact || user.id == MessagesController.getInstance(currentAccount).storiesChangelogUserId); + } + private void applyToList(TLRPC.TL_userStories currentUserStory) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(currentUserStory.user_id); if (user == null) { @@ -740,7 +781,7 @@ private void loadAllStoriesForDialog(long user_id) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(user_id); TLRPC.TL_userStories stories = stories_userStories.stories; allStoriesMap.put(stories.user_id, stories); - if (user != null && (user.contact || user.self)) { + if (user != null && (isContactOrService(user) || user.self)) { applyToList(stories); storiesStorage.putUserStories(stories); } @@ -793,7 +834,7 @@ public void deleteStory(TLRPC.StoryItem storyItem) { req.id.add(storyItem.id); ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { if (error == null) { - + AndroidUtilities.runOnUIThread(this::invalidateStoryLimit); } }); storiesStorage.deleteStory(getSelfUserId(), storyItem.id); @@ -827,7 +868,7 @@ public void deleteStories(ArrayList storyItems) { req.id.add(storyItem.id); } ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - + AndroidUtilities.runOnUIThread(this::invalidateStoryLimit); }); updateDeletedStoriesInLists(getSelfUserId(), storyItems); storiesStorage.deleteStories(getSelfUserId(), req.id); @@ -845,6 +886,7 @@ public void updateStoriesPinned(ArrayList storyItems, boolean p // todo: do update stories in one go in database req.id.add(storyItem.id); } + FileLog.d("StoriesController updateStoriesPinned"); updateStoriesInLists(getSelfUserId(), storyItems); req.pinned = pinned; ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { @@ -859,6 +901,7 @@ private long getSelfUserId() { } public void updateStoryItem(long dialogId, TLRPC.StoryItem storyItem) { + FileLog.d("StoriesController updateStoryItem " + dialogId + " " + (storyItem == null ? "null" : storyItem.id + "@" + storyItem.dialogId)); storiesStorage.updateStoryItem(dialogId, storyItem); updateStoriesInLists(dialogId, Collections.singletonList(storyItem)); } @@ -1063,8 +1106,8 @@ public void loadNextStories(boolean hidden) { } } - public void fillMessagesWithStories(LongSparseArray> messagesWithUnknownStories, Runnable callback) { - storiesStorage.fillMessagesWithStories(messagesWithUnknownStories, callback); + public void fillMessagesWithStories(LongSparseArray> messagesWithUnknownStories, Runnable callback, int classGuid) { + storiesStorage.fillMessagesWithStories(messagesWithUnknownStories, callback, classGuid); } LongSparseArray resolvedStories = new LongSparseArray<>(); @@ -1131,7 +1174,7 @@ public int getTotalStoriesCount(boolean hidden) { public void putStories(long dialogId, TLRPC.TL_userStories stories) { allStoriesMap.put(dialogId, stories); TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialogId); - if (user.contact || user.self) { + if (isContactOrService(user) || user.self) { storiesStorage.putUserStories(stories); applyToList(stories); } @@ -1203,6 +1246,9 @@ private void checkExpireStories(ArrayList dialogListStorie public void checkExpiredStories(long dialogId) { TLRPC.TL_userStories userStories = getStories(dialogId); + if (userStories == null) { + return; + } for (int i = 0; i < userStories.stories.size(); i++) { if (StoriesUtilities.isExpired(currentAccount, userStories.stories.get(i))) { userStories.stories.remove(i); @@ -1220,12 +1266,84 @@ public boolean hasLoadingStories() { return loadingDialogsStories.size() > 0; } + public TLRPC.TL_storiesStealthMode getStealthMode() { + return stealthMode; + } + + public void setStealthMode(TLRPC.TL_storiesStealthMode stealthMode) { + this.stealthMode = stealthMode; + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.stealthModeChanged); + writeStealthMode(stealthMode); + } + + public void setStoryReaction(long dialogId, TLRPC.StoryItem storyItem, ReactionsLayoutInBubble.VisibleReaction visibleReaction) { + if (storyItem == null) { + return; + } + TLRPC.TL_stories_sendReaction req = new TLRPC.TL_stories_sendReaction(); + req.story_id = storyItem.id; + req.user_id = MessagesController.getInstance(currentAccount).getInputUser(dialogId); + if (visibleReaction == null) { + req.reaction = new TLRPC.TL_reactionEmpty(); + // req.flags |= 1; + storyItem.flags &= ~32768; + storyItem.sent_reaction = null; + } else if (visibleReaction.documentId != 0) { + TLRPC.TL_reactionCustomEmoji reactionCustomEmoji = new TLRPC.TL_reactionCustomEmoji(); + reactionCustomEmoji.document_id = visibleReaction.documentId; + req.reaction = reactionCustomEmoji; + // req.flags |= 1; + storyItem.flags |= 32768; + storyItem.sent_reaction = reactionCustomEmoji; + } else if (visibleReaction.emojicon != null) { + TLRPC.TL_reactionEmoji reactionEmoji = new TLRPC.TL_reactionEmoji(); + reactionEmoji.emoticon = visibleReaction.emojicon; + req.reaction = reactionEmoji; + storyItem.flags |= 32768; + storyItem.sent_reaction = reactionEmoji; + } + updateStoryItem(dialogId, storyItem); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + + }); + } + + public void updateStoryReaction(long dialogId, int storyId, TLRPC.Reaction reaction) { + TLRPC.StoryItem storyItem = findStory(dialogId, storyId); + if (storyItem != null) { + storyItem.sent_reaction = reaction; + if (storyItem.sent_reaction != null) { + storyItem.flags |= 32768; + } else { + storyItem.flags &= ~32768; + } + updateStoryItem(dialogId, storyItem); + } + } + + private TLRPC.StoryItem findStory(long dialogId, int storyId) { + TLRPC.TL_userStories stories = allStoriesMap.get(dialogId); + if (stories != null) { + for (int i = 0; i < stories.stories.size(); i++) { + if (stories.stories.get(i).id == storyId) { + return stories.stories.get(i); + } + } + } + return null; + } + + public void onPremiumChanged() { + selfViewsModel.clear(); + } + public class UploadingStory implements NotificationCenter.NotificationCenterDelegate { public final long random_id; public final boolean edit; final StoryEntry entry; + private boolean entryDestroyed; String path; String firstFramePath; float progress; @@ -1328,8 +1446,9 @@ public void cleanup() { editingStories.remove(entry.editStoryId); } NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesUpdated); - if (entry != null) { + if (entry != null && !entry.isEditSaved && !entryDestroyed) { entry.destroy(false); + entryDestroyed = true; } NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.uploadStoryEnd, path); } @@ -1445,7 +1564,7 @@ private void sendUploadedRequest(TLRPC.InputFile uploadedFile) { } TLObject req; - final int captionLimit = MessagesController.getInstance(currentAccount).storyCaptionLengthLimit; + final int captionLimit = UserConfig.getInstance(currentAccount).isPremium() ? MessagesController.getInstance(currentAccount).storyCaptionLengthLimitPremium : MessagesController.getInstance(currentAccount).storyCaptionLengthLimitDefault; if (edit) { TLRPC.TL_stories_editStory editStory = new TLRPC.TL_stories_editStory(); editStory.id = entry.editStoryId; @@ -1461,7 +1580,11 @@ private void sendUploadedRequest(TLRPC.InputFile uploadedFile) { if (caption[0].length() > captionLimit) { caption[0] = caption[0].subSequence(0, captionLimit); } - editStory.entities = MediaDataController.getInstance(currentAccount).getEntities(caption, true); + if (MessagesController.getInstance(currentAccount).storyEntitiesAllowed()) { + editStory.entities = MediaDataController.getInstance(currentAccount).getEntities(caption, true); + } else { + editStory.entities.clear(); + } if (caption[0].length() > captionLimit) { caption[0] = caption[0].subSequence(0, captionLimit); } @@ -1473,6 +1596,21 @@ private void sendUploadedRequest(TLRPC.InputFile uploadedFile) { editStory.privacy_rules.addAll(entry.privacyRules); } + if (entry.editedMediaAreas != null) { + editStory.media_areas.addAll(entry.editedMediaAreas); + } + if (entry.mediaEntities != null) { + for (int i = 0; i < entry.mediaEntities.size(); ++i) { + VideoEditedInfo.MediaEntity mediaEntity = entry.mediaEntities.get(i); + if (mediaEntity.mediaArea != null) { + editStory.media_areas.add(mediaEntity.mediaArea); + } + } + } + if (!editStory.media_areas.isEmpty()) { + editStory.flags |= 8; + } + req = editStory; } else { TLRPC.TL_stories_sendStory sendStory = new TLRPC.TL_stories_sendStory(); @@ -1488,7 +1626,11 @@ private void sendUploadedRequest(TLRPC.InputFile uploadedFile) { if (caption[0].length() > captionLimit) { caption[0] = caption[0].subSequence(0, captionLimit); } - sendStory.entities = MediaDataController.getInstance(currentAccount).getEntities(caption, true); + if (MessagesController.getInstance(currentAccount).storyEntitiesAllowed()) { + sendStory.entities = MediaDataController.getInstance(currentAccount).getEntities(caption, true); + } else { + sendStory.entities.clear(); + } if (caption[0].length() > captionLimit) { caption[0] = caption[0].subSequence(0, captionLimit); } @@ -1502,6 +1644,18 @@ private void sendUploadedRequest(TLRPC.InputFile uploadedFile) { sendStory.period = entry.period; } + if (entry.mediaEntities != null) { + for (int i = 0; i < entry.mediaEntities.size(); ++i) { + VideoEditedInfo.MediaEntity mediaEntity = entry.mediaEntities.get(i); + if (mediaEntity.mediaArea != null) { + sendStory.media_areas.add(mediaEntity.mediaArea); + } + } + if (!sendStory.media_areas.isEmpty()) { + sendStory.flags |= 32; + } + } + req = sendStory; } @@ -1519,6 +1673,8 @@ private void sendUploadedRequest(TLRPC.InputFile uploadedFile) { storyId = updateStory.story.id; if (storyItem == null) { storyItem = updateStory.story; + } else { + storyItem.media = updateStory.story.media; } } if (updates.updates.get(i) instanceof TLRPC.TL_updateStoryID) { @@ -1527,6 +1683,7 @@ private void sendUploadedRequest(TLRPC.InputFile uploadedFile) { storyItem = new TLRPC.TL_storyItem(); storyItem.date = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); storyItem.expire_date = storyItem.date + (entry.period == Integer.MAX_VALUE ? 86400 : entry.period); + storyItem.parsedPrivacy = null; storyItem.privacy = StoryPrivacyBottomSheet.StoryPrivacy.toOutput(entry.privacyRules); storyItem.pinned = entry.period == Integer.MAX_VALUE; storyItem.dialogId = UserConfig.getInstance(currentAccount).clientUserId; @@ -1537,21 +1694,30 @@ private void sendUploadedRequest(TLRPC.InputFile uploadedFile) { } } } + final long did = UserConfig.getInstance(currentAccount).clientUserId; if (canceled) { TLRPC.TL_stories_deleteStories stories_deleteStory = new TLRPC.TL_stories_deleteStories(); stories_deleteStory.id.add(storyId); ConnectionsManager.getInstance(currentAccount).sendRequest(stories_deleteStory, (response1, error1) -> { - + AndroidUtilities.runOnUIThread(StoriesController.this::invalidateStoryLimit); }); } else { if ((storyId == 0 || edit) && storyItem != null) { TLRPC.TL_updateStory tl_updateStory = new TLRPC.TL_updateStory(); - tl_updateStory.user_id = UserConfig.getInstance(currentAccount).clientUserId; + tl_updateStory.user_id = did; tl_updateStory.story = storyItem; AndroidUtilities.runOnUIThread(() -> { MessagesController.getInstance(currentAccount).getStoriesController().processUpdate(tl_updateStory); }); } + final TLRPC.StoryItem storyItemFinal = storyItem; + AndroidUtilities.runOnUIThread(() -> { + entryDestroyed = true; + getDraftsController().saveForEdit(entry, did, storyItemFinal); + if (!edit) { + invalidateStoryLimit(); + } + }); MessagesController.getInstance(currentAccount).processUpdateArray(updates.updates, updates.users, updates.chats, false, updates.date); } } @@ -1613,7 +1779,44 @@ private StoriesList getStoriesList(long userId, int type, boolean createIfNotExi return list; } + private static String storyItemIds(List storyItems) { + try { + if (storyItems == null) { + return "null"; + } + String s = ""; + for (int i = 0; i < storyItems.size(); ++i) { + if (i > 0) s += ", "; + s += storyItems.get(i).id + "@" + storyItems.get(i).dialogId; + } + return s; + } catch (Exception e) { + return "err"; + } + } + + private static String storyItemMessageIds(List storyItems) { + try { + if (storyItems == null) { + return "null"; + } + String s = ""; + for (int i = 0; i < storyItems.size(); ++i) { + if (i > 0) s += ", "; + TLRPC.StoryItem storyItem = storyItems.get(i).storyItem; + if (storyItem == null) { + s += "null"; + } else + s += storyItem.id + "@" + storyItem.dialogId; + } + return s; + } catch (Exception e) { + return "err"; + } + } + public void updateStoriesInLists(long userId, List storyItems) { + FileLog.d("updateStoriesInLists " + userId + " storyItems[" + storyItems.size() + "] {" + storyItemIds(storyItems) + "}"); StoriesList pinned = getStoriesList(userId, StoriesList.TYPE_PINNED, false); StoriesList archived = getStoriesList(userId, StoriesList.TYPE_ARCHIVE, false); if (pinned != null) { @@ -1625,6 +1828,7 @@ public void updateStoriesInLists(long userId, List storyItems) } public void updateDeletedStoriesInLists(long userId, List storyItems) { + FileLog.d("updateDeletedStoriesInLists " + userId + " storyItems[" + storyItems.size() + "] {" + storyItemIds(storyItems) + "}"); StoriesList pinned = getStoriesList(userId, StoriesList.TYPE_PINNED, false); StoriesList archived = getStoriesList(userId, StoriesList.TYPE_ARCHIVE, false); if (pinned != null) { @@ -1705,12 +1909,6 @@ public boolean showVideos() { public void fill(boolean notify) { fill(this.messageObjects, showPhotos, showVideos); - String s = ""; - for (int i = 0; i < this.messageObjects.size(); ++i) { - long id = this.messageObjects.get(i).getId(); - if (i > 0) s += ", "; - s += id; - } if (notify) { AndroidUtilities.cancelRunOnUIThread(this.notify); AndroidUtilities.runOnUIThread(this.notify); @@ -1776,7 +1974,9 @@ private void preloadCache() { final MessagesStorage storage = MessagesStorage.getInstance(currentAccount); storage.getStorageQueue().postRunnable(() -> { SQLiteCursor cursor = null; + HashSet loadUserIds = new HashSet<>(); ArrayList cacheResult = new ArrayList<>(); + final ArrayList loadedUsers = new ArrayList<>(); try { SQLiteDatabase database = storage.getDatabase(); if (type == TYPE_PINNED) { @@ -1791,12 +1991,23 @@ private void preloadCache() { storyItem.dialogId = userId; storyItem.messageId = storyItem.id; MessageObject msg = new MessageObject(currentAccount, storyItem); + for (TLRPC.PrivacyRule rule : storyItem.privacy) { + if (rule instanceof TLRPC.TL_privacyValueDisallowUsers) { + loadUserIds.addAll(((TLRPC.TL_privacyValueDisallowUsers) rule).users); + } else if (rule instanceof TLRPC.TL_privacyValueAllowUsers) { + loadUserIds.addAll(((TLRPC.TL_privacyValueAllowUsers) rule).users); + } + } msg.generateThumbs(false); cacheResult.add(msg); data.reuse(); } } cursor.dispose(); + + if (!loadUserIds.isEmpty()) { + storage.getUsersInternal(TextUtils.join(",", loadUserIds), loadedUsers); + } } catch (Throwable e) { storage.checkSQLException(e); } finally { @@ -1807,7 +2018,9 @@ private void preloadCache() { } AndroidUtilities.runOnUIThread(() -> { + FileLog.d("StoriesList "+type+"{"+userId+"} preloadCache {" + storyItemMessageIds(cacheResult) + "}"); preloading = false; + MessagesController.getInstance(currentAccount).putUsers(loadedUsers, true); if (invalidateAfterPreload) { invalidateAfterPreload = false; toLoad = null; @@ -1936,6 +2149,7 @@ private void saveCache() { SQLitePreparedStatement state = null; ArrayList toSave = new ArrayList<>(); fill(toSave, true, true); + FileLog.d("StoriesList "+type+"{"+userId+"} saveCache {" + storyItemMessageIds(toSave) + "}"); try { SQLiteDatabase database = storage.getDatabase(); if (type == TYPE_PINNED) { @@ -2032,6 +2246,7 @@ public boolean load(boolean force, final int count) { req.limit = count; request = req; } + FileLog.d("StoriesList " + type + "{"+userId+"} load"); loading = true; ConnectionsManager.getInstance(currentAccount).sendRequest(request, (response, err) -> { @@ -2043,6 +2258,9 @@ public boolean load(boolean force, final int count) { newMessageObjects.add(toMessageObject(storyItem)); } AndroidUtilities.runOnUIThread(() -> { + FileLog.d("StoriesList " + type + "{"+userId+"} loaded {" + storyItemMessageIds(newMessageObjects) + "}"); + + MessagesController.getInstance(currentAccount).putUsers(stories.users, false); loading = false; totalCount = stories.count; @@ -2109,6 +2327,7 @@ public boolean load(boolean force, final int count) { // } public void updateDeletedStories(List storyItems) { + FileLog.d("StoriesList " + type + "{"+userId+"} updateDeletedStories {" + storyItemIds(storyItems) + "}"); if (storyItems == null) { return; } @@ -2136,6 +2355,7 @@ public void updateDeletedStories(List storyItems) { } public void updateStories(List storyItems) { + FileLog.d("StoriesList " + type + "{"+userId+"} updateStories {" + storyItemIds(storyItems) + "}"); if (storyItems == null) { return; } @@ -2153,11 +2373,13 @@ public void updateStories(List storyItems) { if (contains != shouldContain) { changed = true; if (!shouldContain) { + FileLog.d("StoriesList remove story " + storyItem.id); removeObject(storyItem.id, true); if (totalCount != -1) { totalCount--; } } else { + FileLog.d("StoriesList put story " + storyItem.id); pushObject(toMessageObject(storyItem), false); if (totalCount != -1) { totalCount++; @@ -2166,6 +2388,7 @@ public void updateStories(List storyItems) { } else if (contains && shouldContain) { MessageObject messageObject = messageObjectsMap.get(storyItem.id); if (messageObject == null || !equal(messageObject.storyItem, storyItem)) { + FileLog.d("StoriesList update story " + storyItem.id); messageObjectsMap.put(storyItem.id, toMessageObject(storyItem)); changed = true; } @@ -2282,4 +2505,277 @@ public void sortHiddenStories() { sortDialogStories(hiddenListStories); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesUpdated); } + + + public HashSet blocklist = new HashSet<>(); + private LongSparseArray blockedOverride = new LongSparseArray<>(); + + private int blocklistCount; + public boolean blocklistFull = false; + private boolean blocklistLoadingReset = false; + private boolean blocklistLoading = false; + private int blocklistReqId; + private long lastBlocklistRequested = 0; + + public void loadBlocklistAtFirst() { + if (lastBlocklistRequested == 0) + loadBlocklist(false); + } + + public void loadBlocklist(boolean reset) { + if (blocklistLoading) { + if (reset && !blocklistLoadingReset) { + ConnectionsManager.getInstance(currentAccount).cancelRequest(blocklistReqId, true); + blocklistReqId = 0; + blocklistLoading = blocklistLoadingReset = false; + } else { + return; + } + } + + if (reset && (System.currentTimeMillis() - lastBlocklistRequested) < 1000 * 60 * 30) { + return; + } + + if (!reset && blocklistFull) { + return; + } + + blocklistLoading = true; + blocklistLoadingReset = reset; + TLRPC.TL_contacts_getBlocked req = new TLRPC.TL_contacts_getBlocked(); + req.my_stories_from = true; + if (reset) { + req.offset = 0; + req.limit = 100; + blocklistFull = false; + } else { + req.offset = blocklist.size(); + req.limit = 25; + } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, err) -> AndroidUtilities.runOnUIThread(() -> { + if (response instanceof TLRPC.TL_contacts_blocked) { + TLRPC.TL_contacts_blocked res = (TLRPC.TL_contacts_blocked) response; + MessagesController.getInstance(currentAccount).putUsers(res.users, false); + MessagesController.getInstance(currentAccount).putChats(res.chats, false); + + blocklist.clear(); + for (TLRPC.TL_peerBlocked peer : res.blocked) { + long id = DialogObject.getPeerDialogId(peer.peer_id); + blocklist.add(id); + } + blocklistCount = Math.max(blocklist.size(), res.count); + blocklistFull = true; + } else if (response instanceof TLRPC.TL_contacts_blockedSlice) { + TLRPC.TL_contacts_blockedSlice res = (TLRPC.TL_contacts_blockedSlice) response; + MessagesController.getInstance(currentAccount).putUsers(res.users, false); + MessagesController.getInstance(currentAccount).putChats(res.chats, false); + + for (TLRPC.TL_peerBlocked peer : res.blocked) { + long id = DialogObject.getPeerDialogId(peer.peer_id); + blocklist.add(id); + } + blocklistCount = res.count; + blocklistFull = blocklist.size() >= blocklistCount; + } else { + return; + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesBlocklistUpdate); + blocklistLoading = false; + lastBlocklistRequested = System.currentTimeMillis(); + })); + } + + public int getBlocklistCount() { + return blocklistCount; + } + + public void updateBlockedUsers(HashSet ids, Runnable done) { + TLRPC.TL_contacts_setBlocked req = new TLRPC.TL_contacts_setBlocked(); + req.my_stories_from = true; + req.limit = blocklist.size(); + blocklistCount -= blocklist.size(); + if (blocklistCount < 0) { + blocklistCount = 0; + } + blocklist.clear(); + for (long id : ids) { + TLRPC.InputPeer inputPeer = MessagesController.getInstance(currentAccount).getInputPeer(id); + if (inputPeer == null || inputPeer instanceof TLRPC.TL_inputPeerEmpty) { + continue; + } + blocklist.add(id); + req.id.add(inputPeer); + } + blocklistCount += blocklist.size(); + req.limit = Math.max(req.limit, blocklist.size()); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (done != null) { + done.run(); + } + })); + } + + public boolean isBlocked(TLRPC.TL_storyView storyView) { + if (storyView == null) { + return false; + } + if (blockedOverride.containsKey(storyView.user_id)) { + return blockedOverride.get(storyView.user_id); + } + if (lastBlocklistRequested == 0) { + return storyView.blocked_my_stories_from || storyView.blocked; + } + if (blocklist.contains(storyView.user_id)) { + return true; + } + return storyView.blocked_my_stories_from || storyView.blocked; + } + + public boolean isBlocked(long did) { + if (blockedOverride.containsKey(did)) { + return blockedOverride.get(did); + } + return blocklist.contains(did); + } + + public void applyStoryViewsBlocked(TLRPC.TL_stories_storyViewsList res) { + if (res == null || res.views == null) { + return; + } + for (int i = 0; i < res.views.size(); ++i) { + TLRPC.TL_storyView view = res.views.get(i); + if (blockedOverride.containsKey(view.user_id)) { + blockedOverride.put(view.user_id, view.blocked_my_stories_from); + } + } + } + + public void updateBlockUser(long did, boolean block) { + updateBlockUser(did, block, true); + } + + public void updateBlockUser(long did, boolean block, boolean request) { + TLRPC.InputPeer inputPeer = MessagesController.getInstance(currentAccount).getInputPeer(did); + if (inputPeer == null || inputPeer instanceof TLRPC.TL_inputPeerEmpty) { + return; + } + + blockedOverride.put(did, block); + if (blocklist.contains(did) != block) { + if (block) { + blocklist.add(did); + blocklistCount++; + } else { + blocklist.remove(did); + blocklistCount--; + } + } + + if (request) { + TLObject req; + if (block) { + TLRPC.TL_contacts_block blockReq = new TLRPC.TL_contacts_block(); + blockReq.my_stories_from = true; + blockReq.id = inputPeer; + req = blockReq; + } else { + TLRPC.TL_contacts_unblock unblockReq = new TLRPC.TL_contacts_unblock(); + unblockReq.my_stories_from = true; + unblockReq.id = inputPeer; + req = unblockReq; + } + ConnectionsManager.getInstance(currentAccount).sendRequest(req, null); + } + + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesBlocklistUpdate); + } + + private boolean storyLimitFetched; + private StoryLimit storyLimitCached; + + public StoryLimit checkStoryLimit() { + final int countLimit = UserConfig.getInstance(currentAccount).isPremium() ? + MessagesController.getInstance(currentAccount).storyExpiringLimitPremium : + MessagesController.getInstance(currentAccount).storyExpiringLimitDefault; + + if (getMyStoriesCount() >= countLimit) { + return new StoryLimit(StoryLimit.LIMIT_COUNT, 0); + } + + if (storyLimitFetched) { + return storyLimitCached; + } + + ConnectionsManager.getInstance(currentAccount).sendRequest(new TLRPC.TL_stories_canSendStory(), (res, err) -> AndroidUtilities.runOnUIThread(() -> { + storyLimitFetched = true; + if (res instanceof TLRPC.TL_boolTrue) { + storyLimitCached = null; + } else if (err != null && err.text != null) { + if (err.text.startsWith("STORY_SEND_FLOOD_WEEKLY_")) { + long until = 0; + try { + until = Long.parseLong(err.text.substring("STORY_SEND_FLOOD_WEEKLY_".length())); + } catch (Exception ignore) {} + storyLimitCached = new StoryLimit(StoryLimit.LIMIT_WEEK, until); + } else if (err.text.startsWith("STORY_SEND_FLOOD_MONTHLY_")) { + long until = 0; + try { + until = Long.parseLong(err.text.substring("STORY_SEND_FLOOD_MONTHLY_".length())); + } catch (Exception ignore) {} + storyLimitCached = new StoryLimit(StoryLimit.LIMIT_MONTH, until); + } + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesLimitUpdate); + })); + return null; + } + + public boolean hasStoryLimit() { + StoryLimit storyLimit = checkStoryLimit(); + return storyLimit != null && storyLimit.active(currentAccount); + } + + public void invalidateStoryLimit() { + storyLimitFetched = false; + storyLimitCached = null; + } + + public static class StoryLimit { + + public static final int LIMIT_COUNT = 1; + public static final int LIMIT_WEEK = 2; + public static final int LIMIT_MONTH = 3; + + public int type; + public long until; + + public StoryLimit(int type, long until) { + this.type = type; + this.until = until; + } + + public int getLimitReachedType() { + switch (type) { + case LIMIT_WEEK: + return LimitReachedBottomSheet.TYPE_STORIES_WEEK; + case LIMIT_MONTH: + return LimitReachedBottomSheet.TYPE_STORIES_MONTH; + default: + case LIMIT_COUNT: + return LimitReachedBottomSheet.TYPE_STORIES_COUNT; + } + } + + public boolean active(int currentAccount) { + switch (type) { + case LIMIT_WEEK: + case LIMIT_MONTH: + return ConnectionsManager.getInstance(currentAccount).getCurrentTime() < until; + case LIMIT_COUNT: + default: + return true; + } + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesLikeButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesLikeButton.java new file mode 100644 index 00000000000..137bf0769e1 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesLikeButton.java @@ -0,0 +1,165 @@ +package org.telegram.ui.Stories; + +import android.content.Context; +import android.graphics.Canvas; +import android.view.View; + +import org.telegram.messenger.DocumentObject; +import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.SvgHelper; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AnimatedEmojiDrawable; +import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; + +import java.util.Objects; + +public class StoriesLikeButton extends View { + + PeerStoriesView.SharedResources sharedResources; + boolean liked; + AnimatedFloat progressToLiked = new AnimatedFloat(this); + ImageReceiver reactionImageReceiver = new ImageReceiver(this); + ImageReceiver animateReactionImageReceiver = new ImageReceiver(this); + AnimatedEmojiDrawable emojiDrawable; + private boolean allowDrawReaction = true; + private boolean isLike; + private boolean drawAnimateImageReciever; + private boolean attachedToWindow; + + ReactionsLayoutInBubble.VisibleReaction currentReaction; + + + public StoriesLikeButton(Context context, PeerStoriesView.SharedResources sharedResources) { + super(context); + this.sharedResources = sharedResources; + reactionImageReceiver.setAllowLoadingOnAttachedOnly(true); + reactionImageReceiver.ignoreNotifications = true; + } + + @Override + protected void onDraw(Canvas canvas) { + if (isLike) { + float progress = progressToLiked.set(liked ? 1f : 0f); + if (progress < 1f) { + sharedResources.likeDrawable.setBounds(getPaddingLeft(), getPaddingTop(), getMeasuredWidth() - getPaddingRight(), getMeasuredHeight() - getPaddingBottom()); + sharedResources.likeDrawable.setAlpha((int) (255)); + sharedResources.likeDrawable.draw(canvas); + } + if (progress > 0) { + sharedResources.likeDrawableFilled.setBounds(getPaddingLeft(), getPaddingTop(), getMeasuredWidth() - getPaddingRight(), getMeasuredHeight() - getPaddingBottom()); + sharedResources.likeDrawableFilled.setAlpha((int) (progress * 255)); + sharedResources.likeDrawableFilled.draw(canvas); + } + } else { + if (allowDrawReaction) { + ImageReceiver receiverToDraw = emojiDrawable != null ? emojiDrawable.getImageReceiver() : reactionImageReceiver; + if (drawAnimateImageReciever && animateReactionImageReceiver.getBitmap() != null) { + receiverToDraw = animateReactionImageReceiver; + int size = getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); + receiverToDraw.setImageCoords(getPaddingLeft() - size / 2f, + getPaddingTop() - size / 2f, + size * 2, + size * 2 + ); + if (animateReactionImageReceiver.getLottieAnimation() != null && animateReactionImageReceiver.getLottieAnimation().isLastFrame()) { + drawAnimateImageReciever = false; + reactionImageReceiver.setCrossfadeAlpha((byte) 0); + } + } else { + if (receiverToDraw != null) { + receiverToDraw.setImageCoords(getPaddingLeft(), + getPaddingTop(), + getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), + getMeasuredHeight() - getPaddingTop() - getPaddingBottom() + ); + } + } + if (receiverToDraw != null) { + receiverToDraw.draw(canvas); + } + } + } + } + + public void setReaction(ReactionsLayoutInBubble.VisibleReaction visibleReaction) { + isLike = visibleReaction == null || (visibleReaction.emojicon != null && visibleReaction.emojicon.equals("\u2764")); + if (visibleReaction != null && visibleReaction.emojicon != null && visibleReaction.emojicon.equals("\u2764")) { + this.liked = true; + } else { + this.liked = false; + } + this.currentReaction = visibleReaction; + if (emojiDrawable != null) { + emojiDrawable.removeView(this); + } + emojiDrawable = null; + if (visibleReaction != null) { + if (visibleReaction.documentId != 0) { + emojiDrawable = new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW, UserConfig.selectedAccount, visibleReaction.documentId); + if (attachedToWindow) { + emojiDrawable.addView(this); + } + } else { + TLRPC.TL_availableReaction r = MediaDataController.getInstance(UserConfig.selectedAccount).getReactionsMap().get(visibleReaction.emojicon); + if (r != null) { + SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(r.static_icon, Theme.key_windowBackgroundGray, 1.0f); + reactionImageReceiver.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastreactframe", svgThumb, "webp", r, 1); + } + } + } + invalidate(); + } + + public void setAllowDrawReaction(boolean b) { + if (allowDrawReaction == b) { + return; + } + allowDrawReaction = b; + invalidate(); + } + + public void prepareAnimateReaction(ReactionsLayoutInBubble.VisibleReaction reaction) { + if (reaction.documentId == 0) { + TLRPC.TL_availableReaction r = MediaDataController.getInstance(UserConfig.selectedAccount).getReactionsMap().get(reaction.emojicon); + if (r != null) { + animateReactionImageReceiver.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_nolimit", null, "tgs", r, 1); + animateReactionImageReceiver.setAutoRepeat(0); + + } + } + } + + public void animateVisibleReaction() { + drawAnimateImageReciever = true; + if (animateReactionImageReceiver.getLottieAnimation() != null) { + animateReactionImageReceiver.getLottieAnimation().setCurrentFrame(0, false, true); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + reactionImageReceiver.onAttachedToWindow(); + animateReactionImageReceiver.onAttachedToWindow(); + attachedToWindow = true; + if (emojiDrawable != null) { + emojiDrawable.addView(this); + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + reactionImageReceiver.onDetachedFromWindow(); + animateReactionImageReceiver.onDetachedFromWindow(); + attachedToWindow = false; + if (emojiDrawable != null) { + emojiDrawable.removeView(this); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesListPlaceProvider.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesListPlaceProvider.java index a18df5b671b..b3e0e61cb55 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesListPlaceProvider.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesListPlaceProvider.java @@ -1,6 +1,7 @@ package org.telegram.ui.Stories; import android.graphics.Canvas; +import android.graphics.Paint; import android.view.View; import org.telegram.messenger.AndroidUtilities; @@ -26,6 +27,12 @@ public class StoriesListPlaceProvider implements StoryViewer.PlaceProvider { private final RecyclerListView recyclerListView; int[] clipPoint = new int[2]; private boolean isHiddenArchive; + LoadNextInterface loadNextInterface; + public boolean hiddedStories; + public boolean onlyUnreadStories; + public boolean onlySelfStories; + public boolean hasPaginationParams; + public static StoriesListPlaceProvider of(RecyclerListView recyclerListView) { return of(recyclerListView, false); @@ -35,6 +42,11 @@ public static StoriesListPlaceProvider of(RecyclerListView recyclerListView, boo return new StoriesListPlaceProvider(recyclerListView, hiddenArchive); } + public StoriesListPlaceProvider with(LoadNextInterface loadNextInterface) { + this.loadNextInterface = loadNextInterface; + return this; + } + public StoriesListPlaceProvider(RecyclerListView recyclerListView, boolean hiddenArchive) { this.recyclerListView = recyclerListView; this.isHiddenArchive = hiddenArchive; @@ -42,7 +54,7 @@ public StoriesListPlaceProvider(RecyclerListView recyclerListView, boolean hidde @Override public void preLayout(long currentDialogId, int messageId, Runnable r) { - if (recyclerListView.getParent() instanceof DialogStoriesCell) { + if (recyclerListView != null && recyclerListView.getParent() instanceof DialogStoriesCell) { DialogStoriesCell dilogsCell = (DialogStoriesCell) recyclerListView.getParent(); if (dilogsCell.scrollTo(currentDialogId)) { dilogsCell.afterNextLayout(r); @@ -89,6 +101,7 @@ public boolean findView(long dialogId, int messageId, int storyId, int type, Sto DialogStoriesCell storiesCell = (DialogStoriesCell) cell.getParent().getParent(); holder.clipParent = storiesCell; holder.clipTop = holder.clipBottom = 0; + holder.alpha = 1; // updateClip(holder); return true; } @@ -102,6 +115,7 @@ public boolean findView(long dialogId, int messageId, int storyId, int type, Sto if (isHiddenArchive) { holder.crossfadeToAvatarImage = cell.avatarImage; } + holder.alpha = 1; updateClip(holder); return true; } @@ -115,6 +129,7 @@ public boolean findView(long dialogId, int messageId, int storyId, int type, Sto holder.storyImage = cell.replyImageReceiver; } holder.clipParent = (View) cell.getParent(); + holder.alpha = 1; updateClip(holder); return true; } @@ -129,6 +144,7 @@ public boolean findView(long dialogId, int messageId, int storyId, int type, Sto holder.storyImage = cell.getPhotoImage(); } holder.clipParent = (View) cell.getParent(); + holder.alpha = 1; updateClip(holder); return true; } @@ -156,6 +172,7 @@ public boolean findView(long dialogId, int messageId, int storyId, int type, Sto } }; holder.clipParent = (View) cell.getParent(); + holder.alpha = 1; updateClip(holder); return true; } @@ -166,6 +183,7 @@ public boolean findView(long dialogId, int messageId, int storyId, int type, Sto holder.params = cell.storyParams; holder.avatarImage = cell.avatarImageView.getImageReceiver(); holder.clipParent = (View) cell.getParent(); + holder.alpha = 1; updateClip(holder); return true; } @@ -176,6 +194,11 @@ public boolean findView(long dialogId, int messageId, int storyId, int type, Sto holder.params = cell.params; holder.avatarImage = cell.avatarView.getImageReceiver(); holder.clipParent = (View) cell.getParent(); + holder.alpha = cell.getAlpha() * cell.getAlphaInternal(); + if (holder.alpha < 1) { + holder.bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + holder.bgPaint.setColor(Theme.getColor(Theme.key_dialogBackground, cell.getResourcesProvider())); + } updateClip(holder); return true; } @@ -186,6 +209,7 @@ public boolean findView(long dialogId, int messageId, int storyId, int type, Sto holder.params = cell.avatarStoryParams; holder.avatarImage = cell.avatarImage; holder.clipParent = (View) cell.getParent(); + holder.alpha = 1; updateClip(holder); return true; } @@ -211,6 +235,21 @@ private void updateClip(StoryViewer.TransitionViewHolder holder) { } } + @Override + public void loadNext(boolean forward) { + if (loadNextInterface != null) { + loadNextInterface.loadNext(forward); + } + } + + public StoryViewer.PlaceProvider setPaginationParaments(boolean hiddedStories, boolean onlyUnreadStories, boolean onlySelfStories) { + this.hiddedStories = hiddedStories; + this.onlyUnreadStories = onlyUnreadStories; + this.onlySelfStories = onlySelfStories; + hasPaginationParams = true; + return this; + } + public interface ClippedView { void updateClip(int[] clip); } @@ -218,4 +257,8 @@ public interface ClippedView { public interface AvatarOverlaysView { boolean drawAvatarOverlays(Canvas canvas); } + + public interface LoadNextInterface { + void loadNext(boolean forward); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java index ec44cd25577..8f5016e4de0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesStorage.java @@ -15,6 +15,7 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BuildVars; import org.telegram.messenger.FileLog; +import org.telegram.messenger.MessageCustomParamsHelper; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; @@ -34,8 +35,6 @@ import java.util.List; import java.util.Locale; -//TODO stories -//support deleting story files public class StoriesStorage { private static final int EXPIRE_AFTER = 60 * 60 * 24;//one day @@ -55,6 +54,7 @@ public void getAllStories(Consumer consumer) { ArrayList userStoriesArray = new ArrayList<>(); ArrayList usersToLoad = new ArrayList<>(); ArrayList chatsToLoad = new ArrayList<>(); + boolean failed = false; try { cursor = database.queryFinalized("SELECT dialog_id, max_read FROM stories_counter"); LongSparseIntArray dialogsCounter = new LongSparseIntArray(); @@ -72,23 +72,28 @@ public void getAllStories(Consumer consumer) { cursor.dispose(); cursor = null; - for (int i = 0; i < dialogsCounter.size(); i++) { long dialogId = dialogsCounter.keyAt(i); int maxReadId = dialogsCounter.valueAt(i); - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, local_path, local_thumb_path FROM stories WHERE dialog_id = %d", dialogId)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, local_path, local_thumb_path, custom_params FROM stories WHERE dialog_id = %d", dialogId)); ArrayList storyItems = new ArrayList<>(); while (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); String path = cursor.stringValue(1); String firstFramePath = cursor.stringValue(2); + NativeByteBuffer customData = cursor.byteBufferValue(3); if (data != null) { TLRPC.StoryItem storyItem = TLRPC.StoryItem.TLdeserialize(data, data.readInt32(true), true); + storyItem.dialogId = dialogId; storyItem.attachPath = path; storyItem.firstFramePath = firstFramePath; + StoryCustomParamsHelper.readLocalParams(storyItem, customData); storyItems.add(storyItem); data.reuse(); } + if (customData != null) { + customData.reuse(); + } } cursor.dispose(); cursor = null; @@ -99,13 +104,18 @@ public void getAllStories(Consumer consumer) { userStories.user_id = dialogId; userStoriesArray.add(userStories); } - } catch (Exception e) { - e.printStackTrace(); + } catch (Throwable e) { + FileLog.e(e); + failed = true; } finally { if (cursor != null) { cursor.dispose(); } } + if (failed) { + AndroidUtilities.runOnUIThread(() -> consumer.accept(null)); + return; + } TLRPC.TL_stories_allStories storiesResponse = new TLRPC.TL_stories_allStories(); storiesResponse.user_stories = userStoriesArray; storiesResponse.users = storage.getUsers(usersToLoad); @@ -116,6 +126,7 @@ public void getAllStories(Consumer consumer) { storiesResponse.user_stories.remove(i); i--; } + Collections.sort(userStories.stories, StoriesController.storiesComparator); } Collections.sort(storiesResponse.user_stories, Comparator.comparingInt(o -> -o.stories.get(o.stories.size() - 1).date)); @@ -131,7 +142,7 @@ private void checkExpiredStories(long dialogId, ArrayList stori ArrayList storiesToDelete = null; for (int i = 0; i < stories.size(); i++) { TLRPC.StoryItem storyItem = stories.get(i); - if (currentTime - stories.get(i).date > EXPIRE_AFTER) { + if (currentTime > stories.get(i).expire_date) { if (storiesToDeleteIds == null) { storiesToDeleteIds = new ArrayList<>(); storiesToDelete = new ArrayList<>(); @@ -148,7 +159,7 @@ private void checkExpiredStories(long dialogId, ArrayList stori try { database.executeFast(String.format(Locale.US, "DELETE FROM stories WHERE dialog_id = %d AND story_id IN (%s)", dialogId, ids)).stepThis().dispose(); } catch (SQLiteException e) { - e.printStackTrace(); + FileLog.e(e); } ArrayList finalStoriesToDelete = storiesToDelete; } @@ -160,7 +171,7 @@ public void putStoriesInternal(long dialogId, TLRPC.TL_userStories userStories) try { if (userStories != null) { ArrayList storyItems = userStories.stories; - SQLitePreparedStatement state = database.executeFast("REPLACE INTO stories VALUES(?, ?, ?, ?, ?)"); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO stories VALUES(?, ?, ?, ?, ?, ?)"); for (int i = 0; i < storyItems.size(); i++) { state.requery(); TLRPC.StoryItem storyItem = storyItems.get(i); @@ -192,6 +203,15 @@ public void putStoriesInternal(long dialogId, TLRPC.TL_userStories userStories) } else { state.bindString(5, storyItem.firstFramePath); } + NativeByteBuffer nativeByteBuffer = StoryCustomParamsHelper.writeLocalParams(storyItem); + if (nativeByteBuffer != null) { + state.bindByteBuffer(6, nativeByteBuffer); + } else { + state.bindNull(6); + } + if (nativeByteBuffer != null) { + nativeByteBuffer.reuse(); + } state.step(); data.reuse(); } @@ -206,7 +226,7 @@ public void putStoriesInternal(long dialogId, TLRPC.TL_userStories userStories) public void putStoryInternal(long dialogId, TLRPC.StoryItem storyItem) { SQLiteDatabase database = storage.getDatabase(); try { - SQLitePreparedStatement state = database.executeFast("REPLACE INTO stories VALUES(?, ?, ?, ?, ?)"); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO stories VALUES(?, ?, ?, ?, ?, ?)"); if (dialogId == UserConfig.getInstance(currentAccount).getClientUserId()) { SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT local_path, local_thumb_path FROM stories WHERE dialog_id = %d AND story_id = %d", dialogId, storyItem.id)); if (cursor.next()) { @@ -235,6 +255,15 @@ public void putStoryInternal(long dialogId, TLRPC.StoryItem storyItem) { } else { state.bindString(5, storyItem.firstFramePath); } + NativeByteBuffer nativeByteBuffer = StoryCustomParamsHelper.writeLocalParams(storyItem); + if (nativeByteBuffer != null) { + state.bindByteBuffer(6, nativeByteBuffer); + } else { + state.bindNull(6); + } + if (nativeByteBuffer != null) { + nativeByteBuffer.reuse(); + } state.step(); data.reuse(); state.dispose(); @@ -307,12 +336,13 @@ private TLRPC.StoryItem getStoryInternal(long user_id, int storyId) { SQLiteCursor cursor = null; TLRPC.StoryItem storyItem = null; try { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, local_path, local_thumb_path FROM stories WHERE dialog_id = %d AND story_id = %d", user_id, storyId)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, local_path, local_thumb_path, custom_params FROM stories WHERE dialog_id = %d AND story_id = %d", user_id, storyId)); if (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); String path = cursor.stringValue(1); String thumbPath = cursor.stringValue(2); + NativeByteBuffer customData = cursor.byteBufferValue(3); if (data != null) { storyItem = TLRPC.StoryItem.TLdeserialize(data, data.readInt32(true), true); storyItem.dialogId = user_id; @@ -320,10 +350,16 @@ private TLRPC.StoryItem getStoryInternal(long user_id, int storyId) { storyItem.firstFramePath = thumbPath; data.reuse(); } + if (storyItem != null) { + StoryCustomParamsHelper.readLocalParams(storyItem, customData); + } + if (customData != null) { + customData.reuse(); + } } cursor.dispose(); } catch (SQLiteException e) { - e.printStackTrace(); + FileLog.e(e); } return storyItem; } @@ -351,19 +387,24 @@ private TLRPC.TL_userStories getStoriesInternal(long dialogId) { cursor.dispose(); cursor = null; - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, local_path, local_thumb_path FROM stories WHERE dialog_id = %d", dialogId)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, local_path, local_thumb_path, custom_params FROM stories WHERE dialog_id = %d", dialogId)); ArrayList storyItems = new ArrayList<>(); while (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); String path = cursor.stringValue(1); String thumbPath = cursor.stringValue(2); + NativeByteBuffer customData = cursor.byteBufferValue(3); if (data != null) { TLRPC.StoryItem storyItem = TLRPC.StoryItem.TLdeserialize(data, data.readInt32(true), true); storyItem.attachPath = path; storyItem.firstFramePath = thumbPath; + StoryCustomParamsHelper.readLocalParams(storyItem, customData); storyItems.add(storyItem); + data.reuse(); + } + if (customData != null) { + customData.reuse(); } - data.reuse(); } cursor.dispose(); cursor = null; @@ -383,12 +424,18 @@ private TLRPC.TL_userStories getStoriesInternal(long dialogId) { } public void updateStoryItem(long dialogId, TLRPC.StoryItem storyItem) { + if (dialogId == 0) { + return; + } storage.getStorageQueue().postRunnable(() -> { updateStoryItemInternal(dialogId, storyItem); }); } private void updateStoryItemInternal(long dialogId, TLRPC.StoryItem storyItem) { + if (dialogId == 0 || storyItem == null) { + return; + } if (storyItem instanceof TLRPC.TL_storyItemDeleted) { FileLog.e("StoriesStorage: try write deleted story"); } @@ -408,7 +455,7 @@ private void updateStoryItemInternal(long dialogId, TLRPC.StoryItem storyItem) { } cursor.dispose(); } - state = database.executeFast("REPLACE INTO stories VALUES(?, ?, ?, ?, ?)"); + state = database.executeFast("REPLACE INTO stories VALUES(?, ?, ?, ?, ?, ?)"); state.requery(); state.bindLong(1, dialogId); @@ -427,6 +474,15 @@ private void updateStoryItemInternal(long dialogId, TLRPC.StoryItem storyItem) { } else { state.bindString(5, thumbPath); } + NativeByteBuffer nativeByteBuffer = StoryCustomParamsHelper.writeLocalParams(storyItem); + if (nativeByteBuffer != null) { + state.bindByteBuffer(6, nativeByteBuffer); + } else { + state.bindNull(6); + } + if (nativeByteBuffer != null) { + nativeByteBuffer.reuse(); + } state.step(); data.reuse(); } catch (Exception e) { @@ -460,17 +516,22 @@ public void processUpdate(TLRPC.TL_updateStory updateStory) { int storyId = updateStory.story.id; boolean storyExist = false; if (updateStory.story instanceof TLRPC.TL_storyItemDeleted) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, local_path, local_thumb_path FROM stories WHERE dialog_id = %d AND story_id = %d", dialogId, storyId)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, local_path, local_thumb_path, custom_params FROM stories WHERE dialog_id = %d AND story_id = %d", dialogId, storyId)); if (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); String path = cursor.stringValue(1); String thumbPath = cursor.stringValue(2); + NativeByteBuffer customData = cursor.byteBufferValue(3); if (data != null) { TLRPC.StoryItem storyItem = TLRPC.StoryItem.TLdeserialize(data, data.readInt32(true), true); storyItem.attachPath = path; storyItem.firstFramePath = thumbPath; + StoryCustomParamsHelper.readLocalParams(storyItem, customData); data.reuse(); } + if (customData != null) { + customData.reuse(); + } storyExist = true; } cursor.dispose(); @@ -538,7 +599,7 @@ public void deleteStories(long dialogId, ArrayList storyIds) { } //storage queue - public void fillMessagesWithStories(LongSparseArray> messagesWithUnknownStories, Runnable runnable) { + public void fillMessagesWithStories(LongSparseArray> messagesWithUnknownStories, Runnable runnable, int classGuid) { if (runnable == null) { return; } @@ -580,7 +641,7 @@ public void fillMessagesWithStories(LongSparseArray> me for (int j = 0; j < messageObjects.size(); j++) { request.id.add(getStoryId(messageObjects.get(j))); } - ConnectionsManager.getInstance(currentAccount).sendRequest(request, (response, error) -> { + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(request, (response, error) -> { if (response != null) { TLRPC.TL_stories_stories stories = (TLRPC.TL_stories_stories) response; for (int j = 0; j < messageObjects.size(); j++) { @@ -608,6 +669,9 @@ public void fillMessagesWithStories(LongSparseArray> me runnable.run(); } }); + if (classGuid != 0) { + ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); + } } } else { runnable.run(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java index dc39fb335fc..0a000923386 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesUtilities.java @@ -1,5 +1,8 @@ package org.telegram.ui.Stories; +import static org.telegram.ui.Stories.StoriesController.STATE_UNREAD; +import static org.telegram.ui.Stories.StoriesController.STATE_UNREAD_CLOSE_FRIEND; + import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; @@ -44,6 +47,7 @@ import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.LaunchActivity; +import java.io.File; import java.util.Collections; public class StoriesUtilities { @@ -141,6 +145,7 @@ public static void drawAvatarWithStory(long dialogId, Canvas canvas, ImageReceiv } if (state == STATE_PROGRESS) { params.animateFromUnreadState = unreadState; + params.progressToProgressSegments = 0; } if (animated) { params.prevState = params.currentState; @@ -216,10 +221,10 @@ public static void drawAvatarWithStory(long dialogId, Canvas canvas, ImageReceiv boolean animateOut = params.prevState == STATE_READ && params.progressToSate != 1f; Paint paint; if (params.isStoryCell) { - checkStoryCellGrayPaint(params.isArchive); + checkStoryCellGrayPaint(params.isArchive, params.resourcesProvider); paint = storyCellGreyPaint[params.isArchive ? 1 : 0]; } else { - checkGrayPaint(); + checkGrayPaint(params.resourcesProvider); paint = grayPaint; } Paint unreadPaint = null; @@ -229,7 +234,7 @@ public static void drawAvatarWithStory(long dialogId, Canvas canvas, ImageReceiv unreadPaint.setAlpha(255); closeFriendsPaint = getCloseFriendsPaint(avatarImage); closeFriendsPaint.setAlpha(255); - checkGrayPaint(); + checkGrayPaint(params.resourcesProvider); } float inset; if (params.drawSegments) { @@ -247,100 +252,7 @@ public static void drawAvatarWithStory(long dialogId, Canvas canvas, ImageReceiv rectTmp.set(params.originalAvatarRect); rectTmp.inset(inset, inset); if (params.drawSegments) { - checkGrayPaint(); - checkStoryCellGrayPaint(params.isArchive); - int globalState; - if (params.crossfadeToDialog != 0) { - globalState = storiesController.getUnreadState(params.crossfadeToDialog); - } else { - globalState = storiesController.getUnreadState(dialogId); - } - - params.globalState = globalState == StoriesController.STATE_READ ? STATE_READ : STATE_HAS_UNREAD; - TLRPC.TL_userStories userStories = storiesController.getStories(params.dialogId); - int storiesCount; - if (params.drawHiddenStoriesAsSegments) { - storiesCount = storiesController.getHiddenList().size(); - } else { - storiesCount = userStories == null || userStories.stories.size() == 1 ? 1 : userStories.stories.size(); - } - Paint globalPaint; - if (globalState == StoriesController.STATE_UNREAD_CLOSE_FRIEND) { - getCloseFriendsPaint(avatarImage); - globalPaint = closeFriendsGradientTools.paint; - } else if (globalState == StoriesController.STATE_UNREAD) { - getActiveCirclePaint(avatarImage, params.isStoryCell); - globalPaint = storiesGradientTools[params.isStoryCell ? 1 : 0].paint; - } else { - globalPaint = params.isStoryCell ? storyCellGreyPaint[params.isArchive ? 1 : 0] : grayPaint; - } - if (storiesCount == 1) { - Paint localPaint = paint; - if (storiesController.hasUnreadStories(dialogId)) { - localPaint = unreadPaint; - } - float startAngle = -90; - float endAngle = 90; - drawSegment(canvas, rectTmp, localPaint, startAngle, endAngle, params); - startAngle = 90; - endAngle = 270; - drawSegment(canvas, rectTmp, localPaint, startAngle, endAngle, params); - - if (params.progressToSegments != 1 && localPaint != globalPaint) { - globalPaint.setAlpha((int) (255 * (1f - params.progressToSegments))); - startAngle = -90; - endAngle = 90; - drawSegment(canvas, rectTmp, globalPaint, startAngle, endAngle, params); - startAngle = 90; - endAngle = 270; - drawSegment(canvas, rectTmp, globalPaint, startAngle, endAngle, params); - globalPaint.setAlpha(255); - } - // canvas.drawCircle(rectTmp.centerX(), rectTmp.centerY(), rectTmp.width() / 2f, localPaint); - } else { - float step = 360 / (float) storiesCount; - int gap = storiesCount > 20 ? 3 : 5; - float gapLen = gap * params.progressToSegments; - if (gapLen > step) { - gapLen = 0;//step * 0.4f; - } - - - int maxUnread = params.drawHiddenStoriesAsSegments ? 0 : Math.max(userStories.max_read_id, storiesController.dialogIdToMaxReadId.get(dialogId, 0)); - for (int i = 0; i < storiesCount; i++) { - Paint segmentPaint = params.isStoryCell ? storyCellGreyPaint[params.isArchive ? 1 : 0] : grayPaint; - if (params.drawHiddenStoriesAsSegments) { - int userUnreadState = storiesController.getUnreadState(storiesController.getHiddenList().get(storiesCount - 1 - i).user_id); - if (userUnreadState == StoriesController.STATE_UNREAD_CLOSE_FRIEND) { - segmentPaint = closeFriendsPaint; - } else if (userUnreadState == StoriesController.STATE_UNREAD) { - segmentPaint = unreadPaint; - } - } else { - if (userStories.stories.get(i).justUploaded || userStories.stories.get(i).id > maxUnread) { - if (userStories.stories.get(i).close_friends) { - segmentPaint = closeFriendsPaint; - } else { - segmentPaint = unreadPaint; - } - } - } - float startAngle = step * i - 90; - float endAngle = startAngle + step; - startAngle += gapLen; - endAngle -= gapLen; - - drawSegment(canvas, rectTmp, segmentPaint, startAngle, endAngle, params); - if (params.progressToSegments != 1 && segmentPaint != globalPaint) { - float strokeWidth = globalPaint.getStrokeWidth(); - //globalPaint.setStrokeWidth(AndroidUtilities.lerp(segmentPaint.getStrokeWidth(), strokeWidth, 1f - params.progressToSegments)); - globalPaint.setAlpha((int) (255 * (1f - params.progressToSegments))); - drawSegment(canvas, rectTmp, globalPaint, startAngle, endAngle, params); - // globalPaint.setStrokeWidth(strokeWidth); - globalPaint.setAlpha(255); - } - } - } + drawSegmentsInternal(canvas, storiesController, avatarImage, params, paint, unreadPaint, closeFriendsPaint); } else { drawCircleInternal(canvas, avatarImage.getParentView(), params, paint); } @@ -351,11 +263,31 @@ public static void drawAvatarWithStory(long dialogId, Canvas canvas, ImageReceiv getActiveCirclePaint(avatarImage, params.isStoryCell); paint = storiesGradientTools[params.isStoryCell ? 1 : 0].paint; } else { - checkGrayPaint(); - paint = grayPaint; + if (params.isStoryCell) { + checkStoryCellGrayPaint(params.isArchive, params.resourcesProvider); + paint = storyCellGreyPaint[params.isArchive ? 1 : 0]; + } else { + checkGrayPaint(params.resourcesProvider); + paint = grayPaint; + } } paint.setAlpha((int) (255 * progressToSate)); - float inset = 0; + + Paint unreadPaint = null; + Paint closeFriendsPaint = null; + if (params.drawSegments) { + unreadPaint = getActiveCirclePaint(avatarImage, params.isStoryCell); + unreadPaint.setAlpha(255); + closeFriendsPaint = getCloseFriendsPaint(avatarImage); + closeFriendsPaint.setAlpha(255); + checkGrayPaint(params.resourcesProvider); + } + float inset; + if (params.drawSegments) { + inset = params.isStoryCell ? -AndroidUtilities.dpf2(3.5f) : 0; + } else { + inset = params.isStoryCell ? -AndroidUtilities.dpf2(2.7f) : 0; + } boolean animateOut = params.prevState == STATE_PROGRESS && params.progressToSate != 1f; if (animateOut) { inset += AndroidUtilities.dp(7) * progressToSate; @@ -366,7 +298,30 @@ public static void drawAvatarWithStory(long dialogId, Canvas canvas, ImageReceiv } rectTmp.set(params.originalAvatarRect); rectTmp.inset(inset, inset); - drawProgress(canvas, params, avatarImage.getParentView(), paint); + if (params.drawSegments && params.currentState == STATE_PROGRESS && params.progressToProgressSegments != 1f) { + params.progressToProgressSegments += 16 / 200f; + if (params.progressToProgressSegments > 1f) { + params.progressToProgressSegments = 1f; + } + float progressToSegments = params.progressToSegments; + params.progressToSegments = 1f - params.progressToProgressSegments; + drawSegmentsInternal(canvas, storiesController, avatarImage, params, paint, unreadPaint, closeFriendsPaint); + params.progressToSegments = progressToSegments; + if (avatarImage.getParentView() != null) { + avatarImage.invalidate(); + avatarImage.getParentView().invalidate(); + } + } else { + if (params.drawSegments) { + unreadState = storiesController.getUnreadState(params.dialogId); + if (unreadState == STATE_UNREAD_CLOSE_FRIEND) { + paint = closeFriendsPaint; + } else if (unreadState == STATE_UNREAD) { + paint = unreadPaint; + } + } + drawProgress(canvas, params, avatarImage.getParentView(), paint); + } } avatarImage.draw(canvas); @@ -386,6 +341,103 @@ public static void drawAvatarWithStory(long dialogId, Canvas canvas, ImageReceiv } } + private static void drawSegmentsInternal(Canvas canvas, StoriesController storiesController, ImageReceiver avatarImage, AvatarStoryParams params, Paint paint, Paint unreadPaint, Paint closeFriendsPaint) { + checkGrayPaint(params.resourcesProvider); + checkStoryCellGrayPaint(params.isArchive, params.resourcesProvider); + int globalState; + if (params.crossfadeToDialog != 0) { + globalState = storiesController.getUnreadState(params.crossfadeToDialog); + } else { + globalState = storiesController.getUnreadState(params.dialogId); + } + + params.globalState = globalState == StoriesController.STATE_READ ? STATE_READ : STATE_HAS_UNREAD; + TLRPC.TL_userStories userStories = storiesController.getStories(params.dialogId); + int storiesCount; + if (params.drawHiddenStoriesAsSegments) { + storiesCount = storiesController.getHiddenList().size(); + } else { + storiesCount = userStories == null || userStories.stories.size() == 1 ? 1 : userStories.stories.size(); + } + Paint globalPaint; + if (globalState == StoriesController.STATE_UNREAD_CLOSE_FRIEND) { + getCloseFriendsPaint(avatarImage); + globalPaint = closeFriendsGradientTools.paint; + } else if (globalState == STATE_UNREAD) { + getActiveCirclePaint(avatarImage, params.isStoryCell); + globalPaint = storiesGradientTools[params.isStoryCell ? 1 : 0].paint; + } else { + globalPaint = params.isStoryCell ? storyCellGreyPaint[params.isArchive ? 1 : 0] : grayPaint; + } + if (storiesCount == 1) { + Paint localPaint = paint; + if (storiesController.hasUnreadStories(params.dialogId)) { + localPaint = unreadPaint; + } + float startAngle = -90; + float endAngle = 90; + drawSegment(canvas, rectTmp, localPaint, startAngle, endAngle, params); + startAngle = 90; + endAngle = 270; + drawSegment(canvas, rectTmp, localPaint, startAngle, endAngle, params); + + if (params.progressToSegments != 1 && localPaint != globalPaint) { + globalPaint.setAlpha((int) (255 * (1f - params.progressToSegments))); + startAngle = -90; + endAngle = 90; + drawSegment(canvas, rectTmp, globalPaint, startAngle, endAngle, params); + startAngle = 90; + endAngle = 270; + drawSegment(canvas, rectTmp, globalPaint, startAngle, endAngle, params); + globalPaint.setAlpha(255); + } + // canvas.drawCircle(rectTmp.centerX(), rectTmp.centerY(), rectTmp.width() / 2f, localPaint); + } else { + float step = 360 / (float) storiesCount; + int gap = storiesCount > 20 ? 3 : 5; + float gapLen = gap * params.progressToSegments; + if (gapLen > step) { + gapLen = 0;//step * 0.4f; + } + + + int maxUnread = params.drawHiddenStoriesAsSegments ? 0 : Math.max(userStories.max_read_id, storiesController.dialogIdToMaxReadId.get(params.dialogId, 0)); + for (int i = 0; i < storiesCount; i++) { + Paint segmentPaint = params.isStoryCell ? storyCellGreyPaint[params.isArchive ? 1 : 0] : grayPaint; + if (params.drawHiddenStoriesAsSegments) { + int userUnreadState = storiesController.getUnreadState(storiesController.getHiddenList().get(storiesCount - 1 - i).user_id); + if (userUnreadState == StoriesController.STATE_UNREAD_CLOSE_FRIEND) { + segmentPaint = closeFriendsPaint; + } else if (userUnreadState == STATE_UNREAD) { + segmentPaint = unreadPaint; + } + } else { + if (userStories.stories.get(i).justUploaded || userStories.stories.get(i).id > maxUnread) { + if (userStories.stories.get(i).close_friends) { + segmentPaint = closeFriendsPaint; + } else { + segmentPaint = unreadPaint; + } + } + } + float startAngle = step * i - 90; + float endAngle = startAngle + step; + startAngle += gapLen; + endAngle -= gapLen; + + drawSegment(canvas, rectTmp, segmentPaint, startAngle, endAngle, params); + if (params.progressToSegments != 1 && segmentPaint != globalPaint) { + float strokeWidth = globalPaint.getStrokeWidth(); + //globalPaint.setStrokeWidth(AndroidUtilities.lerp(segmentPaint.getStrokeWidth(), strokeWidth, 1f - params.progressToSegments)); + globalPaint.setAlpha((int) (255 * (1f - params.progressToSegments))); + drawSegment(canvas, rectTmp, globalPaint, startAngle, endAngle, params); + // globalPaint.setStrokeWidth(strokeWidth); + globalPaint.setAlpha(255); + } + } + } + } + private static int getPredictiveUnreadState(StoriesController storiesController, long dialogId) { TLRPC.User user = MessagesController.getInstance(UserConfig.selectedAccount).getUser(dialogId); if (dialogId != UserConfig.getInstance(UserConfig.selectedAccount).clientUserId && user != null && user.stories_max_id > 0 && !user.stories_unavailable) { @@ -419,7 +471,7 @@ private static void drawProgress(Canvas canvas, AvatarStoryParams params, View v } } - private static void checkStoryCellGrayPaint(boolean isArchive) { + private static void checkStoryCellGrayPaint(boolean isArchive, Theme.ResourcesProvider resourcesProvider) { int index = isArchive ? 1 : 0; if (storyCellGreyPaint[index] == null) { storyCellGreyPaint[index] = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -427,7 +479,7 @@ private static void checkStoryCellGrayPaint(boolean isArchive) { storyCellGreyPaint[index].setStrokeWidth(AndroidUtilities.dpf2(1.3f)); storyCellGreyPaint[index].setStrokeCap(Paint.Cap.ROUND); } - int color = !isArchive ? Theme.getColor(Theme.key_actionBarDefault) : Theme.getColor(Theme.key_actionBarDefaultArchived); + int color = Theme.getColor(!isArchive ? Theme.key_actionBarDefault : Theme.key_actionBarDefaultArchived, resourcesProvider); if (storyCellGrayLastColor != color) { storyCellGrayLastColor = color; float brightness = AndroidUtilities.computePerceivedBrightness(color); @@ -444,14 +496,14 @@ private static void checkStoryCellGrayPaint(boolean isArchive) { } } - private static void checkGrayPaint() { + private static void checkGrayPaint(Theme.ResourcesProvider resourcesProvider) { if (grayPaint == null) { grayPaint = new Paint(Paint.ANTI_ALIAS_FLAG); grayPaint.setStyle(Paint.Style.STROKE); grayPaint.setStrokeWidth(AndroidUtilities.dpf2(1.3f)); grayPaint.setStrokeCap(Paint.Cap.ROUND); } - int color = Theme.getColor(Theme.key_windowBackgroundWhite); + int color = Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider); if (grayLastColor != color) { grayLastColor = color; float brightness = AndroidUtilities.computePerceivedBrightness(color); @@ -513,9 +565,9 @@ public static Paint getActiveCirclePaint(ImageReceiver avatarImage, boolean isDi storiesGradientTools[i].isDiagonal = true; storiesGradientTools[i].isRotate = true; if (isDialogCell) { - storiesGradientTools[i].setColors(0xFF4AED55, 0xFF4DC3FF); + storiesGradientTools[i].setColors(Theme.getColor(Theme.key_stories_circle_dialog1), Theme.getColor(Theme.key_stories_circle_dialog2)); } else { - storiesGradientTools[i].setColors(0xFF39DF3C, 0xFF4DBBFF); + storiesGradientTools[i].setColors(Theme.getColor(Theme.key_stories_circle1), Theme.getColor(Theme.key_stories_circle2)); } storiesGradientTools[i].paint.setStrokeWidth(AndroidUtilities.dpf2(2.3f)); storiesGradientTools[i].paint.setStyle(Paint.Style.STROKE); @@ -525,12 +577,24 @@ public static Paint getActiveCirclePaint(ImageReceiver avatarImage, boolean isDi return storiesGradientTools[i].paint; } + public static void updateColors() { + if (closeFriendsGradientTools != null) { + closeFriendsGradientTools.setColors(Theme.getColor(Theme.key_stories_circle_closeFriends1), Theme.getColor(Theme.key_stories_circle_closeFriends2)); + } + if (storiesGradientTools[0] != null) { + storiesGradientTools[0].setColors(Theme.getColor(Theme.key_stories_circle_dialog1), Theme.getColor(Theme.key_stories_circle_dialog2)); + } + if (storiesGradientTools[1] != null) { + storiesGradientTools[1].setColors(Theme.getColor(Theme.key_stories_circle1), Theme.getColor(Theme.key_stories_circle2)); + } + } + public static Paint getCloseFriendsPaint(ImageReceiver avatarImage) { if (closeFriendsGradientTools == null) { closeFriendsGradientTools = new GradientTools(); closeFriendsGradientTools.isDiagonal = true; closeFriendsGradientTools.isRotate = true; - closeFriendsGradientTools.setColors(0xFFC9EB38, 0xFF09C167); + closeFriendsGradientTools.setColors(Theme.getColor(Theme.key_stories_circle_closeFriends1), Theme.getColor(Theme.key_stories_circle_closeFriends2)); closeFriendsGradientTools.paint.setStrokeWidth(AndroidUtilities.dp(2.3f)); closeFriendsGradientTools.paint.setStyle(Paint.Style.STROKE); closeFriendsGradientTools.paint.setStrokeCap(Paint.Cap.ROUND); @@ -744,8 +808,8 @@ public static void drawArcExcludeArc(Canvas canvas, RectF rect, Paint paint, flo canvas.drawArc(rect, startAngle, endAngle - startAngle, false, paint); } - public static boolean isExpired(int currentAccount, TLRPC.StoryItem newStory) { - return ConnectionsManager.getInstance(currentAccount).getCurrentTime() > newStory.expire_date; + public static boolean isExpired(int currentAccount, TLRPC.StoryItem storyItem) { + return ConnectionsManager.getInstance(currentAccount).getCurrentTime() > storyItem.expire_date; } public static String getStoryImageFilter() { @@ -754,6 +818,128 @@ public static String getStoryImageFilter() { return filterSize + "_" + filterSize; } + public static class EnsureStoryFileLoadedObject { + + long dialogId; + StoriesController storiesController; + + private EnsureStoryFileLoadedObject(StoriesController storiesController, long dialogId) { + this.dialogId = dialogId; + this.storiesController = storiesController; + } + + public Runnable runnable; + private boolean cancelled = false; + ImageReceiver imageReceiver; + + public void cancel() { + cancelled = true; + storiesController.setLoading(dialogId, false); + } + } + + public static EnsureStoryFileLoadedObject ensureStoryFileLoaded(TLRPC.TL_userStories stories, Runnable onDoneOrTimeout) { + if (stories == null || stories.stories.isEmpty() || stories.user_id == UserConfig.getInstance(UserConfig.selectedAccount).clientUserId) { + onDoneOrTimeout.run(); + return null; + } + TLRPC.StoryItem storyItem = null; + StoriesController storiesController = MessagesController.getInstance(UserConfig.selectedAccount).storiesController; + int maxReadId = storiesController.dialogIdToMaxReadId.get(stories.user_id); + + for (int i = 0; i < stories.stories.size(); i++) { + if (stories.stories.get(i).id > maxReadId) { + storyItem = stories.stories.get(i); + break; + } + } + if (storyItem == null) { + storyItem = stories.stories.get(0); + } + + if (storyItem.media != null && storyItem.media.document != null) { + File file = FileLoader.getInstance(UserConfig.selectedAccount).getPathToAttach(storyItem.media.document, "", false); + if (file != null && file.exists()) { + onDoneOrTimeout.run(); + return null; + } + file = FileLoader.getInstance(UserConfig.selectedAccount).getPathToAttach(storyItem.media.document, "", true); + try { + if (file != null) { + int index = file.getName().lastIndexOf("."); + if (index > 0) { + file = new File(file.getParentFile(), file.getName().substring(0, index) + ".temp"); + if (file.exists() && file.length() > 0) { + onDoneOrTimeout.run(); + return null; + } + } + } + } catch (Exception e) { + + } + } else { + TLRPC.Photo photo = storyItem.media != null ? storyItem.media.photo : null; + if (photo != null && photo.sizes != null) { + TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, Integer.MAX_VALUE); + File file = FileLoader.getInstance(UserConfig.selectedAccount).getPathToAttach(size, "", false); + if (file != null && file.exists()) { + onDoneOrTimeout.run(); + return null; + } + } else { + onDoneOrTimeout.run(); + return null; + } + } + + EnsureStoryFileLoadedObject ensureStoryFileLoadedObject = new EnsureStoryFileLoadedObject(storiesController, stories.user_id); + ensureStoryFileLoadedObject.runnable = () -> { + if (ensureStoryFileLoadedObject.cancelled) { + return; + } + onDoneOrTimeout.run(); + }; + Runnable[] runnableRef = new Runnable[1]; + runnableRef[0] = () -> { + runnableRef[0] = null; + ensureStoryFileLoadedObject.runnable.run(); + if (ensureStoryFileLoadedObject.imageReceiver != null) { + ensureStoryFileLoadedObject.imageReceiver.onDetachedFromWindow(); + } + }; + AndroidUtilities.runOnUIThread(runnableRef[0], 3000); + ensureStoryFileLoadedObject.imageReceiver = new ImageReceiver() { + @Override + protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, boolean memCache, int guid) { + boolean res = super.setImageBitmapByKey(drawable, key, type, memCache, guid); + if (runnableRef[0] != null) { + AndroidUtilities.cancelRunOnUIThread(runnableRef[0]); + ensureStoryFileLoadedObject.runnable.run(); + } + AndroidUtilities.runOnUIThread(this::onDetachedFromWindow); + return res; + } + }; + ensureStoryFileLoadedObject.imageReceiver.setAllowLoadingOnAttachedOnly(true); + ensureStoryFileLoadedObject.imageReceiver.onAttachedToWindow(); + + String filter = getStoryImageFilter(); + + if (storyItem.media != null && storyItem.media.document != null) { + ensureStoryFileLoadedObject.imageReceiver.setImage(ImageLocation.getForDocument(storyItem.media.document), filter + "_pframe", null, null, null, 0, null, storyItem, 0); + } else { + TLRPC.Photo photo = storyItem.media != null ? storyItem.media.photo : null; + if (photo != null && photo.sizes != null) { + TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, Integer.MAX_VALUE); + ensureStoryFileLoadedObject.imageReceiver.setImage(null, null, ImageLocation.getForPhoto(size, photo), filter, null, null, null, 0, null, storyItem, 0); + } else { + ensureStoryFileLoadedObject.runnable.run(); + return null; + } + } + return ensureStoryFileLoadedObject; + } public static class AvatarStoryParams { public boolean drawSegments = true; @@ -773,6 +959,7 @@ public static class AvatarStoryParams { public boolean drawHiddenStoriesAsSegments; public long crossfadeToDialog; public float crossfadeToDialogProgress; + public float progressToProgressSegments; private long dialogId; public int currentState; @@ -786,9 +973,17 @@ public static class AvatarStoryParams { ButtonBounce buttonBounce; public boolean allowLongress = false; + public Theme.ResourcesProvider resourcesProvider; + public AvatarStoryParams(boolean isStoryCell) { + this(isStoryCell, null); + } + + public AvatarStoryParams(boolean isStoryCell, Theme.ResourcesProvider resourcesProvider) { this.isStoryCell = isStoryCell; + this.resourcesProvider = resourcesProvider; } + float sweepAngle; boolean inc; float globalAngle; @@ -829,7 +1024,7 @@ public boolean checkOnTouchEvent(MotionEvent event, View view) { } if (dialogId != UserConfig.getInstance(UserConfig.selectedAccount).clientUserId && hasStories) { if (buttonBounce == null) { - buttonBounce = new ButtonBounce(view, 1.5f); + buttonBounce = new ButtonBounce(view, 1.5f, 5f); } else { buttonBounce.setView(view); } @@ -999,62 +1194,6 @@ void load(long dialogId, View view, AvatarStoryParams params) { })); } - private void ensureStoryFileLoaded(TLRPC.TL_userStories stories, Runnable onDoneOrTimeout) { - if (stories == null || stories.stories.isEmpty()) { - onDoneOrTimeout.run(); - return; - } - TLRPC.StoryItem storyItem = null; - int maxReadId = MessagesController.getInstance(currentAccount).storiesController.dialogIdToMaxReadId.get(stories.user_id); - - for (int i = 0; i < stories.stories.size(); i++) { - if (stories.stories.get(i).id > maxReadId) { - storyItem = stories.stories.get(i); - break; - } - } - if (storyItem == null) { - storyItem = stories.stories.get(0); - } - Runnable[] runnableRef = new Runnable[1]; - runnableRef[0] = () -> { - runnableRef[0] = null; - onDoneOrTimeout.run(); - }; - - AndroidUtilities.runOnUIThread(runnableRef[0], 1000); - - ImageReceiver imageReceiver = new ImageReceiver() { - @Override - protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, boolean memCache, int guid) { - boolean res = super.setImageBitmapByKey(drawable, key, type, memCache, guid); - if (runnableRef[0] != null) { - AndroidUtilities.cancelRunOnUIThread(runnableRef[0]); - onDoneOrTimeout.run(); - } - AndroidUtilities.runOnUIThread(this::onDetachedFromWindow); - return res; - } - }; - imageReceiver.setAllowLoadingOnAttachedOnly(true); - imageReceiver.onAttachedToWindow(); - - String filter = getStoryImageFilter(); - - if (storyItem.media != null && storyItem.media.document != null) { - imageReceiver.setImage(ImageLocation.getForDocument(storyItem.media.document), filter + "_pframe", null, null, null, 0, null, storyItem, 0); - } else { - TLRPC.Photo photo = storyItem.media != null ? storyItem.media.photo : null; - if (photo != null && photo.sizes != null) { - TLRPC.PhotoSize size = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, Integer.MAX_VALUE); - imageReceiver.setImage(null, null, ImageLocation.getForPhoto(size, photo), filter, null, null, null, 0, null, storyItem, 0); - } else { - onDoneOrTimeout.run(); - return; - } - } - } - void cancel() { ConnectionsManager.getInstance(currentAccount).cancelRequest(reqId, false); canceled = true; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesViewPager.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesViewPager.java index b66ac70ac4f..39ea5881966 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesViewPager.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoriesViewPager.java @@ -16,6 +16,7 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.FileLog; import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import java.util.ArrayList; @@ -52,6 +53,8 @@ public void run() { }; StoryViewer storyViewer; + private int selectedPositionInPage; + private int updateVisibleItemPosition = -1; public StoriesViewPager(@NonNull Context context, StoryViewer storyViewer, Theme.ResourcesProvider resourcesProvider) { super(context); @@ -134,9 +137,9 @@ public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { if (!pageLayout.isVisible) { pageLayout.setVisible(true); if (days != null) { - pageLayout.peerStoryView.setDay(pageLayout.dialogId, pageLayout.day); + pageLayout.peerStoryView.setDay(pageLayout.dialogId, pageLayout.day, -1); } else { - pageLayout.peerStoryView.setDialogId(pageLayout.dialogId); + pageLayout.peerStoryView.setDialogId(pageLayout.dialogId, -1); } } pageLayout.peerStoryView.setOffset(position); @@ -149,7 +152,6 @@ public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { addOnPageChangeListener(new OnPageChangeListener() { - @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { selectedPosition = position; @@ -175,6 +177,13 @@ public void onPageSelected(int position) { } delegate.onPeerSelected(peerStoriesView.getCurrentPeer(), peerStoriesView.getSelectedPosition()); updateActiveStory(); + if (storyViewer.placeProvider != null) { + if (position < 3) { + storyViewer.placeProvider.loadNext(false); + } else if (position > pagerAdapter.getCount() - 4) { + storyViewer.placeProvider.loadNext(true); + } + } } @Override @@ -271,9 +280,29 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { delegate.onPeerSelected(peerStoriesView.getCurrentPeer(), peerStoriesView.getSelectedPosition()); } } + checkPageVisibility(); updateActiveStory(); } + public void checkPageVisibility() { + if (updateVisibleItemPosition >= 0) { + for (int i = 0; i < getChildCount(); i++) { + if ((Integer) getChildAt(i).getTag() == getCurrentItem() && getCurrentItem() == updateVisibleItemPosition) { + PageLayout pageLayout = ((PageLayout) getChildAt(i)); + if (!pageLayout.isVisible) { + updateVisibleItemPosition = -1; + pageLayout.setVisible(true); + if (days != null) { + pageLayout.peerStoryView.setDay(pageLayout.dialogId, pageLayout.day, selectedPositionInPage); + } else { + pageLayout.peerStoryView.setDialogId(pageLayout.dialogId, selectedPositionInPage); + } + } + } + } + } + } + public void setDelegate(PeerStoriesView.Delegate delegate) { this.delegate = delegate; } @@ -380,6 +409,10 @@ public void lockTouchEvent(long duration) { AndroidUtilities.runOnUIThread(lockTouchRunnable, duration); } + public ArrayList getDialogIds() { + return dialogs; + } + private class PageLayout extends FrameLayout { public PeerStoriesView peerStoryView; @@ -412,4 +445,40 @@ public void setVisible(boolean visible) { } } + public void setCurrentDate(long day, int storyId) { + for (int i = 0; i < days.size(); i++) { + long currentDay = StoriesController.StoriesList.day(storyViewer.storiesList.findMessageObject(days.get(i).get(0))); + if (day == currentDay) { + int position = i; + int positionInPage = 0; + if (storyViewer.reversed) { + position = days.size() - 1 - position; + } + for (int j = 0; j < days.get(i).size(); j++) { + if (days.get(i).get(j) == storyId) { + positionInPage = j; + break; + } + } + if (getCurrentPeerView() == null || getCurrentItem() != position) { + setCurrentItem(position, false); + PeerStoriesView peerView = getCurrentPeerView(); + if (peerView != null) { + PageLayout pageLayout = (PageLayout) peerView.getParent(); + pageLayout.setVisible(true); + if (days != null) { + pageLayout.peerStoryView.setDay(pageLayout.dialogId, pageLayout.day, positionInPage); + } else { + pageLayout.peerStoryView.setDialogId(pageLayout.dialogId, positionInPage); + } + } +// updateVisibleItemPosition = position; +// selectedPositionInPage = positionInPage; + } else { + getCurrentPeerView().selectPosition(positionInPage); + } + break; + } + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java index 67392a8428e..2db9e5586cc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCaptionView.java @@ -1,5 +1,6 @@ package org.telegram.ui.Stories; +import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.SuppressLint; @@ -9,11 +10,11 @@ import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Path; -import android.graphics.Point; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffXfermode; import android.graphics.Shader; +import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.os.Build; import android.text.Layout; @@ -21,6 +22,7 @@ import android.text.SpannableString; import android.text.StaticLayout; import android.text.TextPaint; +import android.text.TextUtils; import android.text.style.CharacterStyle; import android.text.style.ClickableSpan; import android.text.style.URLSpan; @@ -40,27 +42,26 @@ import androidx.dynamicanimation.animation.SpringAnimation; import androidx.dynamicanimation.animation.SpringForce; -import org.checkerframework.checker.units.qual.A; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; -import org.telegram.ui.ActionBar.ActionBarPopupWindow; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.TextSelectionHelper; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedEmojiSpan; +import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LinkPath; import org.telegram.ui.Components.LinkSpanDrawable; +import org.telegram.ui.Components.LoadingDrawable; import org.telegram.ui.Components.StaticLayoutEx; import org.telegram.ui.Components.URLSpanMono; import org.telegram.ui.Components.spoilers.SpoilerEffect; import org.telegram.ui.Components.spoilers.SpoilersClickDetector; -import org.telegram.ui.Components.spoilers.SpoilersTextView; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -83,6 +84,8 @@ public class StoryCaptionView extends NestedScrollView { private float velocitySign; private float velocityY; + private float startMotionX; + private float startMotionY; private float lastMotionX; private float lastMotionY; @@ -247,12 +250,12 @@ public int calculateNewContainerMarginTop(int width, int height) { } final StoryCaptionTextView textView = captionTextview; - final CharSequence text = textView.text; + final CharSequence text = textView.state[0].text; final int textHash = text.hashCode(); final boolean isLandscape = AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y; - if (this.textHash == textHash && this.isLandscape == isLandscape && this.prevHeight == height) { + if (this.textHash == textHash && this.isLandscape == isLandscape && this.prevHeight == height && !textView.updating) { return -1; } @@ -262,17 +265,7 @@ public int calculateNewContainerMarginTop(int width, int height) { textView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); - final Layout layout = textView.fullLayout; - final int lineCount = layout.getLineCount(); - - if (lineCount <= 3) { - return height - textView.getMeasuredHeight(); - } - - int i = Math.min(3, lineCount); - - final int lineHeight = textView.textPaint.getFontMetricsInt(null); - return height - lineHeight * (i + 1);// - AndroidUtilities.dp(8); + return textView.collapsedTextHeight(height); } public void reset() { @@ -479,19 +472,23 @@ public float getProgressToBlackout() { return Utilities.clamp((getScrollY() - captionTextview.getTranslationY()) / maxHeight, 1f, 0); } - boolean expanded; public void expand() { - if (expanded) { + expand(false); + } + + boolean expanded; + public void expand(boolean force) { + if (expanded && !force) { return; } expanded = true; float fromScrollY = getScrollY(); - float toScrollY = (captionContainer.getBottom() - getMeasuredHeight()); float fromP = captionTextview.progressToExpand; float toP = 1f; ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1f); valueAnimator.addUpdateListener(animation -> { float value = (float) animation.getAnimatedValue(); + final float toScrollY = (captionContainer.getBottom() - getMeasuredHeight()); setScrollY((int) AndroidUtilities.lerp(fromScrollY, toScrollY, value)); captionTextview.progressToExpand = AndroidUtilities.lerp(fromP, toP, value); captionTextview.invalidate(); @@ -546,56 +543,440 @@ public boolean hasScroll() { } public void checkCancelTextSelection() { - if (textSelectionHelper.isInSelectionMode()) { + if (textSelectionHelper.isInSelectionMode() && Math.abs(startMotionX - lastMotionX) < AndroidUtilities.touchSlop && Math.abs(startMotionY - lastMotionY) < AndroidUtilities.touchSlop) { textSelectionHelper.getOverlayView(getContext()).checkCancel(lastMotionX, lastMotionY, false); } } - public class StoryCaptionTextView extends View implements TextSelectionHelper.SelectableView, TextSelectionHelper.SimpleSelectabeleView { + public class StoryCaptionTextView extends View implements TextSelectionHelper.SimpleSelectabeleView { private final PorterDuffColorFilter emojiColorFilter; - private LinkSpanDrawable pressedLink; - private AnimatedEmojiSpan pressedEmoji; - private LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(this); TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); TextPaint showMorePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); private final Paint xRefPaint = new Paint(); private final Paint xRefGradinetPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + float showMoreY; + float showMoreX; + + public int collapsedTextHeight(int height) { + return AndroidUtilities.lerp(state[0].collapsedTextHeight(height), state[1] == null ? 0 : state[1].collapsedTextHeight(height), updateT); + } + + public class TextState { + private LinkSpanDrawable pressedLink; + private AnimatedEmojiSpan pressedEmoji; + private final LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(StoryCaptionTextView.this); + + private AnimatedEmojiSpan.EmojiGroupedSpans fullLayoutEmoji; + StaticLayout fullLayout; + private AnimatedEmojiSpan.EmojiGroupedSpans firstLayoutEmoji; + StaticLayout firstLayout; + LineInfo[] nextLinesLayouts; + + protected final List spoilers = new ArrayList<>(); + private final Stack spoilersPool = new Stack<>(); + private final SpoilersClickDetector clickDetector; + + int textHeight; + CharSequence text = ""; + + public boolean translating; + public final AnimatedFloat translateT = new AnimatedFloat(StoryCaptionView.this, 0, 400, CubicBezierInterpolator.EASE_OUT_QUINT); + private final LoadingDrawable loadingDrawable; + + private Path loadingPath = new Path(); + + public int collapsedTextHeight(int height) { + if (fullLayout == null) { + return height - (verticalPadding * 2 + textHeight); + } + final Layout layout = fullLayout; + final int lineCount = layout.getLineCount(); + if (lineCount <= 3) { + return height - (verticalPadding * 2 + textHeight); + } + int i = Math.min(3, lineCount); + final int lineHeight = textPaint.getFontMetricsInt(null); + return height - lineHeight * (i + 1); + } + + public TextState() { + clickDetector = new SpoilersClickDetector(StoryCaptionTextView.this, spoilers, (eff, x, y) -> { + if (isSpoilersRevealed) return; + + eff.setOnRippleEndCallback(() -> post(() -> { + isSpoilersRevealed = true; + // invalidateSpoilers(); + })); + + float rad = (float) Math.sqrt(Math.pow(getWidth(), 2) + Math.pow(getHeight(), 2)); + for (SpoilerEffect ef : spoilers) + ef.startRipple(x, y, rad); + }); + + loadingDrawable = new LoadingDrawable(); + loadingDrawable.usePath(loadingPath); + loadingDrawable.setRadiiDp(4); + loadingDrawable.setColors( + Theme.multAlpha(Color.WHITE, .3f), + Theme.multAlpha(Color.WHITE, .1f), + Theme.multAlpha(Color.WHITE, .2f), + Theme.multAlpha(Color.WHITE, .7f) + ); + loadingDrawable.setCallback(StoryCaptionTextView.this); + } + + public void setup(CharSequence text) { + this.text = text; + sizeCached = 0; + requestLayout(); + } + + public void measure(int width) { + if (TextUtils.isEmpty(text)) { + fullLayout = null; + textHeight = 0; + if (this == state[0]) { + showMore = null; + } + firstLayout = null; + spoilersPool.addAll(spoilers); + spoilers.clear(); + return; + } + fullLayout = makeTextLayout(textPaint, text, width); + textHeight = fullLayout.getHeight(); + float space = textPaint.measureText(" "); + if (fullLayout.getLineCount() > 3) { + float collapsedY = fullLayout.getLineTop(2) + fullLayout.getTopPadding(); + if (this == state[0]) { + String showMoreText = LocaleController.getString("ShowMore", R.string.ShowMore); + showMore = makeTextLayout(showMorePaint, showMoreText, width); + + showMoreY = verticalPadding + collapsedY - AndroidUtilities.dpf2(0.3f); + showMoreX = width + horizontalPadding - showMorePaint.measureText(showMoreText); + } + + firstLayout = makeTextLayout(textPaint, text.subSequence(0, fullLayout.getLineEnd(2)), width); + spoilersPool.addAll(spoilers); + spoilers.clear(); + SpoilerEffect.addSpoilers(StoryCaptionView.this, fullLayout, spoilersPool, spoilers); + + float x = fullLayout.getLineRight(2) + space; + if (nextLinesLayouts != null) { + for (int i = 0; i < nextLinesLayouts.length; i++) { + if (nextLinesLayouts[i] == null) { + continue; + } + AnimatedEmojiSpan.release(StoryCaptionView.this, nextLinesLayouts[i].layoutEmoji); + } + } + nextLinesLayouts = new LineInfo[fullLayout.getLineCount() - 3]; + + if (spoilers.isEmpty()) { + for (int line = 3; line < fullLayout.getLineCount(); ++line) { + int s = fullLayout.getLineStart(line), e = fullLayout.getLineEnd(line); + CharSequence sequence = text.subSequence(Math.min(s, e), Math.max(s, e)); + if (TextUtils.isEmpty(sequence)) { + nextLinesLayouts[line - 3] = null; + continue; + } + final StaticLayout layout = makeTextLayout(textPaint, sequence, width); + LineInfo lineInfo = new LineInfo(); + nextLinesLayouts[line - 3] = lineInfo; + lineInfo.staticLayout = layout; + lineInfo.finalX = fullLayout.getLineLeft(line); + lineInfo.finalY = fullLayout.getLineTop(line) + fullLayout.getTopPadding(); + if (x < showMoreX - AndroidUtilities.dp(16)) { + lineInfo.collapsedY = collapsedY; + lineInfo.collapsedX = x; + x += layout.getLineRight(0) + space; + } else { + lineInfo.collapsedY = lineInfo.finalY; + lineInfo.collapsedX = lineInfo.finalX; + } + } + } + } else { + if (this == state[0]) { + showMore = null; + } + firstLayout = null; + spoilersPool.addAll(spoilers); + spoilers.clear(); + SpoilerEffect.addSpoilers(StoryCaptionTextView.this, fullLayout, spoilersPool, spoilers); + } + clickDetector.setAdditionalOffsets(horizontalPadding, verticalPadding); + } + + public void draw(Canvas canvas, float alpha) { + final float loadingT = this.translateT.set(translating); + if (alpha <= 0) { + return; + } + + alpha = AndroidUtilities.lerp(alpha, alpha * .7f, loadingT); + if (alpha >= 1) { + drawInternal(canvas, loadingT); + } else { + canvas.saveLayerAlpha(0, 0, StoryCaptionView.this.getWidth(), StoryCaptionView.this.getHeight(), (int) (0xFF * alpha), Canvas.ALL_SAVE_FLAG); + drawInternal(canvas, loadingT); + canvas.restore(); + } + + if (loadingT > 0 || translating) { + loadingDrawable.setAlpha((int) (0xFF * loadingT * alpha)); + loadingDrawable.draw(canvas); + StoryCaptionTextView.this.invalidate(); + } + } + + private void putLayoutRects(Layout layout, float tx, float ty) { + float t = 0; + for (int i = 0; i < layout.getLineCount(); ++i) { + float l = layout.getLineLeft(i) - horizontalPadding / 3f; + float r = layout.getLineRight(i) + horizontalPadding / 3f; + if (i == 0) { + t = layout.getLineTop(i) - verticalPadding / 3f; + } + float b = layout.getLineBottom(i); + if (i >= layout.getLineCount() - 1) { + b += verticalPadding / 3f; + } + loadingPath.addRect(tx + l, ty + t, tx + r, ty + b, Path.Direction.CW); + t = b; + } + } + + private void drawInternal(Canvas canvas, float loadingT) { + canvas.save(); + canvas.translate(horizontalPadding, verticalPadding); + if (links.draw(canvas)) { + invalidate(); + } + canvas.restore(); + + final boolean drawLoading = loadingT > 0; + loadingPath.rewind(); + + if (!spoilers.isEmpty() || firstLayout == null) { + if (fullLayout != null) { + canvas.save(); + canvas.translate(horizontalPadding, verticalPadding); + if (textSelectionHelper.isInSelectionMode()) { + textSelectionHelper.draw(canvas); + } + drawLayout(fullLayout, canvas, spoilers); + fullLayoutEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, StoryCaptionTextView.this, fullLayoutEmoji, fullLayout); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, fullLayout, fullLayoutEmoji, 0, spoilers, 0, 0, 0, 1f, emojiColorFilter); + canvas.restore(); + + if (drawLoading) { + putLayoutRects(fullLayout, horizontalPadding, verticalPadding); + } + } + } else { + if (textSelectionHelper.isInSelectionMode()) { + canvas.save(); + canvas.translate(horizontalPadding, verticalPadding); + textSelectionHelper.draw(canvas); + canvas.restore(); + } + if (firstLayout != null) { + canvas.save(); + canvas.translate(horizontalPadding, verticalPadding); + drawLayout(firstLayout, canvas, spoilers); + firstLayoutEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, StoryCaptionTextView.this, firstLayoutEmoji, firstLayout); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, firstLayout, firstLayoutEmoji, 0, spoilers, 0, 0, 0, 1f, emojiColorFilter); + canvas.restore(); + + if (drawLoading) { + putLayoutRects(firstLayout, horizontalPadding, verticalPadding); + } + } + + if (nextLinesLayouts != null) { + for (int i = 0; i < nextLinesLayouts.length; i++) { + LineInfo lineInfo = nextLinesLayouts[i]; + if (lineInfo == null) { + continue; + } + canvas.save(); + if (lineInfo.collapsedX == lineInfo.finalX) { + if (progressToExpand == 0) { + continue; + } + canvas.translate(horizontalPadding + lineInfo.finalX, verticalPadding + lineInfo.finalY); + canvas.saveLayerAlpha(0, 0, lineInfo.staticLayout.getWidth(), lineInfo.staticLayout.getHeight(), (int) (255 * progressToExpand), Canvas.ALL_SAVE_FLAG); + drawLayout(lineInfo.staticLayout, canvas, spoilers); + + if (drawLoading) { + putLayoutRects(lineInfo.staticLayout, horizontalPadding + lineInfo.finalX, verticalPadding + lineInfo.finalY); + } + + lineInfo.staticLayout.draw(canvas); + lineInfo.layoutEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, StoryCaptionTextView.this, lineInfo.layoutEmoji, lineInfo.staticLayout); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, lineInfo.staticLayout, lineInfo.layoutEmoji, 0, spoilers, 0, 0, 0, progressToExpand, emojiColorFilter); + canvas.restore(); + //textPaint.setAlpha(255); + } else { + float offsetX = AndroidUtilities.lerp(lineInfo.collapsedX, lineInfo.finalX, progressToExpand); + float offsetY = AndroidUtilities.lerp(lineInfo.collapsedY, lineInfo.finalY, CubicBezierInterpolator.EASE_OUT.getInterpolation(progressToExpand)); + canvas.translate(horizontalPadding + offsetX, verticalPadding + offsetY); + //drawLayout(lineInfo.staticLayout, canvas, -offsetX, -offsetY); + if (drawLoading) { + putLayoutRects(lineInfo.staticLayout, horizontalPadding + offsetX, verticalPadding + offsetY); + } + lineInfo.staticLayout.draw(canvas); + lineInfo.layoutEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, StoryCaptionTextView.this, lineInfo.layoutEmoji, lineInfo.staticLayout); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, lineInfo.staticLayout, lineInfo.layoutEmoji, 0, spoilers, 0, 0, 0, 1f, emojiColorFilter); + } + canvas.restore(); + } + } + } + } + + final AtomicReference patchedLayout = new AtomicReference<>(); + + private void drawLayout(StaticLayout staticLayout, Canvas canvas, List spoilers) { + if (!spoilers.isEmpty()) { + SpoilerEffect.renderWithRipple(StoryCaptionTextView.this, false, Color.WHITE, 0, patchedLayout, staticLayout, spoilers, canvas, false); + } else { + staticLayout.draw(canvas); + } + } + + public boolean touch(MotionEvent event) { + boolean allowIntercept = true; + if (showMore != null) { + AndroidUtilities.rectTmp.set(showMoreX , showMoreY, showMoreX + showMore.getWidth(), showMoreY + showMore.getHeight()); + if (AndroidUtilities.rectTmp.contains(event.getX(), event.getY())) { + allowIntercept = false; + } + } + boolean linkResult = false; + if (allowIntercept && event.getAction() == MotionEvent.ACTION_DOWN || (pressedLink != null || pressedEmoji != null) && event.getAction() == MotionEvent.ACTION_UP) { + int x = (int) (event.getX() - horizontalPadding); + int y = (int) (event.getY() - verticalPadding); + final int line = fullLayout.getLineForVertical(y); + final int off = fullLayout.getOffsetForHorizontal(line, x); + final float left = fullLayout.getLineLeft(line); + + CharacterStyle touchLink = null; + AnimatedEmojiSpan touchEmoji = null; + if (left <= x && left + fullLayout.getLineWidth(line) >= x && y >= 0 && y <= fullLayout.getHeight()) { + Spannable buffer = new SpannableString(text); + CharacterStyle[] link = buffer.getSpans(off, off, ClickableSpan.class); + if (link == null || link.length == 0) { + link = buffer.getSpans(off, off, URLSpanMono.class); + } + if (link != null && link.length != 0) { + touchLink = link[0]; + if (event.getAction() == MotionEvent.ACTION_DOWN) { + linkResult = true; + links.clear(); + pressedEmoji = null; + pressedLink = new LinkSpanDrawable<>(link[0], null, event.getX(), event.getY()); + pressedLink.setColor(Theme.multAlpha(Color.WHITE, 0.2f)); + links.addLink(pressedLink); + int start = buffer.getSpanStart(pressedLink.getSpan()); + int end = buffer.getSpanEnd(pressedLink.getSpan()); + LinkPath path = pressedLink.obtainNewPath(); + path.setCurrentLayout(fullLayout, start, getPaddingTop()); + fullLayout.getSelectionPath(start, end, path); + + final LinkSpanDrawable savedPressedLink = pressedLink; + textSelectionHelper.clear(); + postDelayed(() -> { + + if (savedPressedLink == pressedLink && pressedLink != null && pressedLink.getSpan() instanceof URLSpan) { + onLinkLongPress((URLSpan) pressedLink.getSpan(), StoryCaptionTextView.this, links::clear); + pressedLink = null; + } + }, ViewConfiguration.getLongPressTimeout()); + } + } + if (pressedLink == null && !linkResult) { + AnimatedEmojiSpan[] emoji = buffer.getSpans(off, off, AnimatedEmojiSpan.class); + if (emoji != null && emoji.length != 0) { + touchEmoji = emoji[0]; + if (event.getAction() == MotionEvent.ACTION_DOWN) { + linkResult = true; // links.clear(); + pressedLink = null; + pressedEmoji = emoji[0]; + } + } + } + } + if (event.getAction() == MotionEvent.ACTION_UP) { + links.clear(); + if (pressedLink != null && pressedLink.getSpan() == touchLink) { + onLinkClick(pressedLink.getSpan(), StoryCaptionView.this); + } else if (pressedEmoji != null && pressedEmoji == touchEmoji) { + onEmojiClick(pressedEmoji); + } + pressedLink = null; + pressedEmoji = null; + linkResult = true; + } + } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { + clearPressedLinks(); + pressedEmoji = null; + linkResult = true; + } + return linkResult; + } + + public void detach() { + AnimatedEmojiSpan.release(StoryCaptionTextView.this, fullLayoutEmoji); + AnimatedEmojiSpan.release(StoryCaptionTextView.this, firstLayoutEmoji); + if (nextLinesLayouts != null) { + for (int i = 0; i < nextLinesLayouts.length; i++) { + if (nextLinesLayouts[i] == null) { + continue; + } + AnimatedEmojiSpan.release(StoryCaptionTextView.this, nextLinesLayouts[i].layoutEmoji); + } + } + } + } + + @Override + public CharSequence getText() { + return state[0].text; + } + + @Override + public Layout getStaticTextLayout() { + return state[0].fullLayout; + } + + TextState[] state = new TextState[2]; + int sizeCached = 0; StaticLayout showMore; - StaticLayout fullLayout; - StaticLayout firstLayout; - LineInfo[] nextLinesLayouts; - - CharSequence text = ""; - int textHeight; - float textX; - float textY; + float progressToExpand; - float showMoreY; - float showMoreX; //spoilers - private SpoilersClickDetector clickDetector; - protected List spoilers = new ArrayList<>(); - private Stack spoilersPool = new Stack<>(); private boolean isSpoilersRevealed; private Path path = new Path(); public boolean allowClickSpoilers = true; int horizontalPadding; int verticalPadding; - private AnimatedEmojiSpan.EmojiGroupedSpans fullLayoutEmoji; - private AnimatedEmojiSpan.EmojiGroupedSpans firstLayoutEmoji; - public StoryCaptionTextView(Context context, Theme.ResourcesProvider resourcesProvider) { super(context); + state[0] = new TextState(); + state[1] = null; + textPaint.setColor(Color.WHITE); - textPaint.linkColor = Theme.getColor(Theme.key_chat_messageLinkIn, resourcesProvider); + textPaint.linkColor = Color.WHITE;//Theme.getColor(Theme.key_chat_messageLinkIn, resourcesProvider); textPaint.setTextSize(AndroidUtilities.dp(15)); showMorePaint.setColor(Color.WHITE); @@ -608,35 +989,82 @@ public StoryCaptionTextView(Context context, Theme.ResourcesProvider resourcesPr xRefGradinetPaint.setShader(new LinearGradient(0, 0, AndroidUtilities.dp(16), 0, new int[]{0, 0xffffffff}, new float[]{0f, 1f}, Shader.TileMode.CLAMP)); xRefGradinetPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); - clickDetector = new SpoilersClickDetector(this, spoilers, (eff, x, y) -> { - if (isSpoilersRevealed) return; - - eff.setOnRippleEndCallback(() -> post(() -> { - isSpoilersRevealed = true; - // invalidateSpoilers(); - })); - - float rad = (float) Math.sqrt(Math.pow(getWidth(), 2) + Math.pow(getHeight(), 2)); - for (SpoilerEffect ef : spoilers) - ef.startRipple(x, y, rad); - }); - emojiColorFilter = new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN); } - public void setText(CharSequence text) { + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + if (state[0] != null && state[0].loadingDrawable == who) { + return true; + } + if (state[1] != null && state[1].loadingDrawable == who) { + return true; + } + return super.verifyDrawable(who); + } + + public void setText(CharSequence text, boolean translating, boolean animated) { if (text == null) { text = ""; } + if (TextUtils.equals(state[0].text, text)) { + state[0].translating = translating; + invalidate(); + return; + } isSpoilersRevealed = false; - // invalidateSpoilers(); - this.text = text; - sizeCached = 0; - if (getMeasuredWidth() > 0) { - createLayout(getMeasuredWidth()); + if (updateAnimator != null) { + updateAnimator.cancel(); + } + updating = false; + if (animated) { + if (state[1] == null) { + state[1] = new TextState(); + } + state[1].setup(state[0].text); + state[1].translating = state[0].translating; + state[1].translateT.set(state[0].translateT.get(), true); + state[0].setup(text); + state[0].translating = translating; + state[0].translateT.set(0, true); + updateT = 1; + animateUpdate(); + } else { + state[0].setup(text); + state[0].translating = translating; + invalidate(); + updateT = 0; } - requestLayout(); - invalidate(); + } + + public float updateT; + public boolean updating = false; + private ValueAnimator updateAnimator; + public void animateUpdate() { + if (updateAnimator != null) { + updateAnimator.cancel(); + } + updating = true; + updateAnimator = ValueAnimator.ofFloat(updateT, 0); + updateAnimator.addUpdateListener(anm -> { + updateT = (float) anm.getAnimatedValue(); + invalidate(); + StoryCaptionTextView.this.requestLayout(); + StoryCaptionView.this.requestLayout(); + }); + updateAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + updating = false; + updateT = 0; + invalidate(); + StoryCaptionTextView.this.requestLayout(); + StoryCaptionView.this.requestLayout(); + } + }); + updateAnimator.setDuration(180); + updateAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT); + updateAnimator.start(); } @SuppressLint("DrawAllocation") @@ -647,136 +1075,26 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { verticalPadding = AndroidUtilities.dp(8); if (sizeCached != size) { sizeCached = size; - createLayout(MeasureSpec.getSize(widthMeasureSpec)); - } - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(verticalPadding * 2 + textHeight, MeasureSpec.EXACTLY)); - } - - private void createLayout(int measuredWidth) { - int width = measuredWidth - horizontalPadding * 2; - fullLayout = makeTextLayout(textPaint, text, width); - textHeight = fullLayout.getHeight(); - textX = horizontalPadding; - textY = verticalPadding; - float space = textPaint.measureText(" "); - if (fullLayout.getLineCount() > 3) { - String showMoreText = LocaleController.getString("ShowMore", R.string.ShowMore); - showMore = makeTextLayout(showMorePaint, showMoreText, width); - - float collapsedY = fullLayout.getLineTop(2) + fullLayout.getTopPadding(); - showMoreY = textY + collapsedY - AndroidUtilities.dpf2(0.3f); - showMoreX = width - horizontalPadding - showMorePaint.measureText(showMoreText); - firstLayout = makeTextLayout(textPaint, text.subSequence(0, fullLayout.getLineEnd(2)), width); - spoilersPool.addAll(spoilers); - spoilers.clear(); - SpoilerEffect.addSpoilers(this, fullLayout, spoilersPool, spoilers); - - float x = fullLayout.getLineRight(2) + space; - if (nextLinesLayouts != null) { - for (int i = 0; i < nextLinesLayouts.length; i++) { - if (nextLinesLayouts[i] == null) { - continue; - } - AnimatedEmojiSpan.release(this, nextLinesLayouts[i].layoutEmoji); - } + int width = MeasureSpec.getSize(widthMeasureSpec) - horizontalPadding * 2; + state[0].measure(width); + if (state[1] != null) { + state[1].measure(width); } - nextLinesLayouts = new LineInfo[fullLayout.getLineCount() - 3]; - - if (spoilers.isEmpty()) { - for (int line = 3; line < fullLayout.getLineCount(); ++line) { - int s = fullLayout.getLineStart(line), e = fullLayout.getLineEnd(line); - final StaticLayout layout = makeTextLayout(textPaint, text.subSequence(Math.min(s, e), Math.max(s, e)), width); - LineInfo lineInfo = new LineInfo(); - nextLinesLayouts[line - 3] = lineInfo; - lineInfo.staticLayout = layout; - lineInfo.finalX = fullLayout.getLineLeft(line); - lineInfo.finalY = fullLayout.getLineTop(line) + fullLayout.getTopPadding(); - if (x < showMoreX - AndroidUtilities.dp(16)) { - lineInfo.collapsedY = collapsedY; - lineInfo.collapsedX = x; - x += layout.getLineRight(0) + space; - } else { - lineInfo.collapsedY = lineInfo.finalY; - lineInfo.collapsedX = lineInfo.finalX; - } - } - } - } else { - showMore = null; - firstLayout = null; - spoilersPool.addAll(spoilers); - spoilers.clear(); - SpoilerEffect.addSpoilers(this, fullLayout, spoilersPool, spoilers); } + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(verticalPadding * 2 + AndroidUtilities.lerp(state[0].textHeight, state[1] == null ? 0 : state[1].textHeight, updateT), MeasureSpec.EXACTLY)); } @Override protected void onDraw(Canvas canvas) { if (showMore != null) { - canvas.saveLayerAlpha(textX - horizontalPadding, textY, getMeasuredWidth(), getMeasuredHeight() - verticalPadding, 255, Canvas.ALL_SAVE_FLAG); + canvas.saveLayerAlpha(0, 0, getMeasuredWidth(), getMeasuredHeight(), 255, Canvas.ALL_SAVE_FLAG); } else { canvas.save(); } - canvas.save(); - canvas.translate(textX, textY); - if (links.draw(canvas)) { - invalidate(); - } - canvas.restore(); - - if (!spoilers.isEmpty() || firstLayout == null) { - if (fullLayout != null) { - canvas.save(); - canvas.translate(textX, textY); - if (textSelectionHelper.isInSelectionMode()) { - textSelectionHelper.draw(canvas); - } - drawLayout(fullLayout, canvas); - fullLayoutEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, fullLayoutEmoji, fullLayout); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, fullLayout, fullLayoutEmoji, 0, spoilers, 0, 0, 0, 1f, emojiColorFilter); - canvas.restore(); - } - } else { - if (textSelectionHelper.isInSelectionMode()) { - canvas.save(); - canvas.translate(textX, textY); - textSelectionHelper.draw(canvas); - canvas.restore(); - } - if (firstLayout != null) { - canvas.save(); - canvas.translate(textX, textY); - drawLayout(firstLayout, canvas); - firstLayoutEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, firstLayoutEmoji, firstLayout); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, firstLayout, firstLayoutEmoji, 0, spoilers, 0, 0, 0, 1f, emojiColorFilter); - canvas.restore(); - } - - if (nextLinesLayouts != null) { - for (int i = 0; i < nextLinesLayouts.length; i++) { - LineInfo lineInfo = nextLinesLayouts[i]; - canvas.save(); - if (lineInfo.collapsedX == lineInfo.finalX) { - textPaint.setAlpha((int) (255 * progressToExpand)); - canvas.translate(textX + lineInfo.finalX, textY + lineInfo.finalY); - drawLayout(lineInfo.staticLayout, canvas); - lineInfo.staticLayout.draw(canvas); - lineInfo.layoutEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, lineInfo.layoutEmoji, lineInfo.staticLayout); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, lineInfo.staticLayout, lineInfo.layoutEmoji, 0, spoilers, 0, 0, 0, progressToExpand, emojiColorFilter); - textPaint.setAlpha(255); - } else { - float offsetX = AndroidUtilities.lerp(lineInfo.collapsedX, lineInfo.finalX, progressToExpand); - float offsetY = AndroidUtilities.lerp(lineInfo.collapsedY, lineInfo.finalY, CubicBezierInterpolator.EASE_OUT.getInterpolation(progressToExpand)); - canvas.translate(textX + offsetX, textY + offsetY); - //drawLayout(lineInfo.staticLayout, canvas, -offsetX, -offsetY); - lineInfo.staticLayout.draw(canvas); - lineInfo.layoutEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, lineInfo.layoutEmoji, lineInfo.staticLayout); - AnimatedEmojiSpan.drawAnimatedEmojis(canvas, lineInfo.staticLayout, lineInfo.layoutEmoji, 0, spoilers, 0, 0, 0, 1f, emojiColorFilter); - } - canvas.restore(); - } - } + state[0].draw(canvas, 1f - updateT); + if (state[1] != null) { + state[1].draw(canvas, updateT); } if (showMore != null) { @@ -796,22 +1114,17 @@ protected void onDraw(Canvas canvas) { showMore.draw(canvas); canvas.restore(); } - canvas.restore(); - } - - AtomicReference patchedLayout = new AtomicReference<>(); - private void drawLayout(StaticLayout staticLayout, Canvas canvas) { - if (!spoilers.isEmpty()) { - SpoilerEffect.renderWithRipple(this, false, Color.WHITE, 0, patchedLayout, staticLayout, spoilers, canvas, false); - } else { - staticLayout.draw(canvas); - } + canvas.restore(); } private StaticLayout makeTextLayout(TextPaint textPaint, CharSequence string, int width) { if (Build.VERSION.SDK_INT >= 24) { - return StaticLayout.Builder.obtain(string, 0, string.length(), textPaint, width).setBreakStrategy(StaticLayout.BREAK_STRATEGY_SIMPLE).setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE).setAlignment(LocaleController.isRTL ? StaticLayoutEx.ALIGN_RIGHT() : StaticLayoutEx.ALIGN_LEFT()).build(); + return StaticLayout.Builder.obtain(string, 0, string.length(), textPaint, width) + .setBreakStrategy(StaticLayout.BREAK_STRATEGY_SIMPLE) + .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE) + .setAlignment(LocaleController.isRTL ? StaticLayoutEx.ALIGN_RIGHT() : StaticLayoutEx.ALIGN_LEFT()) + .build(); } else { return new StaticLayout(string, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } @@ -821,18 +1134,8 @@ public Paint getPaint() { return textPaint; } - @Override - public CharSequence getText() { - return text; - } - - @Override - public StaticLayout getStaticTextLayout() { - return fullLayout; - } - public class LineInfo { - private AnimatedEmojiSpan.EmojiGroupedSpans layoutEmoji; + public AnimatedEmojiSpan.EmojiGroupedSpans layoutEmoji; StaticLayout staticLayout; float collapsedX, collapsedY; float finalX, finalY; @@ -840,85 +1143,13 @@ public class LineInfo { @Override public boolean onTouchEvent(MotionEvent event) { - if (fullLayout == null || disableTouches) { + if (disableTouches) { return false; } - boolean allowIntercept = true; - if (showMore != null) { - AndroidUtilities.rectTmp.set(showMoreX , showMoreY, showMoreX + showMore.getWidth(), showMoreY + showMore.getHeight()); - if (AndroidUtilities.rectTmp.contains(event.getX(), event.getY())) { - allowIntercept = false; - } - } - boolean linkResult = false; - if (allowIntercept && event.getAction() == MotionEvent.ACTION_DOWN || (pressedLink != null || pressedEmoji != null) && event.getAction() == MotionEvent.ACTION_UP) { - int x = (int) (event.getX() - textX); - int y = (int) (event.getY() - textY); - final int line = fullLayout.getLineForVertical(y); - final int off = fullLayout.getOffsetForHorizontal(line, x); - final float left = fullLayout.getLineLeft(line); - - CharacterStyle touchLink = null; - AnimatedEmojiSpan touchEmoji = null; - if (left <= x && left + fullLayout.getLineWidth(line) >= x && y >= 0 && y <= fullLayout.getHeight()) { - Spannable buffer = new SpannableString(text); - CharacterStyle[] link = buffer.getSpans(off, off, ClickableSpan.class); - if (link == null || link.length == 0) { - link = buffer.getSpans(off, off, URLSpanMono.class); - } - if (link != null && link.length != 0) { - touchLink = link[0]; - if (event.getAction() == MotionEvent.ACTION_DOWN) { - linkResult = true; - links.clear(); - pressedEmoji = null; - pressedLink = new LinkSpanDrawable<>(link[0], null, event.getX(), event.getY()); - pressedLink.setColor(0x6662a9e3); - links.addLink(pressedLink); - int start = buffer.getSpanStart(pressedLink.getSpan()); - int end = buffer.getSpanEnd(pressedLink.getSpan()); - LinkPath path = pressedLink.obtainNewPath(); - path.setCurrentLayout(fullLayout, start, getPaddingTop()); - fullLayout.getSelectionPath(start, end, path); - - final LinkSpanDrawable savedPressedLink = pressedLink; - postDelayed(() -> { - if (savedPressedLink == pressedLink && pressedLink != null && pressedLink.getSpan() instanceof URLSpan) { - onLinkLongPress((URLSpan) pressedLink.getSpan(), this, () -> links.clear()); - pressedLink = null; - } - }, ViewConfiguration.getLongPressTimeout()); - } - } - if (pressedLink == null && !linkResult) { - AnimatedEmojiSpan[] emoji = buffer.getSpans(off, off, AnimatedEmojiSpan.class); - if (emoji != null && emoji.length != 0) { - touchEmoji = emoji[0]; - if (event.getAction() == MotionEvent.ACTION_DOWN) { - linkResult = true; // links.clear(); - pressedLink = null; - pressedEmoji = emoji[0]; - } - } - } - } - if (event.getAction() == MotionEvent.ACTION_UP) { - links.clear(); - if (pressedLink != null && pressedLink.getSpan() == touchLink) { - onLinkClick(pressedLink.getSpan(), this); - } else if (pressedEmoji != null && pressedEmoji == touchEmoji) { - onEmojiClick(pressedEmoji); - } - pressedLink = null; - pressedEmoji = null; - linkResult = true; - } - } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { - clearPressedLinks(); - pressedEmoji = null; - linkResult = true; + if (state == null || state[0].fullLayout == null) { + return false; } - + boolean linkResult = state[0].touch(event); boolean b = linkResult || super.onTouchEvent(event); return b; } @@ -926,21 +1157,12 @@ public boolean onTouchEvent(MotionEvent event) { @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - AnimatedEmojiSpan.release(this, fullLayoutEmoji); - AnimatedEmojiSpan.release(this, firstLayoutEmoji); - if (nextLinesLayouts != null) { - for (int i = 0; i < nextLinesLayouts.length; i++) { - if (nextLinesLayouts[i] == null) { - continue; - } - AnimatedEmojiSpan.release(this, nextLinesLayouts[i].layoutEmoji); - } - } + state[0].detach(); } private void clearPressedLinks() { - links.clear(); - pressedLink = null; + state[0].links.clear(); + state[0].pressedLink = null; invalidate(); } @@ -964,19 +1186,27 @@ public void setTranslationY(float translationY) { @Override public boolean dispatchTouchEvent(MotionEvent event) { boolean allowIntercept = true; + if (event.getAction() == MotionEvent.ACTION_DOWN) { + startMotionX = event.getX(); + startMotionY = event.getY(); + } lastMotionX = event.getX(); lastMotionY = event.getY(); if (showMore != null) { - AndroidUtilities.rectTmp.set(showMoreX , showMoreY, showMoreX + showMore.getWidth(), showMoreY + showMore.getHeight()); + AndroidUtilities.rectTmp.set(showMoreX, showMoreY, showMoreX + showMore.getWidth(), showMoreY + showMore.getHeight()); if (AndroidUtilities.rectTmp.contains(event.getX(), event.getY())) { allowIntercept = false; } } - if (allowIntercept && allowClickSpoilers && clickDetector.onTouchEvent(event)) return true; -// if (allowIntercept && (expanded || firstLayout == null)) { -// textSelectionHelper.update(textX, textY); -// textSelectionHelper.onTouchEvent(event); -// } + if (allowIntercept && (expanded || state[0].firstLayout == null)) { + textSelectionHelper.update(horizontalPadding, verticalPadding); + textSelectionHelper.onTouchEvent(event); + } + if (!textSelectionHelper.isInSelectionMode() && allowIntercept && allowClickSpoilers && state[0].clickDetector.onTouchEvent(event)) { + getParent().requestDisallowInterceptTouchEvent(true); + textSelectionHelper.clear(); + return true; + } return super.dispatchTouchEvent(event); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryContainsEmojiButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryContainsEmojiButton.java index 8ada537bfe7..c9ddbdde3ee 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryContainsEmojiButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryContainsEmojiButton.java @@ -363,11 +363,11 @@ private void set(TLRPC.StickerSetCovered set) { private void set(int setsCount) { if (emoji && stickers) { - setText(AndroidUtilities.replaceTags(LocaleController.formatPluralString("StoryContainsStickersEmoji", setsCount))); + setText(AndroidUtilities.replaceSingleTag(LocaleController.formatPluralString("StoryContainsStickersEmoji", setsCount), 0, Theme.getColor(Theme.key_chat_messageLinkIn, loadingDrawable.resourcesProvider), null)); } else if (emoji) { - setText(AndroidUtilities.replaceTags(LocaleController.formatPluralString("StoryContainsEmoji", setsCount))); + setText(AndroidUtilities.replaceSingleTag(LocaleController.formatPluralString("StoryContainsEmoji", setsCount), 0, Theme.getColor(Theme.key_chat_messageLinkIn, loadingDrawable.resourcesProvider), null)); } else { - setText(AndroidUtilities.replaceTags(LocaleController.formatPluralString("StoryContainsStickers", setsCount))); + setText(AndroidUtilities.replaceSingleTag(LocaleController.formatPluralString("StoryContainsStickers", setsCount), 0, Theme.getColor(Theme.key_chat_messageLinkIn, loadingDrawable.resourcesProvider), null)); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCustomParamsHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCustomParamsHelper.java new file mode 100644 index 00000000000..8ffaf343689 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryCustomParamsHelper.java @@ -0,0 +1,96 @@ +package org.telegram.ui.Stories; + +import org.telegram.tgnet.AbstractSerializedData; +import org.telegram.tgnet.NativeByteBuffer; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; + +public class StoryCustomParamsHelper { + + public static boolean isEmpty(TLRPC.StoryItem storyItem) { + return storyItem.detectedLng == null && storyItem.translatedLng == null && !storyItem.translated && storyItem.translatedText == null; + } + + public static void copyParams(TLRPC.StoryItem fromStory, TLRPC.StoryItem toStory) { + toStory.translated = fromStory.translated; + toStory.detectedLng = fromStory.detectedLng; + toStory.translatedText = fromStory.translatedText; + toStory.translatedLng = fromStory.translatedLng; + } + + public static void readLocalParams(TLRPC.StoryItem storyItem, NativeByteBuffer byteBuffer) { + if (byteBuffer == null) { + return; + } + int version = byteBuffer.readInt32(true); + TLObject params; + switch (version) { + case 1: + params = new Params_v1(storyItem); + break; + default: + throw new RuntimeException("(story) can't read params version = " + version); + } + params.readParams(byteBuffer, true); + } + + public static NativeByteBuffer writeLocalParams(TLRPC.StoryItem storyItem) { + if (isEmpty(storyItem)) { + return null; + } + TLObject params = new Params_v1(storyItem); + try { + NativeByteBuffer nativeByteBuffer = new NativeByteBuffer(params.getObjectSize()); + params.serializeToStream(nativeByteBuffer); + return nativeByteBuffer; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + private static class Params_v1 extends TLObject { + + private final static int VERSION = 1; + final TLRPC.StoryItem storyItem; + int flags = 0; + + private Params_v1(TLRPC.StoryItem storyItem) { + this.storyItem = storyItem; + flags += storyItem.translated ? 1 : 0; + flags += storyItem.detectedLng != null ? 2 : 0; + flags += storyItem.translatedText != null ? 4 : 0; + flags += storyItem.translatedLng != null ? 8 : 0; + } + + @Override + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(VERSION); + stream.writeInt32(flags); + if ((flags & 2) != 0) { + stream.writeString(storyItem.detectedLng); + } + if ((flags & 4) != 0) { + storyItem.translatedText.serializeToStream(stream); + } + if ((flags & 8) != 0) { + stream.writeString(storyItem.translatedLng); + } + } + + @Override + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(true); + storyItem.translated = (flags & 1) != 0; + if ((flags & 2) != 0) { + storyItem.detectedLng = stream.readString(exception); + } + if ((flags & 4) != 0) { + storyItem.translatedText = TLRPC.TL_textWithEntities.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 8) != 0) { + storyItem.translatedLng = stream.readString(exception); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryMediaAreasView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryMediaAreasView.java new file mode 100644 index 00000000000..a614745229d --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryMediaAreasView.java @@ -0,0 +1,429 @@ +package org.telegram.ui.Stories; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.RectF; +import android.graphics.Region; +import android.graphics.Shader; +import android.graphics.Xfermode; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.LinearInterpolator; +import android.widget.FrameLayout; + +import com.google.android.exoplayer2.extractor.CeaUtil; +import com.google.zxing.qrcode.decoder.Mode; + +import org.checkerframework.checker.units.qual.A; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.ColoredImageSpan; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.LocationActivity; +import org.telegram.ui.Stories.recorder.HintView2; + +import java.util.ArrayList; + +public class StoryMediaAreasView extends FrameLayout implements View.OnClickListener { + + private AreaView selectedArea = null; + private HintView2 hintView = null; + + private final FrameLayout hintsContainer; + private boolean malicious; + + private Theme.ResourcesProvider resourcesProvider; + + public StoryMediaAreasView(Context context, Theme.ResourcesProvider resourcesProvider) { + super(context); + this.resourcesProvider = resourcesProvider; + + addView(hintsContainer = new FrameLayout(context)); + } + + protected void onHintVisible(boolean hintVisible) { + + } + + protected void presentFragment(BaseFragment fragment) { + + } + + private ArrayList lastMediaAreas; + + public void set(ArrayList mediaAreas) { + if (mediaAreas == lastMediaAreas && (mediaAreas == null || lastMediaAreas == null || mediaAreas.size() == lastMediaAreas.size())) { + return; + } + + if (hintView != null) { + hintView.hide(); + hintView = null; + } + + for (int i = 0; i < getChildCount(); ++i) { + View child = getChildAt(i); + if (child != hintsContainer) { + removeView(child); + i--; + } + } + selectedArea = null; + invalidate(); + onHintVisible(false); + malicious = false; + + lastMediaAreas = mediaAreas; + if (mediaAreas == null) { + return; + } + + shined = false; + + final float W = 1080, H = 1920; + + double totalArea = 0; + for (int i = 0; i < mediaAreas.size(); ++i) { + TLRPC.MediaArea mediaArea = mediaAreas.get(i); + if (mediaArea != null && mediaArea.coordinates != null) { + AreaView areaView = new AreaView(getContext(), this, mediaArea); + areaView.setOnClickListener(this); + addView(areaView); + + totalArea += (mediaArea.coordinates.w / 100f * W) * (mediaArea.coordinates.h / 100f * H); + } + } + malicious = totalArea > W * H * .33f; + + hintsContainer.bringToFront(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int w = MeasureSpec.getSize(widthMeasureSpec); + int h = MeasureSpec.getSize(heightMeasureSpec); + for (int i = 0; i < getChildCount(); ++i) { + View view = getChildAt(i); + if (view == hintsContainer) { + hintsContainer.measure( + MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY) + ); + } else if (view instanceof AreaView) { + AreaView child = (AreaView) getChildAt(i); + child.measure( + MeasureSpec.makeMeasureSpec((int) Math.ceil(child.mediaArea.coordinates.w / 100 * w), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec((int) Math.ceil(child.mediaArea.coordinates.h / 100 * h), MeasureSpec.EXACTLY) + ); + } + } + setMeasuredDimension(w, h); + } + + @Override + public void onClick(View v) { + if (!(v instanceof AreaView)) { + return; + } + + if (selectedArea == v) { + AndroidUtilities.runOnUIThread(() -> { + if (hintView != null) { + hintView.hide(); + hintView = null; + } + onHintVisible(false); + }, 200); + + LocationActivity fragment = new LocationActivity(3); + fragment.setResourceProvider(resourcesProvider); + TLRPC.TL_message message = new TLRPC.TL_message(); + if (selectedArea.mediaArea instanceof TLRPC.TL_mediaAreaVenue) { + TLRPC.TL_mediaAreaVenue areaVenue = (TLRPC.TL_mediaAreaVenue) selectedArea.mediaArea; + TLRPC.TL_messageMediaVenue media = new TLRPC.TL_messageMediaVenue(); + media.venue_id = areaVenue.venue_id; + media.venue_type = areaVenue.venue_type; + media.title = areaVenue.title; + media.address = areaVenue.address; + media.provider = areaVenue.provider; + media.geo = areaVenue.geo; + message.media = media; + } else if (selectedArea.mediaArea instanceof TLRPC.TL_mediaAreaGeoPoint) { + fragment.setInitialMaxZoom(true); + TLRPC.TL_mediaAreaGeoPoint areaGeo = (TLRPC.TL_mediaAreaGeoPoint) selectedArea.mediaArea; + TLRPC.TL_messageMediaGeo media = new TLRPC.TL_messageMediaGeo(); + media.geo = areaGeo.geo; + message.media = media; + } else { + selectedArea = null; + invalidate(); + return; + } + fragment.setSharingAllowed(false); + fragment.setMessageObject(new MessageObject(UserConfig.selectedAccount, message, false, false)); + presentFragment(fragment); + selectedArea = null; + invalidate(); + return; + } + + if (selectedArea != null && malicious) { + onClickAway(); + return; + } + + selectedArea = (AreaView) v; + invalidate(); + if (hintView != null) { + hintView.hide(); + hintView = null; + } + + boolean top = selectedArea.getTranslationY() < AndroidUtilities.dp(100); + + SpannableStringBuilder text = new SpannableStringBuilder(LocaleController.getString("StoryViewLocation", R.string.StoryViewLocation)); + SpannableString arrowRight = new SpannableString(">"); + ColoredImageSpan imageSpan = new ColoredImageSpan(R.drawable.photos_arrow); + imageSpan.translate(dp(2), dp(1)); + arrowRight.setSpan(imageSpan, 0, arrowRight.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + SpannableString arrowLeft = new SpannableString("<"); + imageSpan = new ColoredImageSpan(R.drawable.attach_arrow_right); + imageSpan.translate(dp(-2), dp(1)); + imageSpan.setScale(-1, 1); + arrowLeft.setSpan(imageSpan, 0, arrowLeft.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + AndroidUtilities.replaceCharSequence(">", text, arrowRight); + AndroidUtilities.replaceCharSequence("<", text, arrowLeft); + + final HintView2 thisHint = hintView = new HintView2(getContext(), top ? HintView2.DIRECTION_TOP : HintView2.DIRECTION_BOTTOM) + .setText(text) + .setSelectorColor(0x28ffffff) + .setJointPx(0, selectedArea.getTranslationX() - dp(8)) + .setDuration(5000); + thisHint.setOnHiddenListener(() -> { + hintsContainer.removeView(thisHint); + if (thisHint == hintView) { + selectedArea = null; + invalidate(); + onHintVisible(false); + } + }); + if (top) { + hintView.setTranslationY(selectedArea.getTranslationY() + selectedArea.getMeasuredHeight() / 2f); + } else { + hintView.setTranslationY(selectedArea.getTranslationY() - selectedArea.getMeasuredHeight() / 2f - dp(50)); + } + hintView.setOnClickListener(view -> onClick(selectedArea)); + hintView.setPadding(dp(8), dp(8), dp(8), dp(8)); + hintsContainer.addView(hintView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 50)); + hintView.show(); + onHintVisible(true); + } + + public void closeHint() { + if (hintView != null) { + hintView.hide(); + hintView = null; + } + selectedArea = null; + invalidate(); + onHintVisible(false); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (getChildCount() == 0 || hintView == null || !hintView.shown()) { + return false; + } + if (event.getAction() == MotionEvent.ACTION_UP) { + onClickAway(); + } + super.onTouchEvent(event); + return true; + } + + private void onClickAway() { + if (hintView != null) { + hintView.hide(); + hintView = null; + } + selectedArea = null; + invalidate(); + onHintVisible(false); + + if (malicious) { + for (int i = 0; i < getChildCount(); ++i) { + View child = getChildAt(i); + if (child != hintsContainer) { + child.setClickable(false); + } + } + } + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + for (int i = 0; i < getChildCount(); ++i) { + View view = getChildAt(i); + if (view == hintsContainer) { + view.layout(0, 0, right - left, bottom - top); + } else if (view instanceof AreaView) { + AreaView child = (AreaView) view; + int w = child.getMeasuredWidth(), h = child.getMeasuredHeight(); + child.layout(-w / 2, -h / 2, w / 2, h / 2); + child.setTranslationX((float) (child.mediaArea.coordinates.x / 100 * getMeasuredWidth())); + child.setTranslationY((float) (child.mediaArea.coordinates.y / 100 * getMeasuredHeight())); + child.setRotation((float) child.mediaArea.coordinates.rotation); + } + } + } + + + private final RectF rectF = new RectF(); + private final Paint cutPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + { + cutPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + cutPaint.setColor(0xffffffff); + } + public final AnimatedFloat parentHighlightAlpha = new AnimatedFloat(this, 0, 120, new LinearInterpolator()); + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child == hintsContainer) { + drawHighlight(canvas); + } + return super.drawChild(canvas, child, drawingTime); + } + + private void drawHighlight(Canvas canvas) { + float parentAlpha = parentHighlightAlpha.set(selectedArea != null); + if (parentAlpha > 0) { + canvas.saveLayerAlpha(0, 0, getMeasuredWidth(), getMeasuredHeight(), 0xFF, Canvas.ALL_SAVE_FLAG); + canvas.drawColor(Theme.multAlpha(0x18000000, parentAlpha)); + for (int i = 0; i < getChildCount(); ++i) { + View child2 = getChildAt(i); + if (child2 != hintsContainer) { + AreaView areaView = (AreaView) child2; + float alpha = areaView.highlightAlpha.set(child2 == selectedArea); + if (alpha > 0) { + canvas.save(); + rectF.set(child2.getX(), child2.getY(), child2.getX() + child2.getMeasuredWidth(), child2.getY() + child2.getMeasuredHeight()); + canvas.rotate(child2.getRotation(), rectF.centerX(), rectF.centerY()); + cutPaint.setAlpha((int) (0xFF * alpha)); + canvas.drawRoundRect(rectF, rectF.height() * .2f, rectF.height() * .2f, cutPaint); + canvas.restore(); + } + } + } + canvas.restore(); + } + } + + private boolean shined = false; + public void shine() { + if (shined) { + return; + } + shined = true; + for (int i = 0; i < getChildCount(); ++i) { + View child = getChildAt(i); + if (child instanceof AreaView) { + ((AreaView) child).shine(); + } + } + } + + public boolean hasSelected() { + return selectedArea != null; + } + + public static class AreaView extends View { + + public final AnimatedFloat highlightAlpha; + + public final TLRPC.MediaArea mediaArea; + + public AreaView(Context context, View parent, TLRPC.MediaArea mediaArea) { + super(context); + this.mediaArea = mediaArea; + highlightAlpha = new AnimatedFloat(parent, 0, 120, new LinearInterpolator()); + strokeGradientPaint.setStyle(Paint.Style.STROKE); + } + + private final Paint gradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final Paint strokeGradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private LinearGradient gradient, strokeGradient; + private final Matrix gradientMatrix = new Matrix(); + + private boolean shining = false; + private long startTime; + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (shining && gradient != null) { + float w = getMeasuredWidth() * .7f; + float t = (System.currentTimeMillis() - startTime) / 600f; + float tx = t * (getMeasuredWidth() + w) - w; + + if (t >= 1) { + shining = false; + return; + } + + gradientMatrix.reset(); + gradientMatrix.postScale(w / 40, 1); + gradientMatrix.postTranslate(tx, 0); + gradient.setLocalMatrix(gradientMatrix); + gradientPaint.setShader(gradient); + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + canvas.drawRoundRect(AndroidUtilities.rectTmp, .2f * getMeasuredHeight(), .2f * getMeasuredHeight(), gradientPaint); + + strokeGradient.setLocalMatrix(gradientMatrix); + strokeGradientPaint.setShader(strokeGradient); + final float sw = AndroidUtilities.dpf2(1.5f); + strokeGradientPaint.setStrokeWidth(sw); + AndroidUtilities.rectTmp.inset(sw / 2f, sw / 2f); + canvas.drawRoundRect(AndroidUtilities.rectTmp, .2f * getMeasuredHeight() - sw / 2f, .2f * getMeasuredHeight() - sw / 2f, strokeGradientPaint); + + invalidate(); + } + } + + private final Runnable shineRunnable = this::shineInternal; + + public void shine() { + AndroidUtilities.cancelRunOnUIThread(shineRunnable); + AndroidUtilities.runOnUIThread(shineRunnable, 400L); + } + + private void shineInternal() { + shining = true; + startTime = System.currentTimeMillis(); + gradient = new LinearGradient(0, 0, 40, 0, new int[] { 0x00ffffff, 0x2dffffff, 0x2dffffff, 0x00ffffff }, new float[] { 0, .4f, .6f, 1f }, Shader.TileMode.CLAMP ); + strokeGradient = new LinearGradient(0, 0, 40, 0, new int[] { 0x00ffffff, 0x20ffffff, 0x20ffffff, 0x00ffffff }, new float[] { 0, .4f, .6f, 1f }, Shader.TileMode.CLAMP ); + invalidate(); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryPrivacyButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryPrivacyButton.java index e401c71fd6e..5b30b972b4b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryPrivacyButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryPrivacyButton.java @@ -41,7 +41,7 @@ public class StoryPrivacyButton extends View { private final Paint arrowPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Path arrowPath = new Path(); - private final ButtonBounce bounce = new ButtonBounce(this, .6f); + private final ButtonBounce bounce = new ButtonBounce(this, .6f, 5f); public StoryPrivacyButton(Context context) { super(context); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java index 62fe0795f59..39a35e3eaf4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewer.java @@ -22,6 +22,7 @@ import android.media.AudioManager; import android.net.Uri; import android.os.Build; +import android.util.Log; import android.util.SparseArray; import android.view.GestureDetector; import android.view.Gravity; @@ -45,6 +46,7 @@ import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; +import org.checkerframework.checker.units.qual.A; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AnimationNotificationsLocker; import org.telegram.messenger.BuildVars; @@ -55,6 +57,7 @@ import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; @@ -63,11 +66,14 @@ import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ArticleViewer; import org.telegram.ui.Cells.ChatActionCell; +import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RadialProgress; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.SharedMediaLayout; import org.telegram.ui.Components.SizeNotifierFrameLayout; import org.telegram.ui.Components.VideoPlayer; import org.telegram.ui.LaunchActivity; @@ -75,7 +81,7 @@ import java.util.ArrayList; import java.util.Objects; -public class StoryViewer { +public class StoryViewer implements NotificationCenter.NotificationCenterDelegate { public static boolean animationInProgress; @@ -137,6 +143,7 @@ public class StoryViewer { boolean allowIntercept; + boolean verticalScrollDetected; boolean allowSwipeToDissmiss; GestureDetector gestureDetector; boolean inSwipeToDissmissMode; @@ -149,11 +156,11 @@ public class StoryViewer { private boolean isInTouchMode; private float hideEnterViewProgress; public final TransitionViewHolder transitionViewHolder = new TransitionViewHolder(); - private PlaceProvider placeProvider; + public PlaceProvider placeProvider; Dialog currentDialog; private boolean allowTouchesByViewpager = false; boolean openedFromLightNavigationBar; - Runnable doOnAnimationReady; + ArrayList doOnAnimationReadyRunnables = new ArrayList<>(); // to prevent attach/detach textureView in view pager and // ensure that player is singleton @@ -187,6 +194,7 @@ public class StoryViewer { private static boolean runOpenAnimationAfterLayout; private boolean isPopupVisible; private boolean isBulletinVisible; + public boolean isTranslating = false; public boolean isLongpressed; @@ -210,6 +218,8 @@ public class StoryViewer { private boolean isCaptionPartVisible; private Runnable delayedTapRunnable; private Runnable onCloseListener; + private boolean isLikesReactions; + private float lastStoryContainerHeight; public static boolean isShowingImage(MessageObject messageObject) { if (lastStoryItem == null || messageObject.type != MessageObject.TYPE_STORY && !messageObject.isWebpage() || runOpenAnimationAfterLayout) { @@ -274,6 +284,7 @@ public void open(Context context, int startStoryId, StoriesController.StoriesLis public void open(Context context, TLRPC.TL_userStories userStories, PlaceProvider placeProvider) { if (userStories == null || userStories.stories == null || userStories.stories.isEmpty()) { + doOnAnimationReadyRunnables.clear(); return; } currentAccount = UserConfig.selectedAccount; @@ -293,6 +304,7 @@ public void open(Context context, TLRPC.StoryItem storyItem, int startStoryId, S @SuppressLint("WrongConstant") public void open(Context context, TLRPC.StoryItem storyItem, ArrayList peerIds, int position, StoriesController.StoriesList storiesList, TLRPC.TL_userStories userStories, PlaceProvider placeProvider, boolean reversed) { if (context == null) { + doOnAnimationReadyRunnables.clear(); return; } if (openCloseAnimator != null) { @@ -300,6 +312,7 @@ public void open(Context context, TLRPC.StoryItem storyItem, ArrayList pee openCloseAnimator = null; } if (isShowing) { + doOnAnimationReadyRunnables.clear(); return; } ATTACH_TO_FRAGMENT = !AndroidUtilities.isTablet(); @@ -326,6 +339,7 @@ public void open(Context context, TLRPC.StoryItem storyItem, ArrayList pee progressToDismiss = 0; isShowing = true; isLongpressed = false; + isTranslating = false; savedPositions.clear(); AndroidUtilities.cancelRunOnUIThread(longPressRunnable); windowLayoutParams = new WindowManager.LayoutParams(); @@ -369,23 +383,14 @@ public void onShowPress(@NonNull MotionEvent e) { @Override public boolean onSingleTapUp(@NonNull MotionEvent e) { - PeerStoriesView peerView = storiesViewPager.getCurrentPeerView(); if (selfStoriesViewsOffset != 0) { return false; } - if (allowIntercept && peerView != null) { + if (allowIntercept) { if (keyboardVisible || isCaption || isCaptionPartVisible || isHintVisible || isInTextSelectionMode) { closeKeyboardOrEmoji(); } else { - boolean forward = e.getX() > containerView.getMeasuredWidth() * 0.33f; - if (!peerView.switchToNext(forward)) { - boolean switchToNext = storiesViewPager.switchToNext(forward); - if (!switchToNext && forward) { - close(true); - } else if (switchToNext) { - storiesViewPager.lockTouchEvent(150); - } - } + switchByTap(e.getX() > containerView.getMeasuredWidth() * 0.33f); } } return false; @@ -417,6 +422,7 @@ public boolean onScroll(@NonNull MotionEvent e1, @NonNull MotionEvent e2, float } else { selfStoriesViewsOffset += distanceY; } + Bulletin.hideVisible(windowView); storiesViewPager.getCurrentPeerView().invalidate(); containerView.invalidate(); if (selfStoriesViewsOffset < 0) { @@ -431,6 +437,7 @@ public boolean onScroll(@NonNull MotionEvent e1, @NonNull MotionEvent e2, float k = 0.3f; } swipeToDismissOffset -= distanceY * k; + Bulletin.hideVisible(windowView); updateProgressToDismiss(); return true; } @@ -687,9 +694,17 @@ protected void dispatchDraw(Canvas canvas) { headerView.backupImageView.getImageReceiver().setImageCoords(AndroidUtilities.rectTmp); headerView.backupImageView.getImageReceiver().setRoundRadius((int) (AndroidUtilities.rectTmp.width() / 2f)); headerView.backupImageView.getImageReceiver().setVisible(true, false); - headerView.backupImageView.getImageReceiver().setAlpha(crossfade ? progressToOpen : 1f); + final float alpha = crossfade ? progressToOpen : 1f; + float thisAlpha = alpha; + if (transitionViewHolder != null && transitionViewHolder.alpha < 1 && transitionViewHolder.bgPaint != null) { + transitionViewHolder.bgPaint.setAlpha((int) (0xFF * (1f - progress2))); + canvas.drawCircle(AndroidUtilities.rectTmp.centerX(), AndroidUtilities.rectTmp.centerY(), AndroidUtilities.rectTmp.width() / 2f, transitionViewHolder.bgPaint); + thisAlpha = AndroidUtilities.lerp(transitionViewHolder.alpha, thisAlpha, progress2); + } + headerView.backupImageView.getImageReceiver().setAlpha(thisAlpha); headerView.drawUploadingProgress(canvas, AndroidUtilities.rectTmp, !runOpenAnimationAfterLayout, progressToOpen); headerView.backupImageView.getImageReceiver().draw(canvas); + headerView.backupImageView.getImageReceiver().setAlpha(alpha); headerView.backupImageView.getImageReceiver().setVisible(false, false); } if (progressToOpen != 1f && crossfade) { @@ -762,6 +777,11 @@ public boolean dispatchTouchEvent(MotionEvent ev) { if (peerStoriesView != null && peerStoriesView.checkTextSelectionEvent(ev)) { return true; } + if (isLikesReactions) { + if (peerStoriesView != null && peerStoriesView.checkReactionEvent(ev)) { + return true; + } + } if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) { inSwipeToDissmissMode = false; AndroidUtilities.cancelRunOnUIThread(longPressRunnable); @@ -833,7 +853,7 @@ public void onAnimationEnd(Animator animation) { } boolean rezult = super.dispatchTouchEvent(ev); if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) { - if (selfStoriesViewsOffset != 0 && !flingCalled) { + if (selfStoriesViewsOffset != 0 && !flingCalled && realKeyboardHeight < AndroidUtilities.dp(20)) { cancelSwipeToViews(selfStoryViewsView.progressToOpen > 0.5f); } PeerStoriesView peerView = getCurrentPeerView(); @@ -852,6 +872,7 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN && progressToOpen == 1f) { startX = ev.getX(); startY = ev.getY(); + verticalScrollDetected = false; allowIntercept = !findClickableView(windowView, ev.getX(), ev.getY(), false); allowSwipeToDissmiss = !findClickableView(windowView, ev.getX(), ev.getY(), true); setInTouchMode(allowIntercept && !isCaptionPartVisible); @@ -863,9 +884,12 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { AndroidUtilities.runOnUIThread(longPressRunnable, 400); } } else if (ev.getAction() == MotionEvent.ACTION_MOVE) { + float dy = Math.abs(startY - ev.getY()); + float dx = Math.abs(startX - ev.getX()); + if (dy > dx && !verticalScrollDetected && dy > AndroidUtilities.touchSlop * 2) { + verticalScrollDetected = true; + } if (!inSwipeToDissmissMode && !keyboardVisible && allowSwipeToDissmiss) { - float dy = Math.abs(startY - ev.getY()); - float dx = Math.abs(startX - ev.getX()); if (dy > dx && dy > AndroidUtilities.touchSlop * 2) { inSwipeToDissmissMode = true; PeerStoriesView peerView = storiesViewPager.getCurrentPeerView(); @@ -874,10 +898,8 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { } allowSwipeToReply = !peerView.isSelf; allowSelfStoriesView = peerView.isSelf && !peerView.unsupported && peerView.currentStory.storyItem != null; - if (allowSelfStoriesView) { - if (StoriesUtilities.hasExpiredViews(peerView.currentStory.storyItem)) { - allowSelfStoriesView = false; - } + if (allowSelfStoriesView && keyboardHeight != 0) { + allowSelfStoriesView = false; } if (allowSelfStoriesView) { checkSelfStoriesView(); @@ -899,6 +921,7 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { delayedTapRunnable = null; } setInTouchMode(false); + verticalScrollDetected = false; } boolean selfViewsViewVisible = selfStoryViewsView != null && selfStoryViewsView.progressToOpen == 1f; if (!inSwipeToDissmissMode && !selfViewsViewVisible) { @@ -933,7 +956,7 @@ public void onAnimationEnd(Animator animation) { swipeToDissmissBackAnimator.start(); } } - if (inSwipeToDissmissMode || keyboardVisible || swipeToReplyOffset != 0 || (selfStoriesViewsOffset != 0 && allowIntercept)) { + if (inSwipeToDissmissMode || keyboardVisible || swipeToReplyOffset != 0 || (selfStoriesViewsOffset != 0 && (allowIntercept || verticalScrollDetected)) || isInTextSelectionMode) { gestureDetector.onTouchEvent(event); return true; } else { @@ -961,6 +984,33 @@ protected void onAttachedToWindow() { if (ATTACH_TO_FRAGMENT) { AndroidUtilities.requestAdjustResize(fragment.getParentActivity(), fragment.getClassGuid()); } + Bulletin.addDelegate(this, new Bulletin.Delegate() { + + float[] position = new float[2]; + @Override + public int getBottomOffset(int tag) { + PeerStoriesView child = getCurrentPeerView(); + if (child == null) { + return 0; + } + AndroidUtilities.getViewPositionInParent(child.storyContainer, windowView, position); + return (int) (getMeasuredHeight() - (position[1] + child.storyContainer.getMeasuredHeight())); + } + }); + NotificationCenter.getInstance(currentAccount).addObserver(StoryViewer.this, NotificationCenter.storiesListUpdated); + NotificationCenter.getInstance(currentAccount).addObserver(StoryViewer.this, NotificationCenter.storiesUpdated); + NotificationCenter.getInstance(currentAccount).addObserver(StoryViewer.this, NotificationCenter.articleClosed); + NotificationCenter.getInstance(currentAccount).addObserver(StoryViewer.this, NotificationCenter.openArticle); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + Bulletin.removeDelegate(this); + NotificationCenter.getInstance(currentAccount).removeObserver(StoryViewer.this, NotificationCenter.storiesListUpdated); + NotificationCenter.getInstance(currentAccount).removeObserver(StoryViewer.this, NotificationCenter.storiesUpdated); + NotificationCenter.getInstance(currentAccount).removeObserver(StoryViewer.this, NotificationCenter.articleClosed); + NotificationCenter.getInstance(currentAccount).removeObserver(StoryViewer.this, NotificationCenter.openArticle); } @Override @@ -1015,16 +1065,20 @@ protected void dispatchDraw(Canvas canvas) { if (selfStoryViewsView != null && peerStoriesView != null) { selfStoryViewsView.setOffset(selfStoriesViewsOffset); if (selfStoryViewsView.progressToOpen == 1f) { - storiesViewPager.setVisibility(View.GONE); + storiesViewPager.setVisibility(View.INVISIBLE); } else { storiesViewPager.setVisibility(View.VISIBLE); } + storiesViewPager.checkPageVisibility(); pivotY = peerStoriesView.getTop() + peerStoriesView.storyContainer.getTop(); float progressHalf = selfStoryViewsView.progressToOpen;//Utilities.clamp((selfStoryViewsView.progressToOpen - 0.8f) / 0.2f, 1f, 0); float fromScale = (getMeasuredHeight() - selfStoriesViewsOffset) / getMeasuredHeight(); - float toScale = selfStoryViewsView.toHeight / peerStoriesView.storyContainer.getMeasuredHeight(); + if (peerStoriesView.storyContainer.getMeasuredHeight() > 0) { + lastStoryContainerHeight = peerStoriesView.storyContainer.getMeasuredHeight(); + } + float toScale = selfStoryViewsView.toHeight / lastStoryContainerHeight; float s = AndroidUtilities.lerp(1f, toScale, progressHalf); storiesViewPager.setPivotY(pivotY); storiesViewPager.setPivotX(getMeasuredWidth() / 2f); @@ -1033,9 +1087,9 @@ protected void dispatchDraw(Canvas canvas) { peerStoriesView.forceUpdateOffsets = true; if (selfStoriesViewsOffset == 0) { - peerStoriesView.setViewsThumbImageReceiver(0, null); + peerStoriesView.setViewsThumbImageReceiver(0, 0, 0, null); } else { - peerStoriesView.setViewsThumbImageReceiver(progressHalf, selfStoryViewsView.getCrossfadeToImage()); + peerStoriesView.setViewsThumbImageReceiver(progressHalf, s, pivotY, selfStoryViewsView.getCrossfadeToImage()); } peerStoriesView.invalidate(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { @@ -1103,7 +1157,7 @@ public void switchToNextAndRemoveCurrentPeer() { return; } ArrayList> newDays = new ArrayList<>(storiesViewPager.days); - int index = newDays.indexOf(storiesViewPager.getCurrentPeerView().getCurrentDay()); + int index = storiesViewPager.getCurrentPeerView() == null ? -1 : newDays.indexOf(storiesViewPager.getCurrentPeerView().getCurrentDay()); if (index >= 0) { newDays.remove(index); } else { @@ -1292,6 +1346,12 @@ public void setPopupIsVisible(boolean b) { updatePlayingMode(); } + @Override + public void setTranslating(boolean b) { + StoryViewer.this.isTranslating = b; + updatePlayingMode(); + } + @Override public void setBulletinIsVisible(boolean b) { StoryViewer.this.isBulletinVisible = b; @@ -1322,6 +1382,12 @@ public void setIsInSelectionMode(boolean selectionMode) { updatePlayingMode(); } + @Override + public void setIsLikesReaction(boolean show) { + StoryViewer.this.isLikesReactions = show; + updatePlayingMode(); + } + @Override public int getKeyboardHeight() { return realKeyboardHeight; @@ -1385,6 +1451,9 @@ public void invalidate() { } AndroidUtilities.removeFromParent(aspectRatioFrameLayout); windowView.addView(aspectRatioFrameLayout); + if (surfaceView != null) { + surfaceView.setVisibility(View.INVISIBLE); + } AndroidUtilities.removeFromParent(containerView); windowView.addView(containerView); @@ -1463,9 +1532,12 @@ public WindowInsets onApplyWindowInsets(@NonNull View v, @NonNull WindowInsets i private void showKeyboard() { PeerStoriesView currentPeerView = storiesViewPager.getCurrentPeerView(); if (currentPeerView != null) { - currentPeerView.showKeyboard(); + if (currentPeerView.showKeyboard()) { + AndroidUtilities.runOnUIThread(this::cancelSwipeToReply, 200); + return; + } } - AndroidUtilities.runOnUIThread(this::cancelSwipeToReply, 200); + cancelSwipeToReply(); } ValueAnimator swipeToViewsAnimator; @@ -1474,15 +1546,23 @@ public void cancelSwipeToViews(boolean open) { if (swipeToViewsAnimator != null) { return; } + if (realKeyboardHeight != 0) { + AndroidUtilities.hideKeyboard(selfStoryViewsView); + return; + } if (allowSelfStoriesView || selfStoriesViewsOffset != 0) { locker.lock(); + if (!open && selfStoriesViewsOffset == selfStoryViewsView.maxSelfStoriesViewsOffset) { + selfStoriesViewsOffset = selfStoryViewsView.maxSelfStoriesViewsOffset - 1; + selfStoryViewsView.setOffset(selfStoryViewsView.maxSelfStoriesViewsOffset - 1); + } swipeToViewsAnimator = ValueAnimator.ofFloat(selfStoriesViewsOffset, open ? selfStoryViewsView.maxSelfStoriesViewsOffset : 0); swipeToViewsAnimator.addUpdateListener(animation -> { selfStoriesViewsOffset = (float) animation.getAnimatedValue(); - final PeerStoriesView peerStoriesView = storiesViewPager.getCurrentPeerView(); - if (peerStoriesView != null) { - peerStoriesView.invalidate(); - } +// final PeerStoriesView peerStoriesView = storiesViewPager.getCurrentPeerView(); +// if (peerStoriesView != null) { +// peerStoriesView.invalidate(); +// } containerView.invalidate(); }); swipeToViewsAnimator.addListener(new AnimatorListenerAdapter() { @@ -1516,7 +1596,15 @@ private void checkSelfStoriesView() { } PeerStoriesView peerStoriesView = storiesViewPager.getCurrentPeerView(); if (peerStoriesView != null) { - selfStoryViewsView.setItems(peerStoriesView.getStoryItems(), peerStoriesView.getSelectedPosition()); + if (storiesList != null) { + ArrayList storyItems = new ArrayList<>(); + for (int i = 0; i < storiesList.messageObjects.size(); i++) { + storyItems.add(storiesList.messageObjects.get(i).storyItem); + } + selfStoryViewsView.setItems(storyItems, peerStoriesView.getListPosition()); + } else { + selfStoryViewsView.setItems(peerStoriesView.getStoryItems(), peerStoriesView.getSelectedPosition()); + } } } @@ -1588,6 +1676,26 @@ public boolean getStoryRect(RectF rectF) { return true; } + public void switchByTap(boolean forward) { + PeerStoriesView peerView = storiesViewPager.getCurrentPeerView(); + if (peerView == null) { + return; + } + if (!peerView.switchToNext(forward)) { + if (!storiesViewPager.switchToNext(forward)) { + if (forward) { + close(true); + } else { + if (playerHolder != null) { + playerHolder.loopBack(); + } + } + } else { + storiesViewPager.lockTouchEvent(150); + } + } + } + @Nullable public PeerStoriesView getCurrentPeerView() { if (storiesViewPager == null) { @@ -1690,8 +1798,12 @@ private void updateTransitionParams() { if (storyItem == null && isSingleStory) { storyItem = singleStory; } + if (storiesList != null) { + storyId = dayStoryId; + } transitionViewHolder.clear(); - if (placeProvider.findView(storiesViewPager.getCurrentDialogId(), messageId, storiesList != null ? dayStoryId : storyId, storyItem == null ? -1 : storyItem.messageType, transitionViewHolder)) { + if (placeProvider.findView(storiesViewPager.getCurrentDialogId(), messageId, storyId, storyItem == null ? -1 : storyItem.messageType, transitionViewHolder)) { + transitionViewHolder.storyId = storyId; if (transitionViewHolder.view != null) { int[] loc = new int[2]; transitionViewHolder.view.getLocationOnScreen(loc); @@ -1786,7 +1898,7 @@ public void setOnCloseListener(Runnable listener) { } public boolean isPaused() { - return isPopupVisible || isBulletinVisible || isCaption || isWaiting || isInTouchMode || keyboardVisible || currentDialog != null || allowTouchesByViewpager || isClosed || isRecording || progressToOpen != 1f || selfStoriesViewsOffset != 0 || isHintVisible || (isSwiping && USE_SURFACE_VIEW) || isOverlayVisible || isInTextSelectionMode; + return isPopupVisible || isTranslating || isBulletinVisible || isCaption || isWaiting || isInTouchMode || keyboardVisible || currentDialog != null || allowTouchesByViewpager || isClosed || isRecording || progressToOpen != 1f || selfStoriesViewsOffset != 0 || isHintVisible || (isSwiping && USE_SURFACE_VIEW) || isOverlayVisible || isInTextSelectionMode || isLikesReactions; } public void updatePlayingMode() { @@ -1797,6 +1909,9 @@ public void updatePlayingMode() { if (ATTACH_TO_FRAGMENT && (fragment.isPaused() || !fragment.isLastFragment())) { pause = true; } + if (ArticleViewer.getInstance().isVisible()) { + pause = true; + } storiesViewPager.setPaused(pause); if (playerHolder != null) { @@ -1806,7 +1921,7 @@ public void updatePlayingMode() { playerHolder.play(); } } - storiesViewPager.enableTouch(!keyboardVisible && !isClosed && !isRecording && !isLongpressed && !isInPinchToZoom && selfStoriesViewsOffset == 0); + storiesViewPager.enableTouch(!keyboardVisible && !isClosed && !isRecording && !isLongpressed && !isInPinchToZoom && selfStoriesViewsOffset == 0 && !isInTextSelectionMode); } private boolean findClickableView(FrameLayout windowView, float x, float y, boolean swipeToDissmiss) { @@ -1841,7 +1956,7 @@ private boolean findClickableView(FrameLayout windowView, float x, float y, bool if (currentPeerView != null && currentPeerView.chatActivityEnterView != null && currentPeerView.chatActivityEnterView.isRecordingAudioVideo()) { return true; } - return AndroidUtilities.findClickableView(windowView, x, y); + return AndroidUtilities.findClickableView(windowView, x, y, currentPeerView); } public boolean closeKeyboardOrEmoji() { @@ -1914,6 +2029,7 @@ public void onAnimationEnd(Animator animation) { if (transitionViewHolder.storyImage != null && !foundViewToClose) { transitionViewHolder.storyImage.setAlpha(1f); transitionViewHolder.storyImage.setVisible(true, true); + transitionViewHolder.storyImage = null; } final PeerStoriesView peerStoriesView = getCurrentPeerView(); if (peerStoriesView != null) { @@ -1929,9 +2045,11 @@ public void onAnimationEnd(Animator animation) { openCloseAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); openCloseAnimator.start(); - if (doOnAnimationReady != null) { - doOnAnimationReady.run(); - doOnAnimationReady = null; + if (!doOnAnimationReadyRunnables.isEmpty()) { + for (int i = 0; i < doOnAnimationReadyRunnables.size(); i++) { + doOnAnimationReadyRunnables.get(i).run(); + } + doOnAnimationReadyRunnables.clear(); } } @@ -2074,6 +2192,7 @@ public void release() { } globalInstances.remove(this); + doOnAnimationReadyRunnables.clear(); selfStoriesViewsOffset = 0; lastStoryItem = null; } @@ -2100,6 +2219,9 @@ private float getBlackoutAlpha() { public boolean onBackPressed() { if (selfStoriesViewsOffset != 0) { + if (selfStoryViewsView.onBackPressed()) { + return true; + } cancelSwipeToViews(false); return true; } else if (closeKeyboardOrEmoji()) { @@ -2116,7 +2238,7 @@ public boolean isShown() { public void checkNavBarColor() { if (ATTACH_TO_FRAGMENT && LaunchActivity.instance != null) { - LaunchActivity.instance.checkSystemBarColors(true, false, true, false); + LaunchActivity.instance.checkSystemBarColors(true, true, true, false); //LaunchActivity.instance.setNavigationBarColor(fragment.getNavigationBarColor(), false); } } @@ -2149,6 +2271,9 @@ public void setKeyboardHeightFromParent(int keyboardHeight) { realKeyboardHeight = keyboardHeight; storiesViewPager.setKeyboardHeight(keyboardHeight); storiesViewPager.requestLayout(); + if (selfStoryViewsView != null) { + selfStoryViewsView.setKeyboardHeight(keyboardHeight); + } } } @@ -2294,13 +2419,67 @@ public void openFor(BaseFragment fragment, RecyclerListView recyclerListView, Ch } public void doOnAnimationReady(Runnable runnable) { - doOnAnimationReady = runnable; + if (runnable != null) { + doOnAnimationReadyRunnables.add(runnable); + } + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.storiesListUpdated) { + StoriesController.StoriesList list = (StoriesController.StoriesList) args[0]; + if (storiesList == list) { + PeerStoriesView peerStoriesView = getCurrentPeerView(); + storiesViewPager.setDays(storiesList.userId, storiesList.getDays(), currentAccount); + if (selfStoryViewsView != null) { + TLRPC.StoryItem currentSelectedStory = selfStoryViewsView.getSelectedStory(); + ArrayList storyItems = new ArrayList<>(); + int selectedPosition = 0; + for (int i = 0; i < storiesList.messageObjects.size(); i++) { + if (currentSelectedStory != null && currentSelectedStory.id == storiesList.messageObjects.get(i).storyItem.id) { + selectedPosition = i; + } + storyItems.add(storiesList.messageObjects.get(i).storyItem); + } + selfStoryViewsView.setItems(storyItems, selectedPosition); + } + } + } else if (id == NotificationCenter.storiesUpdated) { + if (placeProvider instanceof StoriesListPlaceProvider) { + StoriesListPlaceProvider storiesListPlaceProvider = (StoriesListPlaceProvider) placeProvider; + if (!storiesListPlaceProvider.hasPaginationParams || storiesListPlaceProvider.onlySelfStories) { + return; + } + StoriesController storiesController = MessagesController.getInstance(currentAccount).getStoriesController(); + ArrayList allStories = storiesListPlaceProvider.hiddedStories ? storiesController.getHiddenList() : storiesController.getDialogListStories(); + boolean changed = false; + ArrayList dialogs = storiesViewPager.getDialogIds(); + for (int i = 0; i < allStories.size(); i++) { + TLRPC.TL_userStories userStories = allStories.get(i); + if (storiesListPlaceProvider.onlyUnreadStories && !storiesController.hasUnreadStories(userStories.user_id)) { + continue; + } + if (!dialogs.contains(userStories.user_id)) { + dialogs.add(userStories.user_id); + changed = true; + } + } + if (changed) { + storiesViewPager.getAdapter().notifyDataSetChanged(); + } + } + } else if (id == NotificationCenter.openArticle || id == NotificationCenter.articleClosed) { + updatePlayingMode(); + } } public interface PlaceProvider { boolean findView(long dialogId, int messageId, int storyId, int type, TransitionViewHolder holder); void preLayout(long currentDialogId, int messageId, Runnable o); + default void loadNext(boolean forward) { + + } } public interface HolderDrawAbove { @@ -2321,9 +2500,13 @@ public static class TransitionViewHolder { public View clipParent; public float clipTop; public float clipBottom; + public Paint bgPaint; + public float alpha = 1; public ImageReceiver crossfadeToAvatarImage; StoriesUtilities.AvatarStoryParams params; + public int storyId; + public void clear() { view = null; params = null; @@ -2336,6 +2519,9 @@ public void clear() { crossfadeToAvatarImage = null; clipTop = 0; clipBottom = 0; + storyId = 0; + bgPaint = null; + alpha = 1; } } @@ -2540,8 +2726,12 @@ boolean release(Runnable whenReleased) { initRunnable = null; dispatchQueue.postRunnable(() -> { if (videoPlayer != null) { - videoPlayer.setTextureView(null); - videoPlayer.setSurfaceView(null); + try { + videoPlayer.setTextureView(null); + videoPlayer.setSurfaceView(null); + } catch (Exception e) { + + } videoPlayer.releasePlayer(false); } if (document != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewsUsersAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewsUsersAlert.java deleted file mode 100644 index d8faa683bda..00000000000 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/StoryViewsUsersAlert.java +++ /dev/null @@ -1,266 +0,0 @@ -package org.telegram.ui.Stories; - -import android.content.Context; -import android.os.Bundle; -import android.text.TextUtils; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; - -import androidx.annotation.NonNull; -import androidx.core.util.Consumer; -import androidx.recyclerview.widget.RecyclerView; - -import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ContactsController; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.R; -import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.TLRPC; -import org.telegram.ui.ActionBar.BaseFragment; -import org.telegram.ui.ActionBar.Theme; -import org.telegram.ui.Cells.FixedHeightEmptyCell; -import org.telegram.ui.Cells.GroupCreateUserCell; -import org.telegram.ui.Cells.ReactedUserHolderView; -import org.telegram.ui.Components.LayoutHelper; -import org.telegram.ui.Components.RecyclerListView; -import org.telegram.ui.Components.UsersAlertBase; -import org.telegram.ui.LaunchActivity; -import org.telegram.ui.ProfileActivity; -import org.telegram.ui.Stories.recorder.ButtonWithCounterView; - -import java.util.ArrayList; - -//TODO stories -//add pagination -public class StoryViewsUsersAlert extends UsersAlertBase { - - private static final int FIRST_PADDING_ITEM = 0; - private static final int USER_ITEM = 1; - private static final int LAST_ITEM = 2; - private static final int BUTTON_PADDING = 3; - - - ListAdapter listAdapter; - boolean showSearch = false; - ArrayList users = new ArrayList<>(); - - StoryViewer storyViewer; - - public StoryViewsUsersAlert(Context context, StoryViewer storyViewer, Theme.ResourcesProvider resourcesProvider) { - super(context, true, storyViewer.currentAccount, resourcesProvider); - showSearch(showSearch = false); - searchListViewAdapter = searchListViewAdapter = new SearchAdapter(); - listView.setAdapter(listViewAdapter = listAdapter = new ListAdapter()); - FrameLayout buttonContainer = new FrameLayout(getContext()); - buttonContainer.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); - ButtonWithCounterView button = new ButtonWithCounterView(getContext(), resourcesProvider); - - buttonContainer.addView(button, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.FILL_HORIZONTAL, 10, 10, 10, 10)); - containerView.addView(buttonContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); - button.setText(LocaleController.getString("Close", R.string.Close), false); - button.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - dismiss(); - } - }); - listView.setOnItemClickListener((view, position) -> { - if (position < 0 || position > listAdapter.items.size() - 1) { - return; - } - TLRPC.TL_storyView user = listAdapter.items.get(position).user; - - if (user != null) { - dismiss(); - - Bundle args = new Bundle(); - args.putLong("user_id", user.user_id); - ProfileActivity profileActivity = new ProfileActivity(args); - - storyViewer.presentFragment(profileActivity); - } - }); - } - - @Override - protected int measurePadding(int availableHeight) { - int padding = super.measurePadding(availableHeight); - if (!showSearch) { - int h = availableHeight - AndroidUtilities.dp(ReactedUserHolderView.STORY_ITEM_HEIGHT_DP) * users.size() - AndroidUtilities.dp(36) - AndroidUtilities.dp(80); - if (h > padding) { - return h; - } - } - return padding; - } - - public void setViews(TLRPC.StoryItem storyItem) { - int viewsCount = storyItem.views != null ? storyItem.views.views_count : 0; - ArrayList recentViewers = storyItem.views != null ? storyItem.views.recent_viewers : new ArrayList<>(); - setTitle(LocaleController.formatPluralStringComma("Views", viewsCount)); - showSearch(viewsCount > 20); - users.clear(); - for (int i = 0; i < recentViewers.size(); i++) { - TLRPC.TL_storyView storyView = new TLRPC.TL_storyView(); - storyView.user_id = recentViewers.get(i); - users.add(storyView); - } - - listAdapter.updateRows(); - } - - private class SearchAdapter extends RecyclerListView.SelectionAdapter { - @NonNull - @Override - public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return null; - } - - @Override - public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { - - } - - @Override - public int getItemCount() { - return 0; - } - - @Override - public boolean isEnabled(RecyclerView.ViewHolder holder) { - return false; - } - } - - private class ListAdapter extends RecyclerListView.SelectionAdapter { - - ArrayList items = new ArrayList<>(); - - @NonNull - @Override - public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View view; - switch (viewType) { - case FIRST_PADDING_ITEM: - view = new View(getContext()) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(36 + (showSearch ? 58 : 0)), MeasureSpec.EXACTLY)); - } - }; - break; - case BUTTON_PADDING: - view = new FixedHeightEmptyCell(getContext(), 64); - break; - case USER_ITEM: - view = new ReactedUserHolderView(ReactedUserHolderView.STYLE_STORY, currentAccount, getContext(), resourcesProvider); - break; - default: - case LAST_ITEM: - view = new View(getContext()); - break; - } - return new RecyclerListView.Holder(view); - } - - @Override - public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { - if (holder.getItemViewType() == USER_ITEM) { - ReactedUserHolderView view = (ReactedUserHolderView) holder.itemView; - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(items.get(position).user.user_id); - - view.setUserReaction(user, null, null, items.get(position).user.date, true, false); - // items.get(position + 1).viewType == USER_ITEM - } - } - - @Override - public int getItemCount() { - return items.size(); - } - - @Override - public boolean isEnabled(RecyclerView.ViewHolder holder) { - return holder.getItemViewType() == USER_ITEM; - } - - public void updateRows() { - items.clear(); - items.add(new Item(FIRST_PADDING_ITEM)); - for (int i = 0; i < users.size(); i++) { - items.add(new Item(USER_ITEM, users.get(i))); - } - items.add(new Item(BUTTON_PADDING)); - if (showSearch) { - items.add(new Item(LAST_ITEM)); - } - notifyDataSetChanged(); - } - - @Override - public int getItemViewType(int position) { - return items.get(position).viewType; - } - } - - public static Runnable preload(int currentAccount, Context context, Theme.ResourcesProvider resourcesProvider, TLRPC.StoryItem storyItem, StoryViewer storyViewer, Consumer alertConsumer) { - TLRPC.TL_stories_getStoryViewsList req = new TLRPC.TL_stories_getStoryViewsList(); - req.id = storyItem.id; - req.limit = 100; - req.offset_id = 0; - req.offset_date = 0; - boolean[] canceled = new boolean[]{false}; - int id = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { - if (canceled[0]) { - return; - } - if (response != null) { - TLRPC.TL_stories_storyViewsList res = (TLRPC.TL_stories_storyViewsList) response; - MessagesController.getInstance(currentAccount).putUsers(res.users, false); - StoryViewsUsersAlert alert = new StoryViewsUsersAlert(context, storyViewer, resourcesProvider); - alert.setTitle(LocaleController.formatPluralStringComma("Views", res.count)); - alert.showSearch(res.count > 20); - alert.users.clear(); - for (int i = 0; i < res.views.size(); i++) { - alert.users.add(res.views.get(i)); - } - alert.listAdapter.updateRows(); - if (res.count > storyItem.views.views_count) { - storyItem.views.recent_viewers.clear(); - for (int i = 0; i < (Math.min(3, res.users.size())); i++) { - storyItem.views.recent_viewers.add(res.users.get(i).id); - } - storyItem.views.views_count = res.count; - } - alertConsumer.accept(alert); - } else { - alertConsumer.accept(null); - } - })); - return new Runnable() { - @Override - public void run() { - canceled[0] = true; - ConnectionsManager.getInstance(currentAccount).cancelRequest(id, false); - } - }; - } - - - private class Item { - final int viewType; - TLRPC.TL_storyView user; - - private Item(int viewType) { - this.viewType = viewType; - } - - private Item(int viewType, TLRPC.TL_storyView user) { - this.viewType = viewType; - this.user = user; - } - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/ButtonWithCounterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/ButtonWithCounterView.java index 60bfb97e3e6..9b9c4ff9e3b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/ButtonWithCounterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/ButtonWithCounterView.java @@ -85,7 +85,7 @@ public ButtonWithCounterView(Context context, boolean filled, Theme.ResourcesPro setWillNotDraw(false); } - public void setText(String newText, boolean animated) { + public void setText(CharSequence newText, boolean animated) { if (animated) { text.cancelAnimation(); } @@ -215,6 +215,8 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { private CircularProgressDrawable loadingDrawable; + private int globalAlpha = 255; + @Override protected void onDraw(Canvas canvas) { rippleView.draw(canvas); @@ -248,7 +250,7 @@ protected void onDraw(Canvas canvas) { (int) ((getMeasuredWidth() - width + getWidth()) / 2f + textWidth), (int) ((getMeasuredHeight() + text.getHeight()) / 2f - dp(1)) ); - text.setAlpha((int) (0xFF * (1f - loadingT) * AndroidUtilities.lerp(.5f, 1f, enabledT))); + text.setAlpha((int) (globalAlpha * (1f - loadingT) * AndroidUtilities.lerp(.5f, 1f, enabledT))); text.setBounds(AndroidUtilities.rectTmp2); text.draw(canvas); @@ -264,11 +266,11 @@ protected void onDraw(Canvas canvas) { canvas.save(); canvas.scale(countScale, countScale, AndroidUtilities.rectTmp2.centerX(), AndroidUtilities.rectTmp2.centerY()); } - paint.setAlpha((int) (0xFF * (1f - loadingT) * countAlpha * countAlpha * AndroidUtilities.lerp(.5f, 1f, enabledT))); + paint.setAlpha((int) (globalAlpha * (1f - loadingT) * countAlpha * countAlpha * AndroidUtilities.lerp(.5f, 1f, enabledT))); canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(10), dp(10), paint); AndroidUtilities.rectTmp2.offset(-dp(.3f), -dp(.4f)); - countText.setAlpha((int) (0xFF * (1f - loadingT) * countAlpha)); + countText.setAlpha((int) (globalAlpha * (1f - loadingT) * countAlpha)); countText.setBounds(AndroidUtilities.rectTmp2); countText.draw(canvas); if (countScale != 1) { @@ -286,4 +288,12 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { info.setClassName("android.widget.Button"); // info.setContentDescription(text.getText() + (lastCount > 0 ? ", " + LocaleController.formatPluralString("Chats", lastCount) : "")); } + + public void setTextAlpha(float v) { + text.setAlpha((int) (v * 255)); + } + + public void setGlobalAlpha(float v) { + globalAlpha = ((int) (v * 255)); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java index 1d431a7f5af..2018b644819 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/CaptionContainerView.java @@ -1,6 +1,7 @@ package org.telegram.ui.Stories.recorder; import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.lerp; import static org.telegram.ui.ActionBar.Theme.RIPPLE_MASK_CIRCLE_20DP; import android.animation.Animator; @@ -56,6 +57,7 @@ import androidx.interpolator.view.animation.FastOutSlowInInterpolator; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLog; import org.telegram.messenger.LiteMode; @@ -113,6 +115,8 @@ public class CaptionContainerView extends FrameLayout { public final KeyboardNotifier keyboardNotifier; public MentionsContainerView mentionContainer; + private int shiftDp = -4; + public CaptionContainerView(Context context, int currentAccount, StoryRecorder.WindowView rootView, FrameLayout containerView, Theme.ResourcesProvider resourcesProvider) { super(context); @@ -176,12 +180,15 @@ public void onTextChanged(CharSequence text, int start, int before, int count) { } } + private int lastLength; + private boolean lastOverLimit; + @Override public void afterTextChanged(Editable s) { EditTextCaption editText2 = editText.getEditText(); if (editText2 != null && editText2.getLayout() != null) { editText2.ignoreClipTop = ( - editText2.getLayout().getHeight() > (dp(180) - editText2.getPaddingTop() - editText2.getPaddingBottom()) + editText2.getLayout().getHeight() > (dp(120) - editText2.getPaddingTop() - editText2.getPaddingBottom()) ); } int length = 0; @@ -190,15 +197,28 @@ public void afterTextChanged(Editable s) { } catch (Exception ignore) { } String limitText = null; - final int limit = MessagesController.getInstance(currentAccount).storyCaptionLengthLimit; + final boolean premium = UserConfig.getInstance(currentAccount).isPremium(); + final int limit = premium ? MessagesController.getInstance(currentAccount).storyCaptionLengthLimitPremium : MessagesController.getInstance(currentAccount).storyCaptionLengthLimitDefault; if (length + 25 > limit) { limitText = "" + (limit - length); } limitTextView.cancelAnimation(); limitTextView.setText(limitText); limitTextView.setTextColor(length >= limit ? 0xffEC7777 : 0xffffffff); + if (length > limit && !premium && length < MessagesController.getInstance(currentAccount).storyCaptionLengthLimitPremium && length > lastLength && captionLimitToast()) { + AndroidUtilities.shakeViewSpring(limitTextView, shiftDp = -shiftDp); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + } + lastLength = length; + + final boolean overLimit = length > limit; + if (overLimit != lastOverLimit) { + onCaptionLimitUpdate(overLimit); + } + lastOverLimit = overLimit; } }); + editText.getEditText().setLinkTextColor(Color.WHITE); addView(editText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 12, 12, 12, 12)); applyButton = new BounceableImageView(context); @@ -221,7 +241,7 @@ public void afterTextChanged(Editable s) { limitTextView.setAnimationProperties(.4f, 0, 320, CubicBezierInterpolator.EASE_OUT_QUINT); limitTextView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); limitTextView.setTranslationX(dp(2)); - addView(limitTextView, LayoutHelper.createFrame(52, 16, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 0, 44)); + addView(limitTextView, LayoutHelper.createFrame(52, 16, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 0, 50)); fadePaint.setShader(fadeGradient); fadePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); @@ -263,21 +283,12 @@ public void afterTextChanged(Editable s) { isPremium || period == 86400 || period == Integer.MAX_VALUE ? null : () -> showPremiumHint.run(period) ); } -// periodPopup.addGap(); - // Select ’Keep Always’ to show the story on your page. -// periodPopup.addText(LocaleController.getString("StoryPeriodKeepHint"), 13); periodPopup.addGap(); periodPopup.addText(LocaleController.getString("StoryPeriodHint"), 13); periodPopup.setDimAlpha(0).show(); }); setPeriod(86400, false); addView(periodButton, LayoutHelper.createFrame(44, 44, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 11, 11)); - -// setOnClickListener(e -> { -// if (!editText.isKeyboardVisible() && !editText.isPopupVisible()) { -// editText.openKeyboard(); -// } -// }); } public void closeKeyboard() { @@ -493,10 +504,11 @@ private void updateShowKeyboard(boolean show, boolean animated) { keyboardAnimator = ValueAnimator.ofFloat(keyboardT, show ? 1 : 0); keyboardAnimator.addUpdateListener(anm -> { keyboardT = (float) anm.getAnimatedValue(); - editText.getEditText().setTranslationX(AndroidUtilities.lerp(AndroidUtilities.dp(-40 + 18), AndroidUtilities.dp(2), keyboardT)); - editText.setTranslationX(AndroidUtilities.lerp(0, AndroidUtilities.dp(-8), keyboardT)); - editText.setTranslationY(AndroidUtilities.lerp(0, AndroidUtilities.dp(12 - 2), keyboardT)); - limitTextView.setAlpha(AndroidUtilities.lerp(0, 1, keyboardT)); + editText.getEditText().setTranslationX(lerp(dp(-40 + 18), dp(2), keyboardT)); + editText.setTranslationX(lerp(0, dp(-8), keyboardT)); + editText.setTranslationY(lerp(0, dp(12 - 2), keyboardT)); + limitTextView.setTranslationX(lerp(-dp(8), dp(2), keyboardT)); + limitTextView.setTranslationY(lerp(-dp(8), 0, keyboardT)); editText.getEmojiButton().setAlpha(keyboardT); applyButton.setAlpha((float) Math.pow(keyboardT, 16)); periodButton.setAlpha(1f - keyboardT); @@ -528,10 +540,11 @@ public void onAnimationEnd(Animator animation) { keyboardAnimator.start(); } else { keyboardT = show ? 1 : 0; - editText.getEditText().setTranslationX(AndroidUtilities.lerp(AndroidUtilities.dp(-40 + 18), AndroidUtilities.dp(2), keyboardT)); - editText.setTranslationX(AndroidUtilities.lerp(0, AndroidUtilities.dp(-8), keyboardT)); - editText.setTranslationY(AndroidUtilities.lerp(0, AndroidUtilities.dp(12 - 2), keyboardT)); - limitTextView.setAlpha(AndroidUtilities.lerp(0, 1, keyboardT)); + editText.getEditText().setTranslationX(lerp(AndroidUtilities.dp(-40 + 18), AndroidUtilities.dp(2), keyboardT)); + editText.setTranslationX(lerp(0, AndroidUtilities.dp(-8), keyboardT)); + editText.setTranslationY(lerp(0, AndroidUtilities.dp(12 - 2), keyboardT)); + limitTextView.setTranslationX(lerp(-dp(8), dp(2), keyboardT)); + limitTextView.setTranslationY(lerp(-dp(8), 0, keyboardT)); editText.getEmojiButton().setAlpha(keyboardT); applyButton.setVisibility(show ? View.VISIBLE : View.GONE); applyButton.setAlpha(show ? 1f : 0f); @@ -566,6 +579,25 @@ public void onAnimationEnd(Animator animation) { } } + public boolean isCaptionOverLimit() { + int length = 0; + try { + length = editText.getEditText().getText().length(); + } catch (Exception ignore) { + } + final boolean premium = UserConfig.getInstance(currentAccount).isPremium(); + final int limit = premium ? MessagesController.getInstance(currentAccount).storyCaptionLengthLimitPremium : MessagesController.getInstance(currentAccount).storyCaptionLengthLimitDefault; + return length > limit; + } + + protected void onCaptionLimitUpdate(boolean overLimit) { + + } + + protected boolean captionLimitToast() { + return false; + } + protected void drawBlurBitmap(Bitmap bitmap, float amount) { // do draw Utilities.stackBlurBitmap(bitmap, (int) amount); @@ -631,7 +663,7 @@ protected void dispatchDraw(Canvas canvas) { } lastHeightTranslation = heightTranslation; - final float pad = AndroidUtilities.lerp(AndroidUtilities.dp(12), 0, keyboardT); + final float pad = lerp(AndroidUtilities.dp(12), 0, keyboardT); AndroidUtilities.rectTmp.set( pad, getHeight() - pad - heightAnimated, @@ -639,7 +671,7 @@ protected void dispatchDraw(Canvas canvas) { getHeight() - pad ); - final float r = AndroidUtilities.lerp(AndroidUtilities.dp(21), 0, keyboardT); + final float r = lerp(AndroidUtilities.dp(21), 0, keyboardT); drawBackground(canvas, AndroidUtilities.rectTmp, r, 1f, this); canvas.save(); @@ -664,14 +696,14 @@ private void drawBackground(Canvas canvas, RectF rectF, float r, float alpha, Vi blurPaint.setAlpha((int) (0xFF * keyboardT * alpha)); canvas.drawRoundRect(rectF, r, r, blurPaint); } - backgroundPaint.setAlpha((int) (blurPaint == null ? 0x80 : AndroidUtilities.lerp(0x80, 0x99, keyboardT) * alpha)); + backgroundPaint.setAlpha((int) (blurPaint == null ? 0x80 : lerp(0x80, 0x99, keyboardT) * alpha)); canvas.drawRoundRect(rectF, r, r, backgroundPaint); } @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { if (child == editText) { - final float pad = AndroidUtilities.lerp(dp(12), 0, keyboardT); + final float pad = lerp(dp(12), 0, keyboardT); AndroidUtilities.rectTmp.set(pad, getHeight() - pad - heightAnimated.get(), getWidth() - pad, getHeight() - pad); float ty = Math.max(0, editText.getHeight() - dp(150 - 7)) * (1f - keyboardT); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DownloadButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DownloadButton.java index 64d528b2c31..761aa450959 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DownloadButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DownloadButton.java @@ -165,7 +165,10 @@ private void onClick() { downloadingVideo = false; } updateImage(); - if (prepare == null) { + if (prepare != null) { + preparing = true; + prepare.run(this::onClickInternal); + } else { onClickInternal(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java index 90deeb0fcc9..a93706e5f14 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DraftsController.java @@ -7,6 +7,7 @@ import androidx.annotation.NonNull; +import org.checkerframework.checker.units.qual.A; import org.telegram.SQLite.SQLiteCursor; import org.telegram.SQLite.SQLiteDatabase; import org.telegram.SQLite.SQLitePreparedStatement; @@ -94,7 +95,17 @@ public void load() { ArrayList deleteEntries = new ArrayList<>(); for (int i = 0; i < savedDrafts.size(); ++i) { StoryEntry entry = savedDrafts.get(i).toEntry(); - if (entry == null || entry.file == null || !entry.file.exists() || now - entry.draftDate > EXPIRATION_PERIOD) { + if (entry == null) { + continue; + } + if ( + entry.file == null || + !entry.file.exists() || + (entry.isEdit ? + (now > entry.editExpireDate) : + (now - entry.draftDate > EXPIRATION_PERIOD) + ) + ) { deleteEntries.add(entry); } else { drafts.add(entry); @@ -205,7 +216,12 @@ public void append(StoryEntry entry) { final StoryDraft draft = new StoryDraft(entry); drafts.remove(entry); drafts.add(0, entry); + append(draft); + } + + private void append(StoryDraft draft) { final MessagesStorage storage = MessagesStorage.getInstance(currentAccount); + FileLog.d("StoryDraft append " + draft.id + " (edit=" + draft.edit + (draft.edit ? ", storyId=" + draft.editStoryId + ", " + (draft.editDocumentId != 0 ? "documentId=" + draft.editDocumentId : "photoId=" + draft.editPhotoId) + ", expireDate=" + draft.editExpireDate : "") + ", now="+System.currentTimeMillis()+")"); storage.getStorageQueue().postRunnable(() -> { SQLitePreparedStatement state = null; try { @@ -218,7 +234,7 @@ public void append(StoryEntry entry) { state.requery(); NativeByteBuffer data = new NativeByteBuffer(draft.getObjectSize()); draft.toStream(data); - state.bindLong(1, id); + state.bindLong(1, draft.id); state.bindLong(2, draft.date); state.bindByteBuffer(3, data); state.step(); @@ -236,6 +252,81 @@ public void append(StoryEntry entry) { NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.storiesDraftsUpdated); } + public void deleteForEdit(TLRPC.StoryItem storyItem) { + if (storyItem == null) { + return; + } + ArrayList toDelete = new ArrayList<>(); + for (StoryEntry draft : drafts) { + if (draft.isEdit && draft.editStoryId == storyItem.id) { + FileLog.d("StoryDraft deleteForEdit storyId=" + storyItem.id); + toDelete.add(draft); + } + } + delete(toDelete); + } + + public void deleteForEdit(long peerId, int storyId) { + ArrayList toDelete = new ArrayList<>(); + for (StoryEntry draft : drafts) { + if (draft.isEdit && draft.editStoryId == storyId && draft.editStoryPeerId == peerId) { + FileLog.d("StoryDraft deleteForEdit (2) storyId=" + storyId); + toDelete.add(draft); + } + } + delete(toDelete); + } + + public void saveForEdit(StoryEntry entry, long dialogId, TLRPC.StoryItem storyItem) { + if (entry == null || storyItem == null || storyItem.media == null) { + return; + } + + ArrayList toDelete = new ArrayList<>(); + for (StoryEntry draft : drafts) { + if (draft.isEdit && draft.editStoryId == storyItem.id) { + toDelete.add(draft); + } + } + delete(toDelete); + + prepare(entry); + final long id = Utilities.random.nextLong(); + entry.draftId = id; + final StoryDraft draft = new StoryDraft(entry); + draft.edit = entry.isEdit = true; + draft.editStoryPeerId = entry.editStoryPeerId = dialogId; + draft.editStoryId = entry.editStoryId = storyItem.id; + draft.editExpireDate = entry.editExpireDate = storyItem.expire_date * 1000L; + if (storyItem.media.document != null) { + draft.editDocumentId = entry.editDocumentId = storyItem.media.document.id; + } else if (storyItem.media.photo != null) { + draft.editPhotoId = entry.editPhotoId =storyItem.media.photo.id; + } + drafts.remove(entry); + drafts.add(0, entry); + append(draft); + } + + public StoryEntry getForEdit(long dialogId, TLRPC.StoryItem storyItem) { + if (storyItem == null) { + return null; + } + for (StoryEntry draft : drafts) { + if (draft.isEdit && storyItem.id == draft.editStoryId && dialogId == draft.editStoryPeerId) { + if (storyItem.media.document != null && storyItem.media.document.id != draft.editDocumentId) { + continue; + } + if (storyItem.media.photo != null && storyItem.media.photo.id != draft.editPhotoId) { + continue; + } + draft.isEditSaved = true; + return draft; + } + } + return null; + } + public void delete(StoryEntry entry) { ArrayList list = new ArrayList<>(1); list.add(entry); @@ -247,7 +338,12 @@ public void deleteExpired() { ArrayList list = new ArrayList<>(); for (int i = 0; i < drafts.size(); ++i) { StoryEntry entry = drafts.get(i); - if (entry != null && now - entry.draftDate > EXPIRATION_PERIOD) { + if (entry != null && ( + entry.isEdit ? + (now > entry.editExpireDate) : + (now - entry.draftDate > EXPIRATION_PERIOD) + )) { + FileLog.d("StoryDraft deleteExpired " + entry.draftId); list.add(entry); } } @@ -262,10 +358,14 @@ public void delete(ArrayList entries) { for (int i = 0; i < entries.size(); ++i) { StoryEntry entry = entries.get(i); if (entry != null) { + FileLog.d("StoryDraft delete " + entry.draftId + " (edit=" + entry.isEdit + (entry.isEdit ? ", storyId=" + entry.editStoryId + ", " + (entry.editDocumentId != 0 ? "documentId=" + entry.editDocumentId : "photoId=" + entry.editPhotoId) + ", expireDate=" + entry.editExpireDate : "") + ", now="+System.currentTimeMillis()+")"); ids.add(entry.draftId); entry.destroy(true); } } + if (ids.isEmpty()) { + return; + } drafts.removeAll(entries); final MessagesStorage storage = MessagesStorage.getInstance(currentAccount); storage.getStorageQueue().postRunnable(() -> { @@ -314,6 +414,7 @@ public static class StoryDraft { public final ArrayList privacyRules = new ArrayList<>(); public String paintFilePath; + public String paintEntitiesFilePath; public long averageDuration; public ArrayList mediaEntities; public List stickers; @@ -325,6 +426,13 @@ public static class StoryDraft { private final ArrayList parts = new ArrayList<>(); + public boolean edit; + public int editStoryId; + public long editStoryPeerId; + public long editDocumentId; + public long editPhotoId; + public long editExpireDate; + public StoryDraft(@NonNull StoryEntry entry) { this.id = entry.draftId; this.date = entry.draftDate; @@ -346,10 +454,11 @@ public StoryDraft(@NonNull StoryEntry entry) { this.gradientTopColor = entry.gradientTopColor; this.gradientBottomColor = entry.gradientBottomColor; CharSequence caption = entry.caption; - this.captionEntities = MediaDataController.getInstance(entry.currentAccount).getEntities(new CharSequence[]{caption}, true); + this.captionEntities = entry.captionEntitiesAllowed ? MediaDataController.getInstance(entry.currentAccount).getEntities(new CharSequence[]{caption}, true) : null; this.caption = caption == null ? "" : caption.toString(); this.privacyRules.addAll(entry.privacyRules); this.paintFilePath = entry.paintFile == null ? "" : entry.paintFile.toString(); + this.paintEntitiesFilePath = entry.paintEntitiesFile == null ? "" : entry.paintEntitiesFile.toString(); this.averageDuration = entry.averageDuration; this.mediaEntities = entry.mediaEntities; this.stickers = entry.stickers; @@ -404,6 +513,9 @@ public StoryEntry toEntry() { if (paintFilePath != null) { entry.paintFile = new File(paintFilePath); } + if (paintEntitiesFilePath != null) { + entry.paintEntitiesFile = new File(paintEntitiesFilePath); + } entry.averageDuration = averageDuration; entry.mediaEntities = mediaEntities; entry.stickers = stickers; @@ -418,6 +530,12 @@ public StoryEntry toEntry() { for (int i = 0; i < parts.size(); ++i) { entry.partsMaxId = Math.max(entry.partsMaxId, parts.get(i).id); } + entry.isEdit = edit; + entry.editStoryId = editStoryId; + entry.editStoryPeerId = editStoryPeerId; + entry.editExpireDate = editExpireDate; + entry.editPhotoId = editPhotoId; + entry.editDocumentId = editDocumentId; return entry; } @@ -488,6 +606,13 @@ public void toStream(AbstractSerializedData stream) { for (int i = 0; i < parts.size(); ++i) { parts.get(i).serializeToStream(stream); } + stream.writeBool(edit); + stream.writeInt32(editStoryId); + stream.writeInt64(editStoryPeerId); + stream.writeInt64(editExpireDate); + stream.writeInt64(editPhotoId); + stream.writeInt64(editDocumentId); + stream.writeString(paintEntitiesFilePath); } public int getObjectSize() { @@ -619,6 +744,20 @@ public StoryDraft(@NonNull AbstractSerializedData stream, boolean exception) { parts.add(part); } } + if (stream.remaining() > 0) { + edit = stream.readBool(exception); + editStoryId = stream.readInt32(exception); + editStoryPeerId = stream.readInt64(exception); + editExpireDate = stream.readInt64(exception); + editPhotoId = stream.readInt64(exception); + editDocumentId = stream.readInt64(exception); + } + if (stream.remaining() > 0) { + paintEntitiesFilePath = stream.readString(exception); + if (paintEntitiesFilePath != null && paintEntitiesFilePath.length() == 0) { + paintEntitiesFilePath = null; + } + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DualCameraView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DualCameraView.java index ed79e7031e4..991b78695e7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DualCameraView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/DualCameraView.java @@ -525,9 +525,13 @@ public boolean dualAvailable() { -1155551678, // XIAOMI MARBLE 1908524435, // XIAOMI SURYA 976847578, // XIAOMI LAUREL_SPROUT + -1489198134, // XIAOMI ALIOTH + 1910814392, // XIAOMI VENUS -713271737, // OPPO OP4F2F -2010722764, // SAMSUNG A52SXQ (A52s 5G) 1407170066, // SAMSUNG D2Q (Note10+) + -821405251, // SAMSUNG BEYOND2 + -1394190955, // SAMSUNG A71 -1394190055, // SAMSUNG B4Q 1407170066, // HUAWEI HWNAM 1407159934, // HUAWEI HWCOR @@ -539,6 +543,8 @@ public boolean dualAvailable() { -1198092731, // MOTOROLA CYPRUS64 -251277614, // MOTOROLA HANOIP -2078385967, // MOTOROLA PSTAR + -2073158771, // MOTOROLA VICKY + 1273004781 // MOTOROLA BLACKJACK // -1426053134 // REALME REE2ADL1 }; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/EmojiBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/EmojiBottomSheet.java index 02e432140c6..0ea721d7aba 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/EmojiBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/EmojiBottomSheet.java @@ -10,54 +10,44 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; -import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; -import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; import android.graphics.drawable.Drawable; -import android.media.Image; import android.os.Build; -import android.os.SystemClock; import android.text.Editable; import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; import android.text.TextWatcher; -import android.util.Log; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.TypedValue; -import android.view.GestureDetector; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewOutlineProvider; -import android.view.animation.OvershootInterpolator; import android.view.inputmethod.EditorInfo; import android.widget.FrameLayout; import android.widget.ImageView; -import android.widget.OverScroller; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; -import androidx.core.math.MathUtils; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearSmoothScrollerCustom; import androidx.recyclerview.widget.RecyclerView; -import org.checkerframework.checker.units.qual.A; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.DocumentObject; import org.telegram.messenger.Emoji; @@ -67,57 +57,471 @@ import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LiteMode; import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MediaController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; +import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.SvgHelper; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.ContextLinkCell; import org.telegram.ui.Cells.StickerSetNameCell; import org.telegram.ui.Components.AnimatedEmojiDrawable; -import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.ButtonBounce; +import org.telegram.ui.Components.CloseProgressDrawable2; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.DrawingInBackgroundThreadDrawable; import org.telegram.ui.Components.EditTextBoldCursor; import org.telegram.ui.Components.EmojiTabsStrip; import org.telegram.ui.Components.EmojiView; +import org.telegram.ui.Components.ExtendedGridLayoutManager; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RecyclerAnimationScrollHelper; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.ScaleStateListAnimator; import org.telegram.ui.Components.SearchStateDrawable; +import org.telegram.ui.Components.Size; import org.telegram.ui.Components.StickerCategoriesListView; import org.telegram.ui.Components.ViewPagerFixed; +import org.telegram.ui.ContentPreviewViewer; import org.telegram.ui.SelectAnimatedEmojiDialog; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; public class EmojiBottomSheet extends BottomSheet implements NotificationCenter.NotificationCenterDelegate { private static final int PAGE_TYPE_EMOJI = 0; private static final int PAGE_TYPE_STICKERS = 1; + private static final int PAGE_TYPE_GIFS = 2; private String query = null; private int categoryIndex = -1; - private class Page extends FrameLayout { + public final TLRPC.Document locationSticker = new TLRPC.Document() {}; + + abstract class IPage extends FrameLayout { + public int currentType; + + public IPage(Context context) { + super(context); + } + + public float top() { + return 0; + } + + public void updateTops() { + + } + + public void bind(int type) { + + } + } + + private class GifPage extends IPage { + + public RecyclerListView listView; + public GifAdapter adapter; + public SearchField searchField; + public ExtendedGridLayoutManager layoutManager; + + public GifPage(Context context) { + super(context); + + listView = new RecyclerListView(context) { + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + final boolean result = ContentPreviewViewer.getInstance().onInterceptTouchEvent(event, listView, 0, previewDelegate, resourcesProvider); + return super.onInterceptTouchEvent(event) || result; + } + }; + listView.setAdapter(adapter = new GifAdapter()); + listView.setLayoutManager(layoutManager = new GifLayoutManager(context)); + listView.addItemDecoration(new RecyclerView.ItemDecoration() { + @Override + public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { + outRect.right = layoutManager.isLastInRow(parent.getChildAdapterPosition(view) - 1) ? 0 : dp(4); + outRect.bottom = dp(4); + } + }); + listView.setClipToPadding(true); + listView.setVerticalScrollBarEnabled(false); + final RecyclerListView.OnItemClickListener onItemClickListener = (view, position) -> { + position--; + if (position < 0 || position >= gifs.size()) { + return; + } + TLRPC.BotInlineResult res = gifs.get(position); + if (res == null) { + return; + } + TLRPC.Document document = res.document; + if (document == null) { + return; + } + if (onDocumentSelected != null) { + onDocumentSelected.run(res, document, true); + } + dismiss(); + }; + listView.setOnTouchListener((v, event) -> ContentPreviewViewer.getInstance().onTouch(event, listView, 0, onItemClickListener, previewDelegate, resourcesProvider)); + listView.setOnItemClickListener(onItemClickListener); + listView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + containerView.invalidate(); + if (keyboardVisible && listView.scrollingByUser && searchField != null && searchField.editText != null) { + closeKeyboard(); + } + + int position = layoutManager.findLastCompletelyVisibleItemPosition(); + if (position + 3 >= adapter.getItemCount() - 1) { + adapter.request(); + } + } + }); + addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, 58, 0, 40)); + + searchField = new SearchField(context, resourcesProvider); + searchField.setOnSearchQuery((query, category) -> { + EmojiBottomSheet.this.query = query; + EmojiBottomSheet.this.categoryIndex = category; + adapter.updateItems(query); + }); + addView(searchField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP)); + } + + private ContentPreviewViewer.ContentPreviewViewerDelegate previewDelegate = new ContentPreviewViewer.ContentPreviewViewerDelegate() { + @Override + public void openSet(TLRPC.InputStickerSet set, boolean clearInputField) { + + } + + @Override + public boolean needSend(int contentType) { + return false; + } + + @Override + public boolean canSchedule() { + return false; + } + + @Override + public boolean isInScheduleMode() { + return false; + } + + @Override + public long getDialogId() { + return 0; + } + + @Override + public boolean isPhotoEditor() { + return true; + } + }; + + @Override + public float top() { + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + Object tag = child.getTag(); + if (tag instanceof Integer && (int) tag == 34) { + return Math.max(0, child.getBottom()); + } + } + return 0; + } + + @Override + public void updateTops() { + float top = Math.max(0, top()); +// tabsStrip.setTranslationY(dp(16) + top); + searchField.setTranslationY(dp(10) + top); +// listView.setBounds(top + listView.getPaddingTop(), listView.getHeight() - listView.getPaddingBottom()); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setPadding(backgroundPaddingLeft, 0, backgroundPaddingLeft, AndroidUtilities.navigationBarHeight); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + public void bind(int type) { + adapter.updateItems(null); + } + + private static final int VIEW_TYPE_PAD = 0; + private static final int VIEW_TYPE_GIF = 1; + + private ArrayList gifs = new ArrayList<>(); + private HashMap> cache = new HashMap<>(); + + private class GifAdapter extends RecyclerListView.SelectionAdapter { + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + if (viewType == VIEW_TYPE_PAD) { + view = new View(getContext()); + } else { + ContextLinkCell cell = new ContextLinkCell(getContext()); + cell.allowButtonBounce(true); + cell.setIsKeyboard(true); + cell.setCanPreviewGif(true); + view = cell; + } + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + final int viewType = holder.getItemViewType(); + if (viewType == VIEW_TYPE_PAD) { + holder.itemView.setTag(34); + holder.itemView.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) maxPadding)); + } else if (viewType == VIEW_TYPE_GIF) { + ((ContextLinkCell) holder.itemView).setLink(gifs.get(position - 1), bot, true, false, false, true); + } + } + + @Override + public int getItemCount() { + return 1 + gifs.size(); + } + + @Override + public int getItemViewType(int position) { + if (position == 0) { + return VIEW_TYPE_PAD; + } + return VIEW_TYPE_GIF; + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return holder.getItemViewType() == VIEW_TYPE_GIF; + } + + public void updateItems(String query) { + if (!TextUtils.equals(this.query, query)) { + if (currentReqId != -1) { + ConnectionsManager.getInstance(currentAccount).cancelRequest(currentReqId, true); + currentReqId = -1; + } + requesting = false; + offset = ""; + } + this.query = query; + AndroidUtilities.cancelRunOnUIThread(searchRunnable); + if (TextUtils.isEmpty(query)) { + gifs.clear(); + searchField.showProgress(false); + notifyDataSetChanged(); + } else { + searchField.showProgress(true); + AndroidUtilities.runOnUIThread(searchRunnable, 1500); + } + } + + private Runnable searchRunnable = this::request; + + private int currentReqId = -1; + private String query; + private TLRPC.User bot; + private String offset; + private boolean requestedBot; + private boolean requesting = false; + + private void request() { + if (requesting) { + return; + } + requesting = true; + searchField.showProgress(true); + + if (currentReqId >= 0) { + ConnectionsManager.getInstance(currentAccount).cancelRequest(currentReqId, true); + currentReqId = -1; + } + + if (bot == null) { + TLObject object = MessagesController.getInstance(currentAccount).getUserOrChat( + MessagesController.getInstance(currentAccount).gifSearchBot + ); + if (object instanceof TLRPC.User) { + bot = (TLRPC.User) object; + } + } + if (bot == null && !requestedBot) { + TLRPC.TL_contacts_resolveUsername req = new TLRPC.TL_contacts_resolveUsername(); + req.username = MessagesController.getInstance(currentAccount).gifSearchBot; + currentReqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (res instanceof TLRPC.TL_contacts_resolvedPeer) { + TLRPC.TL_contacts_resolvedPeer response = (TLRPC.TL_contacts_resolvedPeer) res; + MessagesController.getInstance(currentAccount).putUsers(response.users, false); + MessagesController.getInstance(currentAccount).putChats(response.chats, false); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(response.users, response.chats, true, true); + } + requestedBot = true; + request(); + })); + return; + } + if (bot == null) { + return; + } + + TLRPC.TL_messages_getInlineBotResults req = new TLRPC.TL_messages_getInlineBotResults(); + req.bot = MessagesController.getInstance(currentAccount).getInputUser(bot); + req.query = query == null ? "" : query; + final boolean emptyOffset = TextUtils.isEmpty(offset); + req.offset = offset == null ? "" : offset; + req.peer = new TLRPC.TL_inputPeerEmpty(); + + final String key = "gif_search_" + req.query + "_" + req.offset; + MessagesStorage.getInstance(currentAccount).getBotCache(key, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (!requesting) { + return; + } + if (res instanceof TLRPC.messages_BotResults) { + TLRPC.messages_BotResults response = (TLRPC.messages_BotResults) res; + offset = response.next_offset; + + if (emptyOffset) { + gifs.clear(); + } + int position = gifs.size(); + gifs.addAll(response.results); + if (emptyOffset) { + notifyDataSetChanged(); + } else { + notifyItemRangeInserted(position, gifs.size() - position); + } + + searchField.showProgress(false); + requesting = false; + } else { + currentReqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res2, err2) -> AndroidUtilities.runOnUIThread(() -> { + if (!requesting) { + return; + } + if (res2 instanceof TLRPC.messages_BotResults) { + TLRPC.messages_BotResults response = (TLRPC.messages_BotResults) res2; + MessagesStorage.getInstance(currentAccount).saveBotCache(key, response); + offset = response.next_offset; + + if (emptyOffset) { + gifs.clear(); + } + int position = gifs.size(); + gifs.addAll(response.results); + if (emptyOffset) { + notifyDataSetChanged(); + } else { + notifyItemRangeInserted(position, gifs.size() - position); + } + } + + searchField.showProgress(false); + requesting = false; + })); + } + })); + } + } + + private class GifLayoutManager extends ExtendedGridLayoutManager { + + private final Size size = new Size(); + + public GifLayoutManager(Context context) { + super(context, 100, true); + setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + if (position == 0) { + return getSpanCount(); + } + return getSpanSizeForItem(position - 1); + } + }); + } + + @Override + protected int getFlowItemCount() { + return getItemCount() - 1; + } + + + @Override + protected Size getSizeForItem(int i) { + TLRPC.Document document = null; + ArrayList attributes = null; + if (i >= 0 && i < gifs.size()) { + TLRPC.BotInlineResult result = gifs.get(i); + document = result.document; + if (document != null) { + attributes = document.attributes; + } else if (result.content != null) { + attributes = result.content.attributes; + } else if (result.thumb != null) { + attributes = result.thumb.attributes; + } else { + attributes = null; + } + } + return getSizeForItem(document, attributes); + } + + public Size getSizeForItem(TLRPC.Document document, List attributes) { + size.width = size.height = 100; + if (document != null) { + TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90); + if (thumb != null && thumb.w != 0 && thumb.h != 0) { + size.width = thumb.w; + size.height = thumb.h; + } + } + if (attributes != null) { + for (int b = 0; b < attributes.size(); b++) { + TLRPC.DocumentAttribute attribute = attributes.get(b); + if (attribute instanceof TLRPC.TL_documentAttributeImageSize || attribute instanceof TLRPC.TL_documentAttributeVideo) { + size.width = attribute.w; + size.height = attribute.h; + break; + } + } + } + return size; + } + } + } + + private class Page extends IPage { public EmojiListView listView; public Adapter adapter; public GridLayoutManager layoutManager; @@ -126,8 +530,6 @@ private class Page extends FrameLayout { public int spanCount = 8; - public int currentType; - public Page(Context context) { super(context); @@ -161,7 +563,7 @@ public int getSpanSize(int position) { return; } if (onDocumentSelected != null) { - onDocumentSelected.run(document); + onDocumentSelected.run(null, document, false); } dismiss(); }); @@ -262,6 +664,8 @@ protected boolean onTabClick(int index) { } private float lockTop = -1; + + @Override public float top() { if (lockTop >= 0) { return lockTop; @@ -284,6 +688,7 @@ public float lockTop() { return lockTop + listView.getPaddingTop(); } + @Override public void updateTops() { float top = Math.max(0, top()); tabsStrip.setTranslationY(dp(16) + top); @@ -302,8 +707,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { private boolean resetOnce = false; + @Override public void bind(int type) { - currentType = type; + this.currentType = type; layoutManager.setSpanCount(spanCount = type == PAGE_TYPE_EMOJI ? 8 : 5); if (!resetOnce) { adapter.updateItems(null); @@ -385,7 +791,11 @@ private void updateItems(String query) { itemsCount++; // pan documents.add(null); packs.clear(); + int i = 0; if (currentType == PAGE_TYPE_STICKERS) { + documents.add(locationSticker); + itemsCount++; + ArrayList favorites = mediaDataController.getRecentStickers(MediaDataController.TYPE_FAVE); if (favorites != null && !favorites.isEmpty()) { if (faveSet == null) { @@ -413,7 +823,6 @@ private void updateItems(String query) { MediaDataController.TYPE_EMOJIPACKS : MediaDataController.TYPE_IMAGE )); - int i = 0; for (; i < stickerSets.size(); ++i) { TLRPC.TL_messages_stickerSet set = stickerSets.get(i); @@ -684,6 +1093,7 @@ private void updateItems(String query) { private static final int VIEW_TYPE_HEADER = 1; private static final int VIEW_TYPE_EMOJI = 2; private static final int VIEW_TYPE_NOT_FOUND = 3; + private static final int VIEW_TYPE_COMPONENT = 4; @NonNull @Override @@ -695,6 +1105,8 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int view = new StickerSetNameCell(getContext(), true, resourcesProvider); } else if (viewType == VIEW_TYPE_NOT_FOUND) { view = new NoEmojiView(getContext(), currentType == PAGE_TYPE_EMOJI); + } else if (viewType == VIEW_TYPE_COMPONENT) { + view = new StoryLocationComponentCell(getContext()); } else { view = new EmojiListView.EmojiImageView(getContext(), listView); } @@ -758,6 +1170,9 @@ public int getItemViewType(int position) { } else if (positionToSection.get(position, -1) >= 0) { return VIEW_TYPE_HEADER; } else { + if (position >= 0 && position < documents.size() && documents.get(position) == locationSticker) { + return VIEW_TYPE_COMPONENT; + } return VIEW_TYPE_EMOJI; } } @@ -796,6 +1211,8 @@ public void didReceivedNotification(int id, int account, Object... args) { // private final GestureDetector gestureDetector; private boolean wasKeyboardVisible; + public static int savedPosition = 1; + public EmojiBottomSheet(Context context, Theme.ResourcesProvider resourcesProvider) { super(context, true, resourcesProvider); @@ -812,20 +1229,35 @@ protected void onTabAnimationUpdate() { tabsView.setType(viewPager.getPositionAnimated()); containerView.invalidate(); invalidate(); + savedPosition = viewPager.getCurrentPosition(); } }; + viewPager.currentPosition = savedPosition; viewPager.setAdapter(new ViewPagerFixed.Adapter() { @Override public int getItemCount() { - return 2; + return 3; } @Override public View createView(int viewType) { + if (viewType == 1) { + return new GifPage(context); + } return new Page(context); } + + @Override + public int getItemViewType(int position) { + if (position == 0 || position == 1) { + return 0; + } else { + return 1; + } + } + @Override public void bindView(View view, int position, int viewType) { - ((Page) view).bind(position); + ((IPage) view).bind(position); } }); containerView.addView(viewPager, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL)); @@ -846,6 +1278,7 @@ public void bindView(View view, int position, int viewType) { tabsView.setType(type); } }); + tabsView.setType(viewPager.currentPosition); containerView.addView(tabsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL)); galleryButton = new ImageView(context); @@ -873,8 +1306,16 @@ public void closeKeyboard() { View[] views = viewPager.getViewPages(); for (int i = 0; i < views.length; ++i) { View view = views[i]; - if (view instanceof Page && ((Page) view).searchField != null) { - AndroidUtilities.hideKeyboard(((Page) view).searchField.editText); + if (view instanceof Page) { + Page page = (Page) view; + if (page.searchField != null) { + AndroidUtilities.hideKeyboard(page.searchField.editText); + } + } else if (view instanceof GifPage) { + GifPage page = (GifPage) view; + if (page.searchField != null) { + AndroidUtilities.hideKeyboard(page.searchField.editText); + } } } } @@ -925,7 +1366,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto } private void setupBlurBitmap() { - if (blurBitmap != null || drawBlurBitmap == null || SharedConfig.getDevicePerformanceClass() <= SharedConfig.PERFORMANCE_CLASS_LOW || !LiteMode.isPowerSaverApplied()) { + if (blurBitmap != null || drawBlurBitmap == null || SharedConfig.getDevicePerformanceClass() <= SharedConfig.PERFORMANCE_CLASS_LOW || LiteMode.isPowerSaverApplied()) { return; } final int scale = 16; @@ -937,7 +1378,7 @@ private void setupBlurBitmap() { if (blurBitmapMatrix == null) { blurBitmapMatrix = new Matrix(); } - blurBitmapMatrix.postScale(8, 8); + blurBitmapMatrix.postScale(scale, scale); blurBitmapShader.setLocalMatrix(blurBitmapMatrix); invalidate(); } @@ -982,16 +1423,15 @@ protected void dispatchDraw(Canvas canvas) { backgroundPaint.setAlpha((int) (0xFF * (blurBitmap == null ? .95f : .85f))); View[] views = viewPager.getViewPages(); top = 0; - if (views[0] instanceof Page) { - top += ((Page) views[0]).top() * Utilities.clamp(1f - Math.abs(views[0].getTranslationX() / (float) views[0].getMeasuredWidth()), 1, 0); - if (views[0].getVisibility() == View.VISIBLE) { - ((Page) views[0]).updateTops(); + for (int i = 0; i < views.length; ++i) { + View view = views[i]; + if (!(view instanceof IPage)) { + continue; } - } - if (views[1] instanceof Page) { - top += ((Page) views[1]).top() * Utilities.clamp(1f - Math.abs(views[1].getTranslationX() / (float) views[1].getMeasuredWidth()), 1, 0); - if (views[1].getVisibility() == View.VISIBLE) { - ((Page) views[1]).updateTops(); + IPage page = (IPage) view; + top += page.top() * Utilities.clamp(1f - Math.abs(page.getTranslationX() / (float) page.getMeasuredWidth()), 1, 0); + if (page.getVisibility() == View.VISIBLE) { + page.updateTops(); } } final float statusBar = isActionBarT.set(top <= 0 ? 1 : 0); @@ -999,7 +1439,7 @@ protected void dispatchDraw(Canvas canvas) { AndroidUtilities.rectTmp.set(backgroundPaddingLeft, y, getWidth() - backgroundPaddingLeft, getHeight() + AndroidUtilities.dp(8)); if (blurBitmap != null) { blurBitmapMatrix.reset(); - blurBitmapMatrix.postScale(12, 12); + blurBitmapMatrix.postScale(16, 16); blurBitmapMatrix.postTranslate(0, -getY()); blurBitmapShader.setLocalMatrix(blurBitmapMatrix); canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(14), dp(14), backgroundBlurPaint); @@ -1021,12 +1461,12 @@ protected void dispatchDraw(Canvas canvas) { } @Override - public boolean onTouchEvent(MotionEvent event) { + public boolean dispatchTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN && event.getY() < top) { dismiss(); return true; } - return super.onTouchEvent(event); + return super.dispatchTouchEvent(event); } } @@ -1038,8 +1478,8 @@ public int getContainerViewHeight() { return (int) (containerView.getMeasuredHeight() - viewPager.getY()); } - private Utilities.Callback onDocumentSelected; - public EmojiBottomSheet whenSelected(Utilities.Callback listener) { + private Utilities.Callback3 onDocumentSelected; + public EmojiBottomSheet whenSelected(Utilities.Callback3 listener) { this.onDocumentSelected = listener; return this; } @@ -1475,7 +1915,7 @@ public void prepareDraw(long time) { AndroidUtilities.rectTmp2.set(imageView.getPaddingLeft(), imageView.getPaddingTop(), imageView.getWidth() - imageView.getPaddingRight(), imageView.getHeight() - imageView.getPaddingBottom()); if (imageReceiver != null) { final float aspectRatio = getAspectRatio(imageReceiver); - if (aspectRatio < 0) { + if (aspectRatio < 1) { final float w = AndroidUtilities.rectTmp2.height() * aspectRatio; final int left = (int) (AndroidUtilities.rectTmp2.centerX() - w / 2); final int right = (int) (AndroidUtilities.rectTmp2.centerX() + w / 2); @@ -1614,6 +2054,8 @@ private static class SearchField extends FrameLayout { private final FrameLayout inputBox; private final EditTextBoldCursor editText; private final StickerCategoriesListView categoriesListView; + private boolean clearVisible; + private final ImageView clear; public boolean ignoreTextChange; @@ -1652,12 +2094,19 @@ public boolean onTouchEvent(MotionEvent event) { return super.onTouchEvent(event); } if (event.getAction() == MotionEvent.ACTION_DOWN) { - // todo: open search editText.requestFocus(); AndroidUtilities.showKeyboard(editText); } return super.onTouchEvent(event); } + + @Override + protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { + super.onFocusChanged(focused, direction, previouslyFocusedRect); + if (!focused) { + AndroidUtilities.hideKeyboard(editText); + } + } }; editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); editText.setHintTextColor(Theme.getColor(Theme.key_chat_emojiSearchIcon, resourcesProvider)); @@ -1695,6 +2144,26 @@ public void afterTextChanged(Editable s) { if (editText != null) { editText.animate().cancel(); editText.animate().translationX(0).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + if (clear != null && clearVisible != (!TextUtils.isEmpty(editText.getText()))) { + clearVisible = !clearVisible; + clear.animate().cancel(); + if (clearVisible) { + clear.setVisibility(View.VISIBLE); + } + clear.animate() + .scaleX(clearVisible ? 1f : .7f) + .scaleY(clearVisible ? 1f : .7f) + .alpha(clearVisible ? 1f : 0f) + .withEndAction(() -> { + if (!clearVisible) { + clear.setVisibility(View.GONE); + } + }) + .setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT) + .setDuration(320) + .setStartDelay(clearVisible ? 240 : 0) + .start(); + } } } }); @@ -1763,6 +2232,24 @@ protected boolean isTabIconsAnimationEnabled(boolean loaded) { }); box.addView(categoriesListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.LEFT | Gravity.TOP, 36, 0, 0, 0)); + clear = new ImageView(context); + clear.setScaleType(ImageView.ScaleType.CENTER); + clear.setImageDrawable(new CloseProgressDrawable2(1.25f) { + { setSide(AndroidUtilities.dp(7)); } + @Override + protected int getCurrentColor() { + return Theme.getColor(Theme.key_chat_emojiSearchIcon, resourcesProvider); + } + }); + clear.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), Theme.RIPPLE_MASK_CIRCLE_20DP, AndroidUtilities.dp(15))); + clear.setAlpha(0f); + clear.setScaleX(.7f); + clear.setScaleY(.7f); + clear.setVisibility(View.GONE); + clear.setOnClickListener(e -> clear()); + box.addView(clear, LayoutHelper.createFrame(36, 36, Gravity.RIGHT | Gravity.TOP)); + + searchImageView.setOnClickListener(e -> { if (searchImageDrawable.getIconState() == SearchStateDrawable.State.STATE_BACK) { clear(); @@ -1830,12 +2317,12 @@ private static class TabsView extends View { private float emojiLayoutWidth, emojiLayoutLeft; private StaticLayout stickersLayout; private float stickersLayoutWidth, stickersLayoutLeft; - private StaticLayout masksLayout; - private float masksLayoutWidth, masksLayoutLeft; + private StaticLayout gifsLayout; + private float gifsLayoutWidth, gifsLayoutLeft; private final RectF emojiRect = new RectF(); private final RectF stickersRect = new RectF(); - private final RectF masksRect = new RectF(); + private final RectF gifsRect = new RectF(); private final RectF selectRect = new RectF(); public TabsView(Context context) { @@ -1877,12 +2364,11 @@ private void updateLayouts() { stickersLayoutWidth = stickersLayout.getLineCount() >= 1 ? stickersLayout.getLineWidth(0) : 0; stickersLayoutLeft = stickersLayout.getLineCount() >= 1 ? stickersLayout.getLineLeft(0) : 0; -// masksLayout = new StaticLayout(LocaleController.getString("Masks"), textPaint, getMeasuredWidth(), Layout.Alignment.ALIGN_NORMAL, 1, 0, false); -// masksLayoutWidth = masksLayout.getLineCount() >= 1 ? masksLayout.getLineWidth(0) : 0; -// masksLayoutLeft = masksLayout.getLineCount() >= 1 ? masksLayout.getLineLeft(0) : 0; -// -// float w = dp(12) + emojiLayoutWidth + dp(12 + 12 + 12) + stickersLayoutWidth + dp(12 + 12 + 12) + masksLayoutWidth + dp(12); - float w = dp(12) + emojiLayoutWidth + dp(12 + 12 + 12) + stickersLayoutWidth + dp(12); + gifsLayout = new StaticLayout(LocaleController.getString("AccDescrGIFs", R.string.AccDescrGIFs), textPaint, getMeasuredWidth(), Layout.Alignment.ALIGN_NORMAL, 1, 0, false); + gifsLayoutWidth = gifsLayout.getLineCount() >= 1 ? gifsLayout.getLineWidth(0) : 0; + gifsLayoutLeft = gifsLayout.getLineCount() >= 1 ? gifsLayout.getLineLeft(0) : 0; + + float w = dp(12) + emojiLayoutWidth + dp(12 + 12 + 12) + stickersLayoutWidth + dp(12 + 12 + 12) + gifsLayoutWidth + dp(12); float t = dp(40 - 26) / 2f, b = dp(40 + 26) / 2f; float l = (getMeasuredWidth() - w) / 2f; @@ -1892,19 +2378,18 @@ private void updateLayouts() { stickersRect.set(l, t, l + stickersLayoutWidth + dp(12 + 12), b); l += stickersLayoutWidth + dp(12 + 12 + 12); -// masksLayout.set(l, t, l + masksLayoutWidth + dp(12 + 12), b); -// l += masksLayoutWidth + dp(12 + 12 + 12); + gifsRect.set(l, t, l + gifsLayoutWidth + dp(12 + 12), b); + l += gifsLayoutWidth + dp(12 + 12 + 12); } private RectF getRect(int t) { if (t <= 0) { return emojiRect; - } else { // if (t == 1) + } else if (t == 1) { return stickersRect; + } else { + return gifsRect; } -// else { -// return masksRect; -// } } @Override @@ -1931,11 +2416,11 @@ protected void dispatchDraw(Canvas canvas) { canvas.restore(); } - if (masksLayout != null) { + if (gifsLayout != null) { canvas.save(); - canvas.translate(masksRect.left + dp(12) - masksLayoutLeft, masksRect.top + (masksRect.height() - masksLayout.getHeight()) / 2f); + canvas.translate(gifsRect.left + dp(12) - gifsLayoutLeft, gifsRect.top + (gifsRect.height() - gifsLayout.getHeight()) / 2f); textPaint.setColor(ColorUtils.blendARGB(0xFF838383, 0xFFFFFFFF, Utilities.clamp(1f - Math.abs(type - 2), 1, 0))); - masksLayout.draw(canvas); + gifsLayout.draw(canvas); canvas.restore(); } } @@ -1949,6 +2434,8 @@ public boolean onTouchEvent(MotionEvent event) { onTypeSelected.run(0); } else if (stickersRect.contains(event.getX(), event.getY())) { onTypeSelected.run(1); + } else if (gifsRect.contains(event.getX(), event.getY())) { + onTypeSelected.run(2); } return true; } @@ -1994,4 +2481,82 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { ); } } + + private static class StoryLocationComponentCell extends View { + + private final TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + private final Paint bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private final Drawable pin; + private StaticLayout layout; + private float layoutLeft, layoutWidth; + + private final RectF bounds = new RectF(); + private final ButtonBounce bounce = new ButtonBounce(this); + + public StoryLocationComponentCell(Context context) { + super(context); + + textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rcondensedbold.ttf")); + textPaint.setTextSize(dp(21.3f)); + textPaint.setColor(Color.WHITE); + + pin = context.getResources().getDrawable(R.drawable.map_pin3).mutate(); + pin.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + + bgPaint.setColor(0x19ffffff); + } + + private int lastWidth; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp(60), MeasureSpec.EXACTLY)); + + if (lastWidth != getMeasuredWidth()) { + CharSequence text = LocaleController.getString("AddLocation", R.string.AddLocation); + text = TextUtils.ellipsize(text, textPaint, getMeasuredWidth(), TextUtils.TruncateAt.END); + layout = new StaticLayout(text, textPaint, getMeasuredWidth(), Layout.Alignment.ALIGN_NORMAL, 1f, 0, false); + layoutLeft = layout.getLineCount() <= 0 ? 0 : layout.getLineLeft(0); + layoutWidth = layout.getLineCount() <= 0 ? 0 : layout.getLineWidth(0); + lastWidth = getMeasuredWidth(); + + float width = dp(6 + 24 + 4 + 11.6f) + layoutWidth; + float height = dp(6 + 5) + layout.getHeight(); + bounds.set( + (getMeasuredWidth() - width) / 2f, + (getMeasuredHeight() - height) / 2f, + (getMeasuredWidth() + width) / 2f, + (getMeasuredHeight() + height) / 2f + ); + + pin.setBounds( + (int) (bounds.left + dp(6)), + (int) (bounds.centerY() - dp(12)), + (int) (bounds.left + dp(6 + 24)), + (int) (bounds.centerY() + dp(12)) + ); + } + } + + @Override + protected void dispatchDraw(Canvas canvas) { + canvas.save(); + final float scale = bounce.getScale(.1f); + canvas.scale(scale, scale, bounds.centerX(), bounds.centerY()); + canvas.drawRoundRect(bounds, dp(8), dp(8), bgPaint); + pin.draw(canvas); + canvas.save(); + canvas.translate(bounds.left + dp(6 + 24 + 4) - layoutLeft, bounds.top + dp(6)); + layout.draw(canvas); + canvas.restore(); + canvas.restore(); + } + + @Override + public void setPressed(boolean pressed) { + super.setPressed(pressed); + bounce.setPressed(pressed); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/GalleryListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/GalleryListView.java index a9533642a38..2d18cd04c59 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/GalleryListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/GalleryListView.java @@ -5,12 +5,15 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.ContentUris; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; @@ -20,6 +23,7 @@ import android.graphics.Rect; import android.graphics.Shader; import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.net.Uri; @@ -42,7 +46,9 @@ import android.view.ViewGroup; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.OvershootInterpolator; +import android.widget.EditText; import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -51,30 +57,41 @@ import androidx.recyclerview.widget.LinearSmoothScrollerCustom; import androidx.recyclerview.widget.RecyclerView; +import org.checkerframework.checker.units.qual.A; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.DispatchQueue; import org.telegram.messenger.DispatchQueuePool; +import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MessagesController; +import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.SharedPhotoVideoCell2; import org.telegram.ui.Components.AnimatedFloat; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.DrawingInBackgroundThreadDrawable; +import org.telegram.ui.Components.EditTextBoldCursor; +import org.telegram.ui.Components.FlickerLoadingView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.StickerEmptyView; import java.io.File; import java.io.IOException; @@ -86,19 +103,27 @@ public class GalleryListView extends FrameLayout implements NotificationCenter.NotificationCenterDelegate { private final int currentAccount; - private Theme.ResourcesProvider resourcesProvider; + private final Theme.ResourcesProvider resourcesProvider; private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); public final RecyclerListView listView; public final GridLayoutManager layoutManager; public final Adapter adapter; + private final FrameLayout searchContainer; + private final RecyclerListView searchListView; + private final GridLayoutManager searchLayoutManager; + private final SearchAdapter searchAdapterImages; + private final StickerEmptyView searchEmptyView; + private final KeyboardNotifier keyboardNotifier; + private boolean actionBarShown; private final ActionBar actionBar; private final TextView dropDown; private final Drawable dropDownDrawable; private final ActionBarMenuItem dropDownContainer; + private final ActionBarMenuItem searchItem; public boolean ignoreScroll; public final boolean onlyPhotos; @@ -242,9 +267,197 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { dropDown.setPadding(0, AndroidUtilities.statusBarHeight, AndroidUtilities.dp(10), 0); dropDownContainer.addView(dropDown, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 16, 0, 0, 0)); + searchContainer = new FrameLayout(context); + searchContainer.setVisibility(View.GONE); + searchContainer.setAlpha(0f); + addView(searchContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL)); + + searchListView = new RecyclerListView(context, resourcesProvider); + searchListView.setLayoutManager(searchLayoutManager = new GridLayoutManager(context, 3)); + searchListView.setAdapter(searchAdapterImages = new SearchAdapter() { + @Override + protected void onLoadingUpdate(boolean loading) { + if (searchItem != null) { + searchItem.setShowSearchProgress(loading); + } + searchEmptyView.showProgress(loading, true); + } + + @Override + public void notifyDataSetChanged() { + super.notifyDataSetChanged(); + if (TextUtils.isEmpty(query)) { + searchEmptyView.setStickerType(StickerEmptyView.STICKER_TYPE_ALBUM); + searchEmptyView.title.setText(LocaleController.getString(R.string.SearchImagesType)); + } else { + searchEmptyView.setStickerType(StickerEmptyView.STICKER_TYPE_SEARCH); + searchEmptyView.title.setText(LocaleController.formatString(R.string.NoResultFoundFor, query)); + } + } + }); + searchListView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + if (searchListView.scrollingByUser && searchItem != null && searchItem.getSearchField() != null) { + AndroidUtilities.hideKeyboard(searchItem.getSearchContainer()); + } + } + }); + searchListView.setClipToPadding(true); + searchListView.addItemDecoration(new RecyclerView.ItemDecoration() { + @Override + public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { + final int sz = AndroidUtilities.dp(4); + outRect.top = 0; + outRect.left = outRect.right = outRect.bottom = sz; + if ((parent.getChildAdapterPosition(view) % 3) != 2) { + outRect.right = 0; + } + } + }); + searchContainer.addView(searchListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL)); + + FlickerLoadingView flickerLoadingView = new FlickerLoadingView(context, resourcesProvider) { + @Override + public int getColumnsCount() { + return 3; + } + }; + flickerLoadingView.setViewType(FlickerLoadingView.PHOTOS_TYPE); + flickerLoadingView.setAlpha(0f); + flickerLoadingView.setVisibility(View.GONE); + searchContainer.addView(flickerLoadingView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL)); + + searchEmptyView = new StickerEmptyView(context, flickerLoadingView, StickerEmptyView.STICKER_TYPE_ALBUM, resourcesProvider); + searchEmptyView.title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + searchEmptyView.title.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText, resourcesProvider)); + searchEmptyView.title.setTypeface(null); + searchEmptyView.title.setText(LocaleController.getString(R.string.SearchImagesType)); + keyboardNotifier = new KeyboardNotifier(this, h -> searchEmptyView.animate().translationY(-h / 2f + dp(80)).setDuration(AdjustPanLayoutHelper.keyboardDuration).setInterpolator(AdjustPanLayoutHelper.keyboardInterpolator).start()); + searchContainer.addView(searchEmptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL)); + searchListView.setEmptyView(searchEmptyView); + + searchItem = menu.addItem(0, R.drawable.ic_ab_search).setIsSearchField(true).setActionBarMenuItemSearchListener(new ActionBarMenuItem.ActionBarMenuItemSearchListener() { + + private AnimatorSet animatorSet; + + @Override + public void onSearchCollapse() { + if (animatorSet != null) { + animatorSet.cancel(); + } + ArrayList animators = new ArrayList<>(); + + dropDownContainer.setVisibility(View.VISIBLE); + animators.add(ObjectAnimator.ofFloat(dropDownContainer, SCALE_X, 1f)); + animators.add(ObjectAnimator.ofFloat(dropDownContainer, SCALE_Y, 1f)); + animators.add(ObjectAnimator.ofFloat(dropDownContainer, ALPHA, 1f)); + + final View searchField = searchItem.getSearchField(); + if (searchField != null) { + animators.add(ObjectAnimator.ofFloat(searchField, SCALE_X, .8f)); + animators.add(ObjectAnimator.ofFloat(searchField, SCALE_Y, .8f)); + animators.add(ObjectAnimator.ofFloat(searchField, ALPHA, 0f)); + } + + listView.setVisibility(View.VISIBLE); + animators.add(ObjectAnimator.ofFloat(listView, ALPHA, 1f)); + listView.setFastScrollVisible(true); + animators.add(ObjectAnimator.ofFloat(searchContainer, ALPHA, 0f)); + + ValueAnimator va = ValueAnimator.ofFloat(0, 1); + va.addUpdateListener(anm -> GalleryListView.this.invalidate()); + animators.add(va); + + animatorSet = new AnimatorSet(); + animatorSet.setDuration(320); + animatorSet.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + animatorSet.playTogether(animators); + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (searchField != null) { + searchField.setVisibility(View.INVISIBLE); + } + searchContainer.setVisibility(View.GONE); + } + }); + animatorSet.start(); + } + + @Override + public void onSearchExpand() { + if (animatorSet != null) { + animatorSet.cancel(); + } + ArrayList animators = new ArrayList<>(); + + animators.add(ObjectAnimator.ofFloat(dropDownContainer, SCALE_X, .8f)); + animators.add(ObjectAnimator.ofFloat(dropDownContainer, SCALE_Y, .8f)); + animators.add(ObjectAnimator.ofFloat(dropDownContainer, ALPHA, 0f)); + + final EditTextBoldCursor searchField = searchItem.getSearchField(); + if (searchField != null) { + searchField.setVisibility(View.VISIBLE); + searchField.setHandlesColor(0xffffffff); + animators.add(ObjectAnimator.ofFloat(searchField, SCALE_X, 1f)); + animators.add(ObjectAnimator.ofFloat(searchField, SCALE_Y, 1f)); + animators.add(ObjectAnimator.ofFloat(searchField, ALPHA, 1f)); + } + + searchContainer.setVisibility(View.VISIBLE); + animators.add(ObjectAnimator.ofFloat(listView, ALPHA, 0f)); + listView.setFastScrollVisible(false); + animators.add(ObjectAnimator.ofFloat(searchContainer, ALPHA, 1f)); + searchEmptyView.setVisibility(View.VISIBLE); + + ValueAnimator va = ValueAnimator.ofFloat(0, 1); + va.addUpdateListener(anm -> GalleryListView.this.invalidate()); + animators.add(va); + + animatorSet = new AnimatorSet(); + animatorSet.setDuration(320); + animatorSet.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + animatorSet.playTogether(animators); + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + dropDownContainer.setVisibility(View.GONE); + listView.setVisibility(View.GONE); + } + }); + animatorSet.start(); + } + + @Override + public void onTextChanged(EditText editText) { + final String query = editText.getText().toString(); + searchAdapterImages.load(query); + } + }); + searchItem.setVisibility(View.GONE); + searchItem.setSearchFieldHint(LocaleController.getString("SearchImagesTitle", R.string.SearchImagesTitle)); + + searchListView.setOnItemClickListener((view, position) -> { + if (searchItem != null) { + AndroidUtilities.hideKeyboard(searchItem.getSearchContainer()); + } + if (position < 0 || position >= searchAdapterImages.results.size()) { + return; + } + if (onSelectListener != null) { + onSelectListener.run(searchAdapterImages.results.get(position), null); + } + }); + drafts.clear(); if (!onlyPhotos) { - drafts.addAll(MessagesController.getInstance(currentAccount).getStoriesController().getDraftsController().drafts); + ArrayList draftArray = MessagesController.getInstance(currentAccount).getStoriesController().getDraftsController().drafts; + for (StoryEntry draft : draftArray) { + if (!draft.isEdit) { + drafts.add(draft); + } + } } updateAlbumsDropDown(); @@ -268,6 +481,10 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { } } + public void allowSearch(boolean allow) { + searchItem.setVisibility(allow ? View.VISIBLE : View.GONE); + } + private ArrayList getPhotoEntries(MediaController.AlbumEntry album) { if (album == null) { return new ArrayList<>(); @@ -285,6 +502,23 @@ private ArrayList getPhotoEntries(MediaController.Al return photos; } + public void openSearch() { + actionBar.onSearchFieldVisibilityChanged(searchItem.toggleSearch(true)); + } + + public boolean onBackPressed() { + if (searchItem != null && searchItem.isSearchFieldVisible()) { + EditTextBoldCursor editText = searchItem.getSearchField(); + if (keyboardNotifier.keyboardVisible()) { + AndroidUtilities.hideKeyboard(editText); + return true; + } + actionBar.onSearchFieldVisibilityChanged(searchItem.toggleSearch(true)); + return true; + } + return false; + } + private final AnimatedFloat actionBarT = new AnimatedFloat(this, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); @Override @@ -323,6 +557,11 @@ public MediaController.AlbumEntry getSelectedAlbum() { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { listView.setPinnedSectionOffsetY(AndroidUtilities.statusBarHeight + ActionBar.getCurrentActionBarHeight()); listView.setPadding(dp(6), AndroidUtilities.statusBarHeight + ActionBar.getCurrentActionBarHeight(), dp(1), AndroidUtilities.navigationBarHeight); + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) searchContainer.getLayoutParams(); + lp.leftMargin = 0; + lp.topMargin = AndroidUtilities.statusBarHeight + ActionBar.getCurrentActionBarHeight(); + lp.rightMargin = 0; + lp.bottomMargin = AndroidUtilities.navigationBarHeight; dropDown.setPadding(0, AndroidUtilities.statusBarHeight, AndroidUtilities.dp(10), 0); dropDown.setTextSize(!AndroidUtilities.isTablet() && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y ? 18 : 20); super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -924,16 +1163,30 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } } - private static class HeaderView extends TextView { - public HeaderView(Context context, boolean onlyPhotos) { - super(context); + private class HeaderView extends FrameLayout { - setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - setTextColor(0xFFFFFFFF); - setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); - setPadding(dp(16), dp(16), dp(21), dp(10)); + public TextView textView; + public ImageView searchButton; - setText(LocaleController.getString(onlyPhotos ? R.string.AddImage : R.string.ChoosePhotoOrVideo)); + public HeaderView(Context context, boolean onlyPhotos) { + super(context); + setPadding(dp(onlyPhotos ? 14 : 16), dp(16), dp(8), dp(10)); + + if (onlyPhotos) { + searchButton = new ImageView(context); + searchButton.setImageResource(R.drawable.ic_ab_search); + searchButton.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + searchButton.setBackground(Theme.createSelectorDrawable(436207615)); + searchButton.setOnClickListener(view -> openSearch()); + addView(searchButton, LayoutHelper.createFrame(24, 24, Gravity.RIGHT | Gravity.CENTER_VERTICAL)); + } + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setTextColor(0xFFFFFFFF); + textView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + textView.setText(LocaleController.getString(onlyPhotos ? R.string.AddImage : R.string.ChoosePhotoOrVideo)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, 0, onlyPhotos ? 32 : 0, 0)); } } @@ -1081,20 +1334,26 @@ public int getPadding() { } public int top() { + int resultTop; if (listView == null || listView.getChildCount() <= 0) { - return getPadding(); - } - int top = Integer.MAX_VALUE; - if (listView != null) { - for (int i = 0; i < listView.getChildCount(); ++i) { - View child = listView.getChildAt(i); - int position = listView.getChildAdapterPosition(child); - if (position > 0) { - top = Math.min(top, (int) child.getY()); + resultTop = getPadding(); + } else { + int top = Integer.MAX_VALUE; + if (listView != null) { + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + int position = listView.getChildAdapterPosition(child); + if (position > 0) { + top = Math.min(top, (int) child.getY()); + } } } + resultTop = Math.max(0, Math.min(top, getHeight())); + } + if (listView == null) { + return resultTop; } - return Math.max(0, Math.min(top, getHeight())); + return AndroidUtilities.lerp(0, resultTop, listView.getAlpha()); } @Override @@ -1145,7 +1404,12 @@ public void didReceivedNotification(int id, int account, Object... args) { public void updateDrafts() { drafts.clear(); if (!onlyPhotos) { - drafts.addAll(MessagesController.getInstance(currentAccount).getStoriesController().getDraftsController().drafts); + ArrayList draftArray = MessagesController.getInstance(currentAccount).getStoriesController().getDraftsController().drafts; + for (StoryEntry draft : draftArray) { + if (!draft.isEdit) { + drafts.add(draft); + } + } } updateAlbumsDropDown(); updateContainsDrafts(); @@ -1158,4 +1422,165 @@ private void updateContainsDrafts() { containsDraftFolder = dropDownAlbums != null && !dropDownAlbums.isEmpty() && dropDownAlbums.get(0) == selectedAlbum && drafts.size() > 2; containsDrafts = !containsDraftFolder && (selectedAlbum == draftsAlbum || dropDownAlbums != null && !dropDownAlbums.isEmpty() && dropDownAlbums.get(0) == selectedAlbum); } + + public static final int SEARCH_TYPE_IMAGES = 0; + public static final int SEARCH_TYPE_GIFS = 1; + + private class SearchAdapter extends RecyclerListView.SelectionAdapter { + + public int type; + public ArrayList results = new ArrayList(); + private boolean full; + private boolean loading; + + private int currentReqId = -1; + public String query; + private String lastOffset; + + private TLRPC.User bot; + private boolean triedResolvingBot; + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new RecyclerListView.Holder(new BackupImageView(getContext()) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int size = MeasureSpec.getSize(widthMeasureSpec); + setMeasuredDimension(size, size); + } + }); + } + + private Drawable loadingDrawable = new ColorDrawable(0x10ffffff); + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + BackupImageView imageView = ((BackupImageView) holder.itemView); + TLObject obj = results.get(position); + if (obj instanceof TLRPC.Document) { + imageView.setImage(ImageLocation.getForDocument((TLRPC.Document) obj), "200_200", loadingDrawable, null); + } else if (obj instanceof TLRPC.Photo) { + TLRPC.Photo photo = (TLRPC.Photo) obj; + TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, 320); + imageView.setImage(ImageLocation.getForPhoto(photoSize, photo), "200_200", loadingDrawable, null); + } else if (obj instanceof TLRPC.BotInlineResult) { + TLRPC.BotInlineResult res = (TLRPC.BotInlineResult) obj; + if (res.thumb != null) { + ImageLocation location = ImageLocation.getForPath(res.thumb.url); + imageView.setImage(location, "200_200", loadingDrawable, res); + } else { + imageView.clearImage(); + } + } else { + imageView.clearImage(); + } + } + + @Override + public int getItemCount() { + return results.size(); + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return true; + } + + public void load(String query) { + if (!TextUtils.equals(this.query, query)) { + if (currentReqId != -1) { + ConnectionsManager.getInstance(currentAccount).cancelRequest(currentReqId, true); + currentReqId = -1; + } + loading = false; + lastOffset = null; + } + this.query = query; + AndroidUtilities.cancelRunOnUIThread(searchRunnable); + if (TextUtils.isEmpty(query)) { + this.results.clear(); + onLoadingUpdate(false); + notifyDataSetChanged(); + } else { + onLoadingUpdate(true); + AndroidUtilities.runOnUIThread(searchRunnable, 1500); + } + } + + private final Runnable searchRunnable = this::loadInternal; + + private void loadInternal() { + if (loading) { + return; + } + + onLoadingUpdate(loading = true); + + final MessagesController messagesController = MessagesController.getInstance(currentAccount); + + final String botUsername = type == SEARCH_TYPE_GIFS ? messagesController.gifSearchBot : messagesController.imageSearchBot; + if (bot == null) { + TLObject c = messagesController.getUserOrChat(botUsername); + if (c instanceof TLRPC.User) { + bot = (TLRPC.User) c; + } + } + if (bot == null && !triedResolvingBot) { + TLRPC.TL_contacts_resolveUsername req = new TLRPC.TL_contacts_resolveUsername(); + req.username = botUsername; + currentReqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + triedResolvingBot = true; + loading = false; + if (res instanceof TLRPC.TL_contacts_resolvedPeer) { + TLRPC.TL_contacts_resolvedPeer response = (TLRPC.TL_contacts_resolvedPeer) res; + messagesController.putUsers(response.users, false); + messagesController.putChats(response.chats, false); + MessagesStorage.getInstance(currentAccount).putUsersAndChats(response.users, response.chats, true, true); + loadInternal(); + } + })); + return; + } + if (bot == null) { + return; + } + + TLRPC.TL_messages_getInlineBotResults req = new TLRPC.TL_messages_getInlineBotResults(); + req.bot = messagesController.getInputUser(bot); + req.query = query == null ? "" : query; + req.peer = new TLRPC.TL_inputPeerEmpty(); + req.offset = lastOffset == null ? "" : lastOffset; + final boolean emptyOffset = TextUtils.isEmpty(req.offset); + currentReqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + if (res instanceof TLRPC.messages_BotResults) { + TLRPC.messages_BotResults response = (TLRPC.messages_BotResults) res; + lastOffset = response.next_offset; + + if (emptyOffset) { + results.clear(); + } + + for (int i = 0; i < response.results.size(); ++i) { + TLRPC.BotInlineResult result = response.results.get(i); + if (result.document != null) { + results.add(result.document); + } else if (result.photo != null) { + results.add(result.photo); + } else if (result.content != null) { + results.add(result); + } + } + + onLoadingUpdate(loading = false); + + notifyDataSetChanged(); + } + })); + } + + protected void onLoadingUpdate(boolean loading) { + + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/HintView2.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/HintView2.java index d9b85e336af..4ac5d3fe09e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/HintView2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/HintView2.java @@ -7,15 +7,24 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.content.Context; +import android.content.res.ColorStateList; import android.graphics.Canvas; +import android.graphics.ColorFilter; import android.graphics.CornerPathEffect; +import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Path; +import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.Shader; import android.graphics.Typeface; import android.graphics.drawable.Drawable; +import android.graphics.drawable.RippleDrawable; +import android.os.Build; import android.text.Layout; import android.text.Spannable; import android.text.SpannableString; @@ -23,12 +32,14 @@ import android.text.TextPaint; import android.text.style.ClickableSpan; import android.util.Log; +import android.util.StateSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.animation.OvershootInterpolator; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; @@ -91,11 +102,14 @@ public class HintView2 extends View { private boolean shown; private AnimatedFloat show = new AnimatedFloat(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private Drawable selectorDrawable; + private Paint cutSelectorPaint; + public HintView2(Context context, int direction) { super(context); this.direction = direction; - backgroundPaint.setColor(0xcc282828); + backgroundPaint.setColor(0xe6282828); backgroundPaint.setPathEffect(new CornerPathEffect(rounding)); textDrawable = new AnimatedTextView.AnimatedTextDrawable(true, true, false); @@ -109,6 +123,9 @@ public HintView2(Context context, int direction) { public HintView2 setRounding(float roundingDp) { this.rounding = dp(roundingDp); backgroundPaint.setPathEffect(new CornerPathEffect(rounding)); + if (cutSelectorPaint != null) { + cutSelectorPaint.setPathEffect(new CornerPathEffect(rounding)); + } return this; } @@ -186,53 +203,48 @@ public HintView2 setMaxWidthPx(int widthPx) { return this; } - private static boolean contains(CharSequence text, char c) { - if (text == null) { - return false; - } - for (int i = 0; i < text.length(); ++i) { - if (text.charAt(i) == c) { - return true; + // returns max width + public static int cutInFancyHalf(CharSequence text, TextPaint paint) { + int mid = text.length() / 2; + float leftWidth = 0, rightWidth = 0; + float prevLeftWidth = 0; + float prevRightWidth = Float.MAX_VALUE; + + for (int i = 0; i < 10; ++i) { + // Adjust the mid to point to the nearest space on the left + while (mid > 0 && text.charAt(mid) != ' ') { + mid--; } - } - return false; - } - private static int getTextWidth(CharSequence text, TextPaint paint) { - if (text instanceof Spannable) { - StaticLayout layout = new StaticLayout(text, paint, 99999, Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false); - if (layout.getLineCount() > 0) - return (int) Math.ceil(layout.getLineWidth(0)); - return 0; - } - return (int) paint.measureText(text.toString()); - } + leftWidth = paint.measureText(text.subSequence(0, mid).toString()); + rightWidth = paint.measureText(text.subSequence(mid, text.length()).toString().trim()); - // returns max width - public static int cutInFancyHalf(CharSequence text, TextPaint paint) { - if (text == null) { - return 0; - } - float fullLineWidth = getTextWidth(text, paint); - final int L = text.toString().length(), m = L / 2; - if (L <= 0 || contains(text, '\n')) { - return (int) Math.ceil(fullLineWidth); - } - int l = m - 1, r = m + 1; - int c = m; - while (l >= 0 && r < L) { - if (text.charAt(l) == ' ') { - c = l; + // If we're not making progress, exit the loop. + // (This is a basic way to ensure termination when we can't improve the result.) + if (leftWidth == prevLeftWidth && rightWidth == prevRightWidth) { break; } - if (text.charAt(r) == ' ') { - c = r; + + prevLeftWidth = leftWidth; + prevRightWidth = rightWidth; + + // If left side is shorter, move midpoint to the right. + if (leftWidth < rightWidth) { + mid++; + } + // If right side is shorter or equal, move midpoint to the left. + else { + mid--; + } + + // Ensure mid doesn't go out of bounds + if (mid <= 0 || mid >= text.length()) { break; } - l--; - r++; } - return (int) Math.ceil(Math.max(fullLineWidth * .3f, Math.max(c + .5f, L - c + .5f) / (float) L * fullLineWidth)); + + // Return the max width of the two parts. + return (int) Math.ceil(Math.max(leftWidth, rightWidth)); } public HintView2 useScale(boolean enable) { @@ -280,6 +292,37 @@ public HintView2 setHideByTouch(boolean enable) { return this; } + public HintView2 setSelectorColor(int selectorColor) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + return this; + } + cutSelectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + cutSelectorPaint.setPathEffect(new CornerPathEffect(rounding)); + ColorStateList colorStateList = new ColorStateList( + new int[][]{ StateSet.WILD_CARD }, + new int[]{ selectorColor } + ); + selectorDrawable = new RippleDrawable(colorStateList, null, new Drawable() { + @Override + public void draw(@NonNull Canvas canvas) { + canvas.save(); +// canvas.translate(-boundsWithArrow.left, -boundsWithArrow.top); + canvas.drawPath(path, cutSelectorPaint); + canvas.restore(); + } + @Override + public void setAlpha(int alpha) {} + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) {} + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + }); + selectorDrawable.setCallback(this); + return this; + } + public HintView2 setBounce(boolean enable) { repeatedBounce = enable; return this; @@ -315,6 +358,16 @@ public HintView2 setJoint(float joint, float jointTranslateDp) { return this; } + public HintView2 setJointPx(float joint, float jointTranslatePx) { + if (Math.abs(this.joint - joint) >= 1 || Math.abs(this.jointTranslate - jointTranslatePx) >= 1) { + this.pathSet = false; + invalidate(); + } + this.joint = joint; + this.jointTranslate = jointTranslatePx; + return this; + } + public TextPaint getTextPaint() { if (multiline) { return textPaint; @@ -449,9 +502,10 @@ private void makeLayout(CharSequence text, int width) { textLayoutLeft = left; } - private final ButtonBounce bounce = new ButtonBounce(this, 2f); + private final ButtonBounce bounce = new ButtonBounce(this, 2f, 5f); private float bounceX, bounceY; + private final Rect boundsWithArrow = new Rect(); private final RectF bounds = new RectF(); private final Path path = new Path(); private float arrowX, arrowY; @@ -517,6 +571,12 @@ protected void dispatchDraw(Canvas canvas) { canvas.drawPath(path, backgroundPaint); backgroundPaint.setAlpha(wasAlpha); + if (selectorDrawable != null) { + selectorDrawable.setAlpha((int) (0xFF * alpha)); + selectorDrawable.setBounds(boundsWithArrow); + selectorDrawable.draw(canvas); + } + if (multiline) { canvas.saveLayerAlpha(0, 0, getWidth(), Math.max(getHeight(), height), (int) (0xFF * alpha), Canvas.ALL_SAVE_FLAG); canvas.translate(textX = bounds.left + innerPadding.left - textLayoutLeft, textY = bounds.top + innerPadding.top); @@ -579,6 +639,7 @@ private void rewindPath(float width, float height) { bounds.set(getMeasuredWidth() - getPaddingRight() - arrowHeight - width, top, getMeasuredWidth() - getPaddingRight() - arrowHeight, bottom); } } + boundsWithArrow.set((int) bounds.left, (int) bounds.top, (int) bounds.right, (int) bounds.bottom); path.rewind(); path.moveTo(bounds.left, bounds.bottom); @@ -591,6 +652,7 @@ private void rewindPath(float width, float height) { path.lineTo(bounds.left - arrowHeight, arrowXY - dp(1)); path.lineTo(bounds.left, arrowXY - arrowHalfWidth); path.lineTo(bounds.left, arrowXY - arrowHalfWidth - dp(2)); + boundsWithArrow.left -= arrowHeight; } path.lineTo(bounds.left, bounds.top); if (direction == DIRECTION_TOP) { @@ -602,6 +664,7 @@ private void rewindPath(float width, float height) { path.lineTo(arrowXY + dp(1), bounds.top - arrowHeight); path.lineTo(arrowXY + arrowHalfWidth, bounds.top); path.lineTo(arrowXY + arrowHalfWidth + dp(2), bounds.top); + boundsWithArrow.top -= arrowHeight; } path.lineTo(bounds.right, bounds.top); if (direction == DIRECTION_RIGHT) { @@ -613,6 +676,7 @@ private void rewindPath(float width, float height) { path.lineTo(bounds.right + arrowHeight, arrowXY + dp(1)); path.lineTo(bounds.right, arrowXY + arrowHalfWidth); path.lineTo(bounds.right, arrowXY + arrowHalfWidth + dp(2)); + boundsWithArrow.right += arrowHeight; } path.lineTo(bounds.right, bounds.bottom); if (direction == DIRECTION_BOTTOM) { @@ -624,6 +688,7 @@ private void rewindPath(float width, float height) { path.lineTo(arrowXY - dp(1), bounds.bottom + arrowHeight); path.lineTo(arrowXY - arrowHalfWidth, bounds.bottom); path.lineTo(arrowXY - arrowHalfWidth - dp(2), bounds.bottom); + boundsWithArrow.bottom += arrowHeight; } path.close(); pathSet = true; @@ -631,12 +696,12 @@ private void rewindPath(float width, float height) { @Override protected boolean verifyDrawable(@NonNull Drawable who) { - return who == textDrawable || super.verifyDrawable(who); + return who == textDrawable || who == selectorDrawable || super.verifyDrawable(who); } @Override public boolean onTouchEvent(MotionEvent event) { - if (!hideByTouch || !shown) { + if (!hideByTouch && !hasOnClickListeners() || !shown) { return false; } if (checkTouchLinks(event)) { @@ -657,13 +722,27 @@ private boolean checkTouchTap(MotionEvent event) { bounceX = x; bounceY = y; bounce.setPressed(true); + if (selectorDrawable != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + selectorDrawable.setHotspot(x, y); + selectorDrawable.setState(new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled}); + } return true; } else if (event.getAction() == MotionEvent.ACTION_UP) { - hide(); + if (hasOnClickListeners()) { + performClick(); + } else if (hideByTouch) { + hide(); + } bounce.setPressed(false); + if (selectorDrawable != null) { + selectorDrawable.setState(new int[]{}); + } return true; } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { bounce.setPressed(false); + if (selectorDrawable != null) { + selectorDrawable.setState(new int[]{}); + } return true; } return false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PaintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PaintView.java index fb39c912fd7..4d203b5cc6b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PaintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PaintView.java @@ -1,5 +1,6 @@ package org.telegram.ui.Stories.recorder; +import static org.telegram.messenger.AndroidUtilities.accelerateInterpolator; import static org.telegram.messenger.AndroidUtilities.lerp; import android.animation.Animator; @@ -27,6 +28,9 @@ import android.graphics.SweepGradient; import android.graphics.Typeface; import android.graphics.drawable.GradientDrawable; +import android.location.Address; +import android.location.Geocoder; +import android.location.Location; import android.media.ExifInterface; import android.os.Build; import android.os.Looper; @@ -65,6 +69,7 @@ import org.checkerframework.checker.units.qual.A; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.Bitmaps; import org.telegram.messenger.BuildVars; import org.telegram.messenger.DispatchQueue; @@ -81,16 +86,20 @@ import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.messenger.VideoEditedInfo; +import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarPopupWindow; import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.BubbleActivity; +import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.ChatActivityEnterViewAnimatedIconView; +import org.telegram.ui.Components.ChatAttachAlert; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.EmojiView; import org.telegram.ui.Components.IPhotoPaintView; @@ -107,6 +116,7 @@ import org.telegram.ui.Components.Paint.Views.EditTextOutline; import org.telegram.ui.Components.Paint.Views.EntitiesContainerView; import org.telegram.ui.Components.Paint.Views.EntityView; +import org.telegram.ui.Components.Paint.Views.LocationView; import org.telegram.ui.Components.Paint.Views.PaintCancelView; import org.telegram.ui.Components.Paint.Views.PaintColorsListView; import org.telegram.ui.Components.Paint.Views.PaintDoneView; @@ -249,13 +259,18 @@ public void set(float val) { private int w, h; private ColorPickerBottomSheet colorPickerBottomSheet; + private boolean fileFromGallery; + private File file; + private boolean isVideo; @SuppressLint("NotifyDataSetChanged") - public PaintView(Context context, StoryRecorder.WindowView parent, Activity activity, int currentAccount, Bitmap bitmap, Bitmap originalBitmap, int originalRotation, ArrayList entities, int viewWidth, int viewHeight, MediaController.CropState cropState, Runnable onInit, Theme.ResourcesProvider resourcesProvider) { + public PaintView(Context context, boolean fileFromGallery, File file, boolean isVideo, StoryRecorder.WindowView parent, Activity activity, int currentAccount, Bitmap bitmap, Bitmap originalBitmap, int originalRotation, ArrayList entities, int viewWidth, int viewHeight, MediaController.CropState cropState, Runnable onInit, Theme.ResourcesProvider resourcesProvider) { super(context, activity, true); setDelegate(this); + this.fileFromGallery = fileFromGallery; + this.file = file; + this.isVideo = isVideo; this.parent = parent; - this.initialEntities = entities; this.w = viewWidth; this.h = viewHeight; @@ -303,9 +318,10 @@ public int getColor(int key) { return 0xFF878787; } else if (key == Theme.key_chat_emojiSearchBackground) { return 0x2E878787; + } else if (key == Theme.key_windowBackgroundGray) { + return 0xFF0D0D0D; } - if (resourcesProvider != null) { return resourcesProvider.getColor(key); } else { @@ -313,6 +329,11 @@ public int getColor(int key) { } } + @Override + public Paint getPaint(String paintKey) { + return resourcesProvider.getPaint(paintKey); + } + private ColorFilter animatedEmojiColorFilter; @Override @@ -461,43 +482,66 @@ public void onEntityDeselect() { linePaint.setColor(Color.WHITE); } + private int lastStickyX, lastStickyY; + @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); long dt = Math.min(16, System.currentTimeMillis() - lastUpdate); lastUpdate = System.currentTimeMillis(); - boolean drawStickyX = false, drawStickyY = false; + int stickyX = EntityView.STICKY_NONE, stickyY = EntityView.STICKY_NONE; if (currentEntityView != null && currentEntityView.hasTouchDown() && currentEntityView.hasPanned()) { - drawStickyX = currentEntityView.hasStickyX(); - drawStickyY = currentEntityView.hasStickyY(); + stickyX = currentEntityView.getStickyX(); + stickyY = currentEntityView.getStickyY(); + } + if (stickyX != EntityView.STICKY_NONE) { + lastStickyX = stickyX; + } + if (stickyY != EntityView.STICKY_NONE) { + lastStickyY = stickyY; } - if (drawStickyX && stickyXAlpha != 1f) { - stickyXAlpha = Math.min(1f, stickyXAlpha + dt / 150f); + final float STICKY_DURATION = 150; + if (stickyX != EntityView.STICKY_NONE && stickyXAlpha != 1f) { + stickyXAlpha = Math.min(1f, stickyXAlpha + dt / STICKY_DURATION); invalidate(); - } else if (!drawStickyX && stickyXAlpha != 0f) { - stickyXAlpha = Math.max(0f, stickyXAlpha - dt / 150f); + } else if (stickyX == EntityView.STICKY_NONE && stickyXAlpha != 0f) { + stickyXAlpha = Math.max(0f, stickyXAlpha - dt / STICKY_DURATION); invalidate(); } - if (drawStickyY && stickyYAlpha != 1f) { - stickyYAlpha = Math.min(1f, stickyYAlpha + dt / 150f); + if (stickyY != EntityView.STICKY_NONE && stickyYAlpha != 1f) { + stickyYAlpha = Math.min(1f, stickyYAlpha + dt / STICKY_DURATION); invalidate(); - } else if (!drawStickyY && stickyYAlpha != 0f) { - stickyYAlpha = Math.max(0f, stickyYAlpha - dt / 150f); + } else if (stickyY == EntityView.STICKY_NONE && stickyYAlpha != 0f) { + stickyYAlpha = Math.max(0f, stickyYAlpha - dt / STICKY_DURATION); invalidate(); } if (stickyYAlpha != 0f) { linePaint.setAlpha((int) (stickyYAlpha * 0xFF)); - float y = getMeasuredHeight() / 2f; + float y; + if (lastStickyY == EntityView.STICKY_START) { + y = AndroidUtilities.dp(EntityView.STICKY_PADDING_Y_DP); + } else if (lastStickyY == EntityView.STICKY_CENTER) { + y = getMeasuredHeight() / 2f; + } else { + y = getMeasuredHeight() - AndroidUtilities.dp(EntityView.STICKY_PADDING_Y_DP); + } canvas.drawLine(0, y, getMeasuredWidth(), y, linePaint); } if (stickyXAlpha != 0f) { linePaint.setAlpha((int) (stickyXAlpha * 0xFF)); - float x = getMeasuredWidth() / 2f; + float x; + if (lastStickyX == EntityView.STICKY_START) { + x = AndroidUtilities.dp(EntityView.STICKY_PADDING_X_DP); + } else if (lastStickyX == EntityView.STICKY_CENTER) { + x = getMeasuredWidth() / 2f; + } else { + x = getMeasuredWidth() - AndroidUtilities.dp(EntityView.STICKY_PADDING_X_DP); + } canvas.drawLine(x, 0, x, getMeasuredHeight(), linePaint); } } @@ -509,12 +553,17 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { w = entitiesView.getMeasuredWidth(); } if (h <= 0) { - h = entitiesView.getMeasuredWidth(); + h = entitiesView.getMeasuredHeight(); } + setupEntities(); } }; // addView(entitiesView); - setupEntities(); + + this.initialEntities = entities; + if (w > 0 && h > 0) { + setupEntities(); + } entitiesView.setVisibility(INVISIBLE); @@ -1003,6 +1052,8 @@ public void ignore(boolean ignore) { } } }; + + EmojiBottomSheet.savedPosition = 1; } private ObjectAnimator previewViewTranslationAnimator; @@ -1055,6 +1106,37 @@ private void setNewColor(int color) { animator.start(); } + private LocationView createLocationSticker(TLRPC.MessageMedia location, TLRPC.MediaArea mediaArea, boolean select) { + onTextAdd(); + + forceChanges = true; + + Size paintingSize = getPaintingSize(); + Point position = startPositionRelativeToEntity(null); + float w = entitiesView.getMeasuredWidth() <= 0 ? this.w : entitiesView.getMeasuredWidth(); + int maxWidth = (int) w - AndroidUtilities.dp(14 + 26 + 18); + LocationView view = new LocationView(getContext(), position, currentAccount, location, mediaArea, w / 240f, maxWidth, 3, colorSwatch == null ? 0xFFFFFFFF : colorSwatch.color); + if (position.x == entitiesView.getMeasuredWidth() / 2f) { + view.setStickyX(EntityView.STICKY_CENTER); + } + if (position.y == entitiesView.getMeasuredHeight() / 2f) { + view.setStickyY(EntityView.STICKY_CENTER); + } + view.setDelegate(this); + view.setMaxWidth(maxWidth); + entitiesView.addView(view, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); + if (currentCropState != null) { + view.scale(1.0f / currentCropState.cropScale); + view.rotate(-(currentCropState.transformRotation + currentCropState.cropRotate)); + } + + if (select) { + registerRemovalUndo(view); + selectEntity(view, false); + } + return view; + } + private TextPaintView createText(boolean select) { onTextAdd(); @@ -1063,10 +1145,10 @@ private TextPaintView createText(boolean select) { TextPaintView view = new TextPaintView(getContext(), position, (int) (paintingSize.width / 9), "", colorSwatch, selectedTextType); view.getEditText().betterFraming = true; if (position.x == entitiesView.getMeasuredWidth() / 2f) { - view.setHasStickyX(true); + view.setStickyX(EntityView.STICKY_CENTER); } if (position.y == entitiesView.getMeasuredHeight() / 2f) { - view.setHasStickyY(true); + view.setStickyY(EntityView.STICKY_CENTER); } view.setDelegate(this); view.setMaxWidth(w - AndroidUtilities.dp(7 + 7 + 18)); @@ -1190,16 +1272,20 @@ private boolean selectEntity(EntityView entityView, boolean changeOptions) { if (currentEntityView != null) { if (currentEntityView == entityView) { - if (!editingText) { - if (entityView instanceof TextPaintView) { - enteredThroughText = true; - editSelectedTextEntity(); - } else { - showMenuForEntity(currentEntityView); + if (!entityView.hadMultitouch()) { + if (entityView instanceof LocationView) { + ((LocationView) entityView).setType((((LocationView) entityView).getType() + 1) % 4); + } else if (!editingText) { + if (entityView instanceof TextPaintView) { + enteredThroughText = true; + editSelectedTextEntity(); + } else { + showMenuForEntity(currentEntityView); + } + } else if (currentEntityView instanceof TextPaintView) { + AndroidUtilities.showKeyboard(((TextPaintView) currentEntityView).getFocusedView()); + hideEmojiPopup(false); } - } else if (currentEntityView instanceof TextPaintView) { - AndroidUtilities.showKeyboard(((TextPaintView) currentEntityView).getFocusedView()); - hideEmojiPopup(false); } return true; } else { @@ -1508,14 +1594,107 @@ public void onDismissAnimationStart() { onOpenCloseStickersAlert(false); switchTab(wasSelectedIndex); }); - alert.whenSelected(document -> { - forceChanges = true; - appearAnimation(createSticker(null, document, false)); + alert.whenSelected((parentObject, document, isGif) -> { + if (document == alert.locationSticker) { + showLocationAlert(null, (location, area) -> appearAnimation(createLocationSticker(location, area, false))); + } else { + forceChanges = true; + StickerView stickerView = createSticker(parentObject, document, false); + if (isGif) { + stickerView.setScale(1.5f); + } + appearAnimation(stickerView); + } }); alert.show(); onOpenCloseStickersAlert(true); } + private void showLocationAlert(LocationView editingLocationView, Utilities.Callback2 onLocationSelected) { + ChatAttachAlert locationAlert = new ChatAttachAlert(getContext(), new ChatActivity(null) { + @Override + public long getDialogId() { + return 0; + } + + @Override + public Theme.ResourcesProvider getResourceProvider() { + return resourcesProvider; + } + + @Override + public boolean isKeyboardVisible() { + return false; + } + + @Override + public Activity getParentActivity() { + return AndroidUtilities.findActivity(PaintView.this.getContext()); + } + + @Override + public TLRPC.User getCurrentUser() { + return UserConfig.getInstance(currentAccount).getCurrentUser(); + } + + @Override + public boolean isLightStatusBar() { + return false; + } + + @Override + public void didSelectLocation(TLRPC.MessageMedia location, int locationType, boolean notify, int scheduleDate) { + TLRPC.MediaArea mediaArea; + if (location instanceof TLRPC.TL_messageMediaGeo) { + TLRPC.TL_mediaAreaGeoPoint areaGeo = new TLRPC.TL_mediaAreaGeoPoint(); + areaGeo.geo = location.geo; + mediaArea = areaGeo; + } else if (location instanceof TLRPC.TL_messageMediaVenue) { + TLRPC.TL_messageMediaVenue loc = (TLRPC.TL_messageMediaVenue) location; + if (loc.query_id == -1 || loc.query_id == -2) { + TLRPC.TL_mediaAreaGeoPoint areaGeo = new TLRPC.TL_mediaAreaGeoPoint(); + areaGeo.geo = location.geo; + Utilities.globalQueue.postRunnable(() -> { + try { + Geocoder gcd = new Geocoder(ApplicationLoader.applicationContext, LocaleController.getInstance().getCurrentLocale()); + List
addresses = gcd.getFromLocationName(location.title, 1); + if (addresses.size() <= 0) { + return; + } + areaGeo.geo.lat = addresses.get(0).getLatitude(); + areaGeo.geo._long = addresses.get(0).getLongitude(); + } catch (Exception ignore) {} + }); + mediaArea = areaGeo; + } else { + TLRPC.TL_inputMediaAreaVenue areaVenue = new TLRPC.TL_inputMediaAreaVenue(); + areaVenue.query_id = ((TLRPC.TL_messageMediaVenue) location).query_id; + areaVenue.result_id = ((TLRPC.TL_messageMediaVenue) location).result_id; + mediaArea = areaVenue; + } + } else { + return; + } + onLocationSelected.run(location, mediaArea); + } + }, false, true, false, resourcesProvider); + locationAlert.setDelegate(new ChatAttachAlert.ChatAttachViewDelegate() { + @Override + public void didPressedButton(int button, boolean arg, boolean notify, int scheduleDate, boolean forceDocument) { + + } + }); + if (editingLocationView != null && editingLocationView.location != null && editingLocationView.location.geo != null) { + locationAlert.setStoryLocationPicker(editingLocationView.location.geo.lat, editingLocationView.location.geo._long); + } else if (fileFromGallery) { + locationAlert.setStoryLocationPicker(isVideo, file); + } else { + locationAlert.setStoryLocationPicker(); + } + locationAlert.init(); + locationAlert.show(); + } + protected void onOpenCloseStickersAlert(boolean open) {} protected void onTextAdd() {} @@ -1636,8 +1815,10 @@ public void init() { private void setupEntities() { if (initialEntities != null) { - for (int a = 0, N = initialEntities.size(); a < N; a++) { - VideoEditedInfo.MediaEntity entity = initialEntities.get(a); + ArrayList entities = initialEntities; + initialEntities = null; + for (int a = 0, N = entities.size(); a < N; a++) { + VideoEditedInfo.MediaEntity entity = entities.get(a); EntityView view; if (entity.type == VideoEditedInfo.MediaEntity.TYPE_STICKER) { StickerView stickerView = createSticker(entity.parentObject, entity.document, false); @@ -1682,6 +1863,10 @@ private void setupEntities() { ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); layoutParams.width = entity.viewWidth; layoutParams.height = entity.viewHeight; + } else if (entity.type == VideoEditedInfo.MediaEntity.TYPE_LOCATION) { + LocationView locationView = createLocationSticker(entity.mediaGeo, entity.mediaArea, false); + locationView.setType(entity.subType, entity.color); + view = locationView; } else { continue; } @@ -1692,7 +1877,6 @@ private void setupEntities() { view.setScaleY(entity.scale); view.setRotation((float) (-entity.rotation / Math.PI * 180)); } - initialEntities = null; entitiesView.setVisibility(View.VISIBLE); } } @@ -1802,15 +1986,41 @@ public boolean hasChanges() { return undoStore.canUndo() || forceChanges; } + public static boolean isVideoStickerDocument(TLRPC.Document document) { + if (document != null) { + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeSticker || + attribute instanceof TLRPC.TL_documentAttributeCustomEmoji || + attribute instanceof TLRPC.TL_documentAttributeVideo) { + return "video/webm".equals(document.mime_type) || "video/mp4".equals(document.mime_type); + } + } + } + return false; + } + @Override public Bitmap getBitmap(ArrayList entities, Bitmap[] thumbBitmap) { return getBitmap(entities, (int) paintingSize.width, (int) paintingSize.height, true, true); } public Bitmap getBitmap(ArrayList entities, int resultWidth, int resultHeight, boolean drawPaint, boolean drawEntities) { - Bitmap bitmap = drawPaint ? renderView.getResultBitmap() : null; + Bitmap bitmap; + if (drawPaint) { + bitmap = renderView.getResultBitmap(); + } else if (drawEntities) { + Bitmap ref = renderView.getResultBitmap(); + if (ref != null) { + bitmap = Bitmap.createBitmap(ref.getWidth(), ref.getHeight(), Bitmap.Config.ARGB_8888); + } else { + bitmap = null; + } + } else { + bitmap = null; + } lcm = BigInteger.ONE; - if ((bitmap != null || !drawEntities) && entitiesView.entitiesCount() > 0) { + if (entitiesView.entitiesCount() > 0) { Canvas canvas; Canvas thumbCanvas = null; int count = entitiesView.getChildCount(); @@ -1857,7 +2067,7 @@ public Bitmap getBitmap(ArrayList entities, int res } } boolean isAnimatedSticker = MessageObject.isAnimatedStickerDocument(tlentity.document, true); - if (isAnimatedSticker || MessageObject.isVideoStickerDocument(tlentity.document)) { + if (isAnimatedSticker || isVideoStickerDocument(tlentity.document)) { tlentity.subType |= isAnimatedSticker ? 1 : 4; } if (MessageObject.isTextColorEmoji(tlentity.document)) { @@ -1891,11 +2101,11 @@ public Bitmap getBitmap(ArrayList entities, int res mediaEntity.parentObject = stickerView.getParentObject(); TLRPC.Document document = stickerView.getSticker(); mediaEntity.text = FileLoader.getInstance(UserConfig.selectedAccount).getPathToAttach(document, true).getAbsolutePath(); - if (MessageObject.isAnimatedStickerDocument(document, true) || MessageObject.isVideoStickerDocument(document)) { + if (MessageObject.isAnimatedStickerDocument(document, true) || isVideoStickerDocument(document)) { boolean isAnimatedSticker = MessageObject.isAnimatedStickerDocument(document, true); mediaEntity.subType |= isAnimatedSticker ? 1 : 4; long duration; - if (isAnimatedSticker) { + if (isAnimatedSticker || isVideoStickerDocument(document)) { duration = stickerView.getDuration(); } else { duration = 5000; @@ -1918,10 +2128,34 @@ public Bitmap getBitmap(ArrayList entities, int res Size size = photoView.getBaseSize(); mediaEntity.width = size.width; mediaEntity.height = size.height; - mediaEntity.text = photoView.getPath(); + mediaEntity.text = photoView.getPath(currentAccount); if (photoView.isMirrored()) { mediaEntity.subType |= 2; } + } else if (entity instanceof LocationView) { + LocationView locationView = (LocationView) entity; + mediaEntity.type = VideoEditedInfo.MediaEntity.TYPE_LOCATION; + mediaEntity.subType = (byte) locationView.getType(); + mediaEntity.width = locationView.marker.getWidth(); + mediaEntity.height = locationView.marker.getHeight(); + mediaEntity.text = locationView.marker.getText(); + mediaEntity.color = locationView.getColor(); + mediaEntity.density = locationView.marker.density; + mediaEntity.mediaGeo = locationView.location; + mediaEntity.mediaArea = locationView.mediaArea; + mediaEntity.mediaArea.coordinates = new TLRPC.TL_mediaAreaCoordinates(); + TLRPC.Document emojiDocument = locationView.marker.getCountryCodeEmojiDocument(); + if (emojiDocument != null) { + VideoEditedInfo.EmojiEntity tlentity = new VideoEditedInfo.EmojiEntity(); + tlentity.document_id = emojiDocument.id; + tlentity.document = emojiDocument; + tlentity.documentAbsolutePath = FileLoader.getInstance(currentAccount).getPathToAttach(emojiDocument, true).getAbsolutePath(); + boolean isAnimatedSticker = MessageObject.isAnimatedStickerDocument(tlentity.document, true); + if (isAnimatedSticker || isVideoStickerDocument(tlentity.document)) { + tlentity.subType |= isAnimatedSticker ? 1 : 4; + } + mediaEntity.entities.add(tlentity); + } } else { continue; } @@ -1959,6 +2193,12 @@ public Bitmap getBitmap(ArrayList entities, int res mediaEntity.viewWidth = (int) (mediaEntity.viewHeight * a); mediaEntity.x = cx - mediaEntity.width / 2f; } + } else if (entity instanceof LocationView) { + mediaEntity.mediaArea.coordinates.x = (mediaEntity.x + mediaEntity.width / 2f) * 100; + mediaEntity.mediaArea.coordinates.y = (mediaEntity.y + mediaEntity.height / 2f) * 100; + mediaEntity.mediaArea.coordinates.w = (mediaEntity.width - 2 * ((LocationView) entity).marker.padx * scaleX / (float) entitiesView.getMeasuredWidth()) * 100; + mediaEntity.mediaArea.coordinates.h = (mediaEntity.height - 2 * ((LocationView) entity).marker.pady * scaleY / (float) entitiesView.getMeasuredHeight()) * 100; + mediaEntity.mediaArea.coordinates.rotation = -mediaEntity.rotation / Math.PI * 180; } } if (drawEntities && bitmap != null) { @@ -1976,10 +2216,13 @@ public Bitmap getBitmap(ArrayList entities, int res currentCanvas.rotate(v.getRotation(), mediaEntity.width / 2f / v.getScaleX() * entitiesView.getMeasuredWidth(), mediaEntity.height / 2f / v.getScaleY() * entitiesView.getMeasuredHeight()); // currentCanvas.translate(-entity.getWidth() / (float) entitiesView.getMeasuredWidth() * bitmap.getWidth() / 2f, -entity.getHeight() / (float) entitiesView.getMeasuredHeight() * bitmap.getHeight() / 2f); if (v instanceof TextPaintView && v.getHeight() > 0 && v.getWidth() > 0) { - Bitmap b = Bitmaps.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888); + int w = (int) (v.getWidth() * v.getScaleX()), h = (int) (v.getHeight() * v.getScaleY()); + Bitmap b = Bitmaps.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(b); + c.scale(v.getScaleX(), v.getScaleY()); v.draw(c); - currentCanvas.drawBitmap(b, null, new Rect(0, 0, b.getWidth(), b.getHeight()), null); + currentCanvas.scale(1f / v.getScaleX(), 1f / v.getScaleY()); + currentCanvas.drawBitmap(b, null, new Rect(0, 0, w, h), new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG)); try { c.setBitmap(null); } catch (Exception e) { @@ -2443,6 +2686,8 @@ private void setCurrentSwatch(Swatch swatch, boolean updateInterface) { if (currentEntityView instanceof TextPaintView) { ((TextPaintView) currentEntityView).setSwatch(new Swatch(swatch.color, swatch.colorLocation, swatch.brushWeight)); + } else if (currentEntityView instanceof LocationView) { + ((LocationView) currentEntityView).setColor(swatch.color); } } @@ -2739,8 +2984,10 @@ private void showMenuForEntity(final EntityView entityView) { deleteView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); deleteView.setBackground(Theme.getSelectorDrawable(false)); deleteView.setGravity(Gravity.CENTER_VERTICAL); + deleteView.setLines(1); + deleteView.setSingleLine(); deleteView.setEllipsize(TextUtils.TruncateAt.END); - deleteView.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(14), 0); + deleteView.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(14), 0); deleteView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); deleteView.setTag(0); deleteView.setText(LocaleController.getString("PaintDelete", R.string.PaintDelete)); @@ -2758,8 +3005,10 @@ private void showMenuForEntity(final EntityView entityView) { editView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); editView.setBackground(Theme.getSelectorDrawable(false)); editView.setGravity(Gravity.CENTER_VERTICAL); + editView.setLines(1); + editView.setSingleLine(); editView.setEllipsize(TextUtils.TruncateAt.END); - editView.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); + editView.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(14), 0); editView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); if ((keyboardNotifier.keyboardVisible() && !keyboardNotifier.ignoring) || emojiPadding > 0) { editView.setTag(3); @@ -2787,15 +3036,40 @@ private void showMenuForEntity(final EntityView entityView) { }); } parent.addView(editView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 48)); + } else if (entityView instanceof LocationView) { + TextView editView = new TextView(getContext()); + editView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); + editView.setBackground(Theme.getSelectorDrawable(false)); + editView.setGravity(Gravity.CENTER_VERTICAL); + editView.setLines(1); + editView.setSingleLine(); + editView.setEllipsize(TextUtils.TruncateAt.END); + editView.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(14), 0); + editView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + editView.setTag(1); + editView.setText(LocaleController.getString("PaintEdit", R.string.PaintEdit)); + editView.setOnClickListener(v -> { + selectEntity(null); + showLocationAlert((LocationView) entityView, (location, area) -> { + ((LocationView) entityView).setLocation(currentAccount, location, area); + appearAnimation(entityView); + }); + if (popupWindow != null && popupWindow.isShowing()) { + popupWindow.dismiss(true); + } + }); + parent.addView(editView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 48)); } if (entityView instanceof StickerView || entityView instanceof PhotoView) { TextView flipView = new TextView(getContext()); flipView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); flipView.setBackground(Theme.getSelectorDrawable(false)); + flipView.setLines(1); + flipView.setSingleLine(); flipView.setEllipsize(TextUtils.TruncateAt.END); flipView.setGravity(Gravity.CENTER_VERTICAL); - flipView.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); + flipView.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(14), 0); flipView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); flipView.setTag(4); flipView.setText(LocaleController.getString(R.string.Flip)); @@ -2812,13 +3086,15 @@ private void showMenuForEntity(final EntityView entityView) { parent.addView(flipView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 48)); } - if (!(entityView instanceof PhotoView)) { + if (!(entityView instanceof PhotoView) && !(entityView instanceof LocationView)) { TextView duplicateView = new TextView(getContext()); duplicateView.setTextColor(getThemedColor(Theme.key_actionBarDefaultSubmenuItem)); duplicateView.setBackground(Theme.getSelectorDrawable(false)); + duplicateView.setLines(1); + duplicateView.setSingleLine(); duplicateView.setEllipsize(TextUtils.TruncateAt.END); duplicateView.setGravity(Gravity.CENTER_VERTICAL); - duplicateView.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(16), 0); + duplicateView.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(14), 0); duplicateView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); duplicateView.setTag(2); duplicateView.setText(LocaleController.getString("PaintDuplicate", R.string.PaintDuplicate)); @@ -2884,7 +3160,7 @@ private Point startPositionRelativeToEntity(EntityView entityView) { minimalDistance /= currentCropState.cropScale; } Point position = centerPositionForEntity(); - while (true) { + for (int i = 0; i < 10; ++i) { boolean occupied = false; for (int index = 0; index < entitiesView.getChildCount(); index++) { View view = entitiesView.getChildAt(index); @@ -2999,6 +3275,27 @@ private Size basePhotoSize(String path) { } } + private Size basePhotoSize(TLObject obj) { + float a = 1f; + if (obj instanceof TLRPC.Photo) { + TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(((TLRPC.Photo) obj).sizes, 1000); + if (photoSize != null) { + a = (float) photoSize.w / photoSize.h; + } + } else if (obj instanceof TLRPC.Document) { + + } else if (obj instanceof TLRPC.WebDocument) { + + } + if (a > 1) { + float side = (float) Math.floor(Math.max(w, entitiesView.getMeasuredWidth()) * 0.5); + return new Size(side, side / a); + } else { + float side = (float) Math.floor(Math.max(h, entitiesView.getMeasuredHeight()) * 0.5); + return new Size(side * a, side); + } + } + public void appearAnimation(View view) { float scaleX = view.getScaleX(), scaleY = view.getScaleY(); view.setScaleX(scaleX * .5f); @@ -3123,6 +3420,7 @@ private boolean isFaceAnchorOccupied(PhotoFace face, int anchor, long documentId } public PhotoView createPhoto(String path, boolean select) { + forceChanges = true; Size size = basePhotoSize(path); Pair orientation = AndroidUtilities.getImageOrientation(path); if ((orientation.first / 90 % 2) == 1) { @@ -3143,6 +3441,22 @@ public PhotoView createPhoto(String path, boolean select) { return view; } + public PhotoView createPhoto(TLObject obj, boolean select) { + forceChanges = true; + Size size = basePhotoSize(obj); + PhotoView view = new PhotoView(getContext(), centerPositionForEntity(), 0, 1f, size, obj); + view.centerImage.setLayerNum(4 + 8); +// view.setHasStickyX(true); +// view.setHasStickyY(true); + view.setDelegate(this); + entitiesView.addView(view); + if (select) { + registerRemovalUndo(view); + selectEntity(view); + } + return view; + } + private StickerView createSticker(Object parentObject, TLRPC.Document sticker, boolean select) { PaintView.StickerPosition position = calculateStickerPosition(sticker); StickerView view = new StickerView(getContext(), position.position, position.angle, position.scale, baseStickerSize(), sticker, parentObject) { @@ -3229,20 +3543,22 @@ public boolean onEntityLongClicked(EntityView entityView) { return true; } - private final float[] temp = new float[2]; - private final int[] loc = new int[2]; - @Override - public float[] getTransformedTouch(MotionEvent e, float rawX, float rawY) { + public void getTransformedTouch(float rawX, float rawY, float[] output) { View previewView = (View) renderView.getParent(); + if (previewView == null) { + return; + } View containerView = (View) previewView.getParent(); + if (containerView == null) { + return; + } float x = rawX - previewView.getX() - containerView.getLeft(); float y = rawY - previewView.getY() - containerView.getTop(); x = previewView.getPivotX() + (x - previewView.getPivotX()) / previewView.getScaleX(); y = previewView.getPivotY() + (y - previewView.getPivotY()) / previewView.getScaleY(); - temp[0] = x; - temp[1] = y; - return temp; + output[0] = x; + output[1] = y; } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PlayPauseButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PlayPauseButton.java new file mode 100644 index 00000000000..a461a778d06 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PlayPauseButton.java @@ -0,0 +1,61 @@ +package org.telegram.ui.Stories.recorder; + +import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.view.View; + +import androidx.annotation.NonNull; + +import org.telegram.ui.Components.PlayPauseDrawable; + +public class PlayPauseButton extends View { + + private final static int playSizeDp = 10; + + private final Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + public final PlayPauseDrawable drawable = new PlayPauseDrawable(playSizeDp); + + public PlayPauseButton(Context context) { + super(context); + + circlePaint.setColor(0xFFFFFFFF); + circlePaint.setShadowLayer(1, 0, 0, 0x19000000); + circlePaint.setStyle(Paint.Style.STROKE); + + drawable.setCallback(this); + drawable.setColorFilter(new PorterDuffColorFilter(0xFFFFFFFF, PorterDuff.Mode.SRC_IN)); + } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == drawable || super.verifyDrawable(who); + } + + @Override + protected void onDraw(Canvas canvas) { + circlePaint.setStrokeWidth(dpf2(1.66f)); + canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, dp(10), circlePaint); + + drawable.setBounds(0, 0, dp(playSizeDp), dp(playSizeDp)); + canvas.save(); + canvas.translate((getWidth() - dp(playSizeDp)) / 2f, (getHeight() - dp(playSizeDp)) / 2f); + drawable.draw(canvas); + canvas.restore(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(dp(56), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(dp(56), MeasureSpec.EXACTLY) + ); + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewHighlightView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewHighlightView.java index 4b9b18d1ba9..99d4bdb02fc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewHighlightView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewHighlightView.java @@ -11,6 +11,7 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.RectF; +import android.text.SpannableString; import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; @@ -22,6 +23,7 @@ import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Emoji; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; @@ -73,7 +75,9 @@ protected void dispatchDraw(Canvas canvas) { PeerStoriesView.PeerHeaderView headerView = new PeerStoriesView.PeerHeaderView(getContext(), null); headerView.backupImageView.getAvatarDrawable().setInfo(me); headerView.backupImageView.setForUserOrChat(me, headerView.backupImageView.getAvatarDrawable()); - headerView.titleView.setText(UserObject.getUserName(me)); + CharSequence text = UserObject.getUserName(me); + text = Emoji.replaceEmoji(text, headerView.titleView.getPaint().getFontMetricsInt(), false); + headerView.titleView.setText(text); headerView.setSubtitle(LocaleController.getString("RightNow", R.string.RightNow), false); top.addView(headerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 17, 0, 0)); @@ -139,8 +143,8 @@ public void updateCount() { } public void updateCaption(CharSequence caption) { - caption = AnimatedEmojiSpan.cloneSpans(caption); - storyCaptionView.captionTextview.setText(caption); + caption = AnimatedEmojiSpan.cloneSpans(new SpannableString(caption)); + storyCaptionView.captionTextview.setText(caption, false, false); } private boolean shownTop = false, shownBottom = false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewView.java index 7f9f08ff926..3b3ef3adb37 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/PreviewView.java @@ -26,6 +26,7 @@ import android.widget.FrameLayout; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlayer; import com.google.zxing.common.detector.MathUtils; import org.telegram.messenger.AndroidUtilities; @@ -41,6 +42,7 @@ import org.telegram.ui.Components.VideoPlayer; import org.telegram.ui.Components.VideoTimelinePlayView; +import java.io.File; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; @@ -289,7 +291,11 @@ private void setupImage(StoryEntry entry) { return; } if (bitmap == null) { - String path = entry.getOriginalFile().getPath(); + File file = entry.getOriginalFile(); + if (file == null) { + return; + } + String path = file.getPath(); final long imageIdFinal = imageId; bitmap = StoryEntry.getScaledBitmap(opts -> { @@ -536,6 +542,7 @@ public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { if (seekTo > 0) { videoPlayer.seekTo(seekTo); } + videoPlayer.setMute(entry.muted); videoTimelineView.setVideoPath(uri.toString(), entry.left, entry.right); } @@ -1081,4 +1088,12 @@ public void updatePauseReason(int reasonId, boolean pause) { videoPlayer.setPlayWhenReady(pauseLinks.isEmpty()); } } + + // ignores actual player and other reasons to pause a video + public boolean isPlaying() { + return !pauseLinks.contains(-9982); + } + public void play(boolean play) { + updatePauseReason(-9982, !play); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryEntry.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryEntry.java index a368a5b4167..60a10ea929a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryEntry.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryEntry.java @@ -57,10 +57,17 @@ public class StoryEntry extends IStoryPart { public boolean isDraft; public long draftDate; + public long editStoryPeerId; public int editStoryId; public boolean isEdit; + public boolean isEditSaved; public double fileDuration = -1; public boolean editedMedia, editedCaption, editedPrivacy; + public ArrayList editedMediaAreas; + + public long editDocumentId; + public long editPhotoId; + public long editExpireDate; public boolean isVideo; public File file; @@ -81,6 +88,7 @@ public class StoryEntry extends IStoryPart { public int partsMaxId = 1; public final ArrayList parts = new ArrayList<>(); + public static class Part extends IStoryPart { public File file; public boolean fileDeletable; @@ -120,10 +128,11 @@ public void serializeToStream(AbstractSerializedData stream) { public int gradientTopColor, gradientBottomColor; public CharSequence caption; + public boolean captionEntitiesAllowed = true; public StoryPrivacyBottomSheet.StoryPrivacy privacy; public final ArrayList privacyRules = new ArrayList<>(); - public boolean pinned; + public boolean pinned = true; public boolean allowScreenshots; public int period = 86400; @@ -139,6 +148,7 @@ public void serializeToStream(AbstractSerializedData stream) { // paint public File paintFile; + public File paintEntitiesFile; public long averageDuration = 5000; public ArrayList mediaEntities; public List stickers; @@ -162,7 +172,7 @@ public boolean wouldBeVideo() { if (isAnimated(entity.document, entity.text)) { return true; } - } else if (entity.type == VideoEditedInfo.MediaEntity.TYPE_TEXT && entity.entities != null && !entity.entities.isEmpty()) { + } else if ((entity.type == VideoEditedInfo.MediaEntity.TYPE_TEXT/* || entity.type == VideoEditedInfo.MediaEntity.TYPE_LOCATION*/) && entity.entities != null && !entity.entities.isEmpty()) { for (int j = 0; j < entity.entities.size(); ++j) { VideoEditedInfo.EmojiEntity e = entity.entities.get(j); if (isAnimated(e.document, e.documentAbsolutePath)) { @@ -177,7 +187,7 @@ public boolean wouldBeVideo() { private boolean isAnimated(TLRPC.Document document, String path) { return document != null && ( - MessageObject.isAnimatedStickerDocument(document) || + "video/webm".equals(document.mime_type) || "video/mp4".equals(document.mime_type) || MessageObject.isAnimatedStickerDocument(document, true) && RLottieDrawable.getFramesCount(path, null) > 1 ); } @@ -237,6 +247,20 @@ public void buildPhoto(File dest) { } } + if (paintEntitiesFile != null) { + try { + Bitmap paintBitmap = getScaledBitmap(opts -> BitmapFactory.decodeFile(paintEntitiesFile.getPath(), opts), resultWidth, resultHeight, false); + canvas.save(); + float scale = resultWidth / (float) paintBitmap.getWidth(); + canvas.scale(scale, scale); + canvas.drawBitmap(paintBitmap, 0, 0, bitmapPaint); + canvas.restore(); + paintBitmap.recycle(); + } catch (Exception e) { + FileLog.e(e); + } + } + thumbBitmap = Bitmap.createScaledBitmap(finalBitmap, 40, 22, true); try { @@ -295,9 +319,9 @@ public static Bitmap getScaledBitmap(DecodeBitmap decode, int maxWidth, int maxH shader.setLocalMatrix(matrix); canvas.drawRect(0, 0, w, h, paint); - if (allowBlur && blurRadius > 0) { - Utilities.stackBlurBitmap(scaledBitmap, blurRadius); - } +// if (allowBlur && blurRadius > 0) { +// Utilities.stackBlurBitmap(scaledBitmap, blurRadius); +// } return scaledBitmap; } else { @@ -409,6 +433,10 @@ public void clearPaint() { paintFile.delete(); paintFile = null; } + if (paintEntitiesFile != null) { + paintEntitiesFile.delete(); + paintEntitiesFile = null; + } } public void destroy(boolean draft) { @@ -501,6 +529,7 @@ public static StoryEntry fromStoryItem(File file, TLRPC.StoryItem storyItem) { } catch (Exception ignore) {} entry.setupMatrix(); entry.checkStickers(storyItem); + entry.editedMediaAreas = storyItem.media_areas; return entry; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java index 18d1a99b2e1..56c41c453ae 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryPrivacyBottomSheet.java @@ -22,6 +22,7 @@ import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Build; import android.text.Editable; import android.text.InputType; import android.text.SpannableString; @@ -114,6 +115,7 @@ import org.telegram.ui.Components.StickerEmptyView; import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.ViewPagerFixed; +import org.telegram.ui.Stories.StoriesController; import org.telegram.ui.UsersSelectActivity; import java.util.ArrayList; @@ -136,7 +138,9 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification private static final int PAGE_TYPE_CLOSE_FRIENDS = 1; private static final int PAGE_TYPE_EXCLUDE_CONTACTS = 2; private static final int PAGE_TYPE_SELECT_CONTACTS = 3; + private static final int PAGE_TYPE_EXCLUDE_EVERYONE = 4; private static final int PAGE_TYPE_SEND_AS_MESSAGE = 5; + private static final int PAGE_TYPE_BLOCKLIST = 6; public static final int TYPE_CLOSE_FRIENDS = 1; public static final int TYPE_CONTACTS = 2; @@ -144,6 +148,10 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification public static final int TYPE_EVERYONE = 4; public static final int TYPE_AS_MESSAGE = 5; + private final ArrayList excludedEveryone = new ArrayList<>(); + private final HashMap> excludedEveryoneByGroup = new HashMap<>(); + private int excludedEveryoneCount = 0; + private final ArrayList excludedContacts = new ArrayList<>(); private final ArrayList selectedContacts = new ArrayList<>(); private final HashMap> selectedContactsByGroup = new HashMap<>(); @@ -177,6 +185,7 @@ private HashSet mergeUsers(ArrayList users, HashMap changelog = new LongSparseArray<>(); private final ArrayList selectedUsers = new ArrayList<>(); private final HashMap> selectedUsersByGroup = new HashMap<>(); @@ -317,6 +326,13 @@ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { } contentView.invalidate(); containerView.invalidate(); + + if (pageType == PAGE_TYPE_BLOCKLIST && listView.getChildCount() > 0) { + int position = listView.getChildAdapterPosition(listView.getChildAt(0)); + if (position >= MessagesController.getInstance(currentAccount).getStoriesController().blocklist.size()) { + MessagesController.getInstance(currentAccount).getStoriesController().loadBlocklist(false); + } + } } @Override @@ -358,6 +374,14 @@ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newStat selectedType = TYPE_CONTACTS; updateCheckboxes(true); return; + } else if (item.type == TYPE_EVERYONE) { + if (selectedType == TYPE_EVERYONE) { + activePage = PAGE_TYPE_EXCLUDE_EVERYONE; + viewPager.scrollToPosition(1); + } + selectedType = TYPE_EVERYONE; + updateCheckboxes(true); + return; } if (item.type > 0) { selectedUsers.clear(); @@ -378,6 +402,12 @@ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newStat .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) .show(); } else if (selectedUsersByGroup.containsKey(id)) { + ArrayList userIds = selectedUsersByGroup.get(id); + if (userIds != null) { + for (long userId : userIds) { + changelog.put(userId, false); + } + } selectedUsersByGroup.remove(id); updateSpans(true); } else { @@ -426,7 +456,7 @@ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newStat participantsObj.participants.add(chatParticipant); } selectChat(id, participantsObj); - }); + }, 200); } else { MessagesController.getInstance(currentAccount).loadFullChat(id, 0, true); } @@ -458,6 +488,7 @@ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newStat } } userIds.remove(id); + changelog.put(id, false); } else { Iterator>> iterator = selectedUsersByGroup.entrySet().iterator(); while (iterator.hasNext()) { @@ -473,13 +504,14 @@ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newStat query = null; updateItems(false); } + changelog.put(id, true); } selectedUsers.clear(); selectedUsers.addAll(userIds); updateSpans(true); } - updateButton(true); updateCheckboxes(true); + updateButton(true); searchField.scrollToBottom(); } else if (item.viewType == VIEW_TYPE_CHECK) { if (!(view instanceof TextCell)) { @@ -690,6 +722,9 @@ private void selectChat(long id, TLRPC.ChatParticipants participants) { .setMessage(nonContactsUsers.size() + " members are not in your contact list") .setPositiveButton("Add " + groupUsers.size() + " contacts", (di, a) -> { selectedUsersByGroup.put(id, groupUsers); + for (long userId : groupUsers) { + changelog.put(userId, true); + } updateSpans(true); updateButton(true); updateCheckboxes(true); @@ -701,6 +736,9 @@ private void selectChat(long id, TLRPC.ChatParticipants participants) { } } else { selectedUsersByGroup.put(id, groupUsers); + for (long userId : groupUsers) { + changelog.put(userId, true); + } updateSpans(true); updateButton(true); updateCheckboxes(true); @@ -712,6 +750,8 @@ private void updateSpans(boolean animated) { HashSet userIds = mergeUsers(selectedUsers, selectedUsersByGroup); if (pageType == PAGE_TYPE_SELECT_CONTACTS) { selectedContactsCount = userIds.size(); + } else if (pageType == PAGE_TYPE_EXCLUDE_EVERYONE) { + excludedEveryoneCount = userIds.size(); } final MessagesController messagesController = MessagesController.getInstance(currentAccount); @@ -807,6 +847,13 @@ private void onButton1Click(View v) { privacy.selectedUserIdsByGroup.putAll(selectedContactsByGroup); } else if (selectedType == TYPE_CONTACTS) { privacy = new StoryPrivacy(selectedType, currentAccount, excludedContacts); + } else if (selectedType == TYPE_EVERYONE) { + HashSet users = mergeUsers(excludedEveryone, excludedEveryoneByGroup); + privacy = new StoryPrivacy(selectedType, currentAccount, new ArrayList<>(users)); + privacy.selectedUserIds.clear(); + privacy.selectedUserIds.addAll(excludedEveryone); + privacy.selectedUserIdsByGroup.clear(); + privacy.selectedUserIdsByGroup.putAll(excludedEveryoneByGroup); } else { privacy = new StoryPrivacy(selectedType, currentAccount, null); } @@ -847,6 +894,14 @@ private void onButton1Click(View v) { closeKeyboard(); viewPager.scrollToPosition(0); } + } else if (pageType == PAGE_TYPE_BLOCKLIST) { + HashSet users = mergeUsers(selectedUsers, selectedUsersByGroup); + button.setLoading(true); + MessagesController.getInstance(currentAccount).getStoriesController().updateBlockedUsers(users, () -> { + button.setLoading(false); + closeKeyboard(); + viewPager.scrollToPosition(0); + }); } else { selectedType = pageType; closeKeyboard(); @@ -885,9 +940,13 @@ public float top() { public void bind(int pageType) { this.pageType = pageType; + changelog.clear(); selectedUsers.clear(); selectedUsersByGroup.clear(); - if (pageType == PAGE_TYPE_SEND_AS_MESSAGE) { + if (pageType == PAGE_TYPE_EXCLUDE_EVERYONE) { + selectedUsers.addAll(excludedEveryone); + selectedUsersByGroup.putAll(excludedEveryoneByGroup); + } else if (pageType == PAGE_TYPE_SEND_AS_MESSAGE) { selectedUsers.addAll(messageUsers); } else if (pageType == PAGE_TYPE_CLOSE_FRIENDS) { ArrayList closeFriends = getCloseFriends(); @@ -899,6 +958,8 @@ public void bind(int pageType) { } else if (pageType == PAGE_TYPE_SELECT_CONTACTS) { selectedUsers.addAll(selectedContacts); selectedUsersByGroup.putAll(selectedContactsByGroup); + } else if (pageType == PAGE_TYPE_BLOCKLIST) { + applyBlocklist(false); } layoutManager.setReverseLayout(adapter.reversedLayout = pageType == PAGE_TYPE_SHARE); updateSpans(false); @@ -914,6 +975,33 @@ public void bind(int pageType) { lastSelectedType = -1; } + public void applyBlocklist(boolean notify) { + if (pageType != PAGE_TYPE_BLOCKLIST) { + return; + } + + selectedUsers.clear(); + HashSet blocklist = MessagesController.getInstance(currentAccount).getStoriesController().blocklist; + selectedUsers.addAll(blocklist); + for (int i = 0; i < changelog.size(); ++i) { + long id = changelog.keyAt(i); + boolean blocked = changelog.valueAt(i); + if (blocked) { + if (!selectedUsers.contains(id)) { + selectedUsers.add(id); + } + } else { + selectedUsers.remove(id); + } + } + + if (notify) { + updateItems(true); + updateButton(true); + updateCheckboxes(true); + } + } + private String query; private ArrayList atTop = new ArrayList<>(); @@ -930,6 +1018,7 @@ public void updateItems(boolean animated, boolean notify) { float h = 0; if (pageType == PAGE_TYPE_SHARE) { + ItemInner item; containsHeader = false; sectionCell.setVisibility(View.GONE); // items.add(ItemInner.asPad(dp(84) + 4 * dp(56) + (sendAsMessageEnabled ? dp(120) : dp(64)))); @@ -941,8 +1030,19 @@ public void updateItems(boolean animated, boolean notify) { LocaleController.formatPluralString("StoryPrivacyAlertSubtitle", storyPeriod / 3600) : LocaleController.getString("StoryPrivacyAlertSubtitleProfile", R.string.StoryPrivacyAlertSubtitleProfile) )); - items.add(ItemInner.asType(TYPE_EVERYONE, selectedType == TYPE_EVERYONE)); - ItemInner item; + items.add(item = ItemInner.asType(TYPE_EVERYONE, selectedType == TYPE_EVERYONE, excludedEveryoneCount)); + if (excludedEveryoneCount == 1) { + if (excludedEveryone.size() == 1) { + item.user = MessagesController.getInstance(currentAccount).getUser(excludedEveryone.get(0)); + } else { + for (ArrayList userIds : excludedEveryoneByGroup.values()) { + if (userIds.size() >= 1) { + item.user = MessagesController.getInstance(currentAccount).getUser(userIds.get(0)); + break; + } + } + } + } items.add(item = ItemInner.asType(TYPE_CONTACTS, selectedType == TYPE_CONTACTS, excludedContacts.size())); if (excludedContacts.size() == 1) { item.user = MessagesController.getInstance(currentAccount).getUser(excludedContacts.get(0)); @@ -965,11 +1065,22 @@ public void updateItems(boolean animated, boolean notify) { } } } + int blocklistCount = MessagesController.getInstance(currentAccount).getStoriesController().getBlocklistCount(); + items.add(ItemInner.asShadow(AndroidUtilities.replaceSingleTag( + blocklistCount <= 0 ? + LocaleController.getString("StoryBlockListEmpty") : + LocaleController.formatPluralString("StoryBlockList", blocklistCount), + Theme.key_chat_messageLinkIn, 0, + () -> { + activePage = PAGE_TYPE_BLOCKLIST; + viewPager.scrollToPosition(1); + }, + resourcesProvider + ))); if (!isEdit) { - items.add(ItemInner.asShadow(null)); items.add(ItemInner.asCheck(LocaleController.getString(R.string.StoryAllowScreenshots), 0, allowScreenshots)); items.add(ItemInner.asCheck(LocaleController.getString(R.string.StoryKeep), 1, keepOnMyPage)); - items.add(ItemInner.asShadow(LocaleController.formatPluralString("StoryKeepInfo", storyPeriod / 3600))); + items.add(ItemInner.asShadow(LocaleController.formatPluralString("StoryKeepInfo", (storyPeriod == Integer.MAX_VALUE ? 86400 : storyPeriod) / 3600))); } } else if (pageType == PAGE_TYPE_CLOSE_FRIENDS) { headerView.setText(LocaleController.getString("StoryPrivacyAlertCloseFriendsTitle", R.string.StoryPrivacyAlertCloseFriendsTitle)); @@ -1031,6 +1142,36 @@ public void updateItems(boolean animated, boolean notify) { sectionCell.setText(LocaleController.getString("StoryPrivacyAlertAsMessageSubtitle", R.string.StoryPrivacyAlertAsMessageSubtitle)); updateSectionCell(animated); containsHeader = true; + } else if (pageType == PAGE_TYPE_BLOCKLIST) { + headerView.setText(LocaleController.getString("StoryPrivacyAlertBlocklistTitle", R.string.StoryPrivacyAlertBlocklistTitle)); + headerView.setCloseImageVisible(true); + headerView.backDrawable.setRotation(0f, false); + items.add(ItemInner.asPad()); + items.add(ItemInner.asHeader()); + h += dp(56); + searchPosition = items.size(); + items.add(ItemInner.asSearchField()); + h += dp(150); + items.add(ItemInner.asSection()); + h += dp(32); + sectionCell.setText(LocaleController.getString("StoryPrivacyAlertBlocklistSubtitle", R.string.StoryPrivacyAlertBlocklistSubtitle)); + updateSectionCell(animated); + containsHeader = true; + } else if (pageType == PAGE_TYPE_EXCLUDE_EVERYONE) { + headerView.setText(LocaleController.getString("StoryPrivacyAlertExcludeFromEveryoneTitle", R.string.StoryPrivacyAlertExcludeFromEveryoneTitle)); + headerView.setCloseImageVisible(true); + headerView.backDrawable.setRotation(0f, false); + items.add(ItemInner.asPad()); + items.add(ItemInner.asHeader()); + h += dp(56); + searchPosition = items.size(); + items.add(ItemInner.asSearchField()); + h += dp(150); + items.add(ItemInner.asSection()); + h += dp(32); + sectionCell.setText(LocaleController.getString("StoryPrivacyAlertExcludeFromEveryoneSubtitle", R.string.StoryPrivacyAlertExcludeFromEveryoneSubtitle)); + updateSectionCell(animated); + containsHeader = true; } boolean searching = !TextUtils.isEmpty(query); @@ -1041,8 +1182,9 @@ public void updateItems(boolean animated, boolean notify) { if (pageType == PAGE_TYPE_SEND_AS_MESSAGE) { allOtherUsers = getChats(); } else { - allOtherUsers = getUsers(pageType == PAGE_TYPE_CLOSE_FRIENDS || pageType == PAGE_TYPE_EXCLUDE_CONTACTS, allowSmallChats && pageType == PAGE_TYPE_SELECT_CONTACTS); + allOtherUsers = getUsers(pageType == PAGE_TYPE_CLOSE_FRIENDS || pageType == PAGE_TYPE_EXCLUDE_CONTACTS, allowSmallChats && (pageType == PAGE_TYPE_SELECT_CONTACTS || pageType == PAGE_TYPE_BLOCKLIST)); } + HashSet allSelectedUsers = mergeUsers(selectedUsers, selectedUsersByGroup); if (!searching) { if (!animated) { atTop.clear(); @@ -1065,12 +1207,14 @@ public void updateItems(boolean animated, boolean notify) { TLObject object = atTop.get(i); if (object instanceof TLRPC.User) { TLRPC.User user = (TLRPC.User) object; - items.add(ItemInner.asUser(user, selectedUsers.contains(user.id)).red(pageType == PAGE_TYPE_EXCLUDE_CONTACTS)); + final boolean checked = selectedUsers.contains(user.id); + final boolean halfChecked = !checked && allSelectedUsers.contains(user.id); + items.add(ItemInner.asUser(user, checked, halfChecked).red(pageType == PAGE_TYPE_EXCLUDE_CONTACTS || pageType == PAGE_TYPE_EXCLUDE_EVERYONE)); h += dp(56); count++; } else if (object instanceof TLRPC.Chat) { TLRPC.Chat chat = (TLRPC.Chat) object; - items.add(ItemInner.asChat(chat, selectedUsersByGroup.containsKey(chat.id)).red(pageType == PAGE_TYPE_EXCLUDE_CONTACTS)); + items.add(ItemInner.asChat(chat, selectedUsersByGroup.containsKey(chat.id)).red(pageType == PAGE_TYPE_EXCLUDE_CONTACTS || pageType == PAGE_TYPE_EXCLUDE_EVERYONE)); h += dp(56); count++; } @@ -1083,12 +1227,14 @@ public void updateItems(boolean animated, boolean notify) { } if (object instanceof TLRPC.User) { TLRPC.User user = (TLRPC.User) object; - items.add(ItemInner.asUser(user, selectedUsers.contains(user.id)).red(pageType == PAGE_TYPE_EXCLUDE_CONTACTS)); + final boolean checked = selectedUsers.contains(user.id); + final boolean halfChecked = !checked && allSelectedUsers.contains(user.id); + items.add(ItemInner.asUser(user, checked, halfChecked).red(pageType == PAGE_TYPE_EXCLUDE_CONTACTS || pageType == PAGE_TYPE_EXCLUDE_EVERYONE)); h += dp(56); count++; } else if (object instanceof TLRPC.Chat) { TLRPC.Chat chat = (TLRPC.Chat) object; - items.add(ItemInner.asChat(chat, selectedUsersByGroup.containsKey(chat.id)).red(pageType == PAGE_TYPE_EXCLUDE_CONTACTS)); + items.add(ItemInner.asChat(chat, selectedUsersByGroup.containsKey(chat.id)).red(pageType == PAGE_TYPE_EXCLUDE_CONTACTS || pageType == PAGE_TYPE_EXCLUDE_EVERYONE)); h += dp(56); count++; } @@ -1327,6 +1473,41 @@ public void updateButton(boolean animated) { // button.setText(LocaleController.formatPluralString("StoryPrivacyButtonMessageChats", selectedUsers.size()), animated); button.setCount(selectedUsers.size(), animated); button2.setVisibility(View.GONE); + } else if (pageType == PAGE_TYPE_BLOCKLIST) { + button.setShowZero(false); + button.setEnabled(true); // button.setEnabled(!selectedUsers.isEmpty()); + button.setText(LocaleController.getString("StoryPrivacyButtonSaveCloseFriends", R.string.StoryPrivacyButtonSaveCloseFriends), animated); + StoriesController storiesController = MessagesController.getInstance(currentAccount).getStoriesController(); + if (storiesController.blocklistFull) { + button.setCount(selectedUsers.size(), animated); + } else { + int count = storiesController.getBlocklistCount(); + for (int i = 0; i < changelog.size(); ++i) { + long id = changelog.keyAt(i); + boolean block = changelog.valueAt(i); + if (storiesController.blocklist.contains(id)) { + if (!block) { + count--; + } + } else { + if (block) { + count++; + } else { + count--; + } + } + } + } + button2.setVisibility(View.GONE); + } else if (pageType == PAGE_TYPE_EXCLUDE_EVERYONE) { + int count = excludedEveryoneCount = mergeUsers(excludedEveryone, excludedEveryoneByGroup).size(); +// button.setText(LocaleController.formatPluralString("StoryPrivacyButtonContacts", count), animated); + button.setText(LocaleController.getString("StoryPrivacyButtonSave"), animated); + button.setShowZero(false); + buttonContainer.hide(false, animated); + button.setCount(count, animated); + button.setEnabled(true); + button2.setVisibility(View.GONE); } } @@ -1335,7 +1516,15 @@ private void updateSectionCell(boolean animated) { return; } if (mergeUsers(selectedUsers, selectedUsersByGroup).size() > 0) { - sectionCell.setRightText(LocaleController.getString(R.string.DeselectAll), true, v -> { + sectionCell.setRightText(LocaleController.getString(R.string.UsersDeselectAll), true, v -> { + for (long userId : selectedUsers) { + changelog.put(userId, false); + } + for (ArrayList userIds : selectedUsersByGroup.values()) { + for (long userId : userIds) { + changelog.put(userId, false); + } + } selectedUsers.clear(); selectedUsersByGroup.clear(); messageUsers.clear(); @@ -1355,7 +1544,12 @@ private void updateSectionCell(boolean animated) { private int lastSelectedType = -1; public void updateCheckboxes(boolean animated) { - if (pageType == PAGE_TYPE_EXCLUDE_CONTACTS) { + if (pageType == PAGE_TYPE_EXCLUDE_EVERYONE) { + excludedEveryone.clear(); + excludedEveryoneByGroup.clear(); + excludedEveryone.addAll(selectedUsers); + excludedEveryoneByGroup.putAll(selectedUsersByGroup); + } else if (pageType == PAGE_TYPE_EXCLUDE_CONTACTS) { excludedContacts.clear(); excludedContacts.addAll(selectedUsers); } else if (pageType == PAGE_TYPE_SELECT_CONTACTS) { @@ -1377,15 +1571,20 @@ public void updateCheckboxes(boolean animated) { } } + HashSet allSelectedUsers = mergeUsers(selectedUsers, selectedUsersByGroup); + for (int position = 0; position < items.size(); ++position) { ItemInner item = items.get(position); if (item != null) { if (item.type > 0) { item.checked = selectedType == item.type; + item.halfChecked = false; } else if (item.user != null) { item.checked = selectedUsers.contains(item.user.id); + item.halfChecked = !item.checked && allSelectedUsers.contains(item.user.id); } else if (item.chat != null) { item.checked = selectedUsersByGroup.containsKey(item.chat.id); + item.halfChecked = false; } } } @@ -1394,11 +1593,13 @@ public void updateCheckboxes(boolean animated) { View child = listView.getChildAt(i); if (child instanceof UserCell) { int position = listView.getChildAdapterPosition(child); - if (position < 0 || position >= items.size()) { + if (position < 0 || position >= items.size() || !(child instanceof UserCell)) { continue; } ItemInner item = items.get(position); - ((UserCell) child).setChecked(item.checked, animated); + UserCell cell = (UserCell) child; + cell.setChecked(item.checked || item.halfChecked, animated); + cell.setCheckboxAlpha(item.halfChecked && !item.checked ? .5f : 1f, animated); } } @@ -1450,7 +1651,7 @@ public int getTypeOn(MotionEvent e) { return -1; } ItemInner item = items.get(position); - if (item.viewType != VIEW_TYPE_USER || item.type == TYPE_EVERYONE) { + if (item.viewType != VIEW_TYPE_USER) { return -1; } if (LocaleController.isRTL ? e.getX() < getWidth() - AndroidUtilities.dp(100) : e.getX() > AndroidUtilities.dp(100)) { @@ -1618,12 +1819,14 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi UserCell userCell = (UserCell) holder.itemView; if (item.type > 0) { userCell.setType(item.type, item.typeCount, item.user); + userCell.setCheckboxAlpha(1f, false); } else if (item.user != null) { userCell.setUser(item.user); + userCell.setCheckboxAlpha(item.halfChecked && !item.checked ? .5f : 1f, false); } else if (item.chat != null) { userCell.setChat(item.chat, getParticipantsCount(item.chat)); } - userCell.setChecked(item.checked, false); + userCell.setChecked(item.checked || item.halfChecked, false); userCell.setDivider(divider); userCell.setRedCheckbox(item.red); } else if (viewType == VIEW_TYPE_SECTION) { @@ -1739,6 +1942,7 @@ public int getTopOffset(int tag) { }); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.contactsDidLoad); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.storiesBlocklistUpdate); backgroundPaint.setColor(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); fixNavigationBar(Theme.getColor(Theme.key_dialogBackground, resourcesProvider)); @@ -1762,7 +1966,15 @@ protected boolean canScroll(MotionEvent e) { int page = ((Page) currentView).getTypeOn(e); if (page != -1) { activePage = page; - if (page != TYPE_SELECTED_CONTACTS || !selectedContacts.isEmpty() && !selectedContactsByGroup.isEmpty()) { + if (page == TYPE_SELECTED_CONTACTS) { + if (!selectedContacts.isEmpty() && !selectedContactsByGroup.isEmpty()) { + selectedType = page; + } + } else if (page == TYPE_EVERYONE) { + if (!excludedEveryone.isEmpty() && !excludedEveryoneByGroup.isEmpty()) { + selectedType = page; + } + } else { selectedType = page; } ((Page) currentView).updateCheckboxes(true); @@ -1790,6 +2002,7 @@ protected void onItemSelected(View currentPage, View oldPage, int position, int @Override public void dismissInternal() { NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.contactsDidLoad); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storiesBlocklistUpdate); super.dismissInternal(); } @@ -1901,6 +2114,13 @@ public void dismiss() { privacy.selectedUserIds.addAll(selectedContacts); privacy.selectedUserIdsByGroup.clear(); privacy.selectedUserIdsByGroup.putAll(selectedContactsByGroup); + } else if (selectedType == TYPE_EVERYONE) { + HashSet users = mergeUsers(excludedEveryone, excludedEveryoneByGroup); + privacy = new StoryPrivacy(selectedType, currentAccount, new ArrayList<>(users)); + privacy.selectedUserIds.clear(); + privacy.selectedUserIds.addAll(excludedEveryone); + privacy.selectedUserIdsByGroup.clear(); + privacy.selectedUserIdsByGroup.putAll(excludedEveryoneByGroup); } else if (selectedType == TYPE_CONTACTS) { privacy = new StoryPrivacy(selectedType, currentAccount, excludedContacts); } else { @@ -2058,6 +2278,12 @@ public StoryPrivacyBottomSheet setValue(StoryPrivacy privacy) { selectedContactsByGroup.clear(); selectedContactsByGroup.putAll(privacy.selectedUserIdsByGroup); selectedContactsCount = mergeUsers(selectedContacts, selectedContactsByGroup).size(); + } else if (selectedType == TYPE_EVERYONE) { + excludedEveryone.clear(); + excludedEveryone.addAll(privacy.selectedUserIds); + excludedEveryoneByGroup.clear(); + excludedEveryoneByGroup.putAll(privacy.selectedUserIdsByGroup); + excludedEveryoneCount = mergeUsers(excludedEveryone, excludedEveryoneByGroup).size(); } if (privacy.isShare()) { startedFromSendAsMessage = true; @@ -2096,6 +2322,7 @@ private static class ItemInner extends AdapterWithDiffUtils.Item { public int type; public int typeCount; public boolean checked; + public boolean halfChecked; public boolean red; public int subtractHeight; public int padHeight = -1; @@ -2128,10 +2355,11 @@ public static ItemInner asSection() { ItemInner item = new ItemInner(VIEW_TYPE_SECTION, false); return item; } - public static ItemInner asUser(TLRPC.User user, boolean checked) { + public static ItemInner asUser(TLRPC.User user, boolean checked, boolean halfChecked) { ItemInner item = new ItemInner(VIEW_TYPE_USER, true); item.user = user; item.checked = checked; + item.halfChecked = halfChecked; return item; } public static ItemInner asChat(TLRPC.Chat chat, boolean checked) { @@ -2251,23 +2479,18 @@ private ArrayList getUsers(boolean onlyContacts, boolean includeSmallC final HashMap contains = new HashMap<>(); final ArrayList users = new ArrayList<>(); final ArrayList dialogs = messagesController.getAllDialogs(); - final ConcurrentHashMap contacts; - if (onlyContacts) { - contacts = ContactsController.getInstance(currentAccount).contactsDict; - if (contacts == null || contacts.isEmpty()) { - if (!loadedContacts) { - ContactsController.getInstance(currentAccount).loadContacts(false, 0); - } - loadedContacts = true; + final ConcurrentHashMap contacts = ContactsController.getInstance(currentAccount).contactsDict; + if (contacts == null || contacts.isEmpty()) { + if (!loadedContacts) { + ContactsController.getInstance(currentAccount).loadContacts(false, 0); } - } else { - contacts = null; + loadedContacts = true; } for (int i = 0; i < dialogs.size(); ++i) { TLRPC.Dialog dialog = dialogs.get(i); if (DialogObject.isUserDialog(dialog.id)) { TLRPC.User user = messagesController.getUser(dialog.id); - if (user != null && !user.bot && user.id != 777000 && !UserObject.isUserSelf(user)) { + if (user != null && !user.bot && user.id != 777000 && !UserObject.isUserSelf(user) && !user.deleted) { if (onlyContacts && (contacts == null || contacts.get(user.id) == null)) { continue; } @@ -2279,11 +2502,11 @@ private ArrayList getUsers(boolean onlyContacts, boolean includeSmallC if (chat == null || ChatObject.isForum(chat) || ChatObject.isChannelAndNotMegaGroup(chat)) { continue; } - int participants_count = getParticipantsCount(chat); - if (participants_count > 1) { +// int participants_count = getParticipantsCount(chat); +// if (participants_count > 1) { contains.put(-chat.id, true); users.add(chat); - } +// } } } if (contacts != null) { @@ -2406,6 +2629,24 @@ public void setChecked(boolean checked, boolean animated) { } } + public void setCheckboxAlpha(float alpha, boolean animated) { + if (animated) { + if (Math.abs(checkBox.getAlpha() - alpha) > .1) { + checkBox.animate().cancel(); + checkBox.animate().alpha(alpha).start(); + } + if (Math.abs(radioButton.getAlpha() - alpha) > .1) { + radioButton.animate().cancel(); + radioButton.animate().alpha(alpha).start(); + } + } else { + checkBox.animate().cancel(); + checkBox.setAlpha(alpha); + radioButton.animate().cancel(); + radioButton.setAlpha(alpha); + } + } + private boolean[] isOnline = new boolean[1]; public void setUser(TLRPC.User user) { @@ -2461,8 +2702,8 @@ public void setChat(TLRPC.Chat chat, int participants_count) { subtitleTextView.setTextColor(Theme.getColor(isOnline[0] ? Theme.key_dialogTextBlue2 : Theme.key_dialogTextGray3, resourcesProvider)); checkBox.setVisibility(View.VISIBLE); - checkBox.setAlpha(participants_count > 200 ? .3f : 1f); radioButton.setVisibility(View.GONE); + setCheckboxAlpha(participants_count > 200 ? .3f : 1f, false); } private CharSequence withArrow(CharSequence text) { @@ -2479,7 +2720,16 @@ private CharSequence withArrow(CharSequence text) { public void setType(int type, int count, TLRPC.User singleUser) { if (type == TYPE_EVERYONE) { titleTextView.setText(LocaleController.getString("StoryPrivacyOptionEveryone", R.string.StoryPrivacyOptionEveryone)); - setSubtitle(null); + if (count == 1 && singleUser != null) { + CharSequence text = LocaleController.formatString(R.string.StoryPrivacyOptionExcludePerson, UserObject.getUserName(singleUser)); + text = Emoji.replaceEmoji(text, subtitleTextView.getPaint().getFontMetricsInt(), false); + setSubtitle(withArrow(text)); + } else if (count > 0) { + setSubtitle(withArrow(LocaleController.formatPluralString("StoryPrivacyOptionExcludePeople", count))); + } else { + setSubtitle(withArrow(LocaleController.getString("StoryPrivacyOptionContactsDetail", R.string.StoryPrivacyOptionContactsDetail))); + } + subtitleTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlue2, resourcesProvider)); avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_FILTER_CHANNELS); avatarDrawable.setColor(0xFF16A5F2, 0xFF1180F7); } else if (type == TYPE_CONTACTS) { @@ -2717,6 +2967,9 @@ public boolean onTouchEvent(MotionEvent event) { return super.onTouchEvent(event); } }; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { + editText.setRevealOnFocusHint(false); + } editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); editText.setHintColor(Theme.getColor(Theme.key_groupcreate_hintText, resourcesProvider)); editText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); @@ -2756,33 +3009,38 @@ public void afterTextChanged(Editable s) { } } }); - editText.setOnKeyListener(new OnKeyListener() { - boolean wasEmpty; - @Override - public boolean onKey(View v, int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_DEL) { - if (event.getAction() == KeyEvent.ACTION_DOWN) { - wasEmpty = editText.length() == 0; - } else if (event.getAction() == KeyEvent.ACTION_UP && wasEmpty) { - if (!allSpans.isEmpty()) { - GroupCreateSpan lastSpan = allSpans.get(allSpans.size() - 1); - if (lastSpan == null) { - return false; - } - View[] viewPages = viewPager.getViewPages(); - if (viewPages[0] instanceof Page) { - ((Page) viewPages[0]).onClick(lastSpan); - } - if (viewPages[1] instanceof Page) { - ((Page) viewPages[1]).onClick(lastSpan); - } - return true; - } - } - } - return false; - } - }); +// editText.setOnKeyListener(new OnKeyListener() { +// boolean wasEmpty; +// @Override +// public boolean onKey(View v, int keyCode, KeyEvent event) { +// if (keyCode == KeyEvent.KEYCODE_DEL) { +// if (event.getAction() == KeyEvent.ACTION_DOWN) { +// wasEmpty = editText.length() == 0; +// } else if (event.getAction() == KeyEvent.ACTION_UP && wasEmpty) { +// if (!allSpans.isEmpty()) { +// GroupCreateSpan lastSpan = allSpans.get(allSpans.size() - 1); +// if (lastSpan == null) { +// return false; +// } +// View[] viewPages = viewPager.getViewPages(); +// if (viewPages[0] instanceof Page) { +// ((Page) viewPages[0]).onClick(lastSpan); +// } +// if (viewPages[1] instanceof Page) { +// ((Page) viewPages[1]).onClick(lastSpan); +// } +// return true; +// } +// } +// } +// return false; +// } +// }); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + return super.dispatchKeyEvent(event); } private final AnimatedFloat topGradientAlpha = new AnimatedFloat(this, 0, 300, CubicBezierInterpolator.EASE_OUT_QUINT); @@ -2829,11 +3087,6 @@ protected void dispatchDraw(Canvas canvas) { canvas.restore(); } - @Override - public void requestChildFocus(View child, View focused) { - - } - @Override public boolean dispatchTouchEvent(MotionEvent ev) { // if (!AndroidUtilities.findClickableView(this, ev.getX(), ev.getY())) { @@ -3009,16 +3262,20 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (updateHeight != null) { updateHeight.run(); } + if (scroll) { + post(() -> fullScroll(View.FOCUS_DOWN)); + scroll = false; + } } prevResultContainerHeight = resultContainerHeight; } else if (currentAnimation != null) { if (!ignoreScrollEvent && removingSpans.isEmpty()) { editText.bringPointIntoView(editText.getSelectionStart()); } - } - if (scroll) { - fullScroll(View.FOCUS_DOWN); - scroll = false; + if (scroll) { + fullScroll(View.FOCUS_DOWN); + scroll = false; + } } setMeasuredDimension(width, (int) containerHeight); } @@ -3051,6 +3308,10 @@ public void onAnimationEnd(Animator animator) { if (updateHeight != null) { updateHeight.run(); } + if (scroll) { + fullScroll(View.FOCUS_DOWN); + scroll = false; + } } }); removingSpans.clear(); @@ -3096,6 +3357,10 @@ public void onAnimationEnd(Animator animator) { if (updateHeight != null) { updateHeight.run(); } + if (scroll) { + fullScroll(View.FOCUS_DOWN); + scroll = false; + } } }); animators.clear(); @@ -3160,6 +3425,10 @@ public void onAnimationEnd(Animator animator) { if (updateHeight != null) { updateHeight.run(); } + if (scroll) { + fullScroll(View.FOCUS_DOWN); + scroll = false; + } } }); animators.clear(); @@ -3218,6 +3487,22 @@ public StoryPrivacy(int currentAccount, ArrayList rules) { if (containsRule(rules, TLRPC.TL_privacyValueAllowAll.class) != null) { type = TYPE_EVERYONE; this.rules.add(new TLRPC.TL_inputPrivacyValueAllowAll()); + + TLRPC.TL_privacyValueDisallowUsers disallowUsers = containsRule(rules, TLRPC.TL_privacyValueDisallowUsers.class); + if (disallowUsers != null) { + final TLRPC.TL_inputPrivacyValueDisallowUsers rule = new TLRPC.TL_inputPrivacyValueDisallowUsers(); + final MessagesController messagesController = MessagesController.getInstance(currentAccount); + for (int i = 0; i < disallowUsers.users.size(); ++i) { + long userId = disallowUsers.users.get(i); + TLRPC.InputUser inputUser = messagesController.getInputUser(userId); + if (!(inputUser instanceof TLRPC.TL_inputUserEmpty)) { + rule.users.add(inputUser); + selectedUserIds.add(userId); + selectedInputUsers.add(inputUser); + } + } + this.rules.add(rule); + } } else if (containsRule(rules, TLRPC.TL_privacyValueAllowCloseFriends.class) != null) { type = TYPE_CLOSE_FRIENDS; this.rules.add(new TLRPC.TL_inputPrivacyValueAllowCloseFriends()); @@ -3265,6 +3550,16 @@ public StoryPrivacy(ArrayList rules) { TLRPC.TL_inputPrivacyValueAllowUsers allowUsers; if (containsInputRule(rules, TLRPC.TL_inputPrivacyValueAllowAll.class) != null) { type = TYPE_EVERYONE; + TLRPC.TL_inputPrivacyValueDisallowUsers disallowUsers = containsInputRule(rules, TLRPC.TL_inputPrivacyValueDisallowUsers.class); + if (disallowUsers != null) { + for (int i = 0; i < disallowUsers.users.size(); ++i) { + TLRPC.InputUser inputUser = disallowUsers.users.get(i); + if (inputUser != null) { + selectedUserIds.add(inputUser.user_id); + selectedInputUsers.add(inputUser); + } + } + } } else if (containsInputRule(rules, TLRPC.TL_inputPrivacyValueAllowCloseFriends.class) != null) { type = TYPE_CLOSE_FRIENDS; } else if ((allowUsers = containsInputRule(rules, TLRPC.TL_inputPrivacyValueAllowUsers.class)) != null) { @@ -3322,6 +3617,19 @@ public StoryPrivacy(int type, int currentAccount, ArrayList userIds) { this.type = type; if (type == TYPE_EVERYONE) { this.rules.add(new TLRPC.TL_inputPrivacyValueAllowAll()); + if (currentAccount >= 0 && userIds != null && !userIds.isEmpty()) { + final TLRPC.TL_inputPrivacyValueDisallowUsers rule = new TLRPC.TL_inputPrivacyValueDisallowUsers(); + for (int i = 0; i < userIds.size(); ++i) { + long userId = userIds.get(i); + selectedUserIds.add(userId); + TLRPC.InputUser user = MessagesController.getInstance(currentAccount).getInputUser(userId); + if (user != null && !(user instanceof TLRPC.TL_inputUserEmpty)) { + rule.users.add(user); + selectedInputUsers.add(user); + } + } + this.rules.add(rule); + } } else if (type == TYPE_CLOSE_FRIENDS) { this.rules.add(new TLRPC.TL_inputPrivacyValueAllowCloseFriends()); } else if (type == TYPE_CONTACTS) { @@ -3364,6 +3672,18 @@ public StoryPrivacy(int type, ArrayList inputUserIds, int a) { this.type = type; if (type == TYPE_EVERYONE) { this.rules.add(new TLRPC.TL_inputPrivacyValueAllowAll()); + if (inputUserIds != null && !inputUserIds.isEmpty()) { + final TLRPC.TL_inputPrivacyValueDisallowUsers rule = new TLRPC.TL_inputPrivacyValueDisallowUsers(); + for (int i = 0; i < inputUserIds.size(); ++i) { + TLRPC.InputUser user = inputUserIds.get(i); + if (user != null) { + rule.users.add(user); + selectedUserIds.add(user.user_id); + selectedInputUsers.add(user); + } + } + this.rules.add(rule); + } } else if (type == TYPE_CLOSE_FRIENDS) { this.rules.add(new TLRPC.TL_inputPrivacyValueAllowCloseFriends()); } else if (type == TYPE_CONTACTS) { @@ -3428,6 +3748,13 @@ public String toString() { } TLRPC.InputPrivacyRule rule1 = rules.get(0); if (type == TYPE_EVERYONE) { + TLRPC.InputPrivacyRule rule2 = rules.size() >= 2 ? rules.get(1) : null; + if (rule2 instanceof TLRPC.TL_inputPrivacyValueDisallowUsers) { + final int usersCount = ((TLRPC.TL_inputPrivacyValueDisallowUsers) rule2).users.size(); + if (usersCount > 0) { + return LocaleController.formatPluralString("StoryPrivacyEveryoneExclude", usersCount); + } + } return LocaleController.getString("StoryPrivacyEveryone", R.string.StoryPrivacyEveryone); } else if (type == TYPE_CLOSE_FRIENDS) { return LocaleController.getString("StoryPrivacyCloseFriends", R.string.StoryPrivacyCloseFriends); @@ -3566,9 +3893,9 @@ public boolean containsUser(TLRPC.User user) { return false; } if (type == TYPE_EVERYONE) { - return true; - } else if (type == TYPE_CONTACTS) { return !selectedUserIds.contains(user.id); + } else if (type == TYPE_CONTACTS) { + return !selectedUserIds.contains(user.id) && user.contact; } else if (type == TYPE_CLOSE_FRIENDS) { return user.close_friend; } else if (type == TYPE_SELECTED_CONTACTS) { @@ -3580,7 +3907,10 @@ public boolean containsUser(TLRPC.User user) { @Override public void didReceivedNotification(int id, int account, Object... args) { - if (id == NotificationCenter.contactsDidLoad && viewPager != null) { + if (viewPager == null) { + return; + } + if (id == NotificationCenter.contactsDidLoad) { View[] views = viewPager.getViewPages(); if (views[0] instanceof Page) { ((Page) views[0]).updateItems(true); @@ -3588,6 +3918,18 @@ public void didReceivedNotification(int id, int account, Object... args) { if (views[1] instanceof Page) { ((Page) views[1]).updateItems(true); } + } else if (id == NotificationCenter.storiesBlocklistUpdate) { + View[] views = viewPager.getViewPages(); + for (int i = 0; i < views.length; ++i) { + if (views[i] instanceof Page) { + Page page = (Page) views[i]; + if (page.pageType == PAGE_TYPE_BLOCKLIST) { + page.applyBlocklist(true); + } else if (page.pageType == PAGE_TYPE_SHARE) { + page.updateItems(true); + } + } + } } } @@ -3626,6 +3968,40 @@ private void pullSaved() { } } + String excludedEveryoneString = MessagesController.getInstance(currentAccount).getMainSettings().getString("story_prv_everyoneexcept", null); + if (excludedEveryoneString != null) { + String[] parts = excludedEveryoneString.split(","); + excludedEveryone.clear(); + for (int i = 0; i < parts.length; ++i) { + try { + excludedEveryone.add(Long.parseLong(parts[i])); + } catch (Exception ignore) {} + } + } + + String excludedEveryoneGroupsString = MessagesController.getInstance(currentAccount).getMainSettings().getString("story_prv_grpeveryoneexcept", null); + if (excludedEveryoneGroupsString != null) { + String[] parts = excludedEveryoneGroupsString.split(";"); + excludedEveryoneByGroup.clear(); + for (int i = 0; i < parts.length; ++i) { + String[] parts2 = parts[i].split(","); + if (parts2.length <= 0) { + continue; + } + long id; + try { + id = Long.parseLong(parts2[0]); + } catch (Exception ignore) { + continue; + } + ArrayList userIds = new ArrayList<>(); + for (int j = 1; j < parts2.length; ++j) { + userIds.add(Long.parseLong(parts2[j])); + } + excludedEveryoneByGroup.put(id, userIds); + } + } + String excludedContactsString = MessagesController.getInstance(currentAccount).getMainSettings().getString("story_prv_excluded", null); if (excludedContactsString != null) { String[] parts = excludedContactsString.split(","); @@ -3638,9 +4014,10 @@ private void pullSaved() { } selectedContactsCount = mergeUsers(selectedContacts, selectedContactsByGroup).size(); + excludedEveryoneCount = mergeUsers(excludedEveryone, excludedEveryoneByGroup).size(); allowScreenshots = !MessagesController.getInstance(currentAccount).getMainSettings().getBoolean("story_noforwards", false); - keepOnMyPage = MessagesController.getInstance(currentAccount).getMainSettings().getBoolean("story_keep", false); + keepOnMyPage = MessagesController.getInstance(currentAccount).getMainSettings().getBoolean("story_keep", true); } private void save() { @@ -3651,7 +4028,16 @@ private void save() { } stringBuilder.append(entry.getKey()).append(",").append(TextUtils.join(",", entry.getValue())); } + StringBuilder stringBuilder2 = new StringBuilder(); + for (Map.Entry> entry : excludedEveryoneByGroup.entrySet()) { + if (stringBuilder2.length() > 0) { + stringBuilder2.append(";"); + } + stringBuilder2.append(entry.getKey()).append(",").append(TextUtils.join(",", entry.getValue())); + } MessagesController.getInstance(currentAccount).getMainSettings().edit() + .putString("story_prv_everyoneexcept", TextUtils.join(",", excludedEveryone)) + .putString("story_prv_grpeveryoneexcept", stringBuilder2.toString()) .putString("story_prv_contacts", TextUtils.join(",", selectedContacts)) .putString("story_prv_grpcontacts", stringBuilder.toString()) .putString("story_prv_excluded", TextUtils.join(",", excludedContacts)) diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryRecorder.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryRecorder.java index 48547aed377..78625309b1a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryRecorder.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/recorder/StoryRecorder.java @@ -44,10 +44,17 @@ import android.os.Parcelable; import android.provider.MediaStore; import android.text.Layout; +import android.text.Spannable; import android.text.SpannableString; +import android.text.SpannableStringBuilder; import android.text.Spanned; +import android.text.TextPaint; import android.text.TextUtils; +import android.text.style.CharacterStyle; +import android.text.style.ClickableSpan; +import android.text.style.ForegroundColorSpan; import android.text.style.ImageSpan; +import android.text.style.URLSpan; import android.util.Log; import android.util.Pair; import android.util.TypedValue; @@ -122,21 +129,27 @@ import org.telegram.ui.Components.PhotoFilterBlurControl; import org.telegram.ui.Components.PhotoFilterCurvesControl; import org.telegram.ui.Components.PhotoFilterView; +import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.ScaleStateListAnimator; import org.telegram.ui.Components.SizeNotifierFrameLayout; +import org.telegram.ui.Components.TextStyleSpan; +import org.telegram.ui.Components.URLSpanReplacement; import org.telegram.ui.Components.URLSpanUserMention; import org.telegram.ui.Components.VideoEditTextureView; import org.telegram.ui.Components.VideoTimelinePlayView; import org.telegram.ui.Components.ZoomControlView; import org.telegram.ui.LaunchActivity; +import org.telegram.ui.PremiumPreviewFragment; import org.telegram.ui.Stories.DarkThemeResourceProvider; import org.telegram.ui.Stories.DialogStoriesCell; import org.telegram.ui.Stories.PeerStoriesView; +import org.telegram.ui.Stories.StoriesController; import org.telegram.ui.Stories.StoryViewer; import org.telegram.ui.Stories.StoryWaveEffectView; +import org.telegram.ui.WrappedResourceProvider; import java.io.File; import java.io.FileNotFoundException; @@ -366,6 +379,11 @@ public void open(SourceView sourceView, boolean animated) { cameraViewThumb.setImageDrawable(getCameraThumb()); + StoriesController.StoryLimit storyLimit = MessagesController.getInstance(currentAccount).getStoriesController().checkStoryLimit(); + if (storyLimit != null && storyLimit.active(currentAccount)) { + showLimitReachedSheet(storyLimit, true); + } + navigateTo(PAGE_CAMERA, false); switchToEditMode(EDIT_MODE_NONE, false); @@ -436,6 +454,10 @@ public void openEdit(SourceView sourceView, StoryEntry entry, long time, boolean AndroidUtilities.lockOrientation(activity, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + if (outputEntry != null) { + captionEdit.setText(outputEntry.caption); + } + navigateToPreviewWithPlayerAwait(() -> { animateOpenTo(1, animated, this::onOpenDone); previewButtons.appear(true, true); @@ -443,10 +465,6 @@ public void openEdit(SourceView sourceView, StoryEntry entry, long time, boolean navigateTo(PAGE_PREVIEW, false); switchToEditMode(EDIT_MODE_NONE, false); - if (outputEntry != null) { - captionEdit.setText(outputEntry.caption); - } - addNotificationObservers(); } @@ -460,13 +478,13 @@ public void close(boolean animated) { privacySheet = null; } - if (outputEntry != null) { + if (outputEntry != null && !outputEntry.isEditSaved) { if (wasSend && outputEntry.isEdit) { outputEntry.editedMedia = false; } outputEntry.destroy(false); - outputEntry = null; } + outputEntry = null; if (onClosePrepareListener != null && previewView != null) { if (prepareClosing) { @@ -627,6 +645,9 @@ private void onCloseDone() { if (windowView != null) { Bulletin.removeDelegate(windowView); } + if (captionContainer != null) { + Bulletin.removeDelegate(captionContainer); + } } private Runnable onCloseListener; @@ -770,9 +791,10 @@ public boolean dispatchTouchEvent(MotionEvent ev) { } else { animateContainerBack(); } - } else if (galleryListView != null && galleryListView.getTranslationY() > 0) { + } else if (galleryListView != null && galleryListView.getTranslationY() > 0 && !galleryClosing) { animateGalleryListView(!takingVideo && galleryListView.getTranslationY() < galleryListView.getPadding()); } + galleryClosing = false; modeSwitcherView.stopScroll(0); scrollingY = false; scrollingX = false; @@ -933,7 +955,7 @@ public boolean onFling(@NonNull MotionEvent e1, @NonNull MotionEvent e2, float v animateContainerBack(); } r = true; - } else if (galleryListView != null) { + } else if (galleryListView != null && !galleryClosing) { if (Math.abs(velocityY) > 200 && (!galleryListView.listView.canScrollVertically(-1) || !wasGalleryOpen)) { animateGalleryListView(!takingVideo && velocityY < 0); r = true; @@ -946,6 +968,7 @@ public boolean onFling(@NonNull MotionEvent e1, @NonNull MotionEvent e2, float v if (scrollingX) { r = modeSwitcherView.stopScroll(velocityX) || r; } + galleryClosing = false; scrollingY = false; scrollingX = false; return r; @@ -1320,6 +1343,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { private ToggleButton dualButton; private VideoTimerView videoTimerView; private boolean wasGalleryOpen; + private boolean galleryClosing; private GalleryListView galleryListView; private DraftSavedHint draftSavedHint; private RecordControl recordControl; @@ -1338,6 +1362,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { private DownloadButton downloadButton; private RLottieDrawable muteButtonDrawable; private RLottieImageView muteButton; + private PlayPauseButton playButton; private HintView2 muteHint; private HintView2 dualHint; private HintView2 savedDualHint; @@ -1368,6 +1393,8 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { private StoryEntry outputEntry; private boolean fromGallery; + private boolean videoError; + private boolean isVideo = false; private boolean takingPhoto = false; private boolean takingVideo = false; @@ -1459,7 +1486,17 @@ public void setTranslationY(float translationY) { Bulletin.addDelegate(windowView, new Bulletin.Delegate() { @Override public int getTopOffset(int tag) { - return (int) (dp(56) + dp(56 - 10) * muteButton.getAlpha()); + return dp(56); + } + + @Override + public int getBottomOffset(int tag) { + return Bulletin.Delegate.super.getBottomOffset(tag); + } + + @Override + public boolean clipWithGradient(int tag) { + return true; } }); @@ -1555,6 +1592,7 @@ protected void onTimeDrag(boolean dragStart, long time, boolean dragEnd) { }); previewView.setVisibility(View.GONE); previewView.whenError(() -> { + videoError = true; previewButtons.setShareEnabled(false); downloadButton.showFailedVideo(); }); @@ -1568,11 +1606,62 @@ protected void drawBlurBitmap(Bitmap bitmap, float amount) { windowView.drawBlurBitmap(bitmap, amount); super.drawBlurBitmap(bitmap, amount); } + + @Override + protected boolean captionLimitToast() { + Bulletin visibleBulletin = Bulletin.getVisibleBulletin(); + if (visibleBulletin != null && visibleBulletin.tag == 2) { + return false; + } + final int symbols = MessagesController.getInstance(currentAccount).storyCaptionLengthLimitPremium; + final int times = Math.round((float) symbols / MessagesController.getInstance(currentAccount).storyCaptionLengthLimitDefault); + SpannableStringBuilder text = AndroidUtilities.replaceTags(LocaleController.formatPluralString("CaptionPremiumSubtitle", times, "" + symbols)); + int startIndex = text.toString().indexOf("__"); + if (startIndex >= 0) { + text.replace(startIndex, startIndex + 2, ""); + int endIndex = text.toString().indexOf("__"); + if (endIndex >= 0) { + text.replace(endIndex, endIndex + 2, ""); + text.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_chat_messageLinkIn, resourcesProvider)), startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + text.setSpan(new ClickableSpan() { + @Override + public void updateDrawState(@NonNull TextPaint ds) { + ds.setUnderlineText(false); + } + + @Override + public void onClick(@NonNull View widget) { + openPremium(); + } + }, startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + Bulletin bulletin = BulletinFactory.of(captionContainer, resourcesProvider).createSimpleBulletin(R.raw.caption_limit, LocaleController.getString("CaptionPremiumTitle"), text); + bulletin.tag = 2; + bulletin.setDuration(5000); + bulletin.show(false); + return true; + } + + @Override + protected void onCaptionLimitUpdate(boolean overLimit) { + previewButtons.setShareEnabled(!videoError && !overLimit && (!MessagesController.getInstance(currentAccount).getStoriesController().hasStoryLimit() || (outputEntry != null && outputEntry.isEdit))); + } }; + Bulletin.addDelegate(captionContainer, new Bulletin.Delegate() { + @Override + public int getBottomOffset(int tag) { + return captionEdit.getEditTextHeight() + AndroidUtilities.dp(12); + } + }); captionEdit.setOnHeightUpdate(height -> { if (videoTimelineContainerView != null) { videoTimelineContainerView.setTranslationY(-(captionEdit.getEditTextHeight() + AndroidUtilities.dp(12)) + AndroidUtilities.dp(64)); } + Bulletin visibleBulletin = Bulletin.getVisibleBulletin(); + if (visibleBulletin != null && visibleBulletin.tag == 2) { + visibleBulletin.updatePosition(); + } }); captionEdit.setOnPeriodUpdate(period -> { if (outputEntry != null) { @@ -1586,6 +1675,10 @@ protected void drawBlurBitmap(Bitmap bitmap, float amount) { previewView.updatePauseReason(2, open); videoTimelineContainerView.clearAnimation(); videoTimelineContainerView.animate().alpha(open ? 0f : 1f).setDuration(120).start(); + Bulletin visibleBulletin = Bulletin.getVisibleBulletin(); + if (visibleBulletin != null && visibleBulletin.tag == 2) { + visibleBulletin.updatePosition(); + } }); videoTimelineView = previewView.getTimelineView(); @@ -1624,11 +1717,11 @@ protected void drawBlurBitmap(Bitmap bitmap, float amount) { titleTextView.setAlpha(0f); titleTextView.setVisibility(View.GONE); titleTextView.setEllipsizeByGradient(true); - titleTextView.setRightPadding(AndroidUtilities.dp(96)); + titleTextView.setRightPadding(AndroidUtilities.dp(144)); actionBarContainer.addView(titleTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 56, Gravity.TOP | Gravity.FILL_HORIZONTAL, 71, 0, 0, 0)); downloadButton = new DownloadButton(context, done -> { - applyPaint(true); + applyPaint(); applyFilter(done); }, currentAccount, windowView, resourcesProvider); actionBarContainer.addView(downloadButton, LayoutHelper.createFrame(56, 56, Gravity.TOP | Gravity.RIGHT)); @@ -1660,6 +1753,17 @@ protected void drawBlurBitmap(Bitmap bitmap, float amount) { muteButton.setAlpha(0f); actionBarContainer.addView(muteButton, LayoutHelper.createFrame(56, 56, Gravity.TOP | Gravity.RIGHT, 0, 0, 48, 0)); + playButton = new PlayPauseButton(context); + playButton.setBackground(Theme.createSelectorDrawable(0x20ffffff)); + playButton.setVisibility(View.GONE); + playButton.setAlpha(0f); + playButton.setOnClickListener(e -> { + boolean playing = previewView.isPlaying(); + previewView.play(!playing); + playButton.drawable.setPause(!playing, true); + }); + actionBarContainer.addView(playButton, LayoutHelper.createFrame(56, 56, Gravity.TOP | Gravity.RIGHT, 0, 0, 48 + 48, 0)); + flashButton = new ImageView(context); flashButton.setScaleType(ImageView.ScaleType.CENTER); flashButton.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY)); @@ -1780,12 +1884,37 @@ protected void drawBlurBitmap(Bitmap bitmap, float amount) { privacySheet.dismiss(); privacySheet = null; } - if (!previewButtons.isShareEnabled()) { + if (videoError) { downloadButton.showFailedVideo(); BotWebViewVibrationEffect.APP_ERROR.vibrate(); AndroidUtilities.shakeViewSpring(previewButtons.shareButton, shiftDp = -shiftDp); return; } + if (captionEdit != null && captionEdit.isCaptionOverLimit()) { + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + AndroidUtilities.shakeViewSpring(captionEdit.limitTextView, shiftDp = -shiftDp); + captionEdit.captionLimitToast(); + return; + } + if (!outputEntry.isEdit) { + StoriesController.StoryLimit storyLimit = MessagesController.getInstance(currentAccount).storiesController.checkStoryLimit(); + if (storyLimit != null && storyLimit.active(currentAccount)) { + showLimitReachedSheet(storyLimit, false); + return; + } + } + outputEntry.captionEntitiesAllowed = MessagesController.getInstance(currentAccount).storyEntitiesAllowed(); + if (captionEdit != null && !outputEntry.captionEntitiesAllowed) { + CharSequence text = captionEdit.getText(); + if (text instanceof Spannable && ( + ((Spannable) text).getSpans(0, text.length(), TextStyleSpan.class).length > 0 || + ((Spannable) text).getSpans(0, text.length(), URLSpan.class).length > 0 + )) { + BulletinFactory.of(windowView, resourcesProvider).createSimpleBulletin(R.raw.voip_invite, premiumText(LocaleController.getString("StoryPremiumFormatting", R.string.StoryPremiumFormatting))).show(true); + AndroidUtilities.shakeViewSpring(captionEdit, shiftDp = -shiftDp); + return; + } + } if (outputEntry.isEdit) { outputEntry.editedPrivacy = false; applyFilter(null); @@ -1911,7 +2040,7 @@ private DraftSavedHint getDraftSavedHint() { } private void upload(boolean asStory) { - applyPaint(true); + applyPaint(); if (outputEntry == null) { close(true); return; @@ -1922,7 +2051,7 @@ private void upload(boolean asStory) { outputEntry.editedCaption = !TextUtils.equals(outputEntry.caption, caption); outputEntry.caption = caption; MessagesController.getInstance(currentAccount).getStoriesController().uploadStory(outputEntry, asStory); - if (outputEntry.isDraft) { + if (outputEntry.isDraft && !outputEntry.isEdit) { MessagesController.getInstance(currentAccount).getStoriesController().getDraftsController().delete(outputEntry); } outputEntry.cancelCheckStickers(); @@ -2480,6 +2609,9 @@ public boolean onBackPressed() { if (captionEdit.onBackPressed()) { return false; } else if (galleryListView != null) { + if (galleryListView.onBackPressed()) { + return false; + } animateGalleryListView(false); lastGallerySelectedAlbum = null; return false; @@ -2574,6 +2706,7 @@ public void navigateTo(int page, boolean animated) { animators.add(ObjectAnimator.ofFloat(videoTimelineView, View.ALPHA, page == PAGE_PREVIEW && isVideo ? 1f : 0)); animators.add(ObjectAnimator.ofFloat(muteButton, View.ALPHA, page == PAGE_PREVIEW && isVideo ? 1f : 0)); + animators.add(ObjectAnimator.ofFloat(playButton, View.ALPHA, page == PAGE_PREVIEW && isVideo ? 1f : 0)); animators.add(ObjectAnimator.ofFloat(downloadButton, View.ALPHA, page == PAGE_PREVIEW ? 1f : 0)); // animators.add(ObjectAnimator.ofFloat(privacySelector, View.ALPHA, page == PAGE_PREVIEW ? 1f : 0)); @@ -2608,6 +2741,7 @@ public void onAnimationEnd(Animator animation) { captionContainer.setAlpha(page == PAGE_PREVIEW ? 1f : 0); captionContainer.setTranslationY(page == PAGE_PREVIEW ? 0 : dp(12)); muteButton.setAlpha(page == PAGE_PREVIEW && isVideo ? 1f : 0); + playButton.setAlpha(page == PAGE_PREVIEW && isVideo ? 1f : 0); downloadButton.setAlpha(page == PAGE_PREVIEW ? 1f : 0); // privacySelector.setAlpha(page == PAGE_PREVIEW ? 1f : 0); videoTimelineView.setAlpha(page == PAGE_PREVIEW && isVideo ? 1f : 0); @@ -2705,7 +2839,18 @@ protected void onFullScreen(boolean isFullscreen) { }); } } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getY() < top()) { + galleryClosing = true; + animateGalleryListView(false); + return true; + } + return super.dispatchTouchEvent(ev); + } }; + galleryListView.allowSearch(forAddingPart); galleryListView.setOnBackClickListener(() -> { animateGalleryListView(false); lastGallerySelectedAlbum = null; @@ -2716,58 +2861,17 @@ protected void onFullScreen(boolean isFullscreen) { } if (forAddingPart) { - if (outputEntry == null || !(entry instanceof MediaController.PhotoEntry)) { + if (outputEntry == null) { return; } - MediaController.PhotoEntry photoEntry = (MediaController.PhotoEntry) entry; createPhotoPaintView(); outputEntry.editedMedia = true; - paintView.appearAnimation(paintView.createPhoto(photoEntry.path, false)); -// StoryEntry.Part part = new StoryEntry.Part(); -// part.id = outputEntry.partsMaxId++; -// part.file = new File(photoEntry.path); -// if (photoEntry.width <= 0 || photoEntry.height <= 0) { -// BitmapFactory.Options opts = new BitmapFactory.Options(); -// opts.inJustDecodeBounds = true; -// BitmapFactory.decodeFile(photoEntry.path, opts); -// part.width = opts.outWidth; -// part.height = opts.outHeight; -// } else { -// part.width = photoEntry.width; -// part.height = photoEntry.height; -// } -// part.fileDeletable = false; -// part.matrix.reset(); -// int width = part.width, height = part.height; -// part.matrix.postScale(photoEntry.invert == 1 ? -1.0f : 1.0f, photoEntry.invert == 2 ? -1.0f : 1.0f, width / 2f, height / 2f); -// if (photoEntry.orientation != 0) { -// part.matrix.postTranslate(-width / 2f, -height / 2f); -// part.matrix.postRotate(photoEntry.orientation); -// if (photoEntry.orientation == 90 || photoEntry.orientation == 270) { -// final int swap = height; -// height = width; -// width = swap; -// } -// part.matrix.postTranslate(width / 2f, height / 2f); -// } -// float scale = (float) outputEntry.resultWidth / width; -// if ((float) height / (float) width > 1.29f) { -// scale = Math.max(scale, (float) outputEntry.resultHeight / height); -// } -// part.matrix.postScale(scale, scale); -// part.matrix.postTranslate((outputEntry.resultWidth - width * scale) / 2f, (outputEntry.resultHeight - height * scale) / 2f); -// -// final float randScale = .5f; -//// final float hw = (1f - randScale) * outputEntry.resultWidth / 2f, hh = (1f - randScale) * outputEntry.resultHeight / 2f; -//// float randTranslateX = AndroidUtilities.lerp(-hw, hw, Utilities.fastRandom.nextFloat()); -//// float randTranslateY = AndroidUtilities.lerp(-hh, hh, Utilities.fastRandom.nextFloat()); -//// float randRotate = AndroidUtilities.lerp(-10, 10, Utilities.fastRandom.nextFloat()); -// part.matrix.postScale(randScale, randScale, outputEntry.resultWidth / 2f, outputEntry.resultHeight / 2f); -//// part.matrix.postRotate(randRotate, outputEntry.resultWidth / 2f, outputEntry.resultHeight / 2f); -//// part.matrix.postTranslate(randTranslateX, randTranslateY); -// outputEntry.parts.add(part); -// previewView.set(outputEntry); -// + if (entry instanceof MediaController.PhotoEntry) { + MediaController.PhotoEntry photoEntry = (MediaController.PhotoEntry) entry; + paintView.appearAnimation(paintView.createPhoto(photoEntry.path, false)); + } else if (entry instanceof TLObject) { + paintView.appearAnimation(paintView.createPhoto((TLObject) entry, false)); + } animateGalleryListView(false); } else { if (entry instanceof MediaController.PhotoEntry) { @@ -2899,6 +3003,7 @@ public void onAnimationEnd(Animator animation) { galleryListView = null; galleryOpenCloseAnimator = null; galleryListViewOpening = null; + captionEdit.keyboardNotifier.ignore(currentPage != PAGE_PREVIEW); } }); galleryOpenCloseAnimator.setDuration(450L); @@ -2948,7 +3053,10 @@ private void onNavigateStart(int fromPage, int toPage) { if (isVideo) { muteButton.setVisibility(View.VISIBLE); setIconMuted(outputEntry != null && outputEntry.muted, false); - titleTextView.setRightPadding(AndroidUtilities.dp(96)); + playButton.setVisibility(View.VISIBLE); + previewView.play(true); + playButton.drawable.setPause(previewView.isPlaying(), false); + titleTextView.setRightPadding(AndroidUtilities.dp(144)); } else { titleTextView.setRightPadding(AndroidUtilities.dp(48)); } @@ -2964,23 +3072,26 @@ private void onNavigateStart(int fromPage, int toPage) { captionEdit.setPeriodVisible(outputEntry == null || !outputEntry.isEdit); } if (toPage == PAGE_PREVIEW) { + videoError = false; previewButtons.setShareText(outputEntry != null && outputEntry.isEdit ? LocaleController.getString("Done", R.string.Done) : LocaleController.getString("Next", R.string.Next)); - previewButtons.setShareEnabled(true); // privacySelector.set(outputEntry, false); if (!previewAlreadySet) { previewView.set(outputEntry); } previewAlreadySet = false; - if (outputEntry != null && outputEntry.isDraft) { + captionEdit.editText.getEditText().setOnPremiumMenuLockClickListener(MessagesController.getInstance(currentAccount).storyEntitiesAllowed() ? null : () -> { + BulletinFactory.of(windowView, resourcesProvider).createSimpleBulletin(R.raw.voip_invite, premiumText(LocaleController.getString("StoryPremiumFormatting", R.string.StoryPremiumFormatting))).show(true); + }); + if (outputEntry != null && (outputEntry.isDraft || outputEntry.isEdit)) { if (outputEntry.paintFile != null) { destroyPhotoPaintView(); createPhotoPaintView(); hidePhotoPaintView(); } - if (outputEntry.filterState != null) { - destroyPhotoFilterView(); - createFilterPhotoView(); - } +// if (outputEntry.filterState != null) { +// destroyPhotoFilterView(); +// createFilterPhotoView(); +// } if (outputEntry.isVideo && outputEntry.filterState != null) { VideoEditTextureView textureView = previewView.getTextureView(); if (textureView != null) { @@ -2995,13 +3106,14 @@ private void onNavigateStart(int fromPage, int toPage) { } else { captionEdit.clear(); } + previewButtons.setShareEnabled(!videoError && !captionEdit.isCaptionOverLimit() && (!MessagesController.getInstance(currentAccount).getStoriesController().hasStoryLimit() || (outputEntry != null && outputEntry.isEdit))); muteButton.setImageResource(outputEntry != null && outputEntry.muted ? R.drawable.media_unmute : R.drawable.media_mute); previewView.setVisibility(View.VISIBLE); videoTimelineView.setVisibility(isVideo ? View.VISIBLE : View.GONE); titleTextView.setVisibility(View.VISIBLE); titleTextView.setText(outputEntry != null && outputEntry.isEdit ? LocaleController.getString(R.string.RecorderEditStory) : LocaleController.getString(R.string.RecorderNewStory)); - MediaDataController.getInstance(currentAccount).checkStickers(MediaDataController.TYPE_EMOJIPACKS); - MediaDataController.getInstance(currentAccount).checkFeaturedEmoji(); +// MediaDataController.getInstance(currentAccount).checkStickers(MediaDataController.TYPE_EMOJIPACKS); +// MediaDataController.getInstance(currentAccount).checkFeaturedEmoji(); } if (fromPage == PAGE_PREVIEW) { // privacySelectorHint.hide(); @@ -3039,6 +3151,7 @@ private void onNavigateEnd(int fromPage, int toPage) { previewView.setVisibility(View.GONE); captionContainer.setVisibility(View.GONE); muteButton.setVisibility(View.GONE); + playButton.setVisibility(View.GONE); downloadButton.setVisibility(View.GONE); // privacySelector.setVisibility(View.GONE); previewView.setVisibility(View.GONE); @@ -3059,6 +3172,7 @@ private void onNavigateEnd(int fromPage, int toPage) { previewView.updatePauseReason(3, false); previewView.updatePauseReason(4, false); previewView.updatePauseReason(5, false); + previewView.updatePauseReason(7, false); videoTimeView.setVisibility(outputEntry != null && outputEntry.duration >= 30_000 ? View.VISIBLE : View.GONE); } if (toPage == PAGE_CAMERA && showSavedDraftHint) { @@ -3078,6 +3192,13 @@ private void onNavigateEnd(int fromPage, int toPage) { if (captionEdit != null) { captionEdit.ignoreTouches = toPage != PAGE_PREVIEW; } + + if (toPage == PAGE_PREVIEW) { + MediaDataController.getInstance(currentAccount).checkStickers(MediaDataController.TYPE_IMAGE); + MediaDataController.getInstance(currentAccount).loadRecents(MediaDataController.TYPE_IMAGE, false, true, false); + MediaDataController.getInstance(currentAccount).loadRecents(MediaDataController.TYPE_FAVE, false, true, false); + MessagesController.getInstance(currentAccount).getStoriesController().loadBlocklistAtFirst(); + } } private AnimatorSet editModeAnimator; @@ -3142,6 +3263,7 @@ public void switchToEditMode(int editMode, boolean animated) { } animators.add(ObjectAnimator.ofFloat(muteButton, View.ALPHA, editMode == EDIT_MODE_NONE && isVideo ? 1 : 0)); + animators.add(ObjectAnimator.ofFloat(playButton, View.ALPHA, editMode == EDIT_MODE_NONE && isVideo ? 1 : 0)); animators.add(ObjectAnimator.ofFloat(downloadButton, View.ALPHA, editMode == EDIT_MODE_NONE ? 1 : 0)); // animators.add(ObjectAnimator.ofFloat(privacySelector, View.ALPHA, editMode == EDIT_MODE_NONE ? 1 : 0)); @@ -3227,13 +3349,30 @@ private void createPhotoPaintView() { paintViewBitmap.recycle(); paintViewBitmap = null; } - if (outputEntry != null && outputEntry.isDraft && outputEntry.paintFile != null) { + if (outputEntry != null && (outputEntry.isDraft || outputEntry.isEdit) && outputEntry.paintFile != null) { paintViewBitmap = BitmapFactory.decodeFile(outputEntry.paintFile.getPath()); } if (paintViewBitmap == null) { paintViewBitmap = Bitmap.createBitmap(size.first, size.second, Bitmap.Config.ARGB_8888); } - paintView = new PaintView(activity, windowView, activity, currentAccount, paintViewBitmap, null, previewView.getOrientation(), outputEntry == null ? null : outputEntry.mediaEntities, previewContainer.getMeasuredWidth(), previewContainer.getMeasuredHeight(), new MediaController.CropState(), null, resourcesProvider) { + int w = previewContainer.getMeasuredWidth(), h = previewContainer.getMeasuredHeight(); + paintView = new PaintView( + activity, + outputEntry != null && !outputEntry.fileDeletable, + outputEntry == null ? null : outputEntry.file, + outputEntry != null && outputEntry.isVideo, + windowView, + activity, + currentAccount, + paintViewBitmap, + null, + previewView.getOrientation(), + outputEntry == null ? null : outputEntry.mediaEntities, + w, h, + new MediaController.CropState(), + null, + resourcesProvider + ) { @Override public void onEntityDraggedTop(boolean value) { previewHighlight.show(true, value, actionBarContainer); @@ -3241,6 +3380,7 @@ public void onEntityDraggedTop(boolean value) { @Override protected void onGalleryClick() { + captionEdit.keyboardNotifier.ignore(true); destroyGalleryListView(); createGalleryListView(true); animateGalleryListView(true); @@ -3249,7 +3389,7 @@ protected void onGalleryClick() { @Override public void onEntityDraggedBottom(boolean value) { previewHighlight.updateCaption(captionEdit.getText()); -// previewHighlight.show(false, value, null); + previewHighlight.show(false, value && multitouch, null); } @Override @@ -3265,6 +3405,7 @@ public void onEntityDragEnd(boolean delete) { removeCurrentEntity(); } super.onEntityDragEnd(delete); + multitouch = false; } @Override @@ -3278,6 +3419,28 @@ public void onEntityDragStart() { trash.animate().alpha(1f).setDuration(180).setInterpolator(CubicBezierInterpolator.EASE_OUT).start(); } + private boolean multitouch; + + @Override + public void onEntityDragMultitouchStart() { + multitouch = true; + trash.onDragInfo(false, false); + trash.clearAnimation(); + trash.animate().alpha(0f).withEndAction(() -> { + trash.setVisibility(View.GONE); + }).setDuration(180).setInterpolator(CubicBezierInterpolator.EASE_OUT).start(); + } + + @Override + public void onEntityDragMultitouchEnd() { + multitouch = false; + trash.setVisibility(View.VISIBLE); + trash.setAlpha(0f); + trash.clearAnimation(); + trash.animate().alpha(1f).setDuration(180).setInterpolator(CubicBezierInterpolator.EASE_OUT).start(); + previewHighlight.show(false, false, null); + } + @Override public void onEntityDragTrash(boolean enter) { trash.onDragInfo(enter, false); @@ -3418,6 +3581,7 @@ private void onSwitchEditModeStart(int fromMode, int toMode) { // privacySelector.setVisibility(View.VISIBLE); if (isVideo) { muteButton.setVisibility(View.VISIBLE); + playButton.setVisibility(View.VISIBLE); } videoTimelineView.setVisibility(View.VISIBLE); } @@ -3456,6 +3620,7 @@ private void onSwitchEditModeEnd(int fromMode, int toMode) { if (fromMode == EDIT_MODE_NONE) { captionContainer.setVisibility(View.GONE); muteButton.setVisibility(View.GONE); + playButton.setVisibility(View.GONE); downloadButton.setVisibility(View.GONE); // privacySelector.setVisibility(View.GONE); videoTimelineView.setVisibility(View.GONE); @@ -3470,7 +3635,7 @@ private void onSwitchEditModeEnd(int fromMode, int toMode) { } } - private void applyPaint(boolean drawEntities) { + private void applyPaint() { if (paintView == null || outputEntry == null) { return; } @@ -3484,17 +3649,41 @@ private void applyPaint(boolean drawEntities) { outputEntry.mediaEntities.clear(); } paintView.getBitmap(outputEntry.mediaEntities, outputEntry.resultWidth, outputEntry.resultHeight, false, false); - ArrayList entities = new ArrayList<>(); - Bitmap bitmap = paintView.getBitmap(entities, outputEntry.resultWidth, outputEntry.resultHeight, true, drawEntities && !outputEntry.wouldBeVideo()); - List masks = paintView.getMasks(); - - outputEntry.stickers = masks != null ? new ArrayList<>(masks) : null; - TLRPC.PhotoSize size = ImageLoader.scaleAndSaveImage(bitmap, Bitmap.CompressFormat.PNG, outputEntry.resultWidth, outputEntry.resultHeight, 87, false, 101, 101); - outputEntry.mediaEntities = entities == null || entities.isEmpty() ? null : entities; if (!outputEntry.isVideo) { outputEntry.averageDuration = Utilities.clamp(paintView.getLcm(), 7500L, 5000L); } - outputEntry.paintFile = FileLoader.getInstance(currentAccount).getPathToAttach(size, true); + List masks = paintView.getMasks(); + outputEntry.stickers = masks != null ? new ArrayList<>(masks) : null; + + outputEntry.mediaEntities = new ArrayList<>(); + Bitmap bitmap = paintView.getBitmap(outputEntry.mediaEntities, outputEntry.resultWidth, outputEntry.resultHeight, true, false); + if (outputEntry.mediaEntities.isEmpty()) { + outputEntry.mediaEntities = null; + } + + try { + if (outputEntry.paintFile != null) { + outputEntry.paintFile.delete(); + } + } catch (Exception ignore) {} + try { + if (outputEntry.paintEntitiesFile != null) { + outputEntry.paintEntitiesFile.delete(); + } + } catch (Exception ignore) {} + + outputEntry.paintFile = FileLoader.getInstance(currentAccount).getPathToAttach(ImageLoader.scaleAndSaveImage(bitmap, Bitmap.CompressFormat.PNG, outputEntry.resultWidth, outputEntry.resultHeight, 87, false, 101, 101), true); + if (bitmap != null) { + bitmap.recycle(); + } + + if (!outputEntry.wouldBeVideo()) { + bitmap = paintView.getBitmap(new ArrayList<>(), outputEntry.resultWidth, outputEntry.resultHeight, false, true); + outputEntry.paintEntitiesFile = FileLoader.getInstance(currentAccount).getPathToAttach(ImageLoader.scaleAndSaveImage(bitmap, Bitmap.CompressFormat.PNG, outputEntry.resultWidth, outputEntry.resultHeight, 87, false, 101, 101), true); + if (bitmap != null) { + bitmap.recycle(); + } + } } private void applyFilter(Runnable whenDone) { @@ -3833,9 +4022,10 @@ private void showDismissEntry() { if (outputEntry == null) { return; } + outputEntry.captionEntitiesAllowed = MessagesController.getInstance(currentAccount).storyEntitiesAllowed(); showSavedDraftHint = !outputEntry.isDraft; applyFilter(null); - applyPaint(false); + applyPaint(); destroyPhotoFilterView(); StoryEntry storyEntry = outputEntry; storyEntry.destroy(true); @@ -3946,16 +4136,15 @@ private void requestCameraPermission(boolean force) { private boolean requestGalleryPermission() { if (activity != null) { boolean noGalleryPermission = false; -// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { -// noGalleryPermission = ( -// activity.checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED || -// activity.checkSelfPermission(Manifest.permission.READ_MEDIA_VIDEO) != PackageManager.PERMISSION_GRANTED -// ); -// if (noGalleryPermission) { -// activity.requestPermissions(new String[]{Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VIDEO}, 114); -// } -// } else - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + noGalleryPermission = ( + activity.checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED || + activity.checkSelfPermission(Manifest.permission.READ_MEDIA_VIDEO) != PackageManager.PERMISSION_GRANTED + ); + if (noGalleryPermission) { + activity.requestPermissions(new String[]{Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VIDEO}, 114); + } + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { noGalleryPermission = activity.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED; if (noGalleryPermission) { activity.requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 114); @@ -4098,17 +4287,73 @@ public void didReceivedNotification(int id, int account, Object... args) { if (recordControl != null && !showSavedDraftHint) { recordControl.updateGalleryImage(); } + } else if (id == NotificationCenter.storiesLimitUpdate) { + if (currentPage == PAGE_PREVIEW) { + previewButtons.setShareEnabled(!videoError && !captionEdit.isCaptionOverLimit() && (!MessagesController.getInstance(currentAccount).getStoriesController().hasStoryLimit() || (outputEntry != null && outputEntry.isEdit))); + } else if (currentPage == PAGE_CAMERA) { + StoriesController.StoryLimit storyLimit = MessagesController.getInstance(currentAccount).getStoriesController().checkStoryLimit(); + if (storyLimit != null && storyLimit.active(currentAccount)) { + showLimitReachedSheet(storyLimit, true); + } + } } } public void addNotificationObservers() { NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.albumsDidLoad); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.storiesDraftsUpdated); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.storiesLimitUpdate); } public void removeNotificationObservers() { NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.albumsDidLoad); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storiesDraftsUpdated); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.storiesLimitUpdate); + } + + private boolean shownLimitReached; + private void showLimitReachedSheet(StoriesController.StoryLimit storyLimit, boolean closeRecorder) { + if (shownLimitReached) { + return; + } + final LimitReachedBottomSheet sheet = new LimitReachedBottomSheet(new BaseFragment() { + @Override + public boolean isLightStatusBar() { + return false; + } + + @Override + public Activity getParentActivity() { + return activity; + } + + @Override + public Theme.ResourcesProvider getResourceProvider() { + return new WrappedResourceProvider(resourcesProvider) { + @Override + public void appendColors() { + sparseIntArray.append(Theme.key_dialogBackground, 0xFF1F1F1F); + sparseIntArray.append(Theme.key_windowBackgroundGray, 0xFF333333); + } + }; + } + + @Override + public boolean presentFragment(BaseFragment fragment) { + openPremium(); + return false; + } + }, activity, storyLimit.getLimitReachedType(), currentAccount); + sheet.setOnDismissListener(e -> { + shownLimitReached = false; + previewView.updatePauseReason(7, true); + if (closeRecorder) { + close(true); + } + }); + previewView.updatePauseReason(7, true); + shownLimitReached = true; + sheet.show(); } private boolean isBackgroundVisible; @@ -4130,32 +4375,78 @@ public interface ClosingViewProvider { SourceView getView(); } - private void showPremiumPeriodBulletin(int period) { - final int hours = period / 3600; - BulletinFactory.of(windowView, resourcesProvider) - .createSimpleBulletin(R.raw.fire_on, AndroidUtilities.replaceSingleTag(LocaleController.formatPluralString("StoryPeriodPremium", hours), () -> { - if (previewView != null) { - previewView.updatePauseReason(4, true); - } - PremiumFeatureBottomSheet sheet = new PremiumFeatureBottomSheet(new BaseFragment() { - { currentAccount = StoryRecorder.this.currentAccount; } - @Override - public Dialog showDialog(Dialog dialog) { - dialog.show(); - return dialog; - } + private void openPremium() { + if (previewView != null) { + previewView.updatePauseReason(4, true); + } + if (captionEdit != null) { + captionEdit.hidePeriodPopup(); + } + PremiumFeatureBottomSheet sheet = new PremiumFeatureBottomSheet(new BaseFragment() { + { currentAccount = StoryRecorder.this.currentAccount; } + @Override + public Dialog showDialog(Dialog dialog) { + dialog.show(); + return dialog; + } + @Override + public Activity getParentActivity() { + return StoryRecorder.this.activity; + } + + @Override + public Theme.ResourcesProvider getResourceProvider() { + return new WrappedResourceProvider(resourcesProvider) { @Override - public Activity getParentActivity() { - return StoryRecorder.this.activity; + public void appendColors() { + sparseIntArray.append(Theme.key_dialogBackground, 0xFF1E1E1E); + sparseIntArray.append(Theme.key_windowBackgroundGray, 0xFF000000); } - }, 0, false); - sheet.setOnDismissListener(d -> { - if (previewView != null) { - previewView.updatePauseReason(4, false); - } - }); - sheet.show(); - })).show(true); + }; + } + + @Override + public boolean isLightStatusBar() { + return false; + } + }, PremiumPreviewFragment.PREMIUM_FEATURE_STORIES, false); + sheet.setOnDismissListener(d -> { + if (previewView != null) { + previewView.updatePauseReason(4, false); + } + }); + sheet.show(); + } + + private CharSequence premiumText(String text) { + return AndroidUtilities.replaceSingleTag(text, Theme.key_chat_messageLinkIn, 0, this::openPremium, resourcesProvider); + } + + private void showPremiumPeriodBulletin(int period) { + final int hours = period / 3600; + + Bulletin.BulletinWindow.BulletinWindowLayout window = Bulletin.BulletinWindow.make(activity, new Bulletin.Delegate() { + @Override + public int getTopOffset(int tag) { + return 0; + } + + @Override + public boolean clipWithGradient(int tag) { + return true; + } + }); + WindowManager.LayoutParams params = window.getLayout(); + if (params != null) { + params.height = WindowManager.LayoutParams.WRAP_CONTENT; + params.width = containerView.getWidth(); + params.y = (int) (containerView.getY() + AndroidUtilities.dp(56)); + window.updateLayout(); + } + window.setTouchable(true); + BulletinFactory.of(window, resourcesProvider) + .createSimpleBulletin(R.raw.fire_on, premiumText(LocaleController.formatPluralString("StoryPeriodPremium", hours)), 3) + .show(true); } public void setIconMuted(boolean muted, boolean animated) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java index 1998a851f87..cae833713cf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemePreviewActivity.java @@ -4495,7 +4495,7 @@ public MessagesAdapter(Context context) { messageObject.resetLayout(); messages.add(messageObject); - if (dialogId != 0) { + if (dialogId != 0 && serverWallpaper == null) { message = new TLRPC.TL_message(); message.message = ""; messageObject = new MessageObject(currentAccount, message, true, false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationSetupActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationSetupActivity.java index 6892e565f2b..d1611b2502f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationSetupActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationSetupActivity.java @@ -343,6 +343,9 @@ public void getOutline(View view, Outline outline) { VerticalPositionAutoAnimator.attach(bottomSkipButton); bottomSkipButton.setPadding(AndroidUtilities.dp(32), 0, AndroidUtilities.dp(32), 0); bottomSkipButton.setOnClickListener(v -> { + if (bottomSkipButton.getAlpha() < .5f) { + return; + } if (currentType == TYPE_CREATE_PASSWORD_STEP_1) { needShowProgress(); TLRPC.TL_auth_recoverPassword req = new TLRPC.TL_auth_recoverPassword(); @@ -1085,9 +1088,12 @@ protected void onDraw(Canvas canvas) { actionBar.getTitleTextView().setAlpha(0.0f); if (!emailOnly) { bottomSkipButton.setVisibility(View.VISIBLE); + bottomSkipButton.setAlpha(0f); bottomSkipButton.setText(LocaleController.getString("YourEmailSkip", R.string.YourEmailSkip)); } titleTextView.setText(LocaleController.getString("RecoveryEmailTitle", R.string.RecoveryEmailTitle)); + descriptionText.setText(LocaleController.getString("RecoveryEmailSubtitle", R.string.RecoveryEmailSubtitle)); + descriptionText.setVisibility(View.VISIBLE); outlineTextFirstRow.setText(LocaleController.getString(R.string.PaymentShippingEmailPlaceholder)); editTextFirstRow.setContentDescription(LocaleController.getString(R.string.PaymentShippingEmailPlaceholder)); editTextFirstRow.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI); @@ -1483,6 +1489,10 @@ private void processNext() { break; } case TYPE_ENTER_EMAIL: { + if (!emailOnly && bottomSkipButton.getAlpha() < 1) { + bottomSkipButton.animate().cancel(); + bottomSkipButton.animate().alpha(1f).start(); + } email = editTextFirstRow.getText().toString(); if (!isValidEmail(email)) { onFieldError(outlineTextFirstRow, editTextFirstRow, false); diff --git a/TMessagesProj/src/main/res/drawable-hdpi/large_stealth.png b/TMessagesProj/src/main/res/drawable-hdpi/large_stealth.png new file mode 100644 index 0000000000000000000000000000000000000000..a8ada6754a1d8e8d406b196ca058ec5297eee94d GIT binary patch literal 2033 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91JfH&r1ONa40RR91JOBUy0E^%0TmS$ETS-JgRA>e5ntO;>RS?HrpZUsH z+OC=TN<(e2k~Cc_DAbZNBt?*jEXgSRqrgmrkO))~5+u@I_CSoJB8Wl}N=nTND#ett zO-s#uRi>Gm+vmI7bD4Yg+}(SByKDXAH}K`m%$=EY=KSuR^Vn_CqC}+`xS(dBEG?Uw znws`Jy9aaxtINvD4yM@_y`E%Sfz80t0hp_bKC!d}NbWk9scHAZ_f7LDYCVbd2j@(( zj@=2VCuTDbU0A)9gGQ4h4sSPkMc4*a09< z0H=M!M#_KUzX)`&eKjjjXV-({z^5}PCfUxBr-6Tb!zPgRd5yJwH7QTLoG--C5w1zPD?v zZ5AG%A>b`PSO$3qHUqQt(Vz{1t_Ay}PWAnavQEe|qi23|5XF_&HY<j^fRSXo%rl?hqatp@?p>y}tbkmrE);8idiTxMfA9=*PEecO3RtHLxFBU6jRc<^@vy?oE}avKo& z`4k@wy0f!|ZwuBLTTSc>AQ4aY=qf)Bl2d?_5kt?&c?OqCVO^S#NRQhzlLC-ng2RVG-I;~KHdbt>xA{8d2ZQv z5L%f;x*==QEU9LUa5k<*m-l;COzr>UNp`W~mWK;vRRASkAN)IjPgCN&f<9i;;q}Vy z29{LpbV`c}S)W-Uv@i~086x!s4Slzv4v(U2V`GU&7y9*_|59s@asb%x9!Bka&!#nc z^_7>D(-k&WEst_}-bj(X&cs3Dc{xyV3(*4Wgu!rN6WVK^i|6?pp+FgQ%M-D1Xa%&s z7D7+hU<8Q2=V*}q(fPlg>*pcQR~rty?k9F@Je%hnbGDku+S=g`*Sd4=ZadGx@AGW$ zAoyITi*7H*BOh}*)9S67?qqDYz)u0EBb{Gm_dDC1tyU7{*uo{;n5)-AUgx^jSxh1i zI6aAMhrb=1aJr~f|F2f>m(gB&jEj2eqYWlOIsVuC43}{M~Y2i7ln_}&-fLf>vq4@PxKmv?3K~y32I>&@O z73f&!ldgm+V?!9^wx0aB@03y2Myj=qrQj~FRK(RBj$SC*ONM90V~ZXw!^GO=nPSA`5S=oZ_tC3u{*CHyu+ z5Z^?VH9;6?P5sL=)E2VB8Y1hI6rwFCJ33qV`u6A{f9ZCD#1_@Xi(3qafkLiV>m0m^ zqkAuZL$eK?f5K9g4$*p)ap8imZ;$T#t9B$VD&i!42E#jn&Zv3l2aM}18|eB09U1Kf zosNa}*K3Px&&P-{X)@v(0pArgbfVMPC;NHTE8{Q|gq9D~siY%Z{EOHQ&<_SGR5~K+ zbxnL*$T}ZOAEFn%SmhX{?a?){_gVYQJdV1R^uI$?_0k7C?V7n0V~AgOpn?^mCB{@M zf%fS8Ji}AS`L1_tQ1Jv92ec{3L%T3eEJJ?WG#S6%K%Ym5=2<@sRBv33I1C@})~sD_ zoVGv!wb09Qm)CH4%y+qMLo(MESK53mD-5mL)#-zhOU>P_Gnu?U%MB6FybfC%b zNqh9+*7m&cblM9n0y>5@1?e>&V+W5sJ0)hf3*lDn+O;(C{z~>RtNejFcb^{x-QlKYIFu?!LJ4f;6DQ&bK{ZvUp&NJ zip`_Ir)?;1!Z&nx=GzvJtce6KgAi>(*`au{$v9Gy(q+Kgp^VY3$QY)$%t%c2VnZNl zeI^$sk!&Zh)k}Kgg_&)X70LDh?*eUtJ_jm}B`VE8X$DF&P?~|FoPmD<#o!A_5}U9q P00000NkvXXu0mjfo*t@S literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/media_like.png b/TMessagesProj/src/main/res/drawable-hdpi/media_like.png new file mode 100644 index 0000000000000000000000000000000000000000..2e8421f2fc4c37b25e5292c4119b24f271ecd05f GIT binary patch literal 1406 zcmV-^1%djBP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz1=t)FDR9Fe^S6fVDMHr@Z>5Z0N z*excjtI4_&eSimVAtr_ZiNy873!)ft#Y@~65|#MCgV971Bs>{nK%*ERp}c?^t`A%i zZUKSB5Q?A@E`b%wB7*IciFT3cJ&bKBe7-N9gRH>4;&pYNCD<>k+7YHA(@m{|qTTw7cF7;G9~`K6qC1y_K=nbzjz<=u zqwFIGx!@;eToM!ZhX!u9`&+BkTF6lV__nsTzJv3Re!t(Bo}PZi>2zMl(%mn4;|H_g zZfa_JlmE-h%fHg=^$#e@%voSys}*fdPR`|xjSZIo7EkoG za12h7HcWD9Y3Vg`(1)DlK1yQ5+BeFe!PeH+r%wP>`r7B_=00J}u(FLoyV4*+Tiepo za-Dj}3GN2iaaSIeixIYuBooBegqtUkPDpS5aUpLb8SaQM=@-q z?1`i`AfLu+wrB3+SqSVtia`l>c6Po1u!x%|4JZ582ezRQ?=&!u>E05f!ZhBc1U~Z6 zH&O9<4B#}D4n8_gO-;QIr_&q>k+hj6Cnw((VtBZcE0VFYU)$K&_@vkYI5Y!8Lqo5_ zAnfo{I>gX6;>uDEEI$PS`*uS^LoWOxF4a*?T~}AvivWdwf>$Xh@>3D|_VW6X%len1uzmW|J& zDs^mZ>?YU$;AKOB>FMbY0BBJGweSUCD_$TlF){H@lowEeiQZ-6xUR_L9{k^wl;DSLm&^4Gyru6iRg^e)rts4R8Qm>Jh$k}eyqxq-ooCLg zQOjkTot^!VU$>~=BYr-P@=X?%GalCqexZn^@uB@sd>}-9vHz~Y-=+8P>EdRbkpKVy M07*qoM6N<$f;qT_+yDRo literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/media_like_active.png b/TMessagesProj/src/main/res/drawable-hdpi/media_like_active.png new file mode 100644 index 0000000000000000000000000000000000000000..9f5f32c202b6f3ce903982882be4210e1bda9f10 GIT binary patch literal 716 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 VN%-&!Em{Bo002ovPDHLkV1jQ$Y_9+S delta 1119 zcmV-l1fcue3egFWfqy$mL_t(o3GG)~NK{c2b)3q_I4V6R`{=_g$R1z?(F-A>$4^E{ z5M(7pMkJ)D3Dt-Bkx^tIiXRaui1?x)H9-O~N%Mhbh^eHcNs{@_Ol@Xrt?3@;+T2mc zd#jH+aP`hPd#}CDK6~%8ubbQd@sE2zr*{ADY5}0{9uN?)s(-Ms@KAMi^_kSv)SZ|! zYJj^a2wiM!?B`PUebgI4#D}D(H z2_eF$@Q_TyzpJY&S*)AQ<`3D~+553hT}=iv#t$QO#J!IOy;1e}EvK5F}*(&3~n(rN>}EDa{QvH8tm;H%WQw zS5{V@hOGBu3HcHbyZa;~U_}O1wzs!mBM~W+409OpDl02H0WzZ!#f=rlqCr0+>G@SAx_dH#henHuh1%vvzcJ+yI6jo&^nGkhvqsFjI<)i;qIn z%48a|U(x%dbcFIW8`4(`*s@ zFW-@okw+xMBa4iT++bhQl+&zFOdvKW@hGI1$1vVWT+q4Ss3BP0f?Hp2^7BLkarfCqA=Q873eIe zFn=0xT#rcxDcK6}+j~#UIU(e5xk|-VIc8)YaEpnF2^QcD4GovD#=7HOQBiRUUil){ z=*9H(^xatV3kwTdFXj~pscS#V%gav+@PDkVtWX&AV!>j3aGpmc8RZ>ji{4gRHttduN4C#>ve+C@9FpbgrwbyTE=&(wEEp lwfBW=;IEPUZ}_)(;0K{S9cj())WiS)002ovPDHLkV1l~_CglJC diff --git a/TMessagesProj/src/main/res/drawable-hdpi/media_views_liked.png b/TMessagesProj/src/main/res/drawable-hdpi/media_views_liked.png new file mode 100644 index 0000000000000000000000000000000000000000..0fbb8b1e59ce720a0128543f842f8306e0960082 GIT binary patch literal 662 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM30~3R%i(^Ox z=iBMN+Ae_-$9pH4NSu12yXhJ8jh{?GpBY8C%Y%={`7zSyW;bEi6*75QX*~SuqBdD`x76Bq zOR8c6UYkstwoETWtCwp^+tQWtk*yE(rcU^>>5%g2ol3i$?bj(EU7eiuvMJ6d-RpCB zu)BDO$z08|y1ua&;=EjE7)@Jt@5-i~?;QGPPJHl(_no2H*WIfVOIN&#D4eSq6Mi$QMh0Kqvc|GC0re;E$AE>MfYO%1q(mKB}OUsZ);7el=%f<~8 zj2J7Mcm30JX?|ekV|YM6{o}%4+8<7|6iCFdcKq7;#Ldk{<9}XL1;dfbn(0T(w;BI3 z6F9+qb57#pISqAl=bw;L{5iWsB;caqzI!f5{(1<$VfZcQDw}lr*HhIj_Z_@CP3#{y lra4wGTIBmFjor!W1Gg`W;)I$ftkIw};pyt`Wi4lDow literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_unsave_story.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_unsave_story.png new file mode 100644 index 0000000000000000000000000000000000000000..c834b394c7080ad9baf6a47eb088b8ec849bdb5b GIT binary patch literal 1065 zcmV+^1lIeBP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0lSxEDR9Fe^m_29|K@`VxF@9hW z3@0&BK`??A7NVq32_Bk&kZ2JS1S=~)8Z87NS|p%?f{m3Hb`mYbSg0U^g%;6Rh$0#U z3kxkQqG&|X1kc|;naRy&cXns<1tJCmZ#W4;-h?RrKd1=Nh}7qq)YShvD+ z@Yz&D2S3L98|y&QENGLLA~S7KlL@0zfv@Vx_jUn zY>Y-cD}=R5QkXIEN_kR)+|<-}Po`h#!ptN@y`V2}x5SKd+7$IpfVI=94WX)sQKKHT zV%Brk6t!yLh1ugLW1Zb6HWIvGgc^3b0@icc)K=>0gMWb)?mm$@!FM1_{E6aEYzn_l z@M<^=FF_kUgqFw#&Vtw)XmniBDZx!(?N~HgSt0N>wT+m2c&e7J!j?*Qjv0x^Rl(TW zq*P+t_TQ*@`wir7;X!Uif{GsBtr9g-AX zk180;Y$~>qRBdDUC4rqJ()K8Syz?M4K>_cE(-NA$W~Tn1}bm`uFMFeVCs#6!JBt!}DZj zNkp|U3^HBTiCaZxVv2wozNXxR*)|uVbZL+J)nO58BsLY6jfw)h;RjgL*<)`n zdFm9&+n@x-SvRF8yANPZ?^vPlW%|?WXZ;Oym3>bMrQlCzK2-z7?t^QoZ>}cquA9JI z2Wirg(4VUzE2da01ijmvhVG!3J%L@ejveupKnH8H_2nK(&hy`oCFs}X-6ZJX^A%-7 j{cPv&|3kiw|E2#g_B(uE@8|XE00000NkvXXu0mjfQ)b!4 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_views_reactions.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_views_reactions.png new file mode 100644 index 0000000000000000000000000000000000000000..fbf9e5ee43a6ca5f8831914f4206b054b1ed973e GIT binary patch literal 922 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 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_views_recent.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_views_recent.png new file mode 100644 index 0000000000000000000000000000000000000000..cc24af69b9b80cdc2bae6e93b1ed89e257948925 GIT binary patch literal 882 zcmV-&1C9KNP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uy~+(|@1R9Fe^n7?ZjQ4q&>E$#|Y z1e>5@l}a&SV<|~M(ghSGVDCR*Yas;ESXib=mqz=PHi0xj3oCz+TGUt=5VX){{d_kw zx!v2hyKgt&OefwXzLI-6zLfU65|8D4{zjF{xJ@jZ46 zZl`Jb8~gV`Av16teuuG;uVQ9mD{Ac!Vnf6p!$sxyMRbs64<>Yx|$ zlkqdSM#p|(`$69f?m~ygi!kPkq~<#w??rYi3b8r(5ef(Jem8}Yw_;5LlWX1>%|?s} zQfIuF4~%Cc!Wvzq0i`8KJFZhW4xzVM0v8%Hb(oYE^rDnQ&u24mT7`mc)3G}7|_`(7oV&9Uity`YUbC;eW9Xkabt~!IFzQG3s-i2S`Rrr#ko?z?XxjgsC zkH95s-xqA_0c;dm9T9&KJ~zF0RgZjU&;d@lgr$lP7kh6V6*0Sj=1q7dG|%lTVVt20@Shd^!^>AV*W||0XZ#M%#X&DvH$=807*qo IM6N<$f;D-E82|tP literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_views_recent2.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_views_recent2.png new file mode 100644 index 0000000000000000000000000000000000000000..14a846f3b3c4dc2872eef0f64fc73e6350a55025 GIT binary patch literal 705 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM31CzF=i(^Ox z=i3>!-pq~yZN*&60=5Jwa+HO2UE8+u(#?nt4zGWWd*|9Kq;A-@X`^6v@GtHyUg|$0 ze>8Sw2+lXZBRBhr-uH>#?*!Q6p5>*dKfAm0^qV-Y*7}$6jLY}$ynZWdtD1yvGw%i- zv6uy1+x6C6OkeQO;+(lvZKDV0m4n(HTC=q02W9negt4?gkW~@=spVFvki-%Ys^=KB zDB|R**2hviJi9wZ-3`N&L%G;P(-pJGQs{1!W!1fvhVw7U8f<%K zEN6CwYxafIaK5KpViK|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM31Czg}i(^Ox z=iBM~y_g*Zj`fO76AQ}{zTme(ghf04pq5=bzru@VjUNhOVo_NOn~r#CbF)gT9=Tus zE`5@>S#`b0qLc^8>G|pV=FYx(`|j+SGf$Z?|JPyeUG@I*+p^~$?y~r9;8E#+z!+m9 z)ywzxJ$GYHgYXBQq(vK(H+;+%blk@w;=vwqFEH<5WJ8JV<`ZFd-S$!vEw3NQMVt%# zcEG7l$(B2L)5a6!w)xR3^_4yd%?RzfyU1k|tKM3RSFEg!r=Fa-vv9pA@3FE^jGv}< ztgiZ55cXHK>U4%d&sk1BrTeGEErQj5esrqk_+nbxpc18aOyo@IfgKA%>^dz@*VkHD zT0eh$k72iJLZsJ?s)f@}3%#kzUcO`Mj3qt}YXx@hSbS4v7XRb54_4TwzPS9ZJYkQI z!!4mBnm1oP-)NVudfm)<|5?EglcZPQ;f;Cga6!gZg!@GL<;xn&XPrOu(vs~(5+kpK zs#ShZdGlG#r4hb2s&Cl6OV8C&n0sr|#`sQU%`xZVtjjYGsVYVl zI82JUvg}Zq^qmu$Csf~d9lv_XU+-1j?|j+ghvxs?e))RK=O1#7{0f#Qdf(UDp4&Dh zg6(%~l~rG>*|B-<{)fYN|6!Df*zskrq1^X1+*yq#l_eref_J`>m7T>Ql%DzK;Vdq$ zdB57TIWjh_lUH1Ea_54bB1>wnh=#F0y1qk*WAm!cyLE+$kWTSJ~_Fc z{kAgt)@Fv6b~b^=(LY1>t6DWga93WuufQ7gOX=J9dXeOrv+d@mB?K9L;It?#Dt)<| R#}SmoJYD@<);T3K0RUc;Hy;21 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/mini_forwarded.png b/TMessagesProj/src/main/res/drawable-hdpi/mini_forwarded.png new file mode 100644 index 0000000000000000000000000000000000000000..fe642d6c34fdaa7765c9bb850aee3d62bf0337c0 GIT binary patch literal 431 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfOw!ZEF~o!S z?bN+|jDZ4ff6atCyIi&?m1OmD?d@}08<=I=cuQErrmZ|6Navc6X9P;>n&D1B{Hs4&Z2wnv+r zyG$pGvn6e6|8-o=WcfmN;TZ>4TNG}}OmTANaw}+4C|tNg_(aPgr8P|}R?X6`Jb%5V z$!1OH;>=qWvs~t}Z(1ajF6kUq^t#dU`j@cKz2CJL8E|o5O_=m6-^eReek=3!BY$25 ze*Ty4^*F$^J3-z{VA|h=vkiPd7hk>iPTcjf`}1jASq<+V*?Hcb^{i3&vj>)4QyXt? zSX{{vS$qB6oY$Naew^DOW_)D-_k)G@XWz@*XUJt;{C{SN-E2@`dAj$Ycp$rg)tXy8r#DKH+k$~Jo0(V4MCA2nRpYd> zLucN-nRVlXYW}nLe`lWAelzNA#Q(oc7Z-9b$-I^FU##SS)R{#Zw~YRY%`p~ZzQ8K| zfg}C+3;h;z1;(`8$R3B-#4|s5&j_8}dR^9uU&nWl`R8%vL-8Ms XcK)er@5w9yg)xJttDnm{r-UW|$U>s3 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/mini_views_likes.png b/TMessagesProj/src/main/res/drawable-hdpi/mini_views_likes.png new file mode 100644 index 0000000000000000000000000000000000000000..7f57986a9eb712893472c0d3cf49ccb5e0e718a1 GIT binary patch literal 510 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfEW^{qF~oy+ z>y+JI%#ISR#?q#74na4hLq70s*>tM-iRG5l${CWmEE_j(_|U}R^yUlekz-yLyj-kZ zH`Te{O)Z;w)4QO~V&?y%b3bpMeP<@sc=*ZR#};AvqGy`flh1h1OTPX=e8u#G);rqe zZ-4gT+sQ8HD5N|oc*8`+pcU-r8e}hh`*dgiEXVt4R-baKF3Ok56z{%zUMKO=*5#}} zRgD+wlsvs#!g+LqkKwVJ6|8KDvpx_zC4;Sbw?U(3x)AA4ps?KYHio$nHNwxm%=D*M6dR&%$Kn=lexUQ?0mOaM%%==BevNm?S8tzopr0LjV7Q~&?~ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_customize_s.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_customize_s.png new file mode 100644 index 0000000000000000000000000000000000000000..e6fb8a1d767361ca33a11eee5bddaf862e99cb4b GIT binary patch literal 585 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM`*=A1{$B+ol zx6^ICnH>e%ijOE|zPVzxfI~=dOCSe_SlF%TpW<7-*>k*n!&-fM!YME5kKBSR2cvYS zm?$Nkdv5#fkYL$F<9qBonDf)hpQSy&yYqH`h*n$;YYnScK%)WA@q?2}7M3VnU|GI^ zU**y(^I~JDRVI1|ZEmn$SLppB@m|TdL2DzkN^Z2mH@_!;|DNBL8*}rROkaBP{GuQB zy?^=sKB_pD`tG4cvE|w_wR;Rvf$tOaeopvxOs`(~<>@WHo6IKcX|mmr_(eJ@sdnzn ziAssGGMbxRQ`VWc(k)THT_?sGQygu*xda(J9c+2LB z37y+{as`j(NeW102A9gpTAfeRIB4fltvOr4?S5MOTSxcP4p-9eB=bZkNZRntS@uw+ zrJgm1kA2CD@3QCZB!4eC`(EWp4&ThPx{jIJTO4}&re;1`-D6x+8fomZuIF5sWt~$( F69853;wJzA literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_gallery_locked1.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_gallery_locked1.png new file mode 100644 index 0000000000000000000000000000000000000000..799662cae58fcd72eb6d8c4226f359a450ae63ac GIT binary patch literal 798 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 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_stealth_5min.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_stealth_5min.png new file mode 100644 index 0000000000000000000000000000000000000000..e67173eb9272231ed93ff7a5071c927ca3f1cba7 GIT binary patch literal 1182 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 FV1kD+mFEBe literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_stories_myhide.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_stories_myhide.png new file mode 100644 index 0000000000000000000000000000000000000000..a81201a02cbf61851ee733ce09a7107c20d32042 GIT binary patch literal 1131 zcmV-x1eE)UP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz0)k#D_R9Fe^mraO`VHC&bnlTw) zBa~7KViF0Za}%)O-_>Zc+JBaWDC_Ht&EhU`w2t;~{WTi_%o&oSrkK?;=PG_&}Oq z(u?wE&9PF9c9RzH-n^plPX(ReJlL9((sdDYEJeX3q?2psm~xaUCm-ejrMTv?}{p6v{d?;aaI`Mod()f)rzt{)mf1uc_d!Vb-w4*E7tALBzmn-FeDWu8MS2S z?%#)fg>k|Wdjq%+wD8xOZ;C051A*Qi=y_^`ISYkCAG*5kH=rJLg^4<_KSK9pJI2*u z8dwaF%47FBEu}fkchb|3`2{kB*9D$CW7+i_wqS zFCJrVQTS(qPe9Ti<}TB5hKFl+nKO8Rw-SVXhR4z?Fm|Cwj~0bbEx}|@kUFcvvdg@# zv1_u7-xhp3fj)iSfs0^4B^R4p6!!WwMpu_`9apAEUUwTL6BX5(Wz}vW-Yu&33@}M@ z%_?HlHDThPFu{z(PfAgbgQ9dfkDlDY+)?$fiz0z8QP%oVlLpq!SaxxXR)7PpT8Tb` zYTA8yxe_0VbaGz>q1cDwL5$IB3O=1>gK3~zLaa{}s}@p8Aek1r?Y?x5u|eDa1Go#C zEEc^L=rdcQHQ5sQ!Zp=v_6d(9Ri9ELtn5LU5-IyC#j+V}^CrSx1o|*oANu2;AR((l xCyD;5lVBZK1oZq8v~hM-y}rQvFMs?7egS-ag$>Ex!3qEX002ovPDHLkV1j+(@BaV* literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_stories_order.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_stories_order.png new file mode 100644 index 0000000000000000000000000000000000000000..c5d514be9a04f577a9d647479979e86b35d50e53 GIT binary patch literal 1370 zcmV-g1*Q6lP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91Dxd=Z1ONa40RR91Bme*a0Bb56Y5)KP#7RU!R9Fe^ms_Y+RTPHzQ7bd+ zWDkWUQG)hRnN)_AiVq!xs4ODtKyjc8)KgG&fhdSBls!ZQWkEgl5EPuGAc73Bi#;Sk z`C?ZqGm|o`sJyPeZ#lu7=Ctsc8Srj$`}15Q-vPo= z_!Vr5Efo5PYCyX)b?_ecm^?}Rb;_;H^+rAo7r;+a2byj08Mq3Xn+=bLXTdAr^Kb_Y zY{WS|E`~oB{*aQdVW(xeD~S)K-1VU!(b8Z9?oJKA$Bx0O<6a$5GXvfMcS51PB@wng&}*EZcR_p(tSyT? zU-=YyOMipnDcESURUKpwZKuPvP&l*sGI+97i{fK!$2HKLEH`W?Yye|TI+Gn8bhhfR z(1(MKnf0kq0_`~Hk`lLst|eYvs*EMqE1#shTi8M0+fClu_u)tIm zfOZ2ETk>YaC&9fYz`1$Of8lJ#BWSFa%mQlMEYHClw`L_>U5edcq8b#weZ^Da(!3%1 zI24cNx&vKO%7-68J$E-X_oTZ0*!b7?)jI1EP@4~GQIw!RlKOiwG%ec2a1XpW^cYm! zl6AZp4n?wyU5vIBu7o>bBhcpo3fHCLtFuPq$zPdiE$TPHVfb>c`wuoiv8tBn6HxnI z*`g?pIHPt$tuF=fZgh+9X8Tjr%;+wBUtMP^4hTK(8n@S(YlnY8?Di)H8tZ4F;(#ze^&3l| z3>oD8IKN_-wq5sj;+vT9P3kewPg7CjU7zYFVlGd`AG9^PhIl%hnd`1u_)4z1!xll| zE{kOwz7zyLvdRr_Hn55 zWb_wozhxb*s2PL8*L1a+@Ruus&3Pl@I0vlH_0lJKtu27FT6?B-6eoc?H(*~-GYiH^ zX*4fJe-(<_VVU^#QZ0(d^ZLps>GzCy3%YLp6X?Ukjz>n}5i+06g~SKp-!PsC<@Jc; zOngDt0Z=d>I-}wR7@MtYeLs=54${N7@bhCq)Z@Db--P1X(8Hp6LaQBAB3D@omO|H_ z@X$M_N;Y(8OF7rEByxK7vMJzH#Od$7iy~!^`pk5RbsXb$M>WKE3$S z^&ngiw?fa6f50!`2KXrSOQ9NITmC{vkIhM>;jA c|6vCH1!>WQ`RF4AJOBUy07*qoM6N<$f)xRIs{jB1 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_stories_save.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_stories_save.png new file mode 100644 index 0000000000000000000000000000000000000000..f36eb1c8c6586805fa9f4c90df6c46833954070a GIT binary patch literal 945 zcmV;i15W&jP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz08%ab#R9Fe^mO)EYQ545#%pzfk z5^AFu5kwn7q96jn572-ula_9zHkE`QLCAKJ1?__R2oYGTvH~L^D1)L+;i4cYbFi@2 z@BikW$9*&JIdAlen>p~GbMCq4{O@_^-goDfN*(ERV0#@XH>O8X)Q@i%41#@)^99Gh zh`U`bm%sV(a4%?#|D5m7v%-Zf_uhn{NCPy$IIbxLu_V z-ETK3iKp^@V4b;=OawHFb|_ww;EO==B47q6L~KtPoC14V5i7>U##hje6hsl1!D}$jVu$jIa&z-8Ryn1eD(E@ft6&5yu<$W- zN}Nv@o6z(k34n!^ep%Y^mq%)mQS5gOd`Pwq7ZGvGWd*r-d12i{f$(? zocWwxb#tEEnGoCpk}Yi+c}KwtF!_ry*0>VBaiP)QG$tssApE)`E{O#AEl)V`9{_KG zMEYTDMbQR&A_;8AATje$LjypcF@D~ZpHs+&ps7Rnt^&zF z@H4ie=pA~%NU`ra|8Mje^Gh?Hc5_nG{#;9&gj9zZSAkkCxd8^j7Yz_;jrB1nQQU>B zMet84z=^t6>?I;F=@9l1SOt=Mwh*?qYo9x^Xp`)wVHGx%8snSYA-d%!r*+gEH0See*S zAo&AQ586~10oEZUd literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_stories_stealth.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_stories_stealth.png new file mode 100644 index 0000000000000000000000000000000000000000..c7007407f273559bffa1d1ff508675264e084e0a GIT binary patch literal 1068 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 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_stories_stealth_locked.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_stories_stealth_locked.png new file mode 100644 index 0000000000000000000000000000000000000000..d965f63f8e8a215da1588a5a94c64d8cb320adbc GIT binary patch literal 917 zcmV;G18V$Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uy~|4BqaR9Fe^m(5ERVHAh&7*r~y z*(Ulz3R|>kC$u)&Bq)VJ>mpki2>lEF2`y|_%S03d!9ErRtA!9E3Y5#`-C{#rhZFM^{~b;>LR1jl z)K%sUW6iJvr-LAvip6ZBe*${p5bSp-*F3y~7cdHsSpO4WyQwm;3^I9NDcTp|3#?^R z1W0&ptEiBzCYeNx!&dN>VthOONjM2h@EBgh0w~vBP{l4$nWy;rnMA=Km69mvk+0uw z88fkIqNt3^>l20uJ@(hE0u2?#<~v~)WOpDunE1w2ij8lB*$o>0(9>RDQEYhLl;Fpq zDSikTTOUzu)C!+L_6pkKVyw?x@uJvd2+aCy^E6Ljv7*@Ep;Pk=@6SzK5OZA+e*fT$ z6Gie5ARCE`i1wKu20eXs6-B;wIOq4G^B!c^{a`|a`72@6swn-el<5CerC2}WaxVHU z8MyBTpX00DvR)S_H(&{9*CdK{0qB^>9#}qI<>hc__2Z16h&7mQ2D`m4Y45TS+POus zrXS3PESChez@nR(!?*j%ScAE2FO1|awCV~x&@zG7sbptWKv1_m|bY!YAX*4cfx z_*@5_MNKeai}4pK#8`)k(MZru+FNWc?wM0%?DlC{CQ-ymjB=al|5dUP(FRW}5?rN4&=1jg{mGw!w=fT7*aHWl8}##X7y9_auZv22abUhSBjGW)1>Yd6>6K~FcBH*# zrJ`4C>#BN^>dN(^s4G4K`#`Ths*tKB=0Go)_o&V?-kU_xu~)1gv=0#T(FZi5;VPxq rb-lJ{d(w&)Dj^$2OwkwnZ|DCFE{@1J)C_9200000NkvXXu0mjfsmqkO literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_stories_timer.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_stories_timer.png new file mode 100644 index 0000000000000000000000000000000000000000..13e2f1e43906bd3b59735a2769c1c2c1358cd7a9 GIT binary patch literal 920 zcmV;J184k+P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91B%lKT1ONa40RR91Bme*a04fgS`~Uz00!c(cR9Fe!n7?ZkK@i8^sfdO& z0TC1v&|W+1m)?IO#v+w}fYl2K5n|~dkyat4O|Y~G7_0@62*zKX5~Anl`)qGvArFcQ?D2(dd7ax~`uHXX3X}$Q&@4o3*G5LkXy0iP$^frpNJs`FC8u zsjBL|H-9=R$rix`?1Da#&jc*`)o^_gT=wUDz49+&Is^;Y9)XA8lJon;xCcIfPj2oi z;|*{doOg3S8J__?W3s;lHMqqp9x;{)#f-rLFxf#_0as#7vN<35ntVkup4YM1eyj7E1KK_c1FLyfQMzwZ52^oq%OvE3?ru&Ts+e z29St*oJED>08ZRC-S^(xgpV5IZ-?H-C{AF{)Mm08 z9Mxxj07=#ZjNkm!yZJMpOyG>-b}`D;>Qk+FjO)&Er)5Z7;9p#j=!mnHFp1LRWF2@V z>eMmJP>_0=WVb`vTw++7n(O+AG1~OH!T1hcAvI6sl4xI?$~jXQwNXm;Xz8CD_4NL_ z9NKy$mV4wEbiJ`n_a>)i4gQp8*N2PKxfRnWD@HrjV%@4!;)2W@+f+iuRAN~)I2 za<>XfMn;S}3*Gf>(*5(1XUbFkTlUd~{9V2biZA#adVbP1mn)Xba<^8;W+OX za1V909M7W!RIS@qw7Evf5(aYQZLZ?Lc@s#ojvtAWd}4@ z)R@4tafG!WMnNZi$hVb&y6}+SDauw#&s5ea(&F7}>jAbStGLR(ID9fkxD3ewFd6!x zD30DQjjCHf=o+HFPibrY+MBc;1V5$OR=$P!2hUNM`qVnGj*c1?`N%hZh!0efwL*b7 u^(*^#j8?_YGupMaTL0$XF`>dvdhQSFF@GJ>>5<+50000|k1|%Oc%$NbB7>k44ofy`glX(f`xTHpSruq6Z zXaU(A42G$TlC0TWzSWdSpS4N|DZ_xKM31JguL7srqY z&bQNTvqb_$+BVNRw1jg>$cB*46GAF1e_pIf;+p-Z&4f)gOwhaD2{=j3y>hJVXvaadXzap-HC7P z_ApNVul!m4gXI?Opc|UjWvuHCUJgk4pt#5V_`MwlMjA^P^AFl;d|Oyvy)n;duVC^T zgXxx+d#`%C9$>0r6P{;e8Lt0p!Rd&MK9*vAnUZO15@K5BcKkWHBQ#06veTxlhI>}< zj^mFGxJbM?qph*;@KZ;|7sUm#_c*QQOABr8IezER-c{DEH!iX6bBKTDwIKh%lo^?P z*Uhw;1uvX;{w}aKNdHh;__nFgmvCVGf7vzQXUTeHNBF`5T6Q6IU$B_FxU2*cwf=08QjO#NCv0zhT>Si^?>WY`%Qg5zwl6&HXShyz zjiq+~hN({eiSxSMET2?g*w1zS!4JNlDzBN#ueQj2`kNgrUezmk|Neq~t9B^-O!*V2 iBWAXDURgqr^#|z<{C>*XNP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91D4+uX1ONa40RR91C;$Ke0D9(TtN;K6he!C8Fgc@`Hmx2v#B_ zQX1)CYH4cHLmhwr?OvyK&%NiKp?hFJT=2i^{Wy=k&z|Yf;VuLVSw}9dGS1zyu1I-3EfYFZ# zgR)xS>mfgA03*Nva8FizA$A(P2|Rs|($9(`F96%Yd5}dHa42RzxZiRM;}l&1JRL&0 zR}J7(!QbAQBj3co4?J7gfN_xZsm6QIyF}kCWdACpLNnE7Jd+9=lwzAxtv*KY7>8Vl zth;j>dn^;cBzRY#JLG9?UO|Gjx2^`d%UN^{$Mn2f!B1clxb7+`d7_-~p5Pnj zleokRBaZ>g!ONiR(V=T4*CO?7vRYL+0ndYft5ms!ZM2f$_km-nm<7?-5&I|6cMd+w zH$q<*eOXLHzTk5b8OI~wVpb;hvx

Jb--4#j5bk=<9;K*ZDSB6Kvgq7E>+K455$Z z1&;BHT3OMz)RI&LXlNttiIe4r>&x=BIp9-W-ZE#;68Bkr;3|+6nX*6Z6Y-4(di+LL z5XLJ8-VYp&juV!Lt_y1mO|cvm+uVkXYnDLlKoAxId?L_7GWreSQN_Xs0e#0s4KClu z-}YAiZnbz7vMa3&`_FRH5-?2$UxBW&!5e|!n9ra;7=6Q$TR?dH(WbpGkB%xf5Ruyb z^XP($A0LB1gLjf0J{S1C?gV-`Aiy63;jYG5-Q_&mW&Koqab9%v_l^y^q1(xOD{?8? z7p3Zai{3YBgn-^V6_cedPV$Io%ko#D*_MR-jtr4DI{Qj9M&1lhK846SYv$1}1SC13 zHikKQS@`$6LA2j}=W^b5zKzZ<@pBLku<&Uh?*#Ok)hgp8rVC@Lphio=GZ^f05sTzQ zFM(~&F7YE^C!jY{KCdQE!}=tgD4kmJ7K~2N4<$*r2YMBo7K}cD&&dbx40Zrd?^+(l zrQQ+co$zoG7FWRu(4*7U)}oU*bN_B8MvLhH@U+I7VqEJS>KV2z^Jj7b^@!3ZX;&+V zfAYHul$~1AMe+9nhk>VLg<{m9RfC3|Ae~>;Xh9_Deft0mHd_^b7296W3|hcVpm-fZ z*OyAABh=}Sd=QKTqE;{;-?pID^FwicQ@4P;l}AVg>7M{2)E_<+{Olrh0-90JY-PC= z(??$4Z2w6^%_R*rBo5httaGB#UkH=R8r7>%a2R+C901i0x0uUFcj`myi~I!m!$n+1 z9%ueEulWw9gVQ>N`(T>@h64TPLGPZniF4pQI1ZY5*RH@5BJUZLJ)m1O>O225aX&=8 z{TV~*4>SJ+PN9ddP5Vz5Ct#r0fj44ptyu TorqF000000NkvXXu0mjfiC9Z$ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/media_like.png b/TMessagesProj/src/main/res/drawable-mdpi/media_like.png new file mode 100644 index 0000000000000000000000000000000000000000..19d4006850b0cb2a9c730d8ec13bc9a0e36c4730 GIT binary patch literal 922 zcmV;L17-Y)P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR917@z|H1ONa40RR917ytkO0OB=utpET61W80eR7efgmEB9)Q5eTlYw2t+ ztzg5(ycsnJgb~b}*n%#)aJ5P7qS|FQxvOsKA{-IJe__zBB^jGr*2Ngxl%zmOFf4Gr zGR7hhdlSvKblwzjt3__{ZJ0l|_+H^V{f-`=! zQ@LdEs)>mSeLNmt7CYwLYPCLqrb?odJDtv_WRNvFI(kR=WUH&IW(Eg?!C@GsaG|Lf z8XCI2xw$#c&iP+Q{zSgAvNB8-nZi}Ix3~8hD<`_Tx-`Og%E-k}JxLt#>R$)$J^iE zceb^)T^Ej0BejV6##r24ub@A*lvQ~B-%_}}z3pgfYPwPi-rU?=v$M1FkukhFpwCZD zA)uwD<=XD0*IQ3pU_5 zf;)S9dg{-F7CKv7TWbNBCIB_j0|0Z`#A2(t&8ta6wtdS`Qg+exhP9qyPW_ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/media_like_active.png b/TMessagesProj/src/main/res/drawable-mdpi/media_like_active.png new file mode 100644 index 0000000000000000000000000000000000000000..19f5d4702bcfd3f2023e5756941a50c2e378475a GIT binary patch literal 533 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgftlrbbF~o!S z?$q60%#I>$<&W12N$0X`6p}s|6`-Q<(n@%*=I=|kp}NHd=tNwtTfw=!ql+bq^| zE3&EBfXlzYH@AK3os5h_%0IrHe8wb}EBKdwrv)M|-YuWVcf=;jL`fZLT@$ z6ujOfZ0(Qlf`Sst9~d47SeOORskFRrp1ED)JCCu~Qq5|s;C~I~W~KIx>vmK(ZF{aQmu>Ycy7R{S2PR<~m+XI< z6myyFj^oX{YB4956h1z(*13T3%c3JZf$QV8RIZ*K?fJ%GP407-!@RH91%>;Z_8yY^ z$Y}BN=mg`cHm;^rMp38Lhb9zfxu4py>sW?F%VT+-i|iNcJxUh`9^ZOD`NYDkRod*b z9dBkS?rQrc_5R`aU!lAqzj6el+r4)*_1ZoCukn{PF@JaWvsWwzpeXTl^>bP0l+XkK DFTu`7 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/media_share.png b/TMessagesProj/src/main/res/drawable-mdpi/media_share.png index 518219d822e876b93855f1fc0b17b828c06eb2ed..9835d61431fc6ef747648bd3e81fae3ab2297b55 100644 GIT binary patch delta 771 zcmV+e1N{8g2KWY$fq&vjL_t(Y4dqo|Xp&JBSI0ItBFB1YPa!nwL4uL>u>OFOJhsr6|a z+1gVb_`dJn`#bmdyZ4@Z&c|Z?SJv6tdC+Jyp3&>|r?BzXeSh7&SS&u2PN%(J%a%%| ztfQl&hxbinZf@=xamVBF7s+JONbPJk>rpC|NA^WzadGh`ky+uI*?I^9W(v;Rbh-QC^Y9t;Mr(|H#P zh0jDbH8nNNAb%m@8yE&$_+&Pl&jI5w@LikDv$L~OtZbP`VfkDx_XfwJQ79D0YGySC z0s%REa>ZgXF+Dwf;ddh3)z#Izm;nD`3db-uK0Z#QEqEGg$Sd6jkH>SF{PCn64#yP$ zJMM(Dw6ruvOU8=dYBZV?yE#^v8D9>F`yddh%q9OeWJX3B+QtCrkmh&*zg7u(7f66hKpb zd{tf?l#u~CBGBY;ygf{`X=`ii6~HfQwfZO%K)YEgm3COI*0Wlzw!gQxmsf*Rw<^eV z12OjVcz=+YZ6Hq~^=QMd_WJG`9aj{sHV&`_dE5+^+`PEbG*r8D9 z`wmb~5@m90S65eCg`B>AzyB&><#Ihi?Yhe~ZV3&pND002ovPDHLkV1l+w BeCGfF delta 738 zcmV<80v-MM2G<6Vfq%hCL_t(Y4c%2=Xi{Mm-=?w6HCQFN(NhHpNe^WN2GQ74v4@gi z&`azgO!iRo!4cw{kWu*Fk~9m1QWz6_s4W!5hhz$4O0-F1ps?nj;a~i3zazV0caD4Q ztq$CKzweyi`JL}O-#Opy>-*P5(BlRMfFHsm#M9`}mlG~nUw>bJQmfTAtJP}A=kwh; z2*l~g3t+WcZ?syiMx|2OY&04_F|I};k%w?T#*2Up6pcnzAZ>X(p1T%{*igCL*bCpr{FDwU2R*J~ipnt#pasY3v6#o+Gl?kfu7bULrH z;R9P+TN*NMZ*M<^vDYpqKGBf@3nOm&3Ay^i>Y&ei^Ji#4pRfT zzq_vWdi{B<@^LU2oB=ESwb&x;_~ESa{o(YpSuiJEtBamgWMk4%!T2Z~VgD2P1$O8N U3;^sl1poj507*qoM6N<$g2JzC=Kufz diff --git a/TMessagesProj/src/main/res/drawable-mdpi/media_views_liked.png b/TMessagesProj/src/main/res/drawable-mdpi/media_views_liked.png new file mode 100644 index 0000000000000000000000000000000000000000..bb52ed41c03002db1c56cae894cc8fd86ee8da73 GIT binary patch literal 486 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfEWp#nF~o!S z?G#@>CP#r*Nf(htoN>;N&l{$!E_@wZ&|7}t$W(jo(!@t@yy6WKd<*0b^actGwXN^4 z)tt4ia7JQsl4}2|y3qHb3(_^F{(C$4ePmv6;QMCt`i{*R*YDnOS$2^@QSggJTg|pQg{`8GF3vER z&irKJ(h~=_J8}QA?9uVOuj`>V^Q8WX)ax2E_V0W%t76L3i|wnrr*%$`yP*4O)fXUL zu#T;3ns_kV9Y@iYdyKD@bmMGR1#`D7*qFUC?ZIrvV)vvg^A4Vow=J_va|>iM-)D6A zXV{iy8}keznE4g5ZHz4H-fi{I>P=v^Nxg9)G0pVqnJlF#`9;$=J()M}&)(x4Z>TW^z2&X_AEGQ7i-zG$KS$Z+#bK@d-b>4xFI8J=0d~1tP6x-Gyutv8X-1Uy%gr7ZB z74dC;{bQ5tjCH$rXkJ(p6|?N4h)uhY%R<%*`3Kk|xQ-S}b=FP(^8A!)HPcpg$K7_X zTQ_MQbYGxeUS709?Me*W&EGk$$CVAHv^=hu^wGn5q2F^A>7r@($_4EYiIsRIewi(j zBe+r9fWtI=TBY?1pGn;bpSMOx|7mUw;W5utOJ{mB^>5?-ch^{IC$%}29rsPJZgOb-%d&*j?^u~)4)?yTwNYqc-Gwaqc}tiO};M=RukY)@lO zO1;OkORLlJ+HY9AocYr8xbO97GjHW6mQZ2tw@X|t}C=TeSeB4gcQw`FN^RqQ)_zdRA0km)n~!TpxLHMc4{@*T`3a4Rjyem(zz z@f^ngwiow^r}!6TE0i5Jt7*L!zPd=6SB0=MsB%xx(e+PfSG~w#+^gC`V=j>x<^H*M){}KErTxyT_buIWwZtQ-uh5~ c(%$Sgv&5p*?jI{$CW2C%r>mdKI;Vst06rW+O#lD@ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_views_reactions.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_views_reactions.png new file mode 100644 index 0000000000000000000000000000000000000000..6a17ae52edcf7a5d8a38e79b6e65d764a35d0334 GIT binary patch literal 603 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgf?5L-UV~7Xu z+bMhXSsW#ft##Hg`N8e-XtBVeYnLYpbh<4PJ`(fUM2y0!Lr-@LgQM-0vx@Mqp=QeV+*SJ9dma8^zwf&JV09&alWz}qJAPi3zIEE26(_R%WXW*~`kZgGG~-p_qZcZ( z94d&@MyeTy+#;W(mZj&_@C*^fsY-CPf7&OWG152->;dz#=x*yn-7Ya>E zE#T2y!6BI>bY;rysM?DTHqX}JZu%f+4bYYr6oB|99kX6K64 z{McBilKlN|tA+W#$j7qXpRKH1Cod~FDageArSkDit|g!62ifr4TF1NLe$Thv5@C+F zGXBXb&oPl;klh=5A$8er5B)E)Y|36-{uftp&wD7f&f$8Q|HHXOAr}JND|oLhG;ROd a?>Ybb1FMv*(n; z-Ty0iPO3b6Q&iKwapEMYM<&Y;+Rte8{?Xv+ygA%pu5mzPvuXwV-iaF*&NPqU?24Y) z#yjIkgW>i}tEJk#yI=M7d@x^eg7f2Hj^?lk4xKG93?>7Le&<9;mvn_IiK3RrIW&^$%V zOiGEdoK_EAB0d z?4K?DMP$dG4er|iH>=i*PMJREO97*}rm@t;%K@c}k!lj?v!q|8YDW1^Z!!X-x{sz9SrdRTk0_0C@ scROz9WOscoZ`(4*f6BWq?o|K4`-gjxrL+E34^Yf`y85}Sb4q9e0QWW4QUCw| literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_views_recent.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_views_recent.png new file mode 100644 index 0000000000000000000000000000000000000000..69f3f2a06210893f40d3918558eb5e274464a970 GIT binary patch literal 567 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfY@w%%V~7Xu z(Wx8#4jTxxP3F__SZd7dn3VQhP=No!%(cwSi=_K6u& z{w29@lwH2^Qpe;v%YDD!@4vB8-}BPOrMJI)wt0VeC(H8(H$K=)h(ECOy{!NEcCLd3 zbMXh}6zvaL3({vM8Bch-#P1MCO|!oNoBFFI;-&Hkd1}d;j^}&bcd18n%?|nLMxa)g1W-b>n$I$SS=*6uXX zw!A&#V#H#_vx^$?R^&b3=MyzMI)D3$l^x3!nr5DRQ=cExi~rNr_@Q$gQhz^{5fZ+nr7M4_x3AqjY1?D{m)BqXd3jb1loA*`UHx3vIVCg!0IGuAN&o-= literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_views_recent2.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_views_recent2.png new file mode 100644 index 0000000000000000000000000000000000000000..ddda6321a63a80e56a911b8de36ca520db5b5b6a GIT binary patch literal 501 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfEZ)<_F~o!S z=u}(3!wv$ixhfjLfvtyP8n^?36kaK~-cg8YR9>?95rgMZ-W^Pt6D^nobG3pLKJQJv z9yRHxwc9p{mzDqT?fLkw@3^bshN+f+cdc_TSa(2DqWYioTkZ<2(?yS;?=s~GPvG44 z!2I$prjWT;3THI(CzuwdFH;bB9(I)_|DKdf{=|Y;R#WeBYAshN*U7dxKeOY~js3!E zr3)=*J6N#H<|+L7c!fg0L-aP5z1)^Y7yNGdM0ve`n3dXNn!~XwpnZE5%b5fJHA;?@s9iD(s}MV}t4sWW z;*Z}mE_tlBTqP#_!!|y==O6R+A2Lgg)K2(*=X=r< z+cM+8k9J!V;gyRn*J$nWivE^qSGHBf{$GswysiE+)nUr_-v2L1TC_j2p1EVs5y!@r RQLLcA_H^}gS?83{1OPsz!Z`o{ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/mini_forwarded.png b/TMessagesProj/src/main/res/drawable-mdpi/mini_forwarded.png new file mode 100644 index 0000000000000000000000000000000000000000..ef1015cda7cbd1a0bbb4477c64c7b934310dba90 GIT binary patch literal 335 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uuz(rC1}QWNE&K$ec6z!vhFAzD zCrDg*@c;k+9)~-uNB*Q(imaH(+~N4ZMxc9A4o86S8HNdp<_!_kG@Ki_A{%Z9b-Zqn zkhEba3i&9-6!L)iNdCmqg&X4;epW^BGJ0KM_-Jp!dt=A@hNedvZ49hA8&)1sY|CN@ z5Y*VE_aLB0ujeJ}0(CZCYJ7@H)=ktgb@GaOBpGCHj+u#vW0><99Ur>mdKI;Vst09DCj A8vpmdKI;Vst05z%ixtW}LfqC~j9+6wDU(3Fxl+6%}I6vW{ zg4^8-(=OHA61cvm`pHX;1?yrDWobN^a6#vG+<%4NJetRNb}h)avuXMAHeM#to92n6CN-G@>y(?XxlgurSus5) sUa0JgX|(vR;{k1kJ`04j{yqJ`_s}xs%J-weXF-1UboFyt=akR{0I!vSXaE2J literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_customize_s.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_customize_s.png new file mode 100644 index 0000000000000000000000000000000000000000..95fd2bd4fad59e17e7f5ee5c1953827ad8d5269b GIT binary patch literal 468 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgf%+AxrF~o!S z?UapvOpXF=mK!$-OmWkSYdCU*Mecx`u(eS9(e@3~k1trRa6LL8Q=hZbOh{^_!SV0% z#V0o&KbTtF(&o8u_RX0$Z>AdMEG?RpT&{4VtWl#Y>W93J8BbHfCf)O=-9O6xIe2Em z-OpOj@)iZ~KD*GqN-=t$xB31PRf}CkcBWtEklK>EjOoX^!2KUsxo@b}e%rfL_}pdg zH#^tPe({50OU_Awx+LxYpWn6Ji4Rb9^tAeMbW;39?-xb8>p%b0j=Iz&AjD~C68eb^Y~KJT~cj~87=a>H<`N=*BzA&&V46PQlQ;GLQzA|n%Xp1mnfAIFuXRA5C_ii{*uBE*3wdVZ!Cv&~)gN)1{PH^gfbj;o| nIJLjoneY3W_m;m!^zJo^N^@TLlI`uE4hm6ES3j3^P6?vi literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_gallery_locked1.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_gallery_locked1.png new file mode 100644 index 0000000000000000000000000000000000000000..4d73ed812ccaaca98f318f33d995c2db552e4b5c GIT binary patch literal 572 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgfY?-HvV~7Xu z)2X|?m>oqNHh<*QnsG|2)l4a@$xLifYuPW>S^OM7ME^BS^@{RtzQNh0#9=4Jc|Sg>doHcpZLwCmAa=Wa{I09{Yoz-g*GOgW z_6%nK6u>xp&t!wl_qWb`D06U}_tZ?}0h81Ol~N|xvX4`z2z)elsQVeGa)H%-*0G{z z!V3HMyjGgNQvBAt2rIcYXRY%RwEwg-S7=O25I>fC{P9sw8J3B>x(E99JQO-?&%OQw zW52;#Q%|cRc9B$%eQx&;PZ3K>-^jm^<&#?YL!SRKR*@bYWes=Pmj|>8T}hC0d%!1` z;InI?aRI0Ph8Y%(3;0eXiaYEx4Y{(&w01J6R`L|c~Q0qs|BD6*6s;N9loC%jR0 z8~>)ssb6PH{b!JAxYI3@98vI!!KYkXCU@P3<8iy52~D5d!NT8l%*OWtXWxR{#Q_sH zF36K`xyHLa{oAiTr7GSqk4?4f{!ViEnvnZzb)^x-k#8g? qq}zY0%W&)ghR9FmUA>)u8Lyi=DQ^(3eI}m_iaAeLKbLh*2~7YwBGuOb literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_gallery_locked2.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_gallery_locked2.png new file mode 100644 index 0000000000000000000000000000000000000000..2828a543df7e8bd50b307392fa4d68cf9bb06342 GIT binary patch literal 326 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlfUZSZt)4DsMi zPFP@=u%zwh|NsA=v&@>za^#T1o;edIel#;Z!#bPMWR745KjTMUg?oHQ<~Kx4oh6pR z#QTTwh?9bI;}ZRSH`p& rhGnayGm;kHxhNpP+Xy7~DKao9$``%*IqUTVkRLo<{an^LB{Ts5gtB3R literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_limit_stories.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_limit_stories.png new file mode 100644 index 0000000000000000000000000000000000000000..09730116c44ec9ce218fd59f6a1b5095abe7e080 GIT binary patch literal 637 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgf?763lV~7Xu z+G*a}u7MJ5xkZ}HJWqns^f;Y){6(xTdM+l6m5YG%9aV+fm-zo~fR#3rj9TeLft8?d+* za!agdl8k

?&(=$dp69D{IvK9FOI$W>b5>!Ims-@bI9WhZW!6kn%$t;?KD)_MG!E zgHiT&!~^F={`IVv>V%5d9!<6?`1ChDX(8LJvkgwC9GgRqLC+~UtZ9r!G@MAf#0<>mMJZA*MNWcL2(UE!!_Gvi<=JMXdH>)aoIPg1#fRIS#j zdXm~2efC;ccPDwdPY2_~`=4xmxMVfUWw#0@Pxo){=LX#7K5p>)`SXPfgiAat1xk~90XVVw^|H`oac=^fm%nE(=-ok}5rs+HeMZKr1pUXO@ GgeCw+fcc&P literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_members_list2.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_members_list2.png new file mode 100644 index 0000000000000000000000000000000000000000..5345bb25185a819153920c7b0a9cdfaa50a1072d GIT binary patch literal 661 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgf?7ydrV~7Xu z+sXUArzVOV-%8d0v1QU zHnr$!nRIsN{+)CpZ$j7h^Upt4KG-Y1wSe;o^Ze>_Kkc5+`CdEk`_9tR>)-bKD}2}2 z4_Fx@wPJQdW5oWZ`6r(i9XH&+C%M9Q%^}7!Zar6D>DybD8Kuaax-hX#(mmHEv;M2e zlSHXFr~E91I_CAk^Y+Zjp1EiGoqL)m)c>|I9?HFA#p7%~<-)IzQN}g=fnWP)Wq*r~ zW~z2iusx@8#KY~O#Jl5rJY??i#W%!e@El$KwKq`vNL6`cPoeb2&2DE8^L^NN(*Fkg zTjiGRhxa#xRd`=+kZ?b1dN!(hOa6m3SLDks_&v^_(f<4cx7ylk9o7eP=ezV+`-dO? zrLxoZo7LgSx0$vTEsi%D*FV@;@qIPV+rE%am1|8vsbqtzF+bcFe^6`ne<)ZXxapZ; zj#H=ooxn0h>2`L56`UU>E4cFxR#&idUtp~cXj^mhGsCt-j$aQrWe$n$d2}#!`*o(g zZ23PExF@i0HLdXYIP+Q5nvK`yxfZl-z7kc_kiMP0{IbX+!yk;_CzZ|Hu6C_&sZ^2t zvolTCx3EvUac+7@Lp_gl#(bk&GZWX`?66(P_SX2I(3gtfJ*VXrvY%~@D%)!ow@&oL i^8@*nx#53V{xN)4TfhAOtis2jB;o1m=d#Wzp$P!Rbs3=m literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_message_s.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_message_s.png new file mode 100644 index 0000000000000000000000000000000000000000..7b991cbcd1b83a4317ee504c492499cd83426e53 GIT binary patch literal 670 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfr-P@#WBQ# z_vzHr+Ae`I$9uPbl6tSBb72bW=It9cZQ6LiZ{w0D@*C1mo?~*=jCMVloccO2NXO%( zaz6J&_n!0RR_S+kKD#$FO@05blDg;Lf7hKaJU^#8HRaD&jwPQMCVHsI#|mGO_$&H2 zQ9+=>^z#=svAp)w3dZsk%i?z5e>Jmn){IpNQ}0Cat$JosH{^su0 zo-K(ylX5pSKJ$t*yQzFV>SBRZ>DhI@wpIx@R6O7Q`YW;3?abpE{&$&E{=c|%POIQv z+?w-Z^M7JO#`<#5_{h8b^9%npLJ+MGNlH0OB zXsv#PlX&@(7u74zJL%f~z45UzLCSBT#lFckZOb{%B^(R(-7KY-z*}V7x{mFZ&5Z`{ z5A~jcUm6bm-<@RUDBhG?!4jMO-@$}SJsQWo$1gz!uPm$*`0NtcrPdrTcA3I! zrIZ`QcDR7qEY9);!`bzzjN?oblu0jfLQX*QsFP#3w7Hq(H^#Vubg8v!2-$lE; r4c}pYVQ2pV%QuI)x?eu4xnH{pwIlQz$Fi!nV_s7*AraP#I zNX3=UI=Xwo@0v3+UDdwK`BcrG935f9*Y)j2laf!>`UCm}+plg-+}FaH{>R;E|GcBp zXE%N0^)mQYV8JE6RJ1~_ee#04Us&ZT=b1Oh``u#=T@cYMz2P zQPc6qRHjYp!~^#-$vQ9N75_bUh2L72ApLU=4>wnS=8pBHW>p*SIhsx}dLo+Q@V@1) z-n62L58v~pma(2rJHf+tcKXG;6P~e)UkrY7xq$ylz5JJ+lJ~kL(cwNX8owRvG5*8y zUT2L{``U^5ZJQe8ocm{96I^@t!gCuJDUq*fljK=yFSPyLGjTEdUISj;0;!P8@-J4q zYj62|jX97{>kVhc-WLfO+*t{xFV>W%cBOAHy>PwxnojO>`$j_s?gi~X&M(O0-f=K1 zKtJP{LkdG$@BS6_YE>tNTB{uP{$k91nz7*mkG*4faBfx}L6nF6*2UngG}{ BSCIe! literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_stealth_5min.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_stealth_5min.png new file mode 100644 index 0000000000000000000000000000000000000000..d2ad3cb186c0ba65f9a97261fe0302625a1aa965 GIT binary patch literal 752 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfho$<#WBQ# zck0x$-XVb!$DX^%uV^t%RO!m(-NBJ9-RYGOuyA6x!=a@HZ*Q@gdQ0*|9T5qvcepL4 zl(k~ESy0}Rxg4nhyF6JG**7n{@BCcm{GI-puet5dRnPlgdB1w^_j87mEnPyirbd7G zBB1+n4UaAVdxwp4)@d*8Zan;c`eu<4}dHitK z?cf^Ts$F%S+@@u;3>Qh}8 z7--;!y)X?NSE ze`6BAS;N_s&~B=?sUzBe^X!j5_g$yP8}IlXdL&Qu&F4Jj|9Xmw=N7z9yOz++$X#H0 zP`gt2oaRPxjmhR79v%HJ-YfElE3)@1Xi90m*`-t-+)}FEB9yg!;muP|@*ga}+a8|v zI-taAwqU@Eb4rbNjQ1DF=N(`>5EwewgP)___=4pEjiz zYF06tc=x|l5b)Z-`ztBQ*|)%KTgQsH3q3(cnr|d^{W>1>xu@Uczr5Uq<#DkKRL?E8 zmT0nHu>V+H;>Ni6DdKSrRqcPGRE{rT&X!MGXq?2s`AK4Z)fdU@{5{{iFM3}UT(`G6 z^HgtI|9AOY*XO^n%*bd`{~((4;wP8%s*{(WYzHx7uIr|{ a-hYNbDPONS>!N>yQk$o%pUXO@geCy}W;`bV literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_stealth_locked.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_stealth_locked.png new file mode 100644 index 0000000000000000000000000000000000000000..90873ab93435d7a8bc7a070024726f0e8ddd8514 GIT binary patch literal 624 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgf?3SmCV~7Xu z-KiVBm>mV$iZ7~3bqMTsF_36EVl`D@<7M{^K33jul^rj$eo@s~q2^Id|^g<8y7VN4&W|Blk9^hI{RTlZ*$29vgSPiI}!E z{n44=p6iK%&lLE|3pmxEeEaZ_XQR}KtXqxi4{c_OVAqSu`#7~=m2zaxmo9^O4ZJ7% zmaN=iD#bl#vnIRH*DjVkuGtM4f^rKM+D;U6)Zx5-p=ry{r4sJNLM?m`1jTxGeB7_s z)UfZr+?C!HAK%^Tf8X+VTGiTnr@7p2R3xn~U@80&w)@2V)*dbqhcJ^v$AqKH!tR(J zTi7+>`^u9?*1KL_WA9kJAR|HW)9VG>)aTUld~=*W$K2_d@a;D9jHX*JZ|hzAtgx1O z@j|ng#<|Yid(MY&p3%L*G}mRBwPf|jBbOC;Yd?9eZ_wW2^5LHE4Ed-Ory8yj^<5Ru zU;J2DW|-gbFJk|l<%^Fu={;xL6~MT6&OW!k@Rp5!)3|R^Em?q!LsKPv5|KKge}S@{32`f0-9aOFl?SO4dIJ;WydC-=WD`dqQl%4~C3QLIIbgA{iy$EOv;$ zqwIWN;cAnRi-I{*bEmAwU)ID0;s2YDXfSGsG4RgkH_>4{>#!l!VPm}mPtxIxm^XJF z+LsmV$irt#U7@3y|+pI1z+vm(x%h(9Imyh&2f_6_ds%0accS_E1N^wS0;IW2zB7*P2A=>BVp3_m+dE?r1eZ= z*IhJMq}P74>JN!3fiza(#dBZm;M<&Z-0C2s$g#d2zKyqzuH}q2kln57aD0*aas#Hn zJUOwoTY@f$_gim~b}JSOC^}+&qg}P2XNJ`|@$*WnGv=RDv7E6WC}e9zyhfC4O4Jd< zKUxpllutA+unO1ATgLj}yjPsE+p_+`OHX>1OtA`Ai3cu(S!tipp9cL(#zHP4aLwN0^#87ud#u-&-p=f-$x$}{ zmf5y*C(W}lyeN5p!iu-N9vnwroixr*{%w6>>h7~kyp*OJtEe6M$>84iqS#<1$F3D$ zRz6>TkXYPaWxvNEj<6m5P;+C>W?4nelF{r5}E*o CKlyP0 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_stories_myhide.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_stories_myhide.png new file mode 100644 index 0000000000000000000000000000000000000000..8c4cc9db1de65568509e1e272a2dd05c085e931f GIT binary patch literal 770 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfhot+#WBQ# z_vln#k5EUE~q=oRQo)>w%ttONRi{#%Y{vA6Z0WTJ%)7 zC%N2ua;rDvMNsBf2Lp3mqY0nB{@!nHd~R>?`fExyA0E&7Y@eR?ZthNbRn`ADjp~i- z?dHEgUVsOcN`hlnJP+-*j%bAy^{_Ymp zcG`3aOHXFoZq28Qe44-g;eBzc+4X|nz4T>^)~gjNa#;n;+@`uOcGu?b3z+xMw{R@{ zlzpZCK*5FPAEG4-T5XRX7hmZV&2rP`$}x4v%QNyf$gWf@Y0NpRKjFA|pdF*pUEkgJ z*GuGvxvsf-)#J@$vzIQy0p3wh(msg%xf-hA0J%<Z-?Aok*pcj7#jt_#fCG_OCq0-WTQ`+3sB_`=@Q<51C!ecYiI++`u0B!ufK` z_J?iu6Ko0v_p1vTCvc?f>YC?asJc);LS^Yz4dVx_C$^l>U`bC>58$nG@DDCf+ou1) zg#QrZiJ}jjY7YftwljC!Z+v6=qT#Jl71Q{00001b5ch_0Itp) z=>Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR919H0XL1ONa40RR917ytkO0FgaXVgLXF=1D|BR7efwmdi_3K^VZjniOOa z^nkL6FhR?x7KRkKh%$OCYa_JiL9SG4D=h+{RTKq93&CnriwdHDAV>`r7Zol7g=61XtFX6I2_}%X@-^`r(&YYQBR`#z;uG9ka`Fthq+h9H9;TsI)a=96F zNulp*^2SOg#YU3r;4X|qv5XPuftpl)6aElvNySF+Z$&>-laPaMn1KQ4fO@Ec70>_| zU=XID%Yo3#;WZ4y+7LU3tsE{j*#i=OKpT{2CeBSzL3<}SX|H+cb?^Zm>nqqNVdI=v z^h<*)bF${5rUhMcTOhsC{rJk!*a>?#oQ{5?3HZ(|W81ujltWwQ1|uF5vYKzuvpm?I*zI>A6!cf=C^rO-xa=xaX0{$V=;1&PTyfLbZ$lO z3%07CRln3I$CySxgtI)AE6tLR1V3dp(8nsBfhS=s)Aqs(jUfHxbwtM!)PmniXCYW* z(3bfy#61Q*H0tbv-UZ5`;BTLEf1f_d&;&1nCqhdS_=_KMo5An2JEmhlg;y!xqpc5? z##liU>;)(FxXN6S$+VS&D|0dr{A72cFM<7&^BBDn=05nsEGdIVuct1U2Jg4?U`f21 zyrR6S+QDPcGJ4?KXBFH5Fz_#^zUa3qe1 zeH|vCHpbLRDbj(oO|oV6FGh8UkD>=tyD?dp+dfWrj<`AF=nYTJqi#Z6+S|--1pnjQHZ5nuT2=0_E|1QL2|c}&q@?Y; zoOo>Kzn{JHdd2&TJ~Yx5EImq&Py@UI0?nzoVTJj_q^H;~)Dd<0(Eg!ZzIjU8} zW1S-B*)pl-JyH|yvla`43zo2?IV{?~@toLs6&9%pB0mlp@6%zW35Fi+vE<}X73xV7BWqJORhd?$r8$8ev@>A!PlluI-}XkqN(^poc$KD zP0ZgfNJho@H7z^H@r}vGnLXsNn9U)%JB_xJ&fL-1XIjzp?}8eO53_8y%HOJ5llUXc z=YDAsJrK|3z2LbJ_mc-EyautcC5#8D$h&PXP)1?B)dvRrE|-tzd<4SN38z1q}8VGU1%$$b^4n6x^nyZ)~8hM g55_-b{3UmdKI;Vst0Mhjeod5s; literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_stories_stealth.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_stories_stealth.png new file mode 100644 index 0000000000000000000000000000000000000000..1714a7de1fafcb4313b703f8f8c1389605e19996 GIT binary patch literal 732 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfyvF&#WBQ# z_wH0%{}4x!ww)dxVjczyLxee6STdF>9lY^U-(X6HE2k|>_==8C>N;DNHi~Iyb2)dg zCOR`tl}KL1cK!Lz^0XWMyS0xVJ2ctm%$@Rcb2b-0Yu>l-|FKtJt60UV_bzB`Yxw+y z-*eN%)SIhUe75!aujzA``9*v24;J)s{F zVKLM8dt~31G0D!0{PQ$Z^`F4L=MK>tKNB^ViLaHDne|F?%ls|p7rc6^Jfp~T%k3}s z4=+gSzI)`z&gjlI$?ZJWh75nV2>qJ2Ug&sI_cl(~PLZD#%z0-*O1gA!N$ps8?atEe zQ?-BHGLkc|G=JG47u>T}KPfMS2n8uB*YG12ezJQn=zg5zhG z%9D3~?9th>GDh*3*e%sF+s>WeFFB(z_`@yzX8rW=!|JLF-=9+ZXO<|UF0XgCJ%`oG zw#=?&>C;!UjyS5FJ1qA@B|BYU{_Ci9BK|)=KbRkONn+2NH|Bk_U+5hY-mvcb1M@2n zSibF)58tx$;p_hswQQXJ2duFD=RL_aW4E-e-)H{Ae;HS7{lC_@=dL~|WqG>#xvX~aDZddjX9h1Yi@40UVWDNAb0!Co%5~B)6#F>itAaDd5e4g!%}VWss3iZkJf*f zr}Wu#(w*pz=Xq_O5-oKe4|wVhDArBy@$b&(+r7ZTs-As&fNH(Lo5LqAi+(s@81_W@ zm;VPbtA*Tb2g+vs(bu^BAZs-%d$YIeD&TBu_>#l}E?Ez4c@ z4Wg%_?%hu>IXzR=*W5^Ya@mfy#fyqLIz$bRDXmkvwl4Y0vz+aZ1T?gdGQD_HS>k_T zx6o} z&TY2a3*%SD9-Sdj-jcu9)p28|Q=}f-g6Q))UzN5!y{L3!dei?fWpS?lmF}mN&8`}J zIAFurzeIcE^NY5IY`0Zr99I7Se+JuQgHzoPHmuOoe_?%~KPSdEIaBq8&b#BkUR=-F zKh?Iwy6x1BWY<~uZT?Stcy<@(9k!$0XR42NpXELmw(DbDO0*~ z|3s@We$OTCZj-yJ8@*V*FPPt;_=5TT56wR<%ykywJvZkWylJ?9QvAz(iD>Oa)oq)% eZ=E^c__lq-?5LlC)8$@)Qje#rpUXO@geCyAh9=+u literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_stories_stealth_locked.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_stories_stealth_locked.png new file mode 100644 index 0000000000000000000000000000000000000000..2dbae1438410f338571a995a543fba04056eead8 GIT binary patch literal 628 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDlgf?4GBKV~7Xu z-KmD&haE(Y3yUt<7R0`=Sx+zP?UM&jo-GQy;5)%DRHj7WkH9)H`v$#N4_0v0vG4Bg zXlhp4#Tlv@_UQe5HPzfn%P#Er@!hJIV7Vo@s)ZkxlGYP{T`Srq$7fwpGTZ?g7)6`4?E1 z3$O3Jesno^fcQdxl|8%CTRM#wJi0HCc1t|=ldu6ez|$UHx3vIVCg!0J_Kg AQ~&?~ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_stories_timer.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_stories_timer.png new file mode 100644 index 0000000000000000000000000000000000000000..0f5f475852f2082e680fd9e96601e0a4e68e0344 GIT binary patch literal 689 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfl1oa#WBQ# zcj?sq-ZG9N$G@L5dCu?Tp?Jh4Ap2m{!9&-Sa|MEz`iKV2XlQ-;T|5+AT=nO_zbAe7?#-`x=Ue$dKim8M_q{iF?!*W@sd)9ZYWs-CuA9n32rx0gmg7}v`{!<Dp`l3TmJPP_c-mYAu$GjGuMiGR90j05;rgv&m$#2*0 z-~UnVxnPyuhN$(u`ybu9EvYS)Y__l`Xnw)~;XCNB4Y ztjp2&eNWn~n#bO%xT7I*{f#82z0VA%+;R&1-ns6FGj3&L>c<)WF+XY7J5A5^O zD=ITH*ShbOou@F%VZrNi*)Q#zSbj}iZntWtTh!Nz>($rRuKbfdqxtv-{`m)GpW8hu zlxPk9!O;EZ$E%*T_G?zK#~l=_VV7kBg?d#~dCsCEKIL_@t{awY5+uh=#xt-tLPYFgtHp6atOWhE<$iA6DJY|)r| zUSP(FkJP(;; zGST{||St&3bP0 Hl+XkKL~z}B literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/large_stealth.png b/TMessagesProj/src/main/res/drawable-xhdpi/large_stealth.png new file mode 100644 index 0000000000000000000000000000000000000000..9a344f0f7aeb2d1e561d5e52747f8ba554a9e4ea GIT binary patch literal 2820 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 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/media_share.png b/TMessagesProj/src/main/res/drawable-xhdpi/media_share.png index 078b750c0e5d43348f59a08a292fd6678f6823cf..2cdf169d006804a34954eea60da2db556de9426c 100644 GIT binary patch delta 1822 zcmV+(2jTdP4vG(ufq(Q#L_t(&1?^dTOx0B!7m&wA3a$^XAb}=PIeJJ1IcS4eH6$~d zjTVIqV{@@6N3l_{F*0ZNKuX3RBx^+pB?D$*jFnI!A+HO4KJ+_x zhu`?|yWoY`;=7%lbARW2U+3|C-DS&`U}*>b-#cJ8&+0pXzJCjvGuk-XFxn8>1lpnp zx7gU&z%ysgywKU%`C(gITXuDI^-f5=4vh*eYH%+pDS32kY^-%c1^xZ~)hQ_{_dxm; zi&X>1#Kgoq&1Q4AN_NZ7k&%(#4;(mf9~8K5F)HEF+S;0BkrsoYp`o)ljduAPe*cx9 zpZ^dP@K|h0cz@!WR0&~wdwaivfa`*Sg8VW5LVRbBQ|c`(Eseqa%EhFF_wev=lMwXc z#fy6(-1TUV>jB-}-34Nf{rLF!)vBthr!l_pGM7z{qJNQYEPjMmrJ zCt==%_Ma;;lLA!29?csk^SZ1A52LB6=~c{mDQnOzEPptG9Ur8h#ubvK;V!RjY-~({ z;AUBomX?;cF-KoPCphmwCPtIVw4tb|XxpVrm);y496TipCA|T)FjT^`wzl?Jyn|s` z2{^tFj7Fm`=9jCHZ1tOhuZoF@3FK9PN$ijXkjFD9AY@rxQBe^KCHiH&%a<<~2LuG% zh((TKp?|IV6%i2;H^bH+gcwy&joHUteD(c>&)h zp$8w|8ZyEiZz>{ zd+x?6y_2*Mk_VH*!#Yd}4=6l#r!Frq?*S}cs}P^9z%m~(c4aIDp-;;j#rSFe{{3MJ zAF)=qr$F8eg=J#&p13Bjd3kyHVg8zqRzm`psHmt-0|Nu!$$Y8A_U+p@0mo|Vv{JFv z7JoXl7UkvTJ3wR=nk{x*Lx*KfO8oStg*gUzV}(GV$JPZyR#sLx1Rf9s77EH!ZFsWri2FNoK8X8K=G$Yv42IC$!2t@Q|W#<<<{B=xCO%0ahm?$eNdkoUk z^H0Vl(`n*<{P^*m&d$zvh)KMI_qJ}``hP8cUlHFHs&{a3m~vGSt~0M@jy)~dhlhvX zg6q;Hw1%~*_w)1HfYr1}3ki9FEj$hcYj>Z7=@;lRMVoC{?7DmR?#(I#G65g(+rEAKLP6IJO%v8ImJtfT zrC-2GAI;VOPS6^x_VDoVW2J!`fLhRt=gysb8GSOnD&{qJOhwx*Gc$7w`2H$nU=L+} zPEJm~3u|W#CG7nD{WsFq3uJ^3?|%YG%jPr8HDzaKN5De8kK>&-q~?3VI%~=&?zy?S z_k&KG;LjcgJ0e^iQyUT*gt4t;h#R z*H~Cs_%Jr_ZyBHAbXZte0OqXWt^8`Z_nGQ_n=ZfjJI-&7o4Mz|Gff5MI&{%*olMB3&&%_$hlR3>BJ!E8LB=gCj_7%kOeqr?9tc|OJ32b%lv4W8ObJ5Rxi`Ro^&EnM_mIhjm{)ppS6A0Z$^)aa zJZinF1nJQsGO2$Fbks@xTYs3Fby9D)YuB#LvT#TRp8_G4#$A;7{H#3BN2{1vMuze+ z>nT9tSytIA)5CcD{Q2{*U~W!j6(^>EGQqU8v=9m(9UXlu%-B!z9DbipN=gdCyf`5Y zEijV;lZCDJ_Vyf^9FHZQ)nYyH5Sy{njTTNA;0>Hossw7&Dl;}Q{1AAIWiYu; ziEE}LCor2=lsL;K#a$CDPpM$6?xE0ygoFf!*LpUY<@JLyJ~skyrc?gLH+1;$;Riv_ zX8DB^1*GSb8F9>Vxqng>uqGy2uKd9T{ncVBuk2ZWH&-YL_+ePsAxq>{qTm6xaAcMLEThR)RZ)L%}ZYMGLAiuerGs4 zj^B*q%&rS_;BdbA&N=V==4IFnedVf#Q_d@qT-$LI&UqUyc zAL&NL1eTSRJu^K$U9z^e*1NQ{)HpIS@_Bf8_yd^pKGNs`PSe}l`<~Hg+}Jj2>+9=- zd3kw{V~yWY6~a9~KmQ4U|IZA&>8HV9xWUtb0CyinAx@2tkLL=sTU%T6G@ZG*xeD=) zBi=96)zu|J0DsL<6GFSNuuv<&PEAb}0H78t_!kuwJ%xxgCDwABot^#uJ~S+LGvDCo-zPy(6BieE5zd*l zy1Lo{{stKgpH&1P9^dTj>?jC4BJW#VT&$0ZiaL*ZW^ku8|J2mf%M%k5`7ncjW#;D3 z{r&wP0Dpn63JUMEw6x2});;oGD5O0pDd`gSu^e$&qt-)cCICJwGZfE^?<*@SEwJap zuCA`PmC}Lx)S72PLc%5ZPP3rH5kmc*k&zLBjXr9dZJqOoiHW&@g!F^VgwM>n^YinS z_4V~haKdvScp9BqmNgF@+m_}Y85#K?a!8F#pMU<8o16O>2pp>P@Q9C(zo6K;Oy9uB zLFWYnCZoe1x0_zCKQ}WoQ+^W@gW-Bv3A zwDj<=uVsGpH99=z4&>M;G#brW*yb-XF&uN9V%x0sozWPYb;HBMS>S6bJ*Y&U&_Nh# zM}J30zm&nl)_=N1ahkppj56bWnSW(vWgOnylp}m9Dk`3p>lR*06b)F5DhE-L+FA;s zm(7<2A>OHlP`qM@PpM0iI)XbMq_M zXjc@lQz&6V88VKVnwl3tPhE+M_OFSJEPu|hiIw85YCBGhGUQW%fg=)R8vy97f$(l= zX?a!N2&tdPCTB$)b38j?baHaCK*qo@T3A^4Bo|4Q~BP!PGB_$B^|4cj{Sp!gCB!|tUWiD z7Gq;$UxC@4%L{DvZVp zR?G+@9<8-J@y!5E`4 zIy(9y05PF>rlh2V%PF1f7#;9k=S|ErHj6MDWP<>j>gwtQhDM3sHUj{1&>7IOtGe~! z_e?>M_f!SgPB~475_25kxW6h6W}cnZ1fVjs%<4Gln?5}%Cv~XLDt>b12`&B%W;)s; z9ZCj|5c#8W%)-2|)YSG9fPdhF`C$vROlFE_0~Nqyr^PxUFf%IF^3t=XzUL{lwzj^m%pVFoXdFA4nVA`BezXDzM*yo;%4szl^~Y^0 zPwayt=6SL_HSvxk-Y?YF*1ib7%-RlXfhbo$0{uNniQswZ1}AHm34eE9!qpT3=f9!c zaandawDA~&8XFs5CSb;OCK%=04$a1r&07MXfvu-Qh;>=(e8wLfe>mbRgC(Z&JEm^h zEkjxeI*TYv6gB0F2&*5QUV7lw+;uw;_ z`gVqQwuqxh>*XW|o-QXbA#trv!N2}(_g<2uqoUY4;0b8ASPCmcep~t{w9DI-I7U0`(%DwOj|TL)sz2+2>*BI;G3QkSe^ym$<_+DnWxUUm+^K==1 zC;XRM+~Q1*KP+>Y8@5p>VdI;!?Z3X?-M(X|5XZ(}XPqMM#Bja{;|VRBaU_Owjqy|_ zsc4{x4y((JB}s+9uM0((85gMj82XUxB2Jy z$1(45{#u(gvK^v&+q76O?N6B`uAj|ra#D}y;vS}jZ<+CtYwH!gcVIjU*MsGIbo zW7WOtN#46*|_(mP=)w~ow{1@4evbe4G?q}kYLT{PFXPh;5jA3y|*1);^)Rc z^LS*s>+rqKDTN#heIH1^P&ps?;#~DUAEr&MH{1+nPioBjd~j3Yt}On8j0LwR9CA&)v~-0f6rVOdarQB)nHJP`}1D(2lJWVpGv=P%lZXM@Sd)IF6*2U FngFNAd&B?$ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_unsave_story.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_unsave_story.png new file mode 100644 index 0000000000000000000000000000000000000000..23ef396fa9cf38f224a0a53432b5be860437b017 GIT binary patch literal 1469 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 M07*qoM6N<$f-HkEX8-^I literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_views_reactions2.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_views_reactions2.png new file mode 100644 index 0000000000000000000000000000000000000000..60a20efb2bb8c2fee65dcb4cd22712c8dbb6aa57 GIT binary patch literal 924 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyy~ySip>6gB0F2&*1?oXY+J%49Q@9 zJJUN`#8Ke5v0W28f1FF8NZ=zj{YD9XI{}vO3T|K29R1k>13$iEznCoGGQnY=nvv0}-s#w_-K z=VdcYq+Zvi^v&nU`S4KtGP`46b94gJ8Aid(`HhMNOlxL{n9W@ve}_^3fWCs#Ta_KW zuV$uv(kQ&feypL}C((rC+APBv(d>Fnlf%zAAKMlh{EB_B zGV!s|pWcfOZ`8w2ACgYEsOr^qmglp2qs(-9O*6gAhaOf*{XDTO;h^BN;|HW>+a162 zXHsr@pQ+hpSG9h(z%Lg<%v2eE_Db|N-(6NX`*?oGeP^NKS?#&)>k|Z|Dj({cpHkr6 zv6gB5h8JEDt;RDJFx{Qyw}?q*{$a++;`dA~$m*^QH~ZTa@9 zapnO(pxA!z&ql&CuAXxE%{^=S%md;;q5rW!p^EiW8^6V8#icPVj*`syKk?briisc1 z!;Z-x6w4I}_`kZ~aq6}|GAddPiy9AlIJEd`9iFvELs)bI=c*0O&rCIbvueJp>8hDn zHu=DkvRNw{Gz==djhFN?y}WOFl6(C!t`jPuH{3qUFF@7Td)E)e{bomt$Y&9o2ta6&7Ge!A}gwB75=|4k7DmQ-H^n3p0q^SOY zoHI_9x!;>-R^*9B|9n|t)xF19Tq}^>bzOKwn1@(|s`PXJf(o%ex-RPXm3F#WzVF}p zsU>-5sdjPrlS!vkMK9Hhvt5sg5ZN%XH*;6%hxv?hssbM(IX{-}R86@&N9Y67hmSrT z{Rg*L=+0ID!0>~)t80yJS>U)1w{>Zn+HUAIPINg7&8nJqgLxJ%Qb|1;Kq}A_t%#2^0+T>Vf s{knR3P0!~*v(RJlTepD{<{Rq|{L&jl7ro;YSP#k>p00i_>zopr00lvWWdHyG literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_views_reactions3.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_views_reactions3.png new file mode 100644 index 0000000000000000000000000000000000000000..787c5f82ef7cb2c81b22ae2503a663589b887f69 GIT binary patch literal 1095 zcmV-N1i1T&P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NFu}MThRA>e5m`zAjQ547LS%!Uy zMp0Q2eOOtNMIW^36A4_E1sOqL&@x;_%V<;Us7(;FC@6w9NtCg=wj^n(e&1>YZBB&OYzzFm}JNZMj(HVv7;5LjwHtS^YB*>y%#@Gxv z1#cjmiKb}Rxe~+bAbbXXgN^kNwBOXmKLEWpiNr{a(h_T;FblnfVOLNs?r4+n*xpS8oW#n zv3($mav5V)a2>Rra0U78pi~VbO7Uzy4Pxb3Z&f+Qy(QmSaJG4%gwcb zIV!SG`NeYkRiO&yyWCt07*LUVF={wcccD`MtbCW7YXM(Wq&}R~aHQ^1rS7=^72|d} zfo8#vePStoR^~D|;rje! z<%htSJdDlsDd9Vu8uH6`o1(OPeT$d`lI5=WLWu>tD;hzImRkDm|CYYzQDPyNNFdOl z79fwh4OWQ(g3#U$zf`^Y05X{=2wqa6U-6e`Min-K<|2^y2xC_ZQ&ia~$`hu3lM>(a z%AiuMT(m0SB^djF6YjkS!5YvHcaP{7d}&2PPTGfHY#3*w)yn+_A-o6Vx@_z|PT(t( z!rX!7zbnRIKF=ga?0U>5up{$Ccm2+D4s$`KwmB7(bxKzl~~Y^ z%c6BO&}4!pQBW44|6b{!pYg7ot}ihlvBpH>aC%%(`V^Lz_)#+x+AgT}D$aK+;5`_V zXRJoA_@az6fqIZDhp|4Kj5jF8Hh}(bNOHotQ5CvUCbAX!!PqyP$;sjGgds3CfU~X8 zx}oMXA-PX{G&7`?WBVrD0DbBGM1NhV#lsR~Vv9lkyz(-6IMXjGVU-R~hY41~l`Jce zf8FMWS7}1Y>W``*MVV|3d0RkgJmsaNGl)){6YoI01Mv>TI}qs(`~fatyvg)J@q+*W N002ovPDHLkV1hqM?)(4% literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_views_recent.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_views_recent.png new file mode 100644 index 0000000000000000000000000000000000000000..64c058712705bb1d32097d46574862e63fad56ab GIT binary patch literal 1382 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 Eg0mF6(EtDd literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_views_recent3.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_views_recent3.png new file mode 100644 index 0000000000000000000000000000000000000000..cf3e74e1e5b93dda9e4bd77d96b111b05fee1d98 GIT binary patch literal 1135 zcmV-#1d#iQP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NF*-1n}RA>e5nLAGuQ545nOxB2z zR#fb?1T3vI0ZcTa37Gh(P3*z=1uR_s5LyD-*-==4i4o(YGsf7$`YMc=XhI_E?+aVJK*UXooR45&Z%Sq zS?PGv+t4J7BOECBy7T%Mz6K7Z^@>h^peq|jt1!h(0>gd4XI`7}V%osN^4ORFe)H>1 zXo==a7@Y@3ayXoq2W*W1KZ&`#Y;W4ZxK0}*z4AnvNA94IBpBo_0l%C^ljz0DU{vS4 zUaQf)SS17y9tO&)FqBZ|KC(t{V7fXbn|xv9idm%9$&qNoB6r8>-EK14p@Y0O_IIZ@ z*+F!BID8&&KX8mc>ua3VzudDZcAtCbc{kk5Vtb8|nj7`L-S7?@IRP@UAJOxHxIR*| zJF10o^3e#aUm%8Rl&8oEpm+w@l36B0U!#oW@eChdu%oZJs2?bXjubZmRh34I#_U47 zWMfW^rkC?h->|W|dZZVIsM9GD&O}bD=T!IG6)Q+SnuZENhFcQ@{=j`IyaWvqc}Hy43rn zB!`*b1U8g;AG~g22U-HiV*ta0KtFvLX*uZ{n0jMN2WZXvd$3NXR3FUL^O6JL-vr&w zlVgTZe6t z05ViCF%g|k%3Qakqf+(K-Vp)lqcjQh#nz`kjwGWW$)pp06R9VX*?{**K&o4Ght)Mu zC9z#b>hM}l`h(*+OJ$w5q%s3#2FeVS8QA*_`~zt^gsaN*Y+e8W002ovPDHLkV1gki B@YDbR literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/mini_forwarded.png b/TMessagesProj/src/main/res/drawable-xhdpi/mini_forwarded.png new file mode 100644 index 0000000000000000000000000000000000000000..0439efca2176626572c8dba66db4b219ad423bb6 GIT binary patch literal 589 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz07Sip>6gA}f5OZp5{w%yakF(iWX z?X zOl7Sl0%v|o7be<1xBK=jsFGQK`)=d+dw1?#&*CV0m9OHRgNW6p}|CP-ntL_gJ&cv9>sPZyb_>jQNHSl2?a9im z(i7G{o^(>wO3C1r(~`JcdgiCO@qK$394V-mp$N)p3Jn;;cR>@C@MW& L{an^LB{Ts5&E)C^ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/mini_like_filled.png b/TMessagesProj/src/main/res/drawable-xhdpi/mini_like_filled.png new file mode 100644 index 0000000000000000000000000000000000000000..65a83fd3739c3afdd29804eaab5c0fec8ef8bc7f GIT binary patch literal 556 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz07Sip>6gA}f5OZp5{HqFz;F(iWX z?UemqEQSK@`MFmP9rj}RpHQs+iz#Vs|AGg?H(o^EXPz51Z|{T9uty8m-a66QwWvdB zPV2h(1FbX8q;1}J7_Z~2xOJF~C)*!Vx z)}r0NqFqj-_r#a-b({f7?i0-B-MHc5G9&*`@hszSdOfQDX2#F?E}L}nn)zh0HwXQb zN@}cUc1~qxdd)X+Q*?Hkpz^ZDuiFy1Q#Wl{$`t05DqNzI`?}=PW5veBP6Zs74Z0T9 zn|r)E;N9V)DYbrCtk!~jE7q9kTS1I>8#sM6y`!y|U;U3iJV!FN$W~$BLCGJNO4soH zvD{L++~M=KnRiy6&b83^{VL;Q`?-`$Y6pc27IuovjnmTAbYIqcKvF{Ftj`_UGiho? zmI@bIs!v$UaYU44R=-!=!s2zI+~(1aH**gh7d*&zrz&JYUF2nVMQST>mm9T<=@&+CQuK cUdaAnO)u2_<~UD#Hz=k&UHx3vIVCg!0G5W^&;S4c literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/mini_views_likes.png b/TMessagesProj/src/main/res/drawable-xhdpi/mini_views_likes.png new file mode 100644 index 0000000000000000000000000000000000000000..0a4da8cbe3f9c1accbfd737cd8531afc63335023 GIT binary patch literal 634 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz07Sip>6gA}f5OZp5{_Qcc0F(iWX z?KFFRmOzoCy=^TT0Sj&iDd#wEyzj6mlJoY@;Fl^*86vxdSRH+z3t!MsxuUYWSKlE? zRp_SfpG<+r71^5{)H#aI>WE2(10QCpr}Rax0#piBQ`M1YtYmZx!%~ZqbW-L21959*GuZK1=t^E1qjmthUYn?Yw&u9?hHh&tI8!@zE>E2F3c% z(HB-rGy3m7W^CteXRY-m$VOQIt!Yr7@tPeyT?G+^GhZ`ro|M5H`SZe~8Dh4%2|JEH zQd(}ZwecSdkA`pVf>{lWOIPwv5jOasFzeQVN+z}`%ghQUfdqL96sH&zTyzqiZhCf? z%J#%#CFy1>r>)esHafyLTjfPe^^*xD@ryU?%DmSwWwJgLjSb<6wm&mHLUIVQ4tUs9a!k<0rUSt{gTNnUqd>3Mz2Kem006FuS+6ZndQLGkYC>gTe~DWM4f Dvbz09 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_customize_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_customize_s.png new file mode 100644 index 0000000000000000000000000000000000000000..4de08784af901c8245fe2ada95fb2a4d017de65f GIT binary patch literal 787 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyy~ySip>6gB0F2&*5QUV5;?WaSX{| zeLLg4cc`Pt@x6*WI=}D-oLIym9Q&ld{y<7gKCh-a}2kv7zva8YO&S|@2lbUbDEm>y0YI;Ke+r6r` z7nKFaCW}bhFvi_WNU@9G*>+|{dRv{KlFPfLt9DDR(pJ7V>vD<9Q+dtXvnENG9*m4j zyDMh$P(MBL+m6oXeR7Q_7R`F|@S5eSAK8J*(JOf*H)TiupTa9qAO3UhscmV~c|{)V zUw+&zZvGzeh(O*vt=qG#%DembaY!yZxi5Bw;(XhSjAeK3{pgh2%-a#mK1ui{+uLo+ zg5;eZAM!a_{AM>_Qnuv!DLEO166YG?XRX|*YA#%5*JZ)d-Y}UlnedImzXnbo^1gf@*5CB+y&=)@IfH5A?E|Noz3=@N zvH9Zqf>S=<>+%DW9}A?!QopruY&?*<^+e1HzeknFGgrQ3O}%4LGx-_g&vlOu)-PGI zEL61ZOsdd#2f^oa?S91+aerMreNOJwCwu;UaCagW}v`=TPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NFY)M2xRA>e5m_2AzK@i7t#uz`) z_>mxJ0xDW5DmJ2p1i!FUv9VAQI~yCp6oRG*)?y)wjffV3G+OuxDQv_*1V2zCh!%b! z;s=RnOgw*c?i}mg?!9;KJ@4JY8~ESM&d$uv?CyKFZ=0Gj%4Q&&frg%eTu}D;e0~-- z(}L^*`oHCJxyb;Vz)+~AWQo_KU()$TM23bma4JDtbnxFD_enV1!B%XwuNF&U~KoA ztN{P?9pE6?7&~KE00PegO1E7$QFR1e0_1~6=~UEMUOyuLmjZ~}2A*i<7C(!e-0Bl7 zQ~}tvf|=f#usX170e67X2ZZ0+fL{U0oO%fqSO7Nr!5EN_onBD!LV*4YKnP=0qDZv&0DG(KD|Q-z{%t@$oRo$T7L?kBZsY7M0R2Mn3MgGg*b8JS z$YAjG;JbFfdwogJw*h>%Y~^8J4+$FZycbThy`p!5KtFx&9Wz+RORqmu_!>2k$E z>BMj~c&`rdmta|tUs*p+{}ezw2l|218-&HSBW=0Gc&7#>{4VWQ+ukQ*Cl9y1%JQGF z(r53~<4{^aA37y@^Q?0@qF)N0tD)g9;8pEs?7P4-<1g$Z=yZ+g)M0EFptlneXcFvn zIvFMX?Lgo6Pmz~bviJ4j*8zrs(rKS+`U z6>vUufP@T5e7>sBljz(v+CGJI{altK=rbh%~UPmPC} zHC+L*9WV}Z#yQ6lHk)=WS+_Nq+=>TM@jynxbFh94x{TKlyblb6xYz3@q?gIecY`ya z9SCh_7gYCcLJ?bmeN3R43ibc3A;K@|%HO*j8`2^<0fc@f7q^gID*;+)?*?0d9I)(% wi)P{^53KC@!K$}S;;Cc-vl+-{pr$kM2gGiv^s4v*=>Px#07*qoM6N<$g3V07ga7~l literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_gallery_locked2.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_gallery_locked2.png new file mode 100644 index 0000000000000000000000000000000000000000..8a54e0c327c85e558a54adc78c8291c838b0b1ef GIT binary patch literal 492 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyy~ySip>6gB0F2&*1?o3-few49Q@9 zJI&CG*-@me{IbghCC8jMN7X#66rV6%6N@`=N%#ftmM?nu6z66ra+F=Xq@~qlRi|ux zc$0PEP0>xtfB5UtzVDrR=KsFAv6E7{1XlnXAu^)&yOb zuqjk~f9lwY_d93FZaeig&hp~Lziqe61#kXeI^pwYC#|V$O$+PG4{qF`|7x?Xyy-{R zzhb_VGlh)ZO_wF7-hOky{Nh(Zs}F8cJm^{>(; rGoM$!u@635G}YCC#RV5q5ct9NtBD5O1I{an^LB{Ts5bR55t literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_limit_stories.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_limit_stories.png new file mode 100644 index 0000000000000000000000000000000000000000..6f39e17fba90a012c711c3b1bfa3a1288f185249 GIT binary patch literal 1305 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 Ve6UwC^WFde002ovPDHLkV1n&WGKl~H literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_stealth_25min.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_stealth_25min.png new file mode 100644 index 0000000000000000000000000000000000000000..aa7f9f666982728c7d6e0bb1393440f70c174737 GIT binary patch literal 1746 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 UHBC0)IsgCw07*qoM6N<$g6%Cb00000 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_caption.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_caption.png new file mode 100644 index 0000000000000000000000000000000000000000..7aaafdb82f9e5af5429e3b3e8c5b1720d8530259 GIT binary patch literal 592 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyy~ySip>6gB0F2&*1?o+vVxv7?Q#I zcE)}^mq3AI-xsN9h{!o~ytt4t<&ou-dybnFKZ-lB1(CyUdBoMQIV)bO- zIq#3$yIWkQYJ4)qFYVl)-`}2`vAvyTY01>rp!|U2OQVC}XWi46-WYGRmCWgP4Ve|0O(G9D>T$=6x3rX>4BqImw&2;SA(I4-()M85Q!*#4m^#h>r8 zs^_^Pl}|Dd1N$0eQpCCv&H84v?0;~+tNt2~*kot*n+!+S2i)bfkzctfZ_Tu8DSOwY zZeLgZH~hD(;cbRA;h*A1*>0-sPCgoKF#E~I%)Dwg$9$HXoUC1@1uch#_V7ecESra@^h=Ui?An z_G7KTFIM_W-Dq=f-4^oE%t9nKk)y6&quu3~^rN`dH$HL9Wd1O_Hp(*nl6_&#lmAXL zvp$%BeZj%<#PpP?Rrh(uJsLH$SG+IGD%M>#U*BZI>={{+^@;v0_t4w-!5(DT;EkKac#_N@lG=z+b`2j1S3u6x*Dx`l&c)6><@Wt~$( F698Hf?P>r3 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_link.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_link.png new file mode 100644 index 0000000000000000000000000000000000000000..ce9169c11315412fe92fced46a36eb3b59c18006 GIT binary patch literal 1177 zcmV;K1ZMk*P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NG14%?dRA>e5nNLepQ5eRZKwY@d z%E}6~1cRg?A_Lo3(g!H}3fUs8l`X<*Z&IzTRglz9LFfylP+5x>6=;i!B>DqIW?{ca z=Gg0*xp&SP?@U4S!oxZDp7(v;=bU@*`7={jSF_p({NE#xt5)}ymzO)qbpq@K+d(sU z58i=?U@Di(eWd(%4AD7o8axA~Yzc=+(DP6903ip#EGWmu3EK46IzsYO;G3s>n(HCZ z3)(?5=mN*V2$%=fUUJc0^-hrVyj4N{F*sUE2tM`T3|IipK2xb)CrEa|WzLsll#Qjt z+jji*bRGd`dJ>g?ok-$~zifrY)ZuCZwiDwq@zK5{8wA#dqe;8~$n+%a>r|Q9i6pJy z2XMA-@vbir4meWENq0Zf65kz7R3^A2BgELSokV5bW=5qUU)yeDNb|lB8S^d(m`YAjP$?i9qcttz{v8 zv@lch9g@!&0lShty%vJBpSN4$=)Dc`{>aCQKW4Z_3DQZ*9!AEJy^FVGAYO~( z6X2|15i6dVyF}<1=uG?hs3{Zwb&b4)!Ewt8pj1b4iGuwGoS&NDl7|r+Ph1w_ubTW{ zsUNU8QtLSHHo?=W&R!#NS%|-4@~e8%OOt*{z*$2ul&17;O(^!HbmRCT1u2rQp1kCqCbS z2abhOzn%pdzS}_1_P{43PE+O_SOn+%_NZ$J?f_?9QNinQCZSGWn`0@8ZKvNFl1@{v zXq5xe68I3Cq*w>+)Y%tH7~;=J>z$8U97A|ld?0QCOF*Urb$xJffFpdGZS=v;gUX!j zAl9$M&f>PPDV>1O&hz?UTT|T2Z-ThTsi)MBOF`3VT1Ggmc+szKwnqYoHJ80h+lwfDYg~!_EL}+7id@DxH8VN|Nh! zx@#3h)b$j?_w!i@PU1kwAus{lIzctjbR_Ku;U}r2#3}d7B1cpUoLZ&zo4x)r-2%P< rZ9|@e3AP1ulr^i3Ky3snJOaM~X1h8dH)4$o00000NkvXXu0mjf{oD~K literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_myhide.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_myhide.png new file mode 100644 index 0000000000000000000000000000000000000000..a1e0f0525460481bf1e2874433ae2f3e3462e0c7 GIT binary patch literal 1489 zcmV;?1upuDP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NHJ4r-ARA>e5nOmq;MHt83SzbVo zT3#|zi5~1kMIwPnJyxU=5kdsnQ%^!j_R>pqc~FZ|s1R>-gQ5ru#TSEu9xKr>st3t~ zQIT47qKjSB)9=4o-|0KEX4cHwXD15hgFiF#UH&uQnl+cb_M}M@GVug1j3+QMGO`AI z0FHy-z!`9^!t3X4lyo=~JX2wysbhR@1lzz6$jKEU7XdTC)uDb|Z3s1ZlTWD33JK9I z2Csp$phUjI=@QRFdkGiun+738$oR* z(LD^j=#_g8OzC;>3WQ()XwY6pX9DGX@P#w}PJI_x4W^cMj_;M=7zpJcifc=GqJ9v} z2Dv1T;Ik7fjFJ>6iJb$U2jPrO~m&B#%=yn$RS_%#Wlhaf#YsV7thNLlx zNJ!5r`kD$hfserhJrh|VB;6^bJa0)@-+d_=xOR^PBD?64V8GhvwXn3?v`&JUgo0EMSu<|6YVzL1xuNFon}`vH4UGSs=$9JUk0@kxO6bYs=u#*mYl#!6%o*WPILqyjIm>Uy>Y5Wxz-A!xlvO zcrpf~zg(S4ItB*f8k3MaKI?&YCNICxSQpUMn)tl!f;QD0Oo5XKO^%qpq$H>$iJR~{ zY8|-piKagAy9VqB?|^wpUyQnwo9svt&26SU>(fHA*iIcj2aCwBL+ zvk?6627Zft+H7sga3>gX!ELVsA1aAXr!x%4?cku}x`nzn2%p3WbZ4B;_^Wi_U!i?% z7>Si=-!Ga8{K6BvFRze3hnO7dApylIiSF!CHm(Wmmc-VkzVOqb_$1f>!nfwXP>jcc ziKe(%ET}5)ut3_mB(m2FI9_%9>y2Awn9WgVoJ&yKbztG6Uml%kkM&5mg1EKvM0YuuQ`H-1BE?MntpRuXDp7Sb5jmMuEKfxEiHDkkY*a}RvPhU0GBi_RAlm$`hvxwi(l*HU>K*cjbjArl; zV6r{lyVK$s{-8--sa=>}mshNpNckSRndVQuC<*)?bX@vPah-8AmN@!VuO~U!7=RI< z1>iH_q1T6;oxMZRq64~Fj_~>i%LtqDZ3M`6tP${vO zByj_N>p=6nA9h5*v%t#_G_t=BLY`b3&TJAnj;I~tDd1P&W}X#U4mj2Z0v$7T~v7 znxmpuO@sOz><5}5{g|))S%K~?;6*dK(FQ?1wkEcieOx8vi+~Qhv!Fx{gdGy3`;xtu z?^3TFmgvGHHitapYSV#U1HHrkYaY#-oQ!pZ*C1FLvzZS20MM*&1~W|G_Y!h_)jI%m rk<;fHd%7w&^u5Cg!igu)pC|Ay^He;g{_i9_00000NkvXXu0mjf4CbK4 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_order.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_order.png new file mode 100644 index 0000000000000000000000000000000000000000..e63f28c5801c7dcbc0004ba52192717847f0f5a3 GIT binary patch literal 1876 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 UHM5fQg8%>k07*qoM6N<$f-A5niU0rr literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_stealth.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_stealth.png new file mode 100644 index 0000000000000000000000000000000000000000..48a1b8138029e46152596292b621100cdc420e45 GIT binary patch literal 1515 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 JPDHLkV1jgjjtT$( literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_stealth_locked.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_stealth_locked.png new file mode 100644 index 0000000000000000000000000000000000000000..7f6e47fc591d8f89e3beca39dc50a99e239ebd94 GIT binary patch literal 1203 zcmV;k1WfyhP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NG9Z5t%RA>e5na^)bQ545JZPP~R z4+$bRM3qE>1_@dcB>fYJNN8eVrEDZDB*Mz?jo1* zmU4xuC~_i?z0UMKrfpB9QbSR`VH;y>u{DEvpx*RA zt@vrJOh)#{6U^bWomV>Q8eRC5d=o5&9K1DS6#44JPPZ32U zmn|`*YrtyTKck9(Y!$c#v_M;DR1px?_Sg-qsECa-rU=L$v&>EVhIX+nKrPp?3)}Ud zHXUMX!Ea#YJxWs)0qmt!1cYiqAF!fA)<==IHu_7a2*~WS%uRd563x|?Oc4-y<`nQ0 z-TRzeD$Cm92b{LLui&m%-S4NR#kUOUv75^IB_S;ms>kFeaTtTZq|!W!Hft4>Pi61+NSqa>i?2|Mi zy1*e^;o%IY2m|9ffGa9uCzyDgOzeX01hI~~3D7$-s9@9)`jz82ir$vt7-7Kgx--tI z`q(dcizUV;ATCy(qtryun79k;=p3=0v^vZ!iF9_1_~;xJRYXBsEHRe>aj+t8El%o8 z6^Db?+qCa!^+Q#x;I|jJYeFINDuQuMK)GG%?Hq!buSRz4HgQ^I)O%&9@~+Y!Ug!4#ts0Ki>9( zu>8bu5o`dlFTNlk3jV>lNIKAOude7i@NviHr4y_H=#d%&QSu3+`n3~j5w8GsKtC;N zJ8T2$>jv5y^V*&ABJU0&@k*dYm8}rEyrnors30h+kZWMjn{K9~wrBlU5bSK|Q~x-H z?ud>cI?bL1I&g&-Jf=W&B+wrm+5q%OMXnp{QAONw^IAQq+!_jPNv?BB6IcN3-&Fbt z83g)^X_PirR0K}F!2Yx|%-G}>bu5Df9L$~Qp&bI934|<%D9=E721;!P{sL+7+s=Sa RN67#H002ovPDHLkV1kf34J!Zu literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_timer.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_timer.png new file mode 100644 index 0000000000000000000000000000000000000000..57272f7ebccbe66913c23866ff6d2c717f5fb380 GIT binary patch literal 1389 zcmV-z1(N!SP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NG*GWV{RA>e5nO&$ARTRhXwX2b( zS!RAkQmK`R*V0O*m%^Tev?uW)=_P_fq1T=YKT5nWfiF=J1$~G}em$F5fd!(0W)kVm z>Z(~rSz=kkgBm`oLr0H82R8 ziG1YyDCq0hC`dj5Yy#&&SrJz;CisD<4c3CDw_dL&#@GbC7QZ#%MQ~G!bD8!R;1n1F zr-5V|m;-eduV89#Z|`5|>O%2zz&F6lB^n=sRp7>ES>zLZ zx1z=M@-2aL7WVJbiv+AI7Bqy-X}!3CS2gW4NQK(xHaJr(}47bML_G)j)~!! z5B|EZO$t3Pkj8+|jEsKW;znr*_kw>y0L?s;qlnH4&a;6p^^7|dWx|;PY}QjP_hb

&`IdSa-Jdn=8!|Ryb_g3B4YUk1cy$i8w~_wfGtnN#yKT+``)j%ZAQ+$;s+-lw8x-;%lrMfWO!D4qI0C zXAnQh=!@<0_r0&NZUFwl^`zKD=BJnbW7Y_^`pSy0C3gTPU4})@E@ZO!C{90E63|cI zAa+@K*bxVvoiusOwRy5Pu+!LDI65lSFbbRj64iEHZb3NglxL8|xz24kNF7V881#;G zNuA8{u@2B&Z$iuk5=TU$#+v4L`! zDEGKZ$p~;4_{AckwZN5Lr5hEam?1W*CO`9gXCwbY{RGmdmJ_wGSAX33E1?Pa5k7-QIpj7W7@Mtgqw7_}! zlg3BjX)qnsJ#^{|$Kp5l3A64waXx;jt0fE>nbV8SPx30Qz@PFCfAsAUOy0 vA|f0C+AtpA9pMVPdxe4Z3Ef*^7gY8iVIiwqie&Q@00000NkvXXu0mjfT9Sin literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_views.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_stories_views.png new file mode 100644 index 0000000000000000000000000000000000000000..7293e7e804c85c78a21a10751dd6a7abd2633206 GIT binary patch literal 1388 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 Ho#Orn&c-T3 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/media_like.png b/TMessagesProj/src/main/res/drawable-xxhdpi/media_like.png new file mode 100644 index 0000000000000000000000000000000000000000..e7d7e4bf2e6901af142e6f65753da992950c9142 GIT binary patch literal 3178 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 Qp8x;=07*qoM6N<$f*I}w2><{9 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/media_like_active.png b/TMessagesProj/src/main/res/drawable-xxhdpi/media_like_active.png new file mode 100644 index 0000000000000000000000000000000000000000..6c3ee9bf8637422cd6d331b70671beec7cf7e8d5 GIT binary patch literal 1420 zcmV;71#|j|P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS<_DMuRRCodHn@flkR}_YAg+#?< zM8yX|Vtn9RM9@4If^iWa5nYX-xDedPh@#+5_o6tO2=3fu=gK@5VQ{7RNQ|1`15_Mm zbVNn)t)t_s^Zn2>+`3&=-Bn%HU0qcNe(tTh=bU@~f9|cRuI?H%D7RdJT!CDHT!CDH zT!EA-P>6z8u~-~Op2^^|65i9^6bgkxA8l;L+`~yet%M=8FG}cS?tAnbV-&Us>;?aU zkHF17aPkJ&2Np(ADR~OuTW|o}0$y`7RJ;uKgRi5QyQ&;aHVga;!dMqUZQzrtCNrFf z`4nsgw?P>DjiA{^%4oYJ9}L=oRzpjLZN0sKGn1#;=F$8 z4skoM)yu(CAjDZl(4Ss`DLP+-%W_2OaO31E5aNu&`3jie7L>ws_u(`LksjOJy#C$o zz%eW0NE310u8wVGD~Q!I0;e7@(soYy@l*IsWEH(MdAhBjH8^BV9BCrXtJN{hO`ulO zA!GfuHebgUV|z(3Ej4{A&!Xu`z(}^)$A0qm3Yy74R>hGf;w}va%ob?Iz({sG(@pBO zK;zB9jP@P3H?}}685PB(?a;s$NRLXhZVnA>f!<_Y9r*W|8rTBeH3u`=cW7V>)Rj?D zOxg|&>>EWrOn(M^A0nCAQr6e@YT-t4V4FEs5Cd;<_$OtggU~r|ilab>K&4C_K{BSy zw~V`Ei-|0s$EMKeThT1qbXL#}lX%$*!l4s~v!+u<`sZwM#JfzOk{AavB8o}Vm2=q^ zQv};g-*{@NP1bP+tQ(F~SwSCcuC6PnH*v(*bp>gFRiv@Mz#<)|*e<|r zAp+^^pE7e@LGmgEw9zeFc4b+b_k^Atwt0yoTAl)Fkihda?dqr04#M$oKW?5|tUrjY zre8rws9F8zQqo?B#{vZE_2c8af)q%C*EIU3Lv312k9Arri6gQV1(FkquF}-=M+}-a zPTK~jOOa2&cKaDLyB!W9OvP)EnG9ug1NjG7Zk}(V{&8wu!Rm25R`shtkU&a=NT1W3 z26J@WM0Sl@zd;;5@2c7Y3#815G>JwZXq)A0qKDM_9pdPNcp$6lB5h}6qHfOp0Q5C= z((O3~E(;@$h=meJflR3X0xQ8Q9VgUukF$ze{|#GTXn`~#6Q7~^5%}J0$+rQfd!5zP zc(MU=JE!EDv=sD$q}Uq@(Qho1V-)l~c$EN!UQ>gvkI6F%TMS+_P$d0bGzAkuT@Tx^t*+%ARA2M_Bg(j(@Iqacfi75O_pcm@m zvMv%&jk4yt=Yqgka1lgpS4sFq-3i4pAw*ih$p{rXN3PLv)Y`C|5E=^fT4b$uoCG5p zMkLOOA*Ra8*|o#~Yuh6$&Kb6_R^w5yl5oMLTK-UyPzs zhY$FSe!xbVVPr(G;%H2V#t|!}MB1hqO93AsFn;jSF}xJC8ekl$0>fjH0D>??2!%8c z^St=~ou18{ZqB*)+?$(lZ@6n_<=lPFK6|hIKYOjc*4jIF+<%d$JOX(H@(AP+$Rm)e z2oz+Y;IEQQuNS{sd|lip?iJq>$|isS{DG|T!c0*?z;2b@A^dW)Lc|C->y1EY5 z)zy7eb<4z~Zhse$-UvA7&YgQK1eaIb7JwbQcJ2DS-ie8Mcf?c4#*G{2YT$jZKq5f_ z)jM$Dz*mKgBYyKpMhG==WMlr80FSUo14oV=S?+-}W~72NcHzQ>_X>fyje=Be?fm)k z-^uLi?(Y7V{oIsKpFUmffrK3!aa6c<>(+T@u;!{2tba)(MSTjzQ|8W{`*v0`^W45( zxNzYqZ-t}&h@xT)u07!P_Vzz&lmPS^F;3&8nKNfjZ)|pmx<|P2 zUpbI%C4VI)RV^(oPY1O-di3ZA_V3^Sj8t;Go=+6#!q|d_a^qeU6}wT{`{6p3GR{9V z>SbSL)L*EmsCbv^<8`B^IZNpP#9&$0UC&$K4A=lsmZ5K~tgL*W>P;2DR-7|r0@6v6 z*ok1I!v=Q}bcfD}NQ!Z`KlDkR_NH%9%HB-a8r^8onZ% zvZ=SX_nbXAYZXg0s5j|hOdx-O5X5eWvVz^#EnBvH%IiDp;y1n;%dWF{@#0ys8$Xag z(~vBzNC6-c2-TTm>?TZ(00?gXZRS2obJcz4{vo8)!s>24U{$ zySe=-r9pw^OH1J)(NdB!52Uu+V7r5@W?sQtMDcB)o?VKwvzsY5(BL zl`B7>_YoMzkYl&f^|u1Xz0e*8Pq^R7hTXqH@)7yRs| zO`AU92?rP~_c(udiZkV}pqi6r&6+hs@mqbEOqVZT{^d}`Z|dJA7aYxmnlK@_uYaZd z--iwzT7tlOi?2qk#A;F?9x9^k3B|?5cN4#b$tM7RKV!y>x2kT&LlYMqP1SW_o$G$T zp4ZNvJ^O7E0FRa(3shh@sgP92#ful84wDnxH)qZqWMnpHDz(ZNU`l5z`Qx{nynB7%Itd;Vr)(1Nb$=XL{hc;2 zl+T_$`(vJqu}|4fn2A_ZQ`5utSY$ho=^5ilDX_&qiJdrc;=6W(l*tu)jiTqdLSymR z?eR$UIyC?Q!Y^|v%2c{*#flZh)2B~=*t}$}a{gMDFJJzBmAk~(%>7)w3NQ{yK%{vi z5wpjU2mFkUw#spGF?voyYJa%>n@GZkR0>rw1-i%ePD(0Pv~=mx_iE||8MIojF*?i@ za*g!v-MhaS6dExRG?19MAj*K;*%Rc2O0`~OLr;ycoaYK9Tjt~Blr)&g%X}e*EC^|N zrH`tim^fEd%XJhLRDT;g6JRc`%Te5*@i^j0D;UN*78Gk~_O!8Yu7BsbGJBGS8cNgr z-3v7$kLgZ=JUNBuZM4bb0G>D(W>1k9tk&7%Fy(ZE)d}0TZ~wGu#9UFg^78U~)0{m8 zdJlun7bS9LV=pFVS{tTJHgT{q9DSK|$5tc1eU%UQJ72nkcOsEduO|W;d`>Me7z}t+ z;!Gh^*WLEv$V+{F{eNc~8yhRN0Mw%U96r$XXIe#mNfUVUNL-l`#87 zx(PFuLPv?NGo~?fRpRUGdKOi9Kx9R5a241tCJkcR3cK=Ec}JX%3iHksFXh@0*2iE| zuEiTRZ1}j{xYVm}!GZ-dB|x%x3n7^?F}8on=;_^{=-KYVEq|x6?W3+-@+a*>KZIhi zM^u{+kZc?;w;J%bOu^@BTY3rpC$Hf|$8fPRrDW)2%-0B*|Jm&%E2jw%vvn#P0ExDJ zbe#B`-Wbx}_HmsU$vWVx;pZ|&83rwc@+KbEYctJ+_=NM++ zefMXI05N0BSaI?0?Y1cEe*2CcJ3gy=G4Y_cp2sS3zt8SSs?srL%$U2?0q(k=T)khi zWXXG!*WGWw=PwKN7OC!|{(Z1PobEsdKIX6=UYNLV-+#U@`v=BvPPt1Mrl;Tj+|YZi zc&F`mOj+P|V$-~x1D1Lc(;FcJutw#TC(exEn9Y<>c+&_D0~z{=^mhR|4bU9l^ukIYPh5 zbY`xcXV$YKF(8(#TD9taY>IjAzv})a&g-aNOq^&rO%ibnA#@A7}@XsJ{n0YB4oQwjHKduTrNUpeQ$PSWw*ti$IxFa3@hYf%Re^Q?D zV{D7q&nR<1fp|;r6Q>2)8@B`NPa&#kx2L`uRnHN#+L^d2(Z3=*>DjtLZyQ_k-Be^M zmw(}o+d?NQW2il~!pp`+MWsal%<{PJpIJiVDjDl)bq1Je$5l~kG2w%ui!s>Z{n-PECvVVs{=S$h6*37smo9GuF7oNP1>f`(+GsvnENF`q8 zAo7tteUw{%Akz*02sta>8 zb-^)oI5MYg=kIAJ<3}e?o~-m8q2qZbT=;PqS<)lIAao|lcsFP0qlA2`^llUV;vlj* zVT8F-CQ!^IVPqXr7K-rAzlC>e#&G)edA4gjABX-k@lhhn&dQZ7glYp6Dr?I%pg?;s zc^ubu*vJ-S*g8(o5eo%i;WAto_lbMOdCDV@M<94kHqhMGcw8FbNZg0(GDWSYBIsRf_@w@+MGLS__4> z9W8!8*XPvR(|eyj&(o*vZS(w+U+;78J@=g7`JQurZ|8K>sDB*g5Xd2rLm-Dh4uKp3 zBNTx*N3>sWl3Z^Q=ZS9*rHlv=6=JaN62DV?hfk<3{eE41P2BE#J}5sKsVLApBt+4S z88Zrw9zFVKb93{LZ{EDQrm3mv2PaRSd}7IxCGXMu0`a@WQ5sZC@kf$Kz!xJ60T(fgNyk&@-iVb#-4BE}a3`^mx?T+FGMoHc{U& zo1&^evkF>l?%cT_?Ck7p?14m*o3^&L!+awtio||hl~uu_P#H78T)A@P=SlDgeAV9G zesa;GMIY1m#bRdRh$O6)xpnJSgNwqcQ>UI~DJ9cO`hV`?%9SfWr8-K)ZySjS-8Fss z^l}#*mJq;+u~@|w6%`-Rj5+F-<6cX%dHwqJ535|M`0e5mMPugApZ{UE<1H;Mud0_u z%o2nPXV0Gf0h#?;w=DNqxE(uoJg#zp#H<`KlnOv}7Lz`9>eQ(du3x|YhY*n7ICSXH zQz~b~IDea2qv7CB;7K>^+qbW2;>3wh$%*{6+xxt{ygMdOp8VqRFJHd=(|``=jUPY$`3n~=Jgs*CbWcE;v>y!>KiwngjKR^G0ty{M~;_4Jf zNvmie~@9MlQ-SsDPT z`hQVm0ZKP--u!v_MAzNAxYv?A6t&QVku8}tY0`L>0AWFp;9<`MP_@1{V)Rrh#L_KU zy?XUSVY5;){4)xn2_1@w&Edm`zb0WXhk+3GT(jUB-_l`mI`mc*jxS%ne40`wXM^gO zJpUfb&;&O>K4;FHNzyOB2@=qKCcSY(%YUv;7H4IBef`&0ty=X^Sy|bGs>g`YTj>&3 zvAD9blF;PuZhPEo0GigWUHfU38`RLmvnboQZ+}dqbSX$M`%Iv`p(V6w=gysT63H)< z5EjdJuNYv`HUIjgoBW|koo&~DWni{#+csNY3`%I?fkU>>FNFJB(_R7kspqg_5`WBy z0fdl%rGcf(CSf27rcIkxuFzzwD+~7mspG(b12#0tWVWUxFOHaz!}k3kArgYL@jkJ1 z&?|%ifHKeo==U>AaVbLN>r!a)EtNCktj2Gu&vWI?xpU`!7}EId8#iw3Ua?}uCsmfI z44B!TDXKCl(cZnIM~@z-(Bx-fa(`-Oe^=#Yke{_mI z?>8}PndwzwAno0|_eqtBi~H?yqXbKK?b`K)pvF+b`}gnv3Id6d6@{0ZB1fDp9At%>2bf_AzZUe;;`i&7NL}Z`iQmVWEN}7*_p-@`Oi^8SsAlQoRl~ktQ8F7?n59YehP=5p9GVRNqgbPx{ z7cDUMT3ucJIaQkWdet|U&{^!K127p#%fv%H%&hJ+A;3u|SWSCrAykZgZwrdOD#v?J z?~FLz*@KV7UKPhyOdp()z^W5s<_~zf!&_dLE?s)j0%Na<=oibC3NezzWF9CB7cTs$ z^3?2Gy+k%qv-67dTYszS?$ouN5JvBxQF)xsOvs-w3*017J6TDXc}G)%^1I8HE&GHd zC;QhIQAaU38R8rPve$x~?3zK+-paw!9JG{cY|WZAGu)17dDTk@BTg1?;TmAwOifMA zobL&ZVpXRoYn(>G>2Q_IQ56YkD*$WZ`bI8&OBAl^Oc7G3K>9!{WBJ5oT0Hw0+ zb0VADKCELSK{vXcVCO;a*za};o#k!$phL9I+uU!1?t{`MX##|yDBZGU%Ok2QY~%1? zwl@x0KE^$gixN%jL@-PI7OGAB=(;Ni;)hu`)SV_PI#t88O>T141kt zBNJWYG=F}Zlcsv-9e^Tbsb%#qw+#1u>pPR<&KkeasRG2H4cQ@1zrg(V03tu@b{>VQ z_oXvu&U~L{$Y0#|+)FW5bL>Us$S^YM$tV?oJPX;^F<{OGs3CM**lbNEM_TXbRA73Q z6BCNVo)tKM3jybM2{!QPypQLAg`JGB zov>GR@UQqyLIvL@m6>A!WciqehKA66bK8b{jlzks0u-@2f6x`qe-Ai`BP}G)tbb$y zNPp#O{~hY8zusiO)n+9A9g5K{=8O#vqN^u#-%ctPg{^XcL-|Yyqfn}|I$sqiUCDsq z9TqZ5|4_$_!0#~xdmLC`YlJu|A*9he@XR&U62eV7}uZypV+r@)QQ3A-{alnEB=a&CP?spD>90EB6atP!Q$RUtJ cAWI1R7sy0$VkmPbC;$Ke07*qoM6N<$f?EV0h5!Hn diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/media_views_liked.png b/TMessagesProj/src/main/res/drawable-xxhdpi/media_views_liked.png new file mode 100644 index 0000000000000000000000000000000000000000..f6c124d7562646028c81114d4f38ef833b941bde GIT binary patch literal 1271 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*ISo)IUSLcvKS(M2M(JOx(C&A}Sgb59$FS zEP}t6%m^8}s=I5NnXZ|7$(Qb~s`u*qzNzVDmVyEo&H?9ubHF*^9B>Xe2b=@W0p~z? z2MWWdOl3??P8M@i4R(N?U>TSP=7MkFbpj6y3k!SLk1UwGl45(n+60!c9RuT_4?Iqw zjk!nJ&s;#R2sD6R5Hy}M@H{9nWlC--Xarp#XnbVg2~cD@Z>T&bsswLwQiP7JbGA7DH(NdK=d+C|%09Z}^9V)e+~@E5RHS0D%a{;ngT@I)ju+s$v$mD;I;DcW`9pLuydgLP3q~TS1`L68V}t^S zERYq}h;2dxc hI0u{q&VlqD_y@ss>vRGsl{EkW002ovPDHLkV1g639kKub literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_unsave_story.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_unsave_story.png new file mode 100644 index 0000000000000000000000000000000000000000..5a20459a01d12c1bd416400817f808181f339d99 GIT binary patch literal 2140 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 M07*qoM6N<$f**KUlK=n! literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_views_reactions3.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_views_reactions3.png new file mode 100644 index 0000000000000000000000000000000000000000..96357697b7db0dd45c0b9706e8fbdcc24ed62fa0 GIT binary patch literal 1607 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 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_views_recent2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_views_recent2.png new file mode 100644 index 0000000000000000000000000000000000000000..bfb2277d7b36958ebf889ac26c7459cc7f9f8069 GIT binary patch literal 1378 zcmV-o1)chdP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS<%t=H+RCodHoI7Y0K@^5_ji^l^ zqR}pP5sayVl_Z5=D-x^(AqEs;qhMhtwkj&5va%4gRInA_T4*{^L2WdZCgKAh5K*t+ z53A%lkKN7P*_V6Z&&{2knREXCo}D{8J9~S28fz426lfGEPJve5uG{VQ06xdTFxU)+ zzrDDiK@@><9CpD3fo+ko(x`{a^@a5Zni4F~u_I4LYxb z1hO5xEsHWs;!sT6^U}fUhXAI);*y}s_OD`_vIZZr5U0K1Y}wTC#G_bym!nDQ!7Org z1!udKHFgX_9Eo@t)I}U=A}*IB zZhG&uSb=Cc3G$q9eR4*d?E!I`jO)@X5DKrQgHv&xWOV!y{S1-zy5QUdZe`T3ubY!_ z^j_e41)}G}K#N(S?FSAtM|mkn(b%wuf3=OQ4w3KrXJblX6KJ?zyi>6;xZ4EM?co2_4DL38hW=M|;B9cX36#gRS6M#; zgS$fGnfUS@-P*#&x)y$0SM6A9$)A<)4!j(!hOJ`KJ&jt4KcWsvojo~gZ|H)l5e5r#UqyYwo~TI%UABZEla1!_F$s8#HnKiT9R zn+Wk?mtpG8inw=}Ay9PmdPl8tyono|M!F0$IcHK$8^6nJ8k_#^72yAapxa?#)F!ZV zo;4|Kc+rmuBvx%ueg z;v0js4Mh!)xf<7?{FqN1@$+VoDv(90a}Q`oR-NntWX2Gv?IRT{kQyV>ATP7v@7zP> z6}EX|&t?;+L_p;^UM9eIy|1{5gLbotQ>=N%prx(pP${Vuy{g-E#3c+5PPZyO#6q|o zb~ddliN>I%o#IYU&0GOhdtM`-hgnEZJuRd0=p3kuDc00a`gBc>Y-%2;i&GJinnyAd zh}1mPn?R)IvG6#NbevPJ`C);CLNz~4kwmB{t1A2BCaEWiNkwth;}q1|(m2o>aP#vx kE}@$8MuA3wMgbJ~4P3h>#doqe7XSbN07*qoM6N<$g5Uda@Bjb+ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_views_recent3.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_views_recent3.png new file mode 100644 index 0000000000000000000000000000000000000000..762810d0e0ef34b0eb3f3f7db65249973a244155 GIT binary patch literal 1459 zcmYLJc{~#e93N)da?H_tY*nJM_mCq;?ko3lgqSuOB571S zSI5i|dgfjcNp6kj2zm5J{qg;Mzu({Q`|t0Yg2S2%KwuC603d)to7f&Q`UuBBhx5|% zQ}aXO3bZvx0c!gs=MRmEhZDxr$_k)(sE+}-k_Z6cQREP?LjV9gWG(>DA#)w=$lO1# zXfn?)eH6@6Gg}1!c%?8VM)sjx%SC!=f;QrbAuiY9PlO?-U?Rc^v55*nA|gKEgglxD z#ii_|@F|-bi_F+j3wJFDMA%411d;Fu--Se zUfQ!X>Qqlf+MYa{C5DE`^5$@3Vt!btOU&0V(!RQq{Ge)uM#K`gbGs**o{QY%jR2{% zYpem-(g=j(__U_U7$76=@|sk9;R3BT!p})lu~N+yv`&E-%t*_!ikW;Uik)Uc;QQG_?hX%VpO-$@GbB zgHxBzNz8Rf*HKgH-OuZ*C{3mn1$LLdo8<|;0RPpJY%rhM-r5M9eYG>4<2$YTP8-Ym zb_%#M_pcQHwd^P{`^~&2>ZhKayQ})5`QMX)_a2l4Ch5N=o>$uerDl7L=z(DiVxF)- z&JuTurSX13o+CfmDNK7@4Q$3|^dUMzpI+wQ^U7Eh?K@q8XMKdnX!Y;7N_>rQ+xCkx zw_lPpoE{z1udJ&94gud5GU6Dw9at{%VxSr(&M!+x?tV25rUMtbVmK;MA7uj*VzTao z?pf)0r11!_H%F|lCOuP<8Rf4Frkhe&fsY#IF@+9JMTBk@nzYSO_|i)|QafW^a$yB9 z91Ij*hs>bYW&h?_6~~3!kj$iF@6?2(-W;&boIw+%^6e7ibwdvBFq{WU(un;6*;D4l zrprbWTzlgU6MlJ)TR!0^f&sS=^n)+ty=H&pEjoL%Nt^XqTo!t*!K#TJ+U8cWyW#yJ zrFk4Tf#Mza*Y~~P)kpnr-iH19oz4X40)uyh;mJq;&k5JDw9$bIQ+! zPI!~PlJB>-7R`E3;JPo^pVYG()+S884WRog%pw$V!8dZxH4x=3R|kiFtYC_`%BR2G z3nTSb@5vI0A2lq7a4|vC^F>(1^-;UxUbwklSX46l%IjLyFqzCeiobE?V_eMAJK_v) zd4DRth^UX>7-a9O*FNlUHyJ09@bX;&d-e})De77Dp0x0E$rJW34+yG4oQutIj>rLV z)J`~K?0xLoG6@_s1`O{E^j1+i6Wdlp{t|EU5g*4>j=d^3ORxIfeDcqs$_X03jo@xJ zJ94lV&*WVkYSDpH#DqdQj*0Zdm0{!RWw$0*R9C}_3grpv1TVI%sm9Tp zyEQ8NC^3C6KWHf0uSljciwPb~r&`!a4drH*fd{+9?awF) zuxd+M>j#p6&e0ihxq1FfuLImx4&BRDP-*2hjS|!KvzdMs)qz;lX$~E?X#zCW4 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/mini_forwarded.png b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_forwarded.png new file mode 100644 index 0000000000000000000000000000000000000000..214fa735c1b49975f3bef41a7494800715858a65 GIT binary patch literal 831 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyy~ySip>6gB0F2&*5QUU|Q+v;uw;_ z`gW$jhe)8z@$xGZ_&TR@|Fx8i{d7swM%9f&RFH*p?h?JK2{tMf+*W0Ri<-p)cZZ5A zPB_PU@68OycB_sokjbhpCHU}ke6#U{ zc()^(;er#hn>6K^+AZtFI2P`E^~+}dwrze70z_O_Z{zem?zl_%4#W9_`4`sIE`Rkh2ycK6=fkhM8CdF`@q@qZSdYkABm@`AzNgtx2ceqV7>)Zq__fjYdk`&M`?|2HAd+jnsu&miSDBp+md9tmDGJ5zTMU`ncDg0hP_yM@|-!-p3Gu- zvU#KH6gB0F2&*5QUV4Cdd;uw;_ z`gX>7?~p)|%`7r{rP+Q-x+r7&yE@tzps41@A_=(2eu!c-nINb=kwot#rNk{ewLDIYUOKz z!a39VM7odGePGdP*4@Bw*Kj?7$K?3erWxD`GJ6>14=UbZe19~uAl`g zLpr)Qubou5l|^#-#&Q+Yr9%3iD)xSdqo!>>6fxnbTqd{14YkBQNA9rwu>ZcOSL0s2 zi%0mvfE&iGVY1scE#N%1?`XHoMTMxIWx5GRW;{Hed3BNQgIV%x-NIIjz2%V!UUf8L z-M4eX=MK0EuieIMy^O`*Znao0qrFY1>BYQRa~@q5+mPe^>B07_i(&@P9ar>TTIFhe zBsV0Q{ZsR^%ik2=KNC2;_0$?`heM1P&#yAddS8(ztRJ+-T4D0i}3e!FS& zbk;YwcC58l;8Z#F`M7g*5$_-4SwD{ad2{5pPXA=h;`GTJA^8heFfi#E$1&}lsQ>)6 z_^bO%e%~&%d8I3&8thTW+3uKgP(%H2=#FO21^yE@b5ShaeKAG8iUW@W~iIzKTpSlcI$_i`5pZ=Q6v5WOdZRVV}LIwf$r%q2% zcw=?pUTt0aKetG)zr2DsnC%+9q7PpTukYgR5~yO`!yx@Yx`OrJ-Z!R8Si)a8fMLUY azCWy=t`>;MN#9xoN~WH!elF{r5}E+V22qRv literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/mini_views_likes.png b/TMessagesProj/src/main/res/drawable-xxhdpi/mini_views_likes.png new file mode 100644 index 0000000000000000000000000000000000000000..d68af51a5dd5f355cf528a2a01b930b116ef7e1b GIT binary patch literal 976 zcmV;>126oEP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NFI!Q!9RA>e5nM-RFK@^2&e1IA> znjpppItYgN7~&$h(5)ikUfe4x{s%`_f}3m&>dHSLh#&!VrJx`ZW1^s<5`&m%@D))s zar{o3YC1jLGi`UJryJ(NnX0fUp!s;eJUD72(C1Bqs!7-e*|T3t%NJ)jI!p9P~} zs8}q1p^Po~Uc=zsU>8^net{?80lrm_FF5Z47r`_Lk{OgY!4aU~kwksLQ7{N*L6Ce$ zIRLsMIrVp9;7Jfh98-;qpgHLG<8RaF5E!i)9j*|E6MjE++YC4t?ysTcGCh|214sw1 zG#nk?;jG_hV4Lxka37H^kLkJI1W+AFmsBdoXJCo-JOQ0PCEbO^(;TA(6klogOPO)$H{`|B zT>&+CCR$1H24r;=bidN*;Do8g74yc_WxdWH| zBvAEos!2dblGsEs0@~HifN0B5xc)x&2Oyb*lSr3YDMMr=#P$1hfg~N2NGXm`dHdo>U{(7y< za8xG*>;dmUQklSk{+&r*2;2>H(Zv<5qP}%DPav=ryo!;*TgGJLgBnCOf@lAcgwFXb z&71as$Pii!9z{q(|Bu#H@cH3JJc1AhU!=33RD^q7PI0000;BqR96>AM*}*FF=X0XIXB%# z&OTwS`-!_bX9d4bk6Zs;_jUPtrc+v*dgmx?OiE7Md`r{G;*R@1CD-no->exq-OVS? zcRg8AW|qF$bHb!#0ls^O4xab0FZiPWSNVy`W&0)foUU!!x4O+lPIz{mrR(Y}hP_|c zaa^}qX2>CHDw~v?c#}If`r`4^yiaUCTx)P$?;`E&v|`&aH|+&K{2pB4do=xh$+ga+P-zCK$s`Q*jy$*W?{zEAj4cH#W%WjCI!4K90=JhOA9Va5ry@;$xtF4}$gRq4C= zYxmLC@_mbreRJhmRrvS6_viFWJ9kG2g)qFd%n&nFc&nIb>14?9d=_8km&qlUV$U!< zC^)tIM)0y9<+jmD9b3M~p0QyGO27B)?EN5Ck6M@e&7WQ{uJ{@+GC4VbM`FVlUn@5E zDnS88K@HD@JjY#6{!Lx}@|gi^qPU#?vK_HLtTMI>js-BLKU{Co+v#|~v(ob((gqa%K q(FKg&oTnvZUb;H4xS*n2o)6^RvPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS=B1uF+RCodHn@wm{M-<2Nq!L@= zM_L*XvS}6p$wt&RX?H>wMF|*+2nKAr5nLHJ($tNRO$&mBc2U|zXp3#Nn~H*kmQYX^ zqHRSe?sQQo50#SjeKvbYJ6)0sLcDY>cq0RcN?J~wM5kFTdmC700H9s6ddch?475oF5Wq;Ap zw&ssGut$>*GV-yH(qZ?+VoR$+jZFD3C|>C{Ps0qkyM6 z&Y&oeM*&ZDoIz0_j{=_RID?`<9tAwraRx5y9vA+)KN+h?e~Et;MxKwH(bX`S^T3Z zRQb5+Ftb3kkzM9{@C=Au1cO;Kq|IAk5x6E|iD>JA{y9qG{ssH9_EmE{on;b;cv(z; z0ov~37!FN@*a0x7NjU#7;h?+@oHt_R!W>HCay`;fR)M}W5>8xCDD3hjOpN^0eKTp~ z9A|V}>g0la>%_Rl4|IIP&*?2#AYzZY*`<`_7MMs&l)AL-T(idB_&1yTIuu~zo zfQVt4h$kY-&ZKAH0=_pBp3oz04jEjy%ICnkP@bST2vY^3t_NHP+D=*I1f^YFxeY}O z*Pd_Z7Eg!|BALCi-f5FZ1MBDX5ZdY($V`Fo%dC(qqU|z{?rNrG4|VSYD{;+J+0N6r ze0~T=ffio+xe8wKwGXO?C{3VGq$g#!IQKp|6SE6gYgR&6wVekgYXm{K6U-;X&QYGk zUox6xb3tMWH0^Yh6dzI863R~OFu0dAc8;@@&FwstTgSoo29OW5+CI~dCzeHlIKz>gu40jZ?-_)0cmhhc{3DXQ@BxiTPhvy8@;C-R^frKF*sr^5^c3vx-0n z@R-pHT)W1}Zt9-6&Q2;<1X>yNZ)))O5a*8a72$NFk>pdu=XGg;epD^qVZobFz9O8C zs3aG;&<~U^`zd0iy{l1}*AW=Q%Rt@~a_#5rYAm;?dL`Qn#`OL#&Wx!0#SjeKvbZa3j7Dwx^M^v SPNhNs0000V@L(# z+v~o5OpXF=iEg%xYEr!4KS<@>En?ln<88LamMQxBy~K#b68Aej@v3D(J#$|&_$E}{ z^V0epY-@bQ`Saz)f{hGJ9CQ2^SlwUj|NF_Z%wtuDHh=Q0TzyC5{?z=?(Aq5PI|Ao? zey;6lojad5%>Ar>lGeoH?t_Y)4^5c@U*GY{yj{kVuD0^?#!K~U_Lcm3l-?=3{n(9) z-|MvOue=C(nar-vkagAA>%SjPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS>_DMuRRCodHoO_5Bbri>UePn8; z`6f28hlzobtcqF$ij`zVm=KhbrHNbif*|UTil8h>dVp4B1r-Qt4@yML)QS=#D{83> zvwRe$R;KpQeDwLQdxv}P&hN}`@141OXSM@hXXba#@0{~JJ9p;yoB543HUEoQfm%}= zv+~4=6CH3l0@Q<{;Cyf%=mky#J-|V*4%}5+Tf2j8wuPef1r6X0@GJ0@?HHs=8SY`+I zcYs93Gx$}Jz6HMGyy!bg`zpv_0??V@BYQBK13LTqFV&719l>m%KSq??QfeHtA5rVU zfvD){kAubF4AWr(N@8jZ_9)077jYQKVfN}`4~^3yKxagh9Kzt**b``_LvjfF+3ETd z|IZ7j-9RIVk{>Y8B(y4oTr}0037!KB!Kg$M!|}@?N;Y87H<1LY*(s!FL{$d8Myl04 zK}@2^knRJbMyg+66U&$;2@Z++g!mF*$!?T`5=|mu=j4A1xE;I+UIABmg~V_S(CykK z|DYJ_<*Z7L$iFMt7(#GiWXg0}8PYMoX;!3@DmQ@4effln_9r;g$8cnkaq;1LXXg|t zAoXrBvApAVoK!GcmSr1uDd_qa$l zw?Ey29g5qGPMY7G+oDrS8{pCx{B7{n)T;2=6b+k<4$D(o3uoGJeaYY})kQ&P4*CP@ z);=XL&d3gY^@PHb#{#NYU1wPSf-aNO33ypgM!!;la=){QLA6@$tl|~$(U#4bXmQ`t zYigRF9pwr%-k_`Z~uI!?0=K+^}8oMkvky$aHwIEdexE6_O(12ykYeFY*2 zz;OWhKxCUm&)pvix^XZ$rwQ3^3Jf#81NWgok8AtnQ`Oz6pdnw${`W=4nLXr2v?Yw3 zF4ERJt3SdzwWqeI0v&8m#R%i70(A*fG`Af#bnQZ=0v$4#YTaPF78S_)8Cln-c2PLp z#jFCg&Elg9m!4bu1%#Xn&IDV*BJOHC*)}aB(TWY1gx>m^I%eb_h+hUYILw#dIk>Qi zB0IhFHAVYcf0OtMjkc;a+_W-eTM_5n;m1KiD!YROaT zlRJYnYj+J8H59l(#u<}25qwq`=qaVvCcETo6czn4s35tR58!etuoj~pLf^F@EDe_e zOR8gOe?iuz9YAu5MHJl&Ej-hxN3Xk#j-R2+#90K72MnH4)#nP7y9U*8#Xe5s;+!I6 zJCe4WL)z2W^plbFW@@oHR8Qqj2O4I(M61sFgmz9*BOLVEgWmUriT#q49uJ50%4^fQ z#MJ-P;4lX0`?8$;$9yp}0SyNct&`_Hvj-BgjvUD3H`zh%~+0_>+^aEw6z!;1OVc z!B}$sIDQiN$O4RlaaG9y%j`%Fnno-NNq8r1@voA@sh+yM9uhFDX%&sV%j8&ccVg>q zv^6ZT=C)-eJGVOGT;F1?GXm$U^bzeWP_eNRu?B*rAWHUGJj>D%xd+gfJ-+fOhSz{Z z3x)sdfi?O^9mt-tiV)SAFglY~1mXO48Zpxf+Sost!e@hD3W3%0Q5?(G6H2pw-wSt; z89PV7N}!K?hl8@tEc)wXl;41_e2HPJUxb#NB*FB2=tZFa+NKoI$`QSH6Lx?DKuy+K zb)vo@i&ONn!2Avt{c%{<2a)h_>dviD4@mg!+q?l!iHq^Y4#OB1GwVF0W^8Z#|Wd$+Jo4<>SBP+q{o+mksnasT~aTKjCQtsiA_#C|c2`Tm5_7lGm_pbNLVR`T?7b SnOv3t0000uEtEj!1H=!1iet7<;QlYjY|DVZkLUSj8hq7Xn0NN!{9s7CJUA=G`L)NfH{^mv~xq z%QmAva-D!%@14q3TwmU8-_GNh{M%%zVj1XCa08M zc)4dsU8w{8$cdv~19`=*E+VR!WmB>+XFRhNdPYA$r!N~i8%%nY!A!^eRr<4IFr<*E zhg$C*^?ynq39vNe6BeYsOz8Bbrb`c9^NRSSR^GlOk-+kK3o2ScUfSbK^qjZUb0nQ! zARTX$-IN@lmZO{KpYKY|b`YWY^U}Mn+1{qAORv7uv2L`Zs7f3CFr~=CHM$6WELMCV z30iT_N=LtLWbtx}DTU{lK zBluA2S^`zrH%$*BQ?soIsucQ&QLnE=_B-M1|I|LWc}WG|Sixq_Ng{r!h!r|IFT0~j zN-jY+IfE_^Rfn*o%o_{X8$s)bBKjB}>XdZ2iO@>5XX9&|nl+Teixrt&yn%@V?|er6t+PIE2_QmG^| zi#qM*=KL7Tcs}TCbsRgm8TF>MgBdZid7HZ7*`;#hbR(oeIn2TAshTN)d+xig@fbPq zk-uta)|t2FYFrql_ZEAj8M9*U)5E7#dOi?@e2)k0VFm`RHLEyi@9+tAFfC52e?WrY zrFErix(O45QSPDhx{H;9soZzwerByR z#L3JTn>IK&OG}RrKI5kwD(1Zc89LiQp6S$1QMQX;O>{edJ@yK=a;|jBFheeR&Vlij z`IC(Kj7B-!#+H#W3`XBf5pB2s<@jR40bdhCSb_K3rqwncR$nnJS(f5t7b`sR^$qk{>9g z7QPGB&Aa$sB1*Js$O$JN58n(=oxMiS6HW?$SDjv)LG50+=5;ms*1&jS>t~4&cE+A| z$>gX(rSSd~eB3G5*C#!7U^xvu8{HsNP3=R8r$zz0-%yp%0|>lPjLD4hoV+2uKbK(} z3j?R!MD0kj4fbX(3Ct*263=;#wwMJFX5M4zaIx#hJ7u3^)lyv4V2OL zUHM3Lk9`|af?}$Px?s={x$3)5Ro|_mC&6(ji@#+I=LoP-OM_3O`?W>f8dR@C*0|ed zkR;VDptf6DY5Jq}ZxmN?<=X@LsZo2-SDo?_9MXMWS^btDrcL#2#RkXPQ|c;s9Arx* zpr;GJCU&rFM638NjJ9$t$fU-bka}wF+IF+z%E#r>4<-H4#j`Df`@Jfq`R8tytVe}# z0Ac=foyCjS1TL|+z>Si4Xmaqu-etn$miEQ@t96a_6}fAT{yW;9E0c7JLP}qBl0;G6 z&3v7W{!T8Jx9tD?=Ez^u5$EpBM-By3j1+PrU*Lis$~3(hHOwnZVW_beT{Pax#fxFk zTLm-dl%>qqx^eUZRPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS>)Ja4^RCodHn_GxhRTRg+X_`o> zFtxl?mS{*>F{P;?JxDhpH5#nIq_8A<6D_G8g^C~vA|pZYLCU9mkqps6%uA$s0WDIq z#KJ}kN6q`a-=8@%v%lrJedjip&VoPty4L!yHRs#=oPEwzDy5VeC^JxIpv*v-fieSS z2L7KJs4F_`t5>h~$LB;a7L4>Tgz_d26qQpRS}6B>*haazuCA_?vUdqd84VVIUEm5x zD$*^1$*JuXp@o(8t(l@%Ym@-;1wL}j`LLGp1(ehMCrAbWuE z)nGR`0uDPR)yiNn$SEJBJ{b%LVX~9KIjmC~!zL9zMq=u~d*BlAlgo6j26Mouqy(kw z*^n*S^b>IqmrVcoNjX;_G5~xF{6s-42lpp-5TGcVp6#GSiPL}p^D=Lf>F5T9wu({9SlCB}9d z2OBaoUXUU9Z!j_Fxh=h5beu7)XPt-ATQ1guI0O5vI4(5{j4lDLG^aM&MFt3>*$ssH zl2lYMpr`aB#^~%+M!Qg%IA)tz6kF(1f9N2}j}XsxC#H+k2iI~gjE#HI>F3zUqk0*m zd*F2@%s57ZiWIlQ@hQ*)E zoX`YCJthn_#`KOVmhihi&Q}S4%fuA;ONv^9&Y4Vf?IE}!ldx&egU*K8 ziAvDFM)?lY?uku%0%2pUiYY2V|5VMcRC+^#hMAbO+XhNhg7z5A-jJXNOiaI+c2zTQ zaq?zaWu3$=uCfr)U_pF_;VicK3)or7Vw%O-_hW`~E%$cSssyNaO|BfH;XcPyD>yCY zX*)gbDrZpFeN|$?e*K*o=mkv>!prbTVp3~TN2+w_n1ixi-9Y8(-CVujf?<8Z@ZSM>)ldgq+&Oj0N1e|XNnGaCo_7O z>)3b;aOE!=*=`^hoaK7(>I-s=Efdr5)YoQKUeCn1HG&uWRzQwt z*?HZi4YyZ;{p@&cZv1dI4A|GW7wCH`H>U{=!|7RY5x8=c#@z``##6(A7Q9ogSL*tT z%ihArGnm6HxJ&|PfGfJIFNPzIrU3hva#;?s)?^Y+T9Ey|wiVYYH5p4g8He_>lDTPZ zrqPGbZ9ty~`$;~Fau{J){ArlzNxyJ`Lp_)Q4jDdb>dGnp4~J8&L#}8|x}nJI;7^Hp z1?&ZWqRnJdk(@ew;rK(t=ln@_8;1IM-5lhU zG3|K28y&ZKmWI}k-QYX03H%C9g1B;yiJybC=S4wb#P5g13d7p>D_7>|qt9kDH|wSn zvk2T7KY|=*LgXHxoxzof?JnsY3f=%exD#@y>*4b)Fr?jgUS+L|<{XH)zi+)VX@ux& zl#c?vF{lH6qHlOU1M9(fpxc5mz`m!Vt4dmF?FZYyMu9`FLzIO`P%zgxCkZ+p(8ouC z>&-PvogHha&L^;4on37;?A}OCr+w|vAK;XS7IcnN@BTs{`q!sgx_bux1AjsJBPz%)>i_@%07*qoM6N<$f~EsyNB{r; literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_stealth_25min.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_stealth_25min.png new file mode 100644 index 0000000000000000000000000000000000000000..9f02181da3e60b2972491e9a089850ae968c736f GIT binary patch literal 2695 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 B6O#Y{ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_stealth_5min.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_stealth_5min.png new file mode 100644 index 0000000000000000000000000000000000000000..64fe452261552212353b7aeabf27a9803f816fe3 GIT binary patch literal 2338 zcmV+-3ElRIP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS@j7da6RCodHnro;PRTzfzR(Y$a ztW2$x)GkJZSqCCIS%GbOMvXULb3(zp4gNz+?;sn=~tqO>6{t?dvIm$>;@MLBmpTVLi1Z#jeW)F)2rH zCq#V-#wLktg!+y}i(qnw67xyWkXMYIkHRKMw-dqVg0xr67<{_We;e2gHnwZm?hxs* zXAE=**aPxd3(hOSbTIgsnk5GG5(sTSK=>Fqr0-gf9KqcEx<3pgR zyCdvOAzXW)DIk8OAnUc(333(C^LQ{CyaE0KN%k%cyu&kM4J<3-_W9**s5>h19ik z#WZ3bjk=PSdi2i;q8H+3V4qlPsp}jhKmjCZ?E!pGw`+5ShqOJ|2wXcz;i6o`b#O*= z6R;b~_0)C9EC=Taz}l3|gmrdgAbQ2Ic26c*u;`s%RZB3F??_(P03vl?t zIF0Afe1WOURgB{3GqYERLw zw_*E2IxLlQ%1-dxy_M0LSbQ#Jh&HT_zN?tR+-1SdrOv<_YkUXRNDgjuxf&vJjy?6t&j&ys)5&Xms+ z9V>uqvn-=~rNnLaHR7|lAw-Ir?(lSSxOO`EqO%{HfCEgq;!F!8v>=L8lHMi zkiPl5*555C?^}cH7m9DJQ_ixx{)npe7USybO8F9?4*-h$IeU}+q_r|Tw)1SDk_kef z7OHNh({5AFTP(YRh^u4JIp7N5-u8O3XmNgki3+(uLwVG8#hEDWO1$>O(u1SiXzT{8 zmED)+p6P2Kzs&^LKv_p9mFyoH9|!se1~d5jdxD;$#g-jscl=INHYYNMy8)|uI06u1)H1wI1SbQSfq zl{w13vH9lUzYw~Ff!#%4o*u&k0Z?fYn7W%_8%3T5^I^qnR4O^`hk8EBmfE^jySPB!H{MLRY-_L4nE z9LRPW95;kWxs3G*W){$QwKP8kwtd!z&=GOivDvYgheGrS;F^Bo(!IQAwi>u*JLLL# z-9<@Ew4Dp~0oP_G^{=KL!tNmc`A*C~qD_tj$B}J1rtAR!qF7Co{z6)|u283QDSIw1 z7i|S{8$2UL=2-d*0Vn(Ok@>k5MFem^=!lB5`cZ^#x%26=at-;jBY-yJ5Vqv{&{L+-HGJAgz5$ z$6y;)xb8E7HP+r$jR=P&hC~~-AXkxuz@;w>cY-fKl4*UK1cH6dg-chD-Fz;oYI33h zjDpBoux)-UhyZ%M=?iWE`p;@Yt^+;eJ|RprU+f?{Y1Tx18 z=_qYL8m(z89Ye;_zD1iy?PjgLOhw5#ZqUFP$)pKLn>CH0x=mqP4G=eh78{ZB8eqSt zrKJttPg){PBqb*8O~C`YgajB4?4m6dJHQaPZ$0wT5NRPPF=-xNh$aG!2EK1u2dJM2 z3SXBLGm0$@)}(cGA(ImaAz(AG2mG-$IaL0mby0G&aY&3rz_;2z=>N71b># zt=VlSZlD-RCT)WXofI1k0eU-rF-c)mznFA9$bA|hj)+T~l}ws)$Ft+jTti1Wsuyp!!68D`H#fO*_K$AJdV@B;fn3Ydnq?f9CHt zus4D#yGQ6ln)Vb?pRe^IJ)Q4qEu@WWOjHk`bLFH(oTgx=7>d=Sac3k!8KU*+cmh}o zbgUW5#3jxN!2X^oK~1*mpto2h2@FIhghL}-L)s6djjvz1ZUH);(C6x9+(ti=*4)wx z3@(HT>kO&B`|JC-exDq#J7ineqn+fx2Ai3X18Vr+8f*ss1$QkOinmfs&Hw-a07*qo IM6N<$f=<{-zyJUM literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_stealth_locked.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_stealth_locked.png new file mode 100644 index 0000000000000000000000000000000000000000..07d3cbcea66a58f006cd16f557cdc6dc8f86a05e GIT binary patch literal 1778 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS>TuDShRCodHn@fxpMHGhb0HS~j zVieKDaS#VF#s@w^BF150Sg>GibR}UUi!p4JS;+!HgDy-=OiXlPWamN>6C*@rW7Nb) z;sb>cg-K>Wf`(UQz{mLgGu@Z!(_MGE`}Uo=k3PviRduS)sZ;;0uBoo>u2f1X87LVj z87LVj87LX(WCq5^$L9*2%z=085VHkb3^3?z*ohUIH32asRoUK2T+GQa*xgW7>FVlw zIfrcp+uN{P1?~-S7wICfFhCdSIdC5Q0S<#-z|Y`w`aMb7Ji>qmt8*usNi~x&nFH2= zSHVx9Uik_K1K|3mVToY2dq(9YiT2CDE->n`&7=MjquZN?7&j0COHC4O7lUJNB?lX`ysEg>o23l8+fa4%scgR+*1Gx1tdYlCU6w=7~ZryPQ4~s+qNh}z(#NhNc3N+Bq{u5A!7p=1FndqrD2;e zMb}v~i2<(#e*r7+p_m;KL=)@EY(9ureh%9YGST z=>E#e$0%yfoRFL_rG5L&BnI^$_#3!#g2K(=z_X;-wHHYY=%C9C`TxNBETq`B*tZ8s z3`8e&R&pJ!wk1h0v)`~YLV3O&Y~C`yT6ZQ9d^h+PxbkdXGJJM8Z%vX2e4EP*`7>aF zZ=h-P*lz~yaa+PbJ^-$~n}&p1ZE$t~w8y<01Nqfuhx{|O2A`%5AH#vqmLiFmZ;g!) z<%M7{Ve&+*QAP!h-1|6@bdz;~t|`_e;+O|kgBQRF8>h~6EJ1y-Mi~|OJP%w+^htvm zC5is~+#tzc2!}c=%#i->I>SG)7nUMsYiDuFen2|M!e%Ay0!yRyZGTy;Ib1iW0V(NxIzZ)J7GNhLA)L zB4=-;r^$jIP+UDl_|a+%dcf&P`^aB)kb5Sn7wolg+qEvz357yQ!k>>EJ=(H6=_nb# z5{CUi*QS;CQC#J-ORL9+_DR}I9sq}d?%i~Qt5X2!HYfQ)pJ@v~dmlOK%kH9+y7cRC z@FdXY$;yW)uJv0swuZh_lSJF4Kr_;nF$xs=6IBy(h`&3)8jyJ% zkWFAKAMz#9j}zPEp(~7}uA-(pLEVq9JzyY(Pxn&nvK8}x!3LHG&OIQg>y&X67jdL;ED_?Go!gfz2=B#i8uG=^>=J}+l>*p3DX zGfBt3ng64@qh UavnAjs{jB107*qoM6N<$f(x%E!T|N!rQ*X@uk|vVBbk|3wH%^6bujR4^uF#0u&+N;2 z$tc|^!}zSVfr`rH$;STb3ypJEyE-y3vIsc92rcmwNlJZgi%qxQ@87wsEtfrVT5agO z=>=A+oUdN#{<`onYf-NP>z0Y1m+gAT8}qqr{;B-i#*@Ob?oDi6{+vn5yL{@}lgs1Q z@W-Biv9WKL+{T!cKPx^?I_G#pseyrsLjgpXge!cT{iSV%S!jJo{r_C`<6lhgozrzK zWX_ybxKb{D#ja=hS?0n4&(&tMmK{w#`q#$qV??3-w?6^j-@J6*bI~j!#^I1<*pl{y zEnB4KaIO^hx@j%tR2XDa|H|_gtIA7v*4;s|v&y@F6+LGxvQ4T~u+925>0V%LsATJq@RW!5DZlUH}VpVz>-^`_7zca8Y>MeVGw+M85M?zsgB9RKxL%JJHU zmG2c^TeBjEY!YkIGO2d1x^-Fm*PPq!q8k`8a}Kx1=MAxUzeJW!{J*JOKQM&z$*i-l z+uXU2ZM55d{IuRS`|XcdtAgB`ccz;Db$h4U^>X@j>sM7rbhg;-b=%i`YGaWoG)zHW c@D=~T{5UOYpVaRucA&K4>FVdQ&MBb@0LYyV*#H0l literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_stories_link.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_stories_link.png new file mode 100644 index 0000000000000000000000000000000000000000..ee1e90c6f85eb86251eea8e71c1d6cb179b9ff1d GIT binary patch literal 1766 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS>P)S5VRCodHn@wyMMHt6<1*8dt z#E2jVh=2y;#YiwF>Y-jV0TN6gnAGS=Oq3o(J(zg*BTy_$$88{3A+!N9@z z2`E^5Km_qX!U53w``6uOcrvr^$IQOFZTCt3-QAg;=i~qG&dxkDU9zN+hJl8GhJl8G zhJpFYK&$SK&&{;igZ) z5LmS!St77y-~})ZV&oEy4}uj7hA4vB4NilU@;l0&k0Gh@K8OHrBY?NS8*Kvljru8| zKIboR2T*^s0jPf}lEYLE(??w|x~X<`kh2n;HUGdA48ngLd#}AGn!$_AAG}lao7#?JqMw^22CeSLqRNwt`)t(nlKm z8gaX#EWol#$*GfZ$k^brlbt^n@=+7TMI}sFrwRD12|D=7FFJxUVnmWF$_jWT2|+xj z8t3R!J^`NbTB=u}QYNk_mFt!0&Iv*^J01rQWELK$>{}k?pS>1)EJWuHn%)mSL$`9! zG4i)*tlUz15jns&Lf)0i8v0w{Baq8gPJ(?#Cw6H+nk&nW?|0I!t9wwq4*1B?I48-c z96ciEFtGA!SI(N7Q8sQAzGiNTyF_{D$w@Xs#zu%7#kMmh0@|OG5=YXFrcoMta#E9X z$O*tbJrqgKy{@wC{NWg#b8S(k9I`J>+AnhSx3)$jNC5g# zT{*)=+)M%m+GU}~(3MkMM14s_u5^G>U#rZ{X6z`nYGt?TqXdn6tX8gjTJdxpK}WyH z*@UerPYmz4{`7o~;t`|#M9<2yhUlxBoMZTqWZa`b?B=DYWs(|@^F2PSj{T8m+oNbZ zuu{0oqMc!sxwCRtcal%J?4vaFTK!1fx^_NxT#vFLHv-Pjcih->Bkgw>efedr$tijl zZ5ndQ6L&X7TRk@)q3lHxU^AY&u8LrLB@M>FM$_;ouAjihMN=MkiNW{spEx^?#%M%` zKDSDC<)YUudbp7Lgsz>rV&@qBS``hH?#zv6M{RrSS(GNl@dr`xG&s%m7dcxmAo`g>7-pmp>LsNuMP2DZ%c`A=j52F^AL3!Es^mx21D3qbwTsd?SU5I`dh0}TTW0}TTW1NCL#Klj*s#aMvfWB>pF07*qo IM6N<$f|yV+SpWb4 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_stories_myhide.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_stories_myhide.png new file mode 100644 index 0000000000000000000000000000000000000000..a06e94a30b56f1583a140ba6f83a393bcb504a18 GIT binary patch literal 2220 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 DPd_a9 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_stories_timer.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_stories_timer.png new file mode 100644 index 0000000000000000000000000000000000000000..67bdaad99bdaa8186fd3375d7b8302c4f674dfc6 GIT binary patch literal 1861 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 + + + + + + diff --git a/TMessagesProj/src/main/res/raw/mapstyle_dark.json b/TMessagesProj/src/main/res/raw/mapstyle_dark.json new file mode 100644 index 00000000000..084a0fb5d6e --- /dev/null +++ b/TMessagesProj/src/main/res/raw/mapstyle_dark.json @@ -0,0 +1,186 @@ +[ + { + "elementType": "geometry", + "stylers": [ + { + "color": "#212121" + } + ] + }, + { + "elementType": "labels.icon", + "stylers": [ + { + "visibility": "off" + } + ] + }, + { + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#757575" + } + ] + }, + { + "elementType": "labels.text.stroke", + "stylers": [ + { + "color": "#212121" + } + ] + }, + { + "featureType": "administrative", + "elementType": "geometry", + "stylers": [ + { + "color": "#757575" + } + ] + }, + { + "featureType": "administrative.country", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#9e9e9e" + } + ] + }, + { + "featureType": "administrative.land_parcel", + "stylers": [ + { + "visibility": "off" + } + ] + }, + { + "featureType": "administrative.locality", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#bdbdbd" + } + ] + }, + { + "featureType": "poi", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#757575" + } + ] + }, + { + "featureType": "poi.park", + "elementType": "geometry", + "stylers": [ + { + "color": "#181818" + } + ] + }, + { + "featureType": "poi.park", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#616161" + } + ] + }, + { + "featureType": "poi.park", + "elementType": "labels.text.stroke", + "stylers": [ + { + "color": "#1b1b1b" + } + ] + }, + { + "featureType": "road", + "elementType": "geometry.fill", + "stylers": [ + { + "color": "#2c2c2c" + } + ] + }, + { + "featureType": "road", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#8a8a8a" + } + ] + }, + { + "featureType": "road.arterial", + "elementType": "geometry", + "stylers": [ + { + "color": "#373737" + } + ] + }, + { + "featureType": "road.highway", + "elementType": "geometry", + "stylers": [ + { + "color": "#3c3c3c" + } + ] + }, + { + "featureType": "road.highway.controlled_access", + "elementType": "geometry", + "stylers": [ + { + "color": "#4e4e4e" + } + ] + }, + { + "featureType": "road.local", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#616161" + } + ] + }, + { + "featureType": "transit", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#757575" + } + ] + }, + { + "featureType": "water", + "elementType": "geometry", + "stylers": [ + { + "color": "#000000" + } + ] + }, + { + "featureType": "water", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#3d3d3d" + } + ] + } +] \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index 1c7d94f12f2..ce527fecaff 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -298,6 +298,12 @@ **Telegram** needs access to your contacts so that you can connect with your friends across all your devices. Your contacts will be continuously synced with Telegram\'s heavily encrypted cloud servers. Not now Continue + Turn on notifications + Please allow Telegram to send you notifications to stay in touch with your friends and family. + Get notified about new messages + Learn when you are mentioned in groups + Mute specific chats and types of chats + Continue Your contacts on Telegram Connecting your contacts... This is your Archive @@ -1168,6 +1174,7 @@ Ban user Report spam Translate + Hide Translation Automatic Translation Close Translation Translation failed. Try again later. @@ -1710,6 +1717,7 @@ User unblocked Edit contact Delete contact + Delete Contact Home Mobile Work @@ -2995,6 +3003,7 @@ Accurate to %1$s %1$s away Or choose a venue + Location on map Tap to send this location Live locations Live Location @@ -3251,6 +3260,7 @@ Re-enter new password Recovery email Recovery Email + You can set a recovery email to be able to reset your password and restore access to your Telegram account. Your email Your new email Your email has been changed. @@ -5515,6 +5525,7 @@ This reactions contains emoji from **%d Packs**. This reactions contains emoji from **%d Packs**. This reactions contains emoji from **%d Packs**. + This reaction is an emoji from %s pack. Send message as... VIEW POST Saving content @@ -6161,6 +6172,7 @@ Star Bubble Roboto + Condensed Italic Serif Mono-serif @@ -6717,6 +6729,12 @@ %d recipients %d recipients Everyone + Everyone (-%d) + Everyone (-%d) + Everyone (-%d) + Everyone (-%d) + Everyone (-%d) + Everyone (-%d) Close Friends Contacts %d contacts @@ -6733,13 +6751,13 @@ Contacts (-%d) Share story Edit Privacy Settings - Choose who can view for %d hours - Choose who can view for %d hour - Choose who can view for %d hours - Choose who can view for %d hours - Choose who can view for %d hours - Choose who can view for %d hours - Choose who can view in your profile + Choose who can view your story + Choose who can view your story + Choose who can view your story + Choose who can view your story + Choose who can view your story + Choose who can view your story + Choose who can view your story Close Friends Choose close friends Excluded Contacts @@ -6748,6 +6766,12 @@ Choose contacts Send as message Choose recipients + Hide my stories from + Select people + Everyone except... + Exclude contacts + Hide My Stories From %s + Do Not Hide My Stories From %s Save Settings Post Story Save List @@ -6906,7 +6930,7 @@ Automatically enabled Disabled No one has viewed this story so far. - Only people from **%s’s** Close Friends list can view this story + You are seeing this story because **%s** added you to their list of Close Friends Only some contacts **%s** selected can view this story. Only **%s’s** contacts can view this story. List of viewers isn\'t available after **24 hours** of story expiration. @@ -6915,6 +6939,13 @@ New Story Edit Allow Screenshots + **Select people** who won’t see your stories. + **%d people** won’t see your stories. + **%d person** won’t see your stories. + **%d people** won’t see your stories. + **%d people** won’t see your stories. + **%d people** won’t see your stories. + **%d people** won’t see your stories. Keep on My Page Keep this story on your page even after it expires in %d hours. Privacy settings will apply. Keep this story on your page even after it expires in %d hour. Privacy settings will apply. @@ -7000,9 +7031,80 @@ You can’t post more than **%d stories** in **24 hours**. You can’t post more than **%d stories** in **24 hours**. You can’t post more than **%d stories** in **24 hours**. - Posting stories is currently available only to subscribers of **Telegram Premium**. + Posting stories is currently available only to subscribers of **Telegram Premium**. Hide Stories Unhide Stories + Subscribe to **Telegram Premium** to add links and text formatting to your stories. + Maximum Length Reach + Increase this limit **%1$d** times to **%2$s** symbols by subscribing to __Telegram Premium.__ + To unlock viewers’ lists for expired and saved stories, subscribe to **Telegram Premium.** + Learn More + **Subscribe to Premium** to save other people’s unprotected stories to your gallery. + Upgraded Stories + Priority order, stealth mode, permanent views history and more. + Priority Order + Get more views as your stories are always displayed first. + Stealth Mode + Hide the fact that you viewed other people’s stories. + Permanent Views History + Check who opens your stories — even after they expire. + Expiration Durations + Set custom expiration durations like 6 or 48 hours for your stories. + Save Stories to Gallery + Save other people’s unprotected stories to your Gallery. + Longer Captions + Add ten times longer captions to your stories — up to 2048 symbols. + Links and Formatting + Add links and formatting in captions of your stories. + Upgraded Stories + Stealth Mode + Subscribe to Telegram Premium to hide the fact that you viewed peoples’ stories from them. + Hide Recent Views + Hide my views in the last 5 minutes. + Hide Next Views + Hide my views in the next 25 minutes. + Unlock Stealth Mode + Turn Stealth Mode on to hide the fact that you viewed peoples’ stories from them. + Enable Stealth Mode + Available in %s + Stealth Mode On + The creators of stories you viewed in the last 5 minutes or will view in the next 25 minutes won’t see you in viewers’ lists. + Stealth Mode active – %s + Stealth Mode %s Group Too Large You can select groups that are up to 200 members. + Stealth Mode Is Active + Please wait until the **Stealth Mode** is ready to use again. + View Location > + Like + Long tap for more reactions + All viewers + Reactions First + Newest First + Choose the order for the 
list of viewers. + None of your contacts viewed this story. + Viewers + You are in Stealth Mode now + If you sending a reply or reaction, the creator of the story will also see you in the list of viewers. + Oops + Information about the viewers wasn\'t recorded. + Information about the other viewers wasn\'t recorded. + %s would not be able to see your stories. + %s would be able to see your stories again. + Type to search. + No views + To unlock viewers’ lists for expired and saved stories, subscribe to **Telegram Premium.** + %d like + %d likes + %d likes + %d likes + %d likes + You can post **%1$d** stories in **24** hours.\nSubscribe to **Telegram Premium** to increase this limit to **%2$d**. + Sorry, you can’t post more than **%1$d** stories. + You can post **%1$d** stories in a week.\nSubscribe to **Telegram Premium** to increase this limit to **%2$d**. + Sorry, you can’t post more than **%1$d** stories in a week. + You can post **%1$d** stories in a month.\nSubscribe to **Telegram Premium** to increase this limit to **%2$d**. + Sorry, you can’t post more than **%1$d** stories in a month. + Deselect All + ADD LOCATION diff --git a/TMessagesProj_App/build.gradle b/TMessagesProj_App/build.gradle index 62ecb8b9332..9f0b2df9d38 100644 --- a/TMessagesProj_App/build.gradle +++ b/TMessagesProj_App/build.gradle @@ -176,7 +176,7 @@ android { defaultConfig { minSdkVersion 19 - targetSdkVersion 31 + targetSdkVersion 33 versionName APP_VERSION_NAME ndkVersion "21.4.7075529" diff --git a/TMessagesProj_AppHockeyApp/build.gradle b/TMessagesProj_AppHockeyApp/build.gradle index b20a2c85c4c..2f7d61dd679 100644 --- a/TMessagesProj_AppHockeyApp/build.gradle +++ b/TMessagesProj_AppHockeyApp/build.gradle @@ -144,7 +144,7 @@ android { defaultConfig { minSdkVersion 19 - targetSdkVersion 31 + targetSdkVersion 33 versionName APP_VERSION_NAME ndkVersion "21.4.7075529" diff --git a/TMessagesProj_AppHuawei/build.gradle b/TMessagesProj_AppHuawei/build.gradle index b9ac4c354d6..384c31343d1 100644 --- a/TMessagesProj_AppHuawei/build.gradle +++ b/TMessagesProj_AppHuawei/build.gradle @@ -137,7 +137,7 @@ android { defaultConfig { minSdkVersion 19 - targetSdkVersion 31 + targetSdkVersion 33 versionName APP_VERSION_NAME ndkVersion "21.4.7075529" diff --git a/TMessagesProj_AppHuawei/src/main/java/org/telegram/messenger/HuaweiMapsProvider.java b/TMessagesProj_AppHuawei/src/main/java/org/telegram/messenger/HuaweiMapsProvider.java index 43efbca00bd..f4d9886182a 100644 --- a/TMessagesProj_AppHuawei/src/main/java/org/telegram/messenger/HuaweiMapsProvider.java +++ b/TMessagesProj_AppHuawei/src/main/java/org/telegram/messenger/HuaweiMapsProvider.java @@ -125,6 +125,11 @@ public float getMaxZoomLevel() { return huaweiMap.getMaxZoomLevel(); } + @Override + public float getMinZoomLevel() { + return huaweiMap.getMinZoomLevel(); + } + @SuppressLint("MissingPermission") @Override public void setMyLocationEnabled(boolean enabled) { @@ -156,6 +161,11 @@ public void setOnCameraMoveStartedListener(OnCameraMoveStartedListener onCameraM }); } + @Override + public void setOnCameraIdleListener(Runnable callback) { + huaweiMap.setOnCameraIdleListener(callback::run); + } + @Override public CameraPosition getCameraPosition() { com.huawei.hms.maps.model.CameraPosition pos = huaweiMap.getCameraPosition();