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 | 112 +- .../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 | 108 +- .../ui/Cells/LocationDirectionCell.java | 2 +- .../ui/Cells/ReactedUserHolderView.java | 93 +- .../telegram/ui/Cells/SendLocationCell.java | 2 +- .../ui/Cells/SharingLiveLocationCell.java | 139 +- .../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 | 238 ++-- .../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 | 158 ++- .../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 | 82 +- .../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 | 213 ++-- .../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 | 490 +++++-- .../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 | 1124 +++++++++++++++-- .../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 | 475 ++++--- .../telegram/ui/Stories/StoriesViewPager.java | 75 +- .../telegram/ui/Stories/StoryCaptionView.java | 830 +++++++----- .../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 | 463 ++++++- .../ui/Stories/recorder/HintView2.java | 169 ++- .../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, 15366 insertions(+), 3288 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 bd6343f3b..e03a85d66 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 b7f49c6f5..7d6dc8b3c 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 f6464b533..5c958dc8b 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 457658f4a..a6281473a 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 f52960f1e..9cab3db1c 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 66638636e..344cba957 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 b5a460b49..68ef0738e 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 dff83fdbf..e6716b5b0 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 b2bb47369..11b9cf935 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 755fed8aa..12ff1899e 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 ed042272a..89242e5e9 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.math.BigDecimal; 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 @@ public final class Util { @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 2a9849f91..c7f31914a 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.ContextCompat; 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.TypefaceSpan; 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 class AndroidUtilities { } 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 class AndroidUtilities { 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 class AndroidUtilities { 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 class AndroidUtilities { } 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 class AndroidUtilities { } } + 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 class AndroidUtilities { } 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 class AndroidUtilities { } 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 6c9ff9cf5..5eaa3d40b 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 e847d9222..fc73ae225 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 class ChatMessagesMetadataController { 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 3bfda0b4c..f35882672 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 class ContactsController extends BaseController { 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 class ContactsController extends BaseController { 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 class ContactsController extends BaseController { } } 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 class ContactsController extends BaseController { } } 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 5058d08f3..885a008a5 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 class DatabaseMigrationHelper { 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 f118c0e92..a08da5ab1 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 class DispatchQueue extends Thread { 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 c09f367f1..e5b7f4b11 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 class FilePathDatabase { 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 class FilePathDatabase { 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 @@ public class FilePathDatabase { 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 18f019fc4..f62f59fd2 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 class FileStreamLoadOperation extends BaseDataSource implements FileLoadO } 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 b814b97c6..4ee9d2213 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 class FilesMigrationService extends Service { 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 648a6a21a..5f4831780 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 class GoogleMapsProvider implements IMapsProvider { return googleMap.getMaxZoomLevel(); } + @Override + public float getMinZoomLevel() { + return googleMap.getMinZoomLevel(); + } + @SuppressLint("MissingPermission") @Override public void setMyLocationEnabled(boolean enabled) { @@ -151,6 +156,11 @@ public class GoogleMapsProvider implements IMapsProvider { }); } + @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 0034510b0..75db0a089 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 @@ public interface IMapsProvider { 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 9b48fddca..23ac4df39 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 android.view.View; 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 class ImageReceiver implements NotificationCenter.NotificationCenterDeleg 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 a2e3bf157..1e361830c 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 894b11e05..eee5cd401 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.Build; 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 class LocationController extends BaseController implements NotificationCe } 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 class LocationController extends BaseController implements NotificationCe 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 class LocationController extends BaseController implements NotificationCe 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 class LocationController extends BaseController implements NotificationCe } 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 class LocationController extends BaseController implements NotificationCe 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 260962ed3..3cd122e16 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 class MediaController implements AudioManager.OnAudioFocusChangeListener, 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 class MediaController implements AudioManager.OnAudioFocusChangeListener, } } 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 class MediaController implements AudioManager.OnAudioFocusChangeListener, 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 class MediaController implements AudioManager.OnAudioFocusChangeListener, 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 class MediaController implements AudioManager.OnAudioFocusChangeListener, 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 class MediaController implements AudioManager.OnAudioFocusChangeListener, 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 class MediaController implements AudioManager.OnAudioFocusChangeListener, } sensorManager.unregisterListener(MediaController.this, proximitySensor); }); - if (proximityHasDifferentValues && proximityWakeLock != null && proximityWakeLock.isHeld()) { + if (proximityWakeLock != null && proximityWakeLock.isHeld()) { proximityWakeLock.release(); } } @@ -2072,14 +2112,7 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, 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 class MediaController implements AudioManager.OnAudioFocusChangeListener, 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 class MediaController implements AudioManager.OnAudioFocusChangeListener, 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 class MediaController implements AudioManager.OnAudioFocusChangeListener, 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 class MediaController implements AudioManager.OnAudioFocusChangeListener, return true; } - - public static boolean ignoreAccelerometerGestures() { - return Build.MANUFACTURER.equalsIgnoreCase("samsung"); - } public void updateSilent(boolean value) { isSilent = value; @@ -4738,8 +4770,17 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, 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 class MediaController implements AudioManager.OnAudioFocusChangeListener, } 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 5b28b1331..c916729ae 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 @@ public class MediaDataController extends BaseController { } } - 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 class MediaDataController extends BaseController { AndroidUtilities.runOnUIThread(callback); } } - }); + }, classGuid); if (replyMessageOwners.isEmpty()) { requestsCount[0]--; if (requestsCount[0] == 0) { @@ -5617,7 +5617,7 @@ public class MediaDataController extends BaseController { 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 class MediaDataController extends BaseController { } } }); + 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 class MediaDataController extends BaseController { } } }); + 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 class MediaDataController extends BaseController { } } }); + 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 120700542..30c7df376 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 class MessageObject { 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 class MessageObject { } 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 class MessageObject { 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 class MessageObject { } 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 class MessageObject { 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 e93769d90..77c565936 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.os.SystemClock; 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.LaunchActivity; 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 @@ public class MessagesController extends BaseController implements NotificationCe 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 @@ public class MessagesController extends BaseController implements NotificationCe 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 @@ public class MessagesController extends BaseController implements NotificationCe 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 @@ public class MessagesController extends BaseController implements NotificationCe public int chatlistJoinedLimitDefault; public int chatlistJoinedLimitPremium; public String storiesPosting; + public String storiesEntities; public int checkResetLangpack; @@ -622,6 +633,7 @@ public class MessagesController extends BaseController implements NotificationCe getMessagesStorage().saveDialogFiltersOrder(); getNotificationCenter().postNotificationName(NotificationCenter.dialogFiltersUpdated); + getStoriesController().onPremiumChanged(); } public void lockFiltersInternal() { @@ -1285,6 +1297,7 @@ public class MessagesController extends BaseController implements NotificationCe 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 class MessagesController extends BaseController implements NotificationCe 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 class MessagesController extends BaseController implements NotificationCe 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 class MessagesController extends BaseController implements NotificationCe 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 @@ public class MessagesController extends BaseController implements NotificationCe 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 @@ public class MessagesController extends BaseController implements NotificationCe } 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 != storyCaptionLengthLimit) { - storyCaptionLengthLimit = (int) number.value; - editor.putInt("storyCaptionLengthLimit", storyCaptionLengthLimit); + 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 != storyCaptionLengthLimitPremium) { + storyCaptionLengthLimitPremium = (int) number.value; + editor.putInt("storyCaptionLengthLimitPremium", storyCaptionLengthLimitPremium); changed = true; } } @@ -3174,6 +3234,50 @@ public class MessagesController extends BaseController implements NotificationCe } 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 @@ public class MessagesController extends BaseController implements NotificationCe } 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 @@ public class MessagesController extends BaseController implements NotificationCe } } } + 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 @@ public class MessagesController extends BaseController implements NotificationCe 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 class MessagesController extends BaseController implements NotificationCe } } } + } else if (id == NotificationCenter.currentUserPremiumStatusChanged) { + loadAppConfig(false); } } @@ -5729,7 +5856,7 @@ public class MessagesController extends BaseController implements NotificationCe } } }; - 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 class MessagesController extends BaseController implements NotificationCe } 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 class MessagesController extends BaseController implements NotificationCe req.channel = getInputChannel(chatId); req.filter = new TLRPC.TL_channelParticipantsRecent(); req.offset = 0; - req.limit = 32; + req.limit = count; getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (error == null) { TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; @@ -8011,6 +8138,7 @@ public class MessagesController extends BaseController implements NotificationCe } 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 class MessagesController extends BaseController implements NotificationCe } 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 class MessagesController extends BaseController implements NotificationCe if (!guids.contains(guid)) { guids.add(guid); } - boolean needGetDifference = false; if (shortPollChannels.indexOfKey(chat.id) < 0) { - needGetDifference = true; + if (needPollConsumer != null) { + AndroidUtilities.runOnUIThread(() -> { + 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 class MessagesController extends BaseController implements NotificationCe updateInterfaceWithMessages(dialogId, arr, false); getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); }); - }); + }, 0); } }); @@ -14723,6 +14855,7 @@ public class MessagesController extends BaseController implements NotificationCe blockePeers.delete(id); } getNotificationCenter().postNotificationName(NotificationCenter.blockedUsersDidLoad); + getStoriesController().updateBlockUser(id, finalUpdate.blocked_my_stories_from, false); })); } else if (baseUpdate instanceof TLRPC.TL_updateNotifySettings) { if (updatesOnMainThread == null) { @@ -14780,6 +14913,11 @@ public class MessagesController extends BaseController implements NotificationCe } pushMessages.add(obj); } + } else if (baseUpdate instanceof TLRPC.TL_updateStoriesStealthMode) { + if (updatesOnMainThread == null) { + updatesOnMainThread = new ArrayList<>(); + } + updatesOnMainThread.add(baseUpdate); } else if (baseUpdate instanceof TLRPC.TL_updateDialogPinned) { if (updatesOnMainThread == null) { updatesOnMainThread = new ArrayList<>(); @@ -14912,7 +15050,7 @@ public class MessagesController extends BaseController implements NotificationCe updatesOnMainThread = new 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 class MessagesController extends BaseController implements NotificationCe } int threadId = update.top_msg_id; getMediaDataController().saveDraft(did, threadId, update.draft, null, true); + } else if (baseUpdate instanceof TLRPC.TL_updateStoriesStealthMode) { + TLRPC.TL_updateStoriesStealthMode storiesStealthModeUpdate = (TLRPC.TL_updateStoriesStealthMode) baseUpdate; + getStoriesController().setStealthMode(storiesStealthModeUpdate.stealth_mode); } else if (baseUpdate instanceof TLRPC.TL_updateReadFeaturedStickers) { getMediaDataController().markFeaturedStickersAsRead(false, false); } else if (baseUpdate instanceof TLRPC.TL_updateReadFeaturedEmojiStickers) { @@ -16096,6 +16237,8 @@ public class MessagesController extends BaseController implements NotificationCe getNotificationCenter().postNotificationName(NotificationCenter.voiceTranscriptionUpdate, null, (Long) update.transcription_id, (String) update.text, null, (Boolean) !update.pending); } } + } else if (baseUpdate instanceof TLRPC.TL_updateSentStoryReaction) { + storiesController.updateStoryReaction(((TLRPC.TL_updateSentStoryReaction) baseUpdate).user_id, ((TLRPC.TL_updateSentStoryReaction) baseUpdate).story_id, ((TLRPC.TL_updateSentStoryReaction) baseUpdate).reaction); } } if (editor != null) { @@ -16235,7 +16378,7 @@ public class MessagesController extends BaseController implements NotificationCe } } } - getMediaDataController().loadReplyMessagesForMessages(arrayList, dialogId, false, 0,null); + getMediaDataController().loadReplyMessagesForMessages(arrayList, dialogId, false, 0,null, 0); getNotificationCenter().postNotificationName(NotificationCenter.replaceMessagesObjects, dialogId, arrayList, false); } } @@ -16967,7 +17110,7 @@ public class MessagesController extends BaseController implements NotificationCe } } } - getMediaDataController().loadReplyMessagesForMessages(messages, dialogId, scheduled, 0, null); + getMediaDataController().loadReplyMessagesForMessages(messages, dialogId, scheduled, 0, null, 0); getNotificationCenter().postNotificationName(NotificationCenter.didReceiveNewMessages, dialogId, messages, scheduled); if (lastMessage == null || scheduled) { @@ -18241,4 +18384,31 @@ public class MessagesController extends BaseController implements NotificationCe return false; } } + + public boolean storyEntitiesAllowed() { + switch (storiesEntities) { + case "premium": + return getUserConfig().isPremium(); + case "enabled": + return true; + default: + case "disabled": + return false; + } + } + + public boolean storyEntitiesAllowed(TLRPC.User user) { + if (user != null && user.id == storiesChangelogUserId) { + return true; + } + switch (storiesEntities) { + case "premium": + return user != null && user.premium; + case "enabled": + return true; + default: + case "disabled": + return false; + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index f15a4aa04..2fd1bc172 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -95,7 +95,7 @@ public class MessagesStorage extends BaseController { } } - public final static int LAST_DB_VERSION = 127; + public final static int LAST_DB_VERSION = 128; private boolean databaseMigrationInProgress; public boolean showClearDatabaseAlert; private LongSparseIntArray dialogIsForum = new LongSparseIntArray(); @@ -202,6 +202,7 @@ public class MessagesStorage extends BaseController { public MessagesStorage(int instance) { super(instance); storageQueue = new DispatchQueue("storageQueue_" + instance); + storageQueue.setPriority(8); storageQueue.postRunnable(() -> openDatabase(1)); } @@ -671,7 +672,7 @@ public class MessagesStorage extends BaseController { 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 0211c54e9..e297dc3bc 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 f8250d34e..56d685a26 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 class PushListenerController { 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 3e73d297f..ab1535634 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 @@ public class SharedConfig { 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 class SharedConfig { 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 class SharedConfig { 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 class SharedConfig { messageSeenHintCount = 3; emojiInteractionsHintCount = 3; dayNightThemeSwitchHintCount = 3; + stealthModeSendMessageConfirm = 2; dayNightWallpaperSwitchHint = 0; saveConfig(); } @@ -825,6 +830,14 @@ public class SharedConfig { 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 class SharedConfig { 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 04548a583..8b4f0b8aa 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 @@ public class TranslateController extends BaseController { 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 8f7838a84..0eb03d41f 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 class VideoEditedInfo { 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 class VideoEditedInfo { 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 class VideoEditedInfo { 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 class VideoEditedInfo { 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 class VideoEditedInfo { 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 5db3620d5..4c91e7555 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 class Browser { 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 class Browser { } 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 224baaac4..f96214372 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.MessageObject; 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 class TextureRenderer { 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 @@ public class TextureRenderer { 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 class TextureRenderer { 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 class TextureRenderer { 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 class TextureRenderer { 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 class TextureRenderer { 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 class TextureRenderer { } 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 class TextureRenderer { 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 5a5d00fbd..401d60e2e 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.os.SystemClock; 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 class ConnectionsManager extends BaseController { } 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 d9ee03b66..996df75f8 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.SvgHelper; 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { case 0x26ffde7d: result = new TL_updateDialogFilter(); break; - case 0x246a4b22: + case 0xebe07752: result = new TL_updatePeerBlocked(); break; case 0xed85eab5: @@ -32949,6 +32958,9 @@ public class TLRPC { 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 class TLRPC { 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 class TLRPC { } 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 class TLRPC { } } + 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { } } - - public static abstract class Reaction extends TLObject { public static Reaction TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { @@ -53365,8 +53408,10 @@ public class TLRPC { } 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { 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,25 +69320,35 @@ public class TLRPC { } } - 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); @@ -69308,7 +69383,175 @@ public class TLRPC { } } + 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) { + 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); + stream.writeInt32(reactions_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_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 class TLRPC { } } 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 class TLRPC { 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 class TLRPC { } 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 class TLRPC { } 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 class TLRPC { } 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 class TLRPC { 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 class TLRPC { } 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 class TLRPC { 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 class TLRPC { } users.add(object); } + stealth_mode = TL_storiesStealthMode.TLdeserialize(stream, stream.readInt32(exception), exception); } public void serializeToStream(AbstractSerializedData stream) { @@ -69754,16 +70164,30 @@ public class TLRPC { 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 class TLRPC { 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 class TLRPC { } 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 class TLRPC { 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 class TLRPC { 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 class TLRPC { } 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 class TLRPC { } 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 class TLRPC { } 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 class TLRPC { 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 class TLRPC { } 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 class TLRPC { 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 class TLRPC { } } + 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 48123b210..5d301f725 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 @@ public class ActionBar extends FrameLayout { 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 377ba1e51..ad5365bbd 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 class ActionBarLayout extends FrameLayout implements INavigationLayout, F 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 21fcfb643..9256e0337 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 class ActionBarMenu extends LinearLayout { } } - 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 82d88c386..28c1b073c 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 class ActionBarMenuItem extends FrameLayout { 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 8affa9321..dd3cb892c 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 class ActionBarMenuSubItem extends FrameLayout { 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 7116843f0..cde9699d6 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 abstract class BaseFragment { } 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 1fe0fb575..65566b2be 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.os.Bundle; 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 @@ public class BottomSheet extends Dialog { 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 @@ public class BottomSheet extends Dialog { } } + @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 1d531c5e1..aa2f89f45 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.content.Context; 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.ColorDrawable; 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.AnimationUtils; 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 @@ public final class FloatingToolbar { 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 @@ public final class FloatingToolbar { 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 @@ public final class FloatingToolbar { 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 final class FloatingToolbar { 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 final class FloatingToolbar { }); } + 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 @@ public final class FloatingToolbar { } }; 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 @@ public final class FloatingToolbar { 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 @@ public final class FloatingToolbar { 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 @@ public final class FloatingToolbar { } }; 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 @@ public final class FloatingToolbar { 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 @@ public final class FloatingToolbar { 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 @@ public final class FloatingToolbar { 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 final class FloatingToolbar { 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 final class FloatingToolbar { params.width = menuItemButtonWidth; menuItemButton.setLayoutParams(params); availableWidth -= menuItemButtonWidth; - remainingMenuItems.pop(); + it.remove(); } else { break; } @@ -876,6 +981,13 @@ public final class FloatingToolbar { 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 final class FloatingToolbar { }; } - 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 final class FloatingToolbar { 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 final class FloatingToolbar { 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 final class FloatingToolbar { } 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 @@ public final class FloatingToolbar { 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 @@ public final class FloatingToolbar { 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 6b67ebb38..70c02ca0a 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 @@ public class SimpleTextView extends View implements Drawable.Callback { 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 3ee0b432e..b932f502a 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 class Theme { 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 class Theme { 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 8e2f8b311..d8ab63133 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 class ThemeColors { 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 class ThemeColors { 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 24ca40293..b8cddf34b 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 @@ public class ActionIntroActivity extends BaseFragment implements LocationControl } @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 7ca2aa577..9d2835a5f 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.tgnet.TLRPC; 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 abstract class BaseLocationAdapter extends RecyclerListView.SelectionAdap 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 abstract class BaseLocationAdapter extends RecyclerListView.SelectionAdap 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 @@ public abstract class BaseLocationAdapter extends RecyclerListView.SelectionAdap } 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 @@ public abstract class BaseLocationAdapter extends RecyclerListView.SelectionAdap 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 @@ public abstract class BaseLocationAdapter extends RecyclerListView.SelectionAdap } 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 abstract class BaseLocationAdapter extends RecyclerListView.SelectionAdap 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 abstract class BaseLocationAdapter extends RecyclerListView.SelectionAdap 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 abstract class BaseLocationAdapter extends RecyclerListView.SelectionAdap 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 abstract class BaseLocationAdapter extends RecyclerListView.SelectionAdap 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 1a897adb7..d718af337 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 class DialogsAdapter extends RecyclerListView.SelectionAdapter implements 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 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements 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 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements }; 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 class DialogsAdapter extends RecyclerListView.SelectionAdapter implements 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 class DialogsAdapter extends RecyclerListView.SelectionAdapter implements } } - 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 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements } else { dialogsHeight += cellHeight; } + } else if (itemInternals.get(i).viewType == VIEW_TYPE_FLICKER) { + dialogsHeight += cellHeight; } } dialogsHeight += size - 1; @@ -1480,6 +1485,7 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements 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 f2adcc30f..90af25e53 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.View; 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.LocationPoweredCell; 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 @@ public class LocationActivityAdapter extends BaseLocationAdapter implements Loca } @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 class LocationActivityAdapter extends BaseLocationAdapter implements Loca 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); } - return (locationType == LocationActivity.LOCATION_TYPE_SEND_WITH_LIVE ? 6 : 5) + places.size() + (needEmptyView ? 1 : 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 count + locations.size() + places.size() + (needEmptyView ? 1 : 0); } } @@ -269,7 +310,7 @@ public class LocationActivityAdapter extends BaseLocationAdapter implements Loca 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 class LocationActivityAdapter extends BaseLocationAdapter implements Loca 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 class LocationActivityAdapter extends BaseLocationAdapter implements Loca 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 class LocationActivityAdapter extends BaseLocationAdapter implements Loca 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 class LocationActivityAdapter extends BaseLocationAdapter implements Loca } 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 class LocationActivityAdapter extends BaseLocationAdapter implements Loca } 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 class LocationActivityAdapter extends BaseLocationAdapter implements Loca 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 class LocationActivityAdapter extends BaseLocationAdapter implements Loca 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 class LocationActivityAdapter extends BaseLocationAdapter implements Loca @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 81083b49b..fcf362dfa 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 @@ import androidx.recyclerview.widget.RecyclerView; 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 class LocationActivitySearchAdapter extends BaseLocationAdapter { @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; - - LocationCell locationCell = (LocationCell) holder.itemView; - locationCell.setLocation(place, iconUrl, position, position != getItemCount() - 1); + 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)); + } + } } - public TLRPC.TL_messageMediaVenue getItem(int i) { - if (isSearching()) - return null; - if (i >= 0 && i < places.size()) { - return places.get(i); + @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 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 e6d922214..504935764 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 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg 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 36307bbfe..c9183971b 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 @@ public class BasePermissionsActivity extends Activity { } } 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 83af78d8e..bdb9b620a 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 class CacheControlActivity extends BaseFragment implements NotificationCe } 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 676458d93..69f471c5f 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 @@ public class CameraScanActivity extends BaseFragment { 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 8d2a8be2a..7ebed445c 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 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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 class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate // 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 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } 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 class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate 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 d78c3ae94..2cfc4a9f7 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.UserConfig; 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 class ContextLinkCell extends FrameLayout implements DownloadController.F 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 class ContextLinkCell extends FrameLayout implements DownloadController.F private ContextLinkCellDelegate delegate; + private ButtonBounce buttonBounce; + public ContextLinkCell(Context context) { this(context, false, null); } @@ -165,6 +168,12 @@ public class ContextLinkCell extends FrameLayout implements DownloadController.F 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 class ContextLinkCell extends FrameLayout implements DownloadController.F 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 @@ public class ContextLinkCell extends FrameLayout implements DownloadController.F 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 class ContextLinkCell extends FrameLayout implements DownloadController.F 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 eea62e77c..211d11732 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 class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava private Path thumbPath; private SpoilerEffect thumbSpoiler = new SpoilerEffect(); + private boolean drawForwardIcon; public void setMoving(boolean moving) { this.moving = moving; @@ -951,6 +952,7 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava drawNameLock = false; drawVerified = false; drawPremium = false; + drawForwardIcon = false; drawScam = 0; drawPinBackground = false; thumbsCount = 0; @@ -1577,6 +1579,15 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava } } } + 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 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava 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 @@ public class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava } 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 class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava @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 class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava @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 class DialogCell extends BaseCell implements StoriesListPlaceProvider.Ava @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 9873e8a90..f18798dae 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 class DrawerActionCell extends FrameLayout { 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 @@ public class DrawerActionCell extends FrameLayout { 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 @@ public class DrawerActionCell extends FrameLayout { } 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 e903a569e..dc392ca53 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.animation.ValueAnimator; 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.view.ViewGroup; 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 class LocationCell extends FrameLayout { 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)); + 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 TextView(context); - addressTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - addressTextView.setMaxLines(1); - addressTextView.setEllipsize(TextUtils.TruncateAt.END); - addressTextView.setSingleLine(true); + 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 class LocationCell extends FrameLayout { 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 class LocationCell extends FrameLayout { } } + 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 (label != null) { - addressTextView.setText(label); - } else if (location != null) { - addressTextView.setText(location.address); + if (location != null) { + nameTextView.setText(getTitle(location), allowTextAnimation && !LocaleController.isRTL && animated); } - if (icon != null) - imageView.setImage(icon, null, null); + if (label != null) { + addressTextView.setText(label, allowTextAnimation && !LocaleController.isRTL); + } else if (location != null) { + 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); + } + } + circleDrawable.getPaint().setColor(color); setWillNotDraw(false); setClickable(location == null); @@ -163,7 +211,7 @@ public class LocationCell extends FrameLayout { @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 @@ public class LocationCell extends FrameLayout { 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 63529ec6d..8ecf14234 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 class LocationDirectionCell extends FrameLayout { 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 edf223619..50c933c07 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.view.accessibility.AccessibilityNodeInfo; 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.ActionBar.Theme; 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.messenger.LocaleController; 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 class ReactedUserHolderView extends FrameLayout { 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 class ReactedUserHolderView extends FrameLayout { 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 class ReactedUserHolderView extends FrameLayout { 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 class ReactedUserHolderView extends FrameLayout { } 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 class ReactedUserHolderView extends FrameLayout { } 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 class ReactedUserHolderView extends FrameLayout { } 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 @@ public class ReactedUserHolderView extends FrameLayout { 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 0df8883cb..60a9f99e6 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 class SendLocationCell extends FrameLayout { 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 417345c9f..4ad4eb637 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.PorterDuff; 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.AvatarDrawable; 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 class SharingLiveLocationCell extends FrameLayout { 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 class SharingLiveLocationCell extends FrameLayout { 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,12 +224,49 @@ public class SharingLiveLocationCell extends FrameLayout { } 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; + boolean noTitle = TextUtils.isEmpty(messageObject.messageOwner.media.title); + if (noTitle) { + name = ""; + avatarDrawable = null; + if (fromId > 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(fromId); + if (user != null) { + 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); + if (chat != null) { + 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)); @@ -163,24 +276,6 @@ public class SharingLiveLocationCell extends FrameLayout { combinedDrawable.setCustomSize(AndroidUtilities.dp(42), AndroidUtilities.dp(42)); combinedDrawable.setIconSize(AndroidUtilities.dp(24), AndroidUtilities.dp(24)); avatarImageView.setImageDrawable(combinedDrawable); - } else { - name = ""; - avatarDrawable = null; - if (fromId > 0) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(fromId); - if (user != null) { - avatarDrawable = new AvatarDrawable(user); - name = UserObject.getUserName(user); - avatarImageView.setForUserOrChat(user, avatarDrawable); - } - } else { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-fromId); - if (chat != null) { - avatarDrawable = new AvatarDrawable(chat); - name = chat.title; - avatarImageView.setForUserOrChat(chat, avatarDrawable); - } - } } 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 b3559708e..ea575db55 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.Layout; 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 abstract class TextSelectionHelper 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 abstract class TextSelectionHelper 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 @@ public abstract class TextSelectionHelper 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 2d716c02b..1e423d5b1 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 class ChatActivity extends BaseFragment implements NotificationCenter.Not } 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 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void createTopPanel() { - if (topChatPanelView != null || getContext() == null) { + if (contentView == null || topChatPanelView != null || getContext() == null) { return; } @@ -7395,6 +7395,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not 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 class ChatActivity extends BaseFragment implements NotificationCenter.Not 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 class ChatActivity extends BaseFragment implements NotificationCenter.Not 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 class ChatActivity extends BaseFragment implements NotificationCenter.Not } 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 class ChatActivity extends BaseFragment implements NotificationCenter.Not } 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 class ChatActivity extends BaseFragment implements NotificationCenter.Not 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 class ChatActivity extends BaseFragment implements NotificationCenter.Not } flagSecure.detach(); + + super.onBecomeFullyHidden(); } public void saveKeyboardPositionBeforeTransition() { @@ -23151,6 +23164,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } 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 class ChatActivity extends BaseFragment implements NotificationCenter.Not } 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 4293ce0ba..a460bbbe3 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 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente 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 40d422a4b..00a7f3f6b 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.DialogInterface; 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.Editable; 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.view.inputmethod.EditorInfo; 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.Components.voip.VoIPHelper; 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 2ee416349..85931eec6 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 class AnimatedFileDrawable extends BitmapDrawable implements Animatable, 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 class AnimatedFileDrawable extends BitmapDrawable implements Animatable, public void setIsWebmSticker(boolean b) { isWebmSticker = b; - PRERENDER_FRAME = false; if (isWebmSticker) { + PRERENDER_FRAME = false; useSharedQueue = true; } } @@ -723,6 +723,7 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, @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 0046ce03f..8051053d1 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 class AnimatedTextView extends View { 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 5de35c21b..c7fee6d38 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 b67a0533b..9c44539de 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 class Bulletin { } } + 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 @@ public class Bulletin { // 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 class Bulletin { 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 class Bulletin { 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 class Bulletin { 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 @@ public class Bulletin { ); } } + + 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 d4c274e8d..84d46bf3c 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 final class BulletinFactory { 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 final class BulletinFactory { 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 3726e8b5f..64d51ace7 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 @@ package org.telegram.ui.Components; 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 class ButtonBounce { 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 class ButtonBounce { 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 9e61dfa0a..f1fac0839 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 36730d03c..f48d7c996 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 class ChatActivityEnterView extends BlurredFrameLayout implements Notific } }; + 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 class ChatActivityEnterView extends BlurredFrameLayout implements Notific } 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 class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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 class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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 class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific emojiView.hideSearchKeyboard(); } } + if (allowConfirm && showConfirmAlert(() -> { + sendMessageInternal(notify, scheduleDate, false); + })) { + return; + } if (videoToSendMessageObject != null) { delegate.needStartRecordVideo(4, notify, scheduleDate); hideRecordedAudioPanel(true); @@ -5579,6 +5609,10 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } } + 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 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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 class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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 class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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 class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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 class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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 class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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 class ChatActivityEnterView extends BlurredFrameLayout implements Notific ); 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 class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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 class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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 class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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 class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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 class ChatActivityEnterView extends BlurredFrameLayout implements Notific } 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 (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, result.document); + accountInstance.getMessagesController().saveGif(parent, document); + } + } else if (gif instanceof TLRPC.BotInlineResult) { + TLRPC.BotInlineResult result = (TLRPC.BotInlineResult) gif; + + 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); + } + } + + TLRPC.User bot = (TLRPC.User) 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(); } } - - TLRPC.User bot = (TLRPC.User) 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 (delegate != null) { + delegate.onMessageSend(null, notify, scheduleDate); } - if (searchingType != 0) { - setSearchingTypeInternal(0, true); - emojiView.closeSearch(true); - emojiView.hideSearchKeyboard(); - } - } - if (delegate != null) { - delegate.onMessageSend(null, notify, scheduleDate); + }; + if (!showConfirmAlert(runnable)) { + runnable.run(); } } } @@ -8911,27 +8955,32 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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()) { - if (delegate != null) { - delegate.onUpdateSlowModeButton(slowModeButton, true, slowModeButton.getText()); + Runnable runnable = () -> { + if (slowModeTimer > 0 && !isInScheduleMode()) { + if (delegate != null) { + delegate.onUpdateSlowModeButton(slowModeButton, true, slowModeButton.getText()); + } + return; } - 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(""); + } + MediaDataController.getInstance(currentAccount).addRecentSticker(MediaDataController.TYPE_IMAGE, parent, sticker, (int) (System.currentTimeMillis() / 1000), false); + }; + if (!showConfirmAlert(runnable)) { + runnable.run(); } - 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(""); - } - MediaDataController.getInstance(currentAccount).addRecentSticker(MediaDataController.TYPE_IMAGE, parent, sticker, (int) (System.currentTimeMillis() / 1000), false); } } @@ -10330,7 +10379,7 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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 class ChatActivityEnterView extends BlurredFrameLayout implements Notific } 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 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific 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 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements Notific } 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 88a529c0d..cb60f4b81 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.AnimatorSet; 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.PhotoPickerActivity; 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 class ChatAttachAlert extends BottomSheet implements NotificationCenter.N 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 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N 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 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N 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 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } 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 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } } - 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 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } 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 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N 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 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @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 class ChatAttachAlert extends BottomSheet implements NotificationCenter.N 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 class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } 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 class ChatAttachAlert extends BottomSheet implements NotificationCenter.N actionBarAnimation = null; } }); + actionBarAnimation.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + actionBarAnimation.setDuration(380); actionBarAnimation.start(); } else { if (show) { @@ -3813,7 +3861,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N 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 class ChatAttachAlert extends BottomSheet implements NotificationCenter.N 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 class ChatAttachAlert extends BottomSheet implements NotificationCenter.N 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 b2c21220f..939cf1737 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.PorterDuffColorFilter; 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.ImageView; 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.Theme; 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.ShadowSectionCell; 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 class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa 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 class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa 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 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa } }; 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 class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa } }); 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 class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa } 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 class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa 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 class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa 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 class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa 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 class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa super.notifyDataSetChanged(); } }; + searchAdapter.setMyLocationDenied(locationDenied); searchAdapter.setDelegate(0, places -> { searchInProgress = false; updateEmptyView(); @@ -1109,6 +1140,9 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa } 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 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa } } }); + 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 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa 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 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa 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 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa 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 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa 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 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa 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 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa 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 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa 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 class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa } } 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 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa 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 class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa 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 607a3c349..c2cc7b17a 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.AnimatorListenerAdapter; 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 class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou } 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 class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou } } + 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 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou } } 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 class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou 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 34e95b01b..a8cb2bc9e 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 class ColoredImageSpan extends ReplacementSpan { 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 class ColoredImageSpan extends ReplacementSpan { @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 class ColoredImageSpan extends ReplacementSpan { 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 class ColoredImageSpan extends ReplacementSpan { 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 class ColoredImageSpan extends ReplacementSpan { 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 d723a4bea..4359b7e43 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 class CombinedDrawable extends Drawable implements Drawable.Callback { @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 ef2e96033..f4fcf4ff9 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.Build; 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 class EditTextBoldCursor extends EditTextEffects { 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 class EditTextBoldCursor extends EditTextEffects { 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 class EditTextBoldCursor extends EditTextEffects { public void setHintColor(int value) { hintColor = value; + if (hintAnimatedDrawable != null) { + hintAnimatedDrawable.setTextColor(hintColor); + } invalidate(); } @@ -470,6 +486,14 @@ public class EditTextBoldCursor extends EditTextEffects { 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 class EditTextBoldCursor extends EditTextEffects { 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 class EditTextBoldCursor extends EditTextEffects { } 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 class EditTextBoldCursor extends EditTextEffects { @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 @@ public class EditTextBoldCursor extends EditTextEffects { } invalidate(); } - int oldColor = getPaint().getColor(); + 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) { - 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 (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()); + 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 (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 class EditTextBoldCursor extends EditTextEffects { } 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 class EditTextBoldCursor extends EditTextEffects { 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 7ca022730..ce5650be1 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 class EmojiTabsStrip extends ScrollableHorizontalScrollView { } } 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 class EmojiTabsStrip extends ScrollableHorizontalScrollView { } 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 class EmojiTabsStrip extends ScrollableHorizontalScrollView { @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 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { @Override protected void onDraw(Canvas canvas) { - if (!wasVisible) { + if (!isVisible) { return; } super.onDraw(canvas); @@ -1118,17 +1119,17 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { } } - 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 class EmojiTabsStrip extends ScrollableHorizontalScrollView { 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 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { 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 34a1e8659..c857e405a 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 class FillLastLinearLayoutManager extends LinearLayoutManager { @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 class FillLastLinearLayoutManager extends LinearLayoutManager { 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 7d8b56903..9b92541ca 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 b1077983c..265d6172e 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 class GradientTools { 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 936e22e30..918dd5bcc 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 class ImageUpdater implements NotificationCenter.NotificationCenterDelega 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 fa4a45f46..30a02492b 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 class InstantCameraView extends FrameLayout implements NotificationCenter 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 class InstantCameraView extends FrameLayout implements NotificationCenter 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 class InstantCameraView extends FrameLayout implements NotificationCenter } } + @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 b5e22efca..29133a390 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 androidx.core.graphics.ColorUtils; 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.BaseFragment; 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 class ItemOptions { 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 @@ public class ItemOptions { 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 @@ public class ItemOptions { 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 class ItemOptions { 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 class ItemOptions { } 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 class ItemOptions { }); 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); - } - - lastLayout.addView(subItem, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); return this; } + public ItemOptions makeMultiline(boolean changeSize) { + if (context == null || lastLayout.getItemsCount() <= 0) { + return this; + } + + 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 class ItemOptions { 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 class ItemOptions { 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 class ItemOptions { getPointOnScreen(scrimView, container, point); y = point[1]; } + if (ignoreX) { + point[0] = 0; + } final Bitmap cachedBitmap; final Paint cachedBitmapPaint; @@ -449,6 +483,14 @@ public class ItemOptions { } 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 9b879abcd..24fb9ab07 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 class LoadingDrawable extends Drawable { @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 a218649aa..b20ea9121 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 428f59f09..6108e1791 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 @@ public class MediaActivity extends BaseFragment implements SharedMediaLayout.Sha @Override protected void showActionMode(boolean show) { + if (type == TYPE_MEDIA) { + super.showActionMode(show); + return; + } if (isActionModeShowed == show) { return; } @@ -707,13 +711,15 @@ public class MediaActivity extends BaseFragment implements SharedMediaLayout.Sha 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 class MediaActivity extends BaseFragment implements SharedMediaLayout.Sha @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 9ca164e80..c122cebc6 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.Canvas; 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.AndroidUtilities; 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 class MentionsContainerView extends BlurredFrameLayout implements Notific 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 class MentionsContainerView extends BlurredFrameLayout implements Notific 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 class MentionsContainerView extends BlurredFrameLayout implements Notific 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 @@ public class MentionsContainerView extends BlurredFrameLayout implements Notific 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 f733033ef..ac1f16f65 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 class MessageContainsEmojiButton extends FrameLayout implements Notificat } } - 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 @@ public class MessageContainsEmojiButton extends FrameLayout implements Notificat 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 class MessageContainsEmojiButton extends FrameLayout implements Notificat 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 c80d44ad5..80922d0be 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 384255308..c42127e7c 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 android.text.TextPaint; 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 @@ public class EditTextOutline extends EditTextBoldCursor { 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 @@ public class EditTextOutline extends EditTextBoldCursor { 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 ba87a238b..0b6d45679 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 class EntitiesContainerView extends FrameLayout implements ScaleGestureDe 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 class EntitiesContainerView extends FrameLayout implements ScaleGestureDe } } - 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 dc0a6f2ee..e5f6d1734 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.content.Context; 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_THRESHOLD_DP = 16; - private final static float STICKY_TRIGGER_DP = 6; + private final static float STICKY_TRIGGER_DP = 12; + + 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 class EntityView extends FrameLayout { 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 @@ public class EntityView extends FrameLayout { 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 @@ public class EntityView extends FrameLayout { 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 class EntityView extends FrameLayout { 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 class EntityView extends FrameLayout { 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 @@ public class EntityView extends FrameLayout { 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 @@ public class EntityView extends FrameLayout { delegate.onEntityDragEnd(announcedTrash); announcedDrag = false; } + announcedMultitouchDrag = false; if (!recognizedLongPress && !hasPanned && !hasTransformed && !announcedSelection && delegate != null) { delegate.onEntitySelected(this); } @@ -196,12 +241,22 @@ public class EntityView extends FrameLayout { 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 class EntityView extends FrameLayout { 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 @@ public class EntityView extends FrameLayout { public void onAnimationEnd(Animator animation) { if (animation == stickyXAnimator) { stickyXAnimator = null; - - hasFromStickyXAnimation = false; } } }); @@ -294,6 +413,9 @@ public class EntityView extends FrameLayout { } 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 @@ public class EntityView extends FrameLayout { public void onAnimationEnd(Animator animation) { if (animation == stickyYAnimator) { stickyYAnimator = null; - - hasFromStickyYAnimation = false; } } }); stickyYAnimator.start(); } + 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); + } + } + + private void updateStickyY() { + AndroidUtilities.cancelRunOnUIThread(setStickyYRunnable); + if (stickyY == stickyYRunnableValue) { + return; + } + stickyY = stickyYRunnableValue; + if (getParent() instanceof EntitiesContainerView) { + ((EntitiesContainerView) getParent()).invalidate(); + } + 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; - if (hasFromStickyXAnimation) { - fromStickyX = position.x; - } - if (hasFromStickyYAnimation) { - fromStickyY = position.y; - } - 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 class EntityView extends FrameLayout { 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 @@ public class EntityView extends FrameLayout { 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 @@ public class EntityView extends FrameLayout { 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 class EntityView extends FrameLayout { private void rotateInternal(float angle) { setRotation(angle); + if (stickyX != STICKY_NONE || stickyY != STICKY_NONE) { + updatePosition(); + } updateSelectionView(); } @@ -550,6 +735,7 @@ public class EntityView extends FrameLayout { return; } selectionView = createSelectionView(); + selectionView.hide(lastIsMultitouch); selectionContainer.addView(selectionView); selectT = 0; } @@ -579,12 +765,13 @@ public class EntityView extends FrameLayout { } } + 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 class EntityView extends FrameLayout { 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 class EntityView extends FrameLayout { 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 class EntityView extends FrameLayout { 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 class EntityView extends FrameLayout { } 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 @@ public class EntityView extends FrameLayout { 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 a4af78ac1..e81339f09 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 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh 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 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh 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 @@ public class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh }; 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 class LPhotoPaintView extends SizeNotifierFrameLayoutPhoto implements IPh 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 000000000..72986f3c7 --- /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 000000000..1ba9b4e53 --- /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 255cee5ab..f096b18d4 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 android.widget.FrameLayout; 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 @@ public class PhotoView extends EntityView { } } + private TLObject object; private String path; private int anchor = -1; private boolean mirrored = false; @@ -71,6 +74,33 @@ public class PhotoView extends EntityView { 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 @@ public class PhotoView extends EntityView { 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 @@ public class PhotoView extends EntityView { 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 @@ public class PhotoView extends EntityView { 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 cfd89f716..5b24da7d9 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 @@ public class StickerView extends EntityView { 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 @@ public class StickerView extends EntityView { 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 b708b6615..b3ea8ed9d 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.Path; 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.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.ui.ActionBar.Theme; import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.LayoutHelper; @@ -142,6 +136,26 @@ public class TextPaintView extends EntityView { }); } + @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 @@ public class TextPaintView extends EntityView { 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 @@ public class TextPaintView extends EntityView { 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 e9b833dee..1615d3bb7 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 class PhotoPaintView extends FrameLayout implements IPhotoPaintView, Enti } @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 000000000..408a0e8cf --- /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 a645375e8..0e216d8a5 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 @@ public class DoubleLimitsPageView extends FrameLayout implements PagerHeaderView 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 49a0447e7..a3ad0a45e 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 class DoubledLimitsBottomSheet extends BottomSheetWithRecyclerListView im } 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 class DoubledLimitsBottomSheet extends BottomSheetWithRecyclerListView im 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 @@ public class DoubledLimitsBottomSheet extends BottomSheetWithRecyclerListView im 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 @@ public class DoubledLimitsBottomSheet extends BottomSheetWithRecyclerListView im @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 @@ public class DoubledLimitsBottomSheet extends BottomSheetWithRecyclerListView im 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 class DoubledLimitsBottomSheet extends BottomSheetWithRecyclerListView im 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 @@ public class DoubledLimitsBottomSheet extends BottomSheetWithRecyclerListView im public static class Adapter extends RecyclerListView.SelectionAdapter { + private final Theme.ResourcesProvider resourcesProvider; + int rowCount; int headerRow; int limitsStartRow; @@ -261,9 +263,11 @@ public class DoubledLimitsBottomSheet extends BottomSheetWithRecyclerListView im 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 class DoubledLimitsBottomSheet extends BottomSheetWithRecyclerListView im 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 @@ public class DoubledLimitsBottomSheet extends BottomSheetWithRecyclerListView im 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 class DoubledLimitsBottomSheet extends BottomSheetWithRecyclerListView im 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 07620e16e..3d78fc3b1 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 class LimitPreviewView extends LinearLayout { 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 @@ public class LimitPreviewView extends LinearLayout { } 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); } + + @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); + } + } + + @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.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)); - } - } - - 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)); - } - } - - 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 @@ public class LimitPreviewView extends LinearLayout { 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 @@ public class LimitPreviewView extends LinearLayout { 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 class LimitPreviewView extends LinearLayout { 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 @@ public class LimitPreviewView extends LinearLayout { 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 @@ public class LimitPreviewView extends LinearLayout { } } 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 @@ public class LimitPreviewView extends LinearLayout { 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 1f03b36ff..2a080128f 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.LayoutHelper; 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { } } }; - 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { } 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { }, 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { } } - 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 class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { } 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 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { 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 9b8a2c30a..100f97be3 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.ArrayList; 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 class PremiumAppIconsPreviewView extends FrameLayout implements PagerHead } 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 9358c9a92..b40fb5905 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 @@ public class PremiumButtonView extends FrameLayout { 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 be6e31978..e2957c303 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.animation.ValueAnimator; 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 class PremiumFeatureBottomSheet extends BottomSheet implements Notificati } 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 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati 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 class PremiumFeatureBottomSheet extends BottomSheet implements Notificati } }; 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 class PremiumFeatureBottomSheet extends BottomSheet implements Notificati @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 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati } 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 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati } } + 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 class PremiumFeatureBottomSheet extends BottomSheet implements Notificati 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 class PremiumFeatureBottomSheet extends BottomSheet implements Notificati 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 class PremiumFeatureBottomSheet extends BottomSheet implements Notificati } } }); - 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 class PremiumFeatureBottomSheet extends BottomSheet implements Notificati 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 class PremiumFeatureBottomSheet extends BottomSheet implements Notificati 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 class PremiumFeatureBottomSheet extends BottomSheet implements Notificati @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 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati @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 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati } 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 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati 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 class PremiumFeatureBottomSheet extends BottomSheet implements Notificati }; 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 class PremiumFeatureBottomSheet extends BottomSheet implements Notificati } 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))); } - closeLayout.setAlpha(1f - progressToFullscreenView); + if (toViewOffset >= 0) { + float progressLocal = progress; + localOffset = Math.min(localOffset, (int) (toViewOffset * progressLocal + topGlobalOffset * (1f - progressLocal))); + } + 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 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati } 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 77a305ed4..280572241 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 class PremiumGradient { //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 class PremiumGradient { } 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 class PremiumGradient { } 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 c00068da4..80e4d070d 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 class StarParticlesView extends View { 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 class StarParticlesView extends View { } public void updateColors() { - int c = Theme.getColor(colorKey); + int c = Theme.getColor(colorKey, resourcesProvider); if (lastColor != c) { lastColor = c; generateBitmaps(); @@ -203,7 +204,7 @@ public class StarParticlesView extends View { } 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 @@ public class StarParticlesView extends View { } 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 @@ public class StarParticlesView extends View { } 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 @@ public class StarParticlesView extends View { } 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 @@ public class StarParticlesView extends View { 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 @@ public class StarParticlesView extends View { 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 000000000..d728c621c --- /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 9f0ffc17c..a514de455 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 @@ public class VideoScreenPreview extends FrameLayout implements PagerHeaderView, 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 class VideoScreenPreview extends FrameLayout implements PagerHeaderView, } 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 class VideoScreenPreview extends FrameLayout implements PagerHeaderView, 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 b488aec41..6b553b78a 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 8378ae451..8437bcbba 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 class AnimatedEmojiEffect { 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 class AnimatedEmojiEffect { 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 e52e253b2..f17ccc7f5 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.Gravity; 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 android.widget.FrameLayout; 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 @@ public class CustomEmojiReactionsWindow { 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 class CustomEmojiReactionsWindow { 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 class CustomEmojiReactionsWindow { 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 @@ public class CustomEmojiReactionsWindow { } 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 @@ public class CustomEmojiReactionsWindow { 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 class CustomEmojiReactionsWindow { 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 class CustomEmojiReactionsWindow { 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 class CustomEmojiReactionsWindow { @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 @@ public class CustomEmojiReactionsWindow { 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 @@ public class CustomEmojiReactionsWindow { 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 6345b698a..406dfebd1 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.RectF; 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 class ReactionsContainerLayout extends FrameLayout implements Notificatio 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 class ReactionsContainerLayout extends FrameLayout implements Notificatio 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 class ReactionsContainerLayout extends FrameLayout implements Notificatio 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 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio 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 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio 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 class ReactionsContainerLayout extends FrameLayout implements Notificatio } } + 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 class ReactionsContainerLayout extends FrameLayout implements Notificatio } public void reset() { + isHiddenNextReaction = true; pressedReactionPosition = 0; pressedProgress = 0; + pullingLeftOffset = 0; pressedReaction = null; clicked = false; AndroidUtilities.forEachViews(recyclerListView, view -> { @@ -1284,12 +1301,20 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio 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 class ReactionsContainerLayout extends FrameLayout implements Notificatio @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 class ReactionsContainerLayout extends FrameLayout implements Notificatio 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 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio 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 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio } 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 class ReactionsContainerLayout extends FrameLayout implements Notificatio 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 class ReactionsContainerLayout extends FrameLayout implements Notificatio @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 3601c8510..f6199deca 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 @@ public class ReplaceableIconDrawable extends Drawable implements Animator.Animat } 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 91ab540a9..ce9ecf2d9 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 class SearchField extends FrameLayout { 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 class SearchField extends FrameLayout { 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 @@ public class SearchField extends FrameLayout { 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 class SearchField extends FrameLayout { 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 b6f0d6e23..a3a4259ca 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.GridLayoutManager; 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 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter 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 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } } 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 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } 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 49b113f0a..e4a3553d9 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 class StickerEmptyView extends FrameLayout implements NotificationCenter. 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 class StickerEmptyView extends FrameLayout implements NotificationCenter. } } + 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 class StickerEmptyView extends FrameLayout implements NotificationCenter. 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 5f3537057..1099aa2c9 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 class TextViewSwitcher extends ViewSwitcher { } 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 56bf41362..24cdb5ced 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 @@ import java.util.ArrayList; 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 4d4881a84..835bfb47c 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 class WallpaperUpdater { 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 9d9919bf4..0cc802b04 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 @@ import java.util.List; 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 class SpoilersClickDetector { 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 class SpoilersClickDetector { 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 class SpoilersClickDetector { 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 db22d390c..2a8dce968 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 @@ public class ContentPreviewViewer { 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 @@ public class ContentPreviewViewer { ActionBarPopupWindow popupWindow; private ActionBarPopupWindow visibleMenu; private ContentPreviewViewerDelegate delegate; + private boolean isPhotoEditor; private boolean isRecentSticker; @@ -193,7 +198,7 @@ public class ContentPreviewViewer { private Runnable showSheetRunnable = new Runnable() { @Override public void run() { - if (parentActivity == null) { + if (parentActivity == null || isPhotoEditor) { return; } closeOnDismiss = true; @@ -704,6 +709,9 @@ public class ContentPreviewViewer { 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 class ContentPreviewViewer { } 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 class ContentPreviewViewer { } 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 @@ public class ContentPreviewViewer { 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 class ContentPreviewViewer { 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 class ContentPreviewViewer { public void setDelegate(ContentPreviewViewerDelegate contentPreviewViewerDelegate) { delegate = contentPreviewViewerDelegate; + if (delegate != null) { + isPhotoEditor = delegate.isPhotoEditor(); + } } public void setParentActivity(Activity activity) { @@ -1431,7 +1445,7 @@ public class ContentPreviewViewer { 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 63ca8d76c..53669f0bb 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.Components.ViewPagerFixed; 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 class DialogsActivity extends BaseFragment implements NotificationCenter. 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 class DialogsActivity extends BaseFragment implements NotificationCenter. private FragmentContextView fragmentLocationContextView; private FragmentContextView fragmentContextView; private DialogsHintCell dialogsHintCell; + private boolean dialogsHintCellVisible; private Long cacheSize, deviceSize; private ArrayList frozenDialogsList; @@ -1541,11 +1543,11 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. 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 class DialogsActivity extends BaseFragment implements NotificationCenter. 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 class DialogsActivity extends BaseFragment implements NotificationCenter. 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 class DialogsActivity extends BaseFragment implements NotificationCenter. } 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 class DialogsActivity extends BaseFragment implements NotificationCenter. 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 class DialogsActivity extends BaseFragment implements NotificationCenter. 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 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. }; 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 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. 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 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. }; 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 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. return; } if (isPremiumRestoreHintVisible()) { + dialogsHintCellVisible = true; dialogsHintCell.setVisibility(View.VISIBLE); dialogsHintCell.setOnClickListener(v -> { presentFragment(new PremiumPreviewFragment("dialogs_hint").setSelectAnnualByDefault()); @@ -5472,8 +5461,12 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. 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 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. 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 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. LocaleController.getString(R.string.ClearStorageHintMessage) ); } else { + dialogsHintCellVisible = false; dialogsHintCell.setVisibility(View.GONE); } } @@ -6427,11 +6422,21 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. 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 class DialogsActivity extends BaseFragment implements NotificationCenter. 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 class DialogsActivity extends BaseFragment implements NotificationCenter. if (undoView[0] != null) { undoView[0].hide(true, 0); } + super.onBecomeFullyHidden(); } @Override @@ -7144,6 +7150,13 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } 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 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. 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 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } if (actionBarColorAnimator != null) { actionBarColorAnimator.cancel(); + actionBarColorAnimator = null; + } + if (progressToActionMode == 0) { + return; } float translateListHeight = 0; if (hasStories) { @@ -9556,6 +9570,17 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. 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 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. 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 class DialogsActivity extends BaseFragment implements NotificationCenter. 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 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. if (storyHint != null) { storyHint.hide(); } - if (manyStoriesHint != null) { - manyStoriesHint.hide(); - } } } @@ -11498,6 +11532,13 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. 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 e7ac9b0d8..f67c7331f 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.PorterDuff; 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 @@ public class DownloadProgressIcon extends View implements NotificationCenter.Not } } canvas.restore(); + if (getAlpha() != 0) { + wasDrawn = true; + } } @Override @@ -160,13 +168,15 @@ public class DownloadProgressIcon extends View implements NotificationCenter.Not 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 class DownloadProgressIcon extends View implements NotificationCenter.Not } } + @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 88e4c3f9f..560082161 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 class FilterCreateActivity extends BaseFragment { float width, height; private boolean outline; + private int color; public NewSpan(boolean outline) { this.outline = outline; @@ -1994,6 +1995,10 @@ public class FilterCreateActivity extends BaseFragment { } } + 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 class FilterCreateActivity extends BaseFragment { 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 01cd22e16..507282c53 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.LinearLayoutManager; 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 class LaunchActivity extends BasePermissionsActivity implements INavigati } } 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 class LaunchActivity extends BasePermissionsActivity implements INavigati @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 class LaunchActivity extends BasePermissionsActivity implements INavigati } } 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 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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 { + finalDialogIds = dialogIds; + } + if (requestWhenNeeded) { + for (int i = 0; i < finalDialogIds.length; ++i) { + toLoadPeerIds.add(finalDialogIds[i]); } } else { - for (int i = 0; i < dialogIds.length; ++i) { - peerIds.add(dialogIds[i]); + for (int i = 0; i < finalDialogIds.length; ++i) { + peerIds.add(finalDialogIds[i]); } } if (!toLoadPeerIds.isEmpty() && requestWhenNeeded) { @@ -7522,7 +7535,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati 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 a613d6b22..c629419dc 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.LinearLayout; 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 class LocationActivity extends BaseFragment implements NotificationCenter 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 class LocationActivity extends BaseFragment implements NotificationCenter 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 class LocationActivity extends BaseFragment implements NotificationCenter 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 class LocationActivity extends BaseFragment implements NotificationCenter AndroidUtilities.fixGoogleMapsBug(); } + private boolean initialMaxZoom; + public void setInitialMaxZoom(boolean initialMaxZoom) { + this.initialMaxZoom = initialMaxZoom; + } + @Override public boolean onFragmentCreate() { super.onFragmentCreate(); @@ -494,6 +500,11 @@ public class LocationActivity extends BaseFragment implements NotificationCenter 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 class LocationActivity extends BaseFragment implements NotificationCenter } 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 class LocationActivity extends BaseFragment implements NotificationCenter } 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 class LocationActivity extends BaseFragment implements NotificationCenter } 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 class LocationActivity extends BaseFragment implements NotificationCenter 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 class LocationActivity extends BaseFragment implements NotificationCenter 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 @@ public class LocationActivity extends BaseFragment implements NotificationCenter } }; 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 @@ public class LocationActivity extends BaseFragment implements NotificationCenter } } }; - 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 class LocationActivity extends BaseFragment implements NotificationCenter }); } 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 class LocationActivity extends BaseFragment implements NotificationCenter }); } - 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 class LocationActivity extends BaseFragment implements NotificationCenter }); 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 class LocationActivity extends BaseFragment implements NotificationCenter 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 class LocationActivity extends BaseFragment implements NotificationCenter } } 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 class LocationActivity extends BaseFragment implements NotificationCenter }); 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 class LocationActivity extends BaseFragment implements NotificationCenter } }); } - 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 class LocationActivity extends BaseFragment implements NotificationCenter 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 class LocationActivity extends BaseFragment implements NotificationCenter 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 class LocationActivity extends BaseFragment implements NotificationCenter 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 class LocationActivity extends BaseFragment implements NotificationCenter 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 class LocationActivity extends BaseFragment implements NotificationCenter } 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 class LocationActivity extends BaseFragment implements NotificationCenter 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 class LocationActivity extends BaseFragment implements NotificationCenter 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 @@ public class LocationActivity extends BaseFragment implements NotificationCenter 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 @@ public class LocationActivity extends BaseFragment implements NotificationCenter 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 @@ public class LocationActivity extends BaseFragment implements NotificationCenter } 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 @@ public class LocationActivity extends BaseFragment implements NotificationCenter 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 @@ public class LocationActivity extends BaseFragment implements NotificationCenter } 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 @@ public class LocationActivity extends BaseFragment implements NotificationCenter 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 @@ public class LocationActivity extends BaseFragment implements NotificationCenter } 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 @@ public class LocationActivity extends BaseFragment implements NotificationCenter 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 @@ public class LocationActivity extends BaseFragment implements NotificationCenter 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 @@ public class LocationActivity extends BaseFragment implements NotificationCenter 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 class LocationActivity extends BaseFragment implements NotificationCenter } 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 class LocationActivity extends BaseFragment implements NotificationCenter } 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 class LocationActivity extends BaseFragment implements NotificationCenter } } - @Override - public boolean hasForceLightStatusBar() { - return true; - } - @Override public void onLowMemory() { super.onLowMemory(); @@ -2729,19 +2756,20 @@ public class LocationActivity extends BaseFragment implements NotificationCenter 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 class LocationActivity extends BaseFragment implements NotificationCenter 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 086379171..ea97ad406 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 class LoginActivity extends BaseFragment implements NotificationCenter.No .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 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No 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 @@ public class LoginActivity extends BaseFragment implements NotificationCenter.No 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 000000000..02a06dfbc --- /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 1a8a5a4cd..9e8affb56 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 class PaymentFormActivity extends BaseFragment implements NotificationCen } 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 15d072785..1bd4b12df 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 class PeopleNearbyActivity extends BaseFragment implements NotificationCe } @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 b3287f2f5..b5db12750 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.ColorFilter; 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.TextPaint; 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.TransitionManager; 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.LiteMode; 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.R; 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.ImageUpdater; 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.SpeedIconDrawable; 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.VideoSeekPreviewImage; 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 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @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 class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @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 class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } captionTextViewSwitcher = new CaptionTextViewSwitcher(containerView.getContext()); - captionTextViewSwitcher.setFactory(() -> createCaptionTextView()); + captionTextViewSwitcher.setFactory(() -> new CaptionTextView(activityContext)); captionTextViewSwitcher.setVisibility(View.INVISIBLE); setCaptionHwLayerEnabled(true); @@ -6026,7 +6065,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 class PhotoViewer implements NotificationCenter.NotificationCenterDelegat }).start(); } - private TextView createCaptionTextView() { - SpoilersTextView textView = new SpoilersTextView(activityContext) { - - private LinkSpanDrawable pressedLink; - private LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(this); - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (getLayout() == null) { - return false; + 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; } - 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); + openCaptionEnter(); + }); + } - 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); + private LinkSpanDrawable pressedLink; + private LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(this); - 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()); - } + @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()); } } - if (event.getAction() == MotionEvent.ACTION_UP) { - links.clear(); - if (pressedLink != null && pressedLink.getSpan() == touchLink) { - onLinkClick(pressedLink.getSpan(), this); - } - 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; - canvas.save(); - canvas.translate(getPaddingLeft(), 0); - if (links.draw(canvas)) { - invalidate(); - } - 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); - } - - @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()); - } - - private final ColorFilter emojiTextColorFilter = new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN); - - @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); + @Override + protected void onDraw(Canvas canvas) { + if (textSelectionHelper != null && textSelectionHelper.isInSelectionMode()) { 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); + if (textSelectionHelper != null && getStaticTextLayout() != null && textSelectionHelper.isCurrent(this)) { + textSelectionHelper.draw(canvas); + } 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)); + canvas.save(); + canvas.translate(getPaddingLeft(), 0); + if (links.draw(canvas)) { + invalidate(); + } + 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); + } + + @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(); + } + + 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 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat boolean isVideo = false; CharSequence caption = null; + boolean captionTranslating = false; String newFileName = getFileName(index); MessageObject newMessageObject = null; @@ -12147,7 +12263,47 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } 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 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } - 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 class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } + 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 class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } 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 class PhotoViewer implements NotificationCenter.NotificationCenterDelegat 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 54668ef93..4b93584b8 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.ImageView; 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 class PremiumFeatureCell extends FrameLayout { 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 7d3ffcc62..e86f2eb71 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.graphics.drawable.Drawable; 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.PremiumGradient; 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 class PremiumPreviewFragment extends BaseFragment implements Notification 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 class PremiumPreviewFragment extends BaseFragment implements Notification 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 class PremiumPreviewFragment extends BaseFragment implements Notification 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 class PremiumPreviewFragment extends BaseFragment implements Notification }); } + 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 class PremiumPreviewFragment extends BaseFragment implements Notification 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 class PremiumPreviewFragment extends BaseFragment implements Notification 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 class PremiumPreviewFragment extends BaseFragment implements Notification 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 class PremiumPreviewFragment extends BaseFragment implements Notification 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 class PremiumPreviewFragment extends BaseFragment implements Notification 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 6b1bfacb4..7aa159917 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 class ProfileActivity extends BaseFragment implements NotificationCenter. 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 class ProfileActivity extends BaseFragment implements NotificationCenter. 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 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } 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 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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 class ProfileActivity extends BaseFragment implements NotificationCenter. 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 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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 class ProfileActivity extends BaseFragment implements NotificationCenter. if (undoView != null) { undoView.hide(true, 0); } + super.onBecomeFullyHidden(); } public void setPlayProfileAnimation(int type) { @@ -7218,7 +7229,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. 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 cad97efbf..0546d80ad 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 @@ package org.telegram.ui; 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 class RecyclerListViewScroller { } 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 class RecyclerListViewScroller { 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 32e7c5c85..25df3ba9d 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 class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } 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 class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } 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 823c631a8..1c8b6a302 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 class StickersActivity extends BaseFragment implements NotificationCenter @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 @@ public class StickersActivity extends BaseFragment implements NotificationCenter } }; itemAnimator.setMoveDuration(350); + itemAnimator.setSupportsChangeAnimations(false); itemAnimator.setMoveInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); listView.setItemAnimator(itemAnimator); layoutManager = new LinearLayoutManager(context) { @@ -346,8 +347,6 @@ public class StickersActivity extends BaseFragment implements NotificationCenter 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 class StickersActivity extends BaseFragment implements NotificationCenter 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 593170db3..8feb636ad 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 class DarkThemeResourceProvider implements Theme.ResourcesProvider { 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 class DarkThemeResourceProvider implements Theme.ResourcesProvider { 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 class DarkThemeResourceProvider implements Theme.ResourcesProvider { 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 class DarkThemeResourceProvider implements Theme.ResourcesProvider { 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 b98156487..e272d3c67 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.animation.ValueAnimator; 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.TextUtils; 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.DefaultItemAnimator; 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.ImageReceiver; 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.ActionBar.Theme; 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 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter } 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter }); 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter } 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 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter } } 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 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter } public void updateColors() { + StoriesUtilities.updateColors(); int color = getTextColor(); titleView.setTextColor(color); @@ -745,7 +820,6 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter StoryCell cell = (StoryCell) view; cell.invalidate(); }); - } private int getTextColor() { @@ -801,6 +875,12 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter } 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 DialogStoriesCell extends FrameLayout implements NotificationCenter public int position; public boolean isLast; public boolean isFirst; + public StoriesUtilities.EnsureStoryFileLoadedObject cancellable; TLRPC.User user; TLRPC.Chat chat; @@ -1037,18 +1116,27 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 class DialogStoriesCell extends FrameLayout implements NotificationCenter @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 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter if (System.currentTimeMillis() < checkedStoryNotificationDeletion) { return; } - NotificationsController.getInstance(currentAccount).processIgnoreStories(); +// NotificationsController.getInstance(currentAccount).processIgnoreStories(); checkedStoryNotificationDeletion = System.currentTimeMillis() + 1000L * 60; } @@ -1616,7 +1712,7 @@ public class DialogStoriesCell extends FrameLayout implements NotificationCenter .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 class DialogStoriesCell extends FrameLayout implements NotificationCenter 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 c4ac21db8..609e5d462 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.content.Intent; 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.graphics.ColorUtils; 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.BulletinFactory; 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.LayoutHelper; 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.ScaleStateListAnimator; 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.Components.voip.CellFlickerDrawable; 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica // 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica }); } - 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica }); 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } - 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } }); } - 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica }); } + 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica if (attachedToWindow) { chatActivityEnterView.onResume(); } + checkStealthMode(false); reactionsContainerIndex = getChildCount(); } @@ -1641,10 +1951,42 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica }); } - 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } - private void bindInternal() { + private void bindInternal(int startFromPosition) { deletedPeer = false; forceUpdateOffsets = true; if (dialogId >= 0) { @@ -1987,7 +2329,10 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica @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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } else if (!animateSubtitle) { headerView.progressToUploading = 0; } - Bulletin.hideVisible(); + Bulletin.hideVisible(storyContainer); storyCaptionView.reset(); cancelWaiting(); } @@ -2584,22 +3022,16 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } - 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica // 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica if (reactionsContainerLayout != null) { reactionsContainerLayout.reset(); } + if (likesReactionLayout != null) { + likesReactionLayout.reset(); + } if (instantCameraView != null) { AndroidUtilities.removeFromParent(instantCameraView); instantCameraView.hideCamera(true); @@ -3299,9 +3795,17 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } - 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica isVisible = visible; if (visible) { imageReceiver.setCurrentAlpha(1f); + checkStealthMode(false); } } @@ -3414,6 +3919,31 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } + 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica void setPopupIsVisible(boolean b); + void setTranslating(boolean b); + void setBulletinIsVisible(boolean b); void setIsInPinchToZoom(boolean b); @@ -3640,6 +4172,8 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica void setIsSwiping(boolean swiping); void setIsInSelectionMode(boolean selectionMode); + + void setIsLikesReaction(boolean show); } public class StoryItemHolder { @@ -3649,6 +4183,54 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica return; } - if (reactionsContainerLayout != null) { reactionsContainerLayout.setVisibility(progressToKeyboard > 0 ? View.VISIBLE : View.GONE); } @@ -4092,7 +4685,7 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica } 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 @@ public class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 class PeerStoriesView extends SizeNotifierFrameLayout implements Notifica 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 9d6a54c7a..e8e3e2543 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.AnimatorListenerAdapter; 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.view.animation.OvershootInterpolator; 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 abstract class SelfStoriesPreviewView extends View { return false; } }); + private float textWidth; public void onCenteredImageTap() { @@ -111,6 +128,7 @@ public abstract class SelfStoriesPreviewView extends View { 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 @@ public abstract class SelfStoriesPreviewView extends View { 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 @@ public abstract class SelfStoriesPreviewView extends View { 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 @@ public abstract class SelfStoriesPreviewView extends View { } boolean checkScroll; + @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); @@ -142,8 +168,8 @@ public abstract class SelfStoriesPreviewView extends View { // 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 @@ public abstract class SelfStoriesPreviewView extends View { } 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 @@ public abstract class SelfStoriesPreviewView extends View { } ValueAnimator scrollAnimator; + public void scrollToPosition(int p, boolean animated, boolean force) { if ((lastClosestPosition == p && !force) || getMeasuredHeight() <= 0) { return; @@ -306,10 +345,10 @@ public abstract class SelfStoriesPreviewView extends View { return lastClosestPosition; } - public ImageReceiver getCenteredImageReciever() { + public ImageHolder getCenteredImageReciever() { for (int i = 0; i < lastDrawnImageReceivers.size(); i++) { if (lastDrawnImageReceivers.get(i).position == lastClosestPosition) { - return lastDrawnImageReceivers.get(i).receiver; + return lastDrawnImageReceivers.get(i); } } return null; @@ -363,13 +402,17 @@ public abstract class SelfStoriesPreviewView extends View { invalidate(); } - private class ImageHolder { + public class ImageHolder { ImageReceiver receiver = new ImageReceiver(SelfStoriesPreviewView.this); int position; + StaticLayout layout; + TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG); public ImageHolder() { receiver.setAllowLoadingOnAttachedOnly(true); receiver.setRoundRadius(AndroidUtilities.dp(6)); + paint.setColor(Color.WHITE); + paint.setTextSize(AndroidUtilities.dp(13)); } void onBind(int position) { @@ -382,12 +425,63 @@ public abstract class SelfStoriesPreviewView extends View { } else { StoriesUtilities.setImage(receiver, storyItem.uploadingStory); } - + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); + if (storyItem.storyItem != null) { + formatCounterText(spannableStringBuilder, storyItem.storyItem.views, false); + } + if (spannableStringBuilder.length() == 0) { + layout = null; + } else { + layout = StaticLayoutEx.createStaticLayout(spannableStringBuilder, paint, (int) (textWidth + 1), Layout.Alignment.ALIGN_CENTER, 1.0f, 0f, false, null, Integer.MAX_VALUE, 1); + if (layout.getLineCount() > 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 a5d8290d5..f060affe9 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; - public SelfStoryViewsPage(StoryViewer storyViewer, @NonNull Context context) { + 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, 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 class SelfStoryViewsPage extends FrameLayout implements NotificationCente 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)); - addView(titleView); + 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) { + + } + + @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 @@ public class SelfStoryViewsPage extends FrameLayout implements NotificationCente } 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); - int totalCount = serverItem.views == null ? 0 : serverItem.views.views_count; - if (model == null || model.totalCount != totalCount) { - if (model != null) { - model.release(); - } - model = new ViewsModel(currentAccount, serverItem); - model.loadNext(); - MessagesController.getInstance(currentAccount).storiesController.selfViewsModel.put(serverItem.id, model); + 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; } - if (serverItem.views == null || serverItem.views.views_count == 0) { - titleView.setText(LocaleController.getString("NobodyViewsTitle", R.string.NobodyViewsTitle)); + defaultModel = MessagesController.getInstance(currentAccount).storiesController.selfViewsModel.get(serverItem.id); + int totalCount = serverItem.views == null ? 0 : serverItem.views.views_count; + if (defaultModel == null || defaultModel.totalCount != totalCount) { + if (defaultModel != null) { + defaultModel.release(); + } + defaultModel = new ViewsModel(currentAccount, serverItem, true); + defaultModel.reloadIfNeed(state, showContactsFilter, showReactionsSort); + defaultModel.loadNext(); + MessagesController.getInstance(currentAccount).storiesController.selfViewsModel.put(serverItem.id, defaultModel); } else { - titleView.setText(LocaleController.formatPluralStringComma("Views", serverItem.views.views_count)); + defaultModel.reloadIfNeed(state, showContactsFilter, showReactionsSort); + } + if (currentModel != null) { + currentModel.removeListener(this); + } + currentModel = defaultModel; + if (currentModel != null && isAttachedToWindow) { + currentModel.addListener(this); + } + 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 { + 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 class SelfStoryViewsPage extends FrameLayout implements NotificationCente 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 class SelfStoryViewsPage extends FrameLayout implements NotificationCente @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 class SelfStoryViewsPage extends FrameLayout implements NotificationCente } } } + } 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 class SelfStoryViewsPage extends FrameLayout implements NotificationCente 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 class SelfStoryViewsPage extends FrameLayout implements NotificationCente 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 class SelfStoryViewsPage extends FrameLayout implements NotificationCente 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 class SelfStoryViewsPage extends FrameLayout implements NotificationCente } } + 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 class SelfStoryViewsPage extends FrameLayout implements NotificationCente 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 class SelfStoryViewsPage extends FrameLayout implements NotificationCente } 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 class SelfStoryViewsPage extends FrameLayout implements NotificationCente 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 class SelfStoryViewsPage extends FrameLayout implements NotificationCente } 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 class SelfStoryViewsPage extends FrameLayout implements NotificationCente } 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 e2d250eee..2f5f5e1f4 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 androidx.viewpager.widget.ViewPager; 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 class SelfStoryViewsView extends FrameLayout { 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 class SelfStoryViewsView extends FrameLayout { 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 class SelfStoryViewsView extends FrameLayout { } }); viewPager.setAdapter(pagerAdapter = new PagerAdapter() { + @Override public int getCount() { return storyItems.size(); @@ -125,14 +177,25 @@ public class SelfStoryViewsView extends FrameLayout { @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 @@ public class SelfStoryViewsView extends FrameLayout { container.addView(item); - itemViews.add(item); return item; } @@ -185,6 +247,37 @@ public class SelfStoryViewsView extends FrameLayout { 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 @@ public class SelfStoryViewsView extends FrameLayout { 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 @@ public class SelfStoryViewsView extends FrameLayout { 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 class SelfStoryViewsView extends FrameLayout { } } + 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 class SelfStoryViewsView extends FrameLayout { 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 class SelfStoryViewsView extends FrameLayout { @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 class SelfStoryViewsView extends FrameLayout { @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 class SelfStoryViewsView extends FrameLayout { @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 class SelfStoryViewsView extends FrameLayout { if (ev.getAction() == MotionEvent.ACTION_DOWN) { gesturesEnabled = true; } - if (!gesturesEnabled) { + if (!gesturesEnabled || keyboardHeight > 0) { return false; } try { @@ -348,7 +484,7 @@ public class SelfStoryViewsView extends FrameLayout { 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 class SelfStoryViewsView extends FrameLayout { } } + 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 000000000..576cbc835 --- /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 ae830706e..11e61e965 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 @@ package org.telegram.ui.Stories; 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.AccountInstance; 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.messenger.support.LongSparseIntArray; 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.Iterator; 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 class StoriesController { 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 class StoriesController { 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 @@ public class StoriesController { 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 @@ public class StoriesController { 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 @@ public class StoriesController { } 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 @@ public class StoriesController { preloadUserStories(stories); } } + FileLog.d("StoriesController applyNewStories " + stories.user_id); updateStoriesInLists(stories.user_id, stories.stories); } @@ -576,7 +613,7 @@ public class StoriesController { 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 class StoriesController { 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 class StoriesController { 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 class StoriesController { }); } + 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 @@ public class StoriesController { 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 class StoriesController { 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 class StoriesController { 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 class StoriesController { // 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 @@ public class StoriesController { } 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 class StoriesController { } } - 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 class StoriesController { 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 @@ public class StoriesController { 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 class StoriesController { 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 class StoriesController { 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 @@ public class StoriesController { } 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 @@ public class StoriesController { 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 @@ public class StoriesController { 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 @@ public class StoriesController { 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 @@ public class StoriesController { 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 @@ public class StoriesController { 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 @@ public class StoriesController { 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 @@ public class StoriesController { } } } + 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 @@ public class StoriesController { 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 class StoriesController { } 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 class StoriesController { 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 @@ public class StoriesController { 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 @@ public class StoriesController { 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 @@ public class StoriesController { } 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 @@ public class StoriesController { 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 class StoriesController { 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 class StoriesController { 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 class StoriesController { // } public void updateDeletedStories(List storyItems) { + FileLog.d("StoriesList " + type + "{"+userId+"} updateDeletedStories {" + storyItemIds(storyItems) + "}"); if (storyItems == null) { return; } @@ -2136,6 +2355,7 @@ public class StoriesController { } public void updateStories(List storyItems) { + FileLog.d("StoriesList " + type + "{"+userId+"} updateStories {" + storyItemIds(storyItems) + "}"); if (storyItems == null) { return; } @@ -2153,11 +2373,13 @@ public class StoriesController { 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 class StoriesController { } 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 class StoriesController { 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 000000000..137bf0769 --- /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 a18df5b67..b3e0e61cb 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 class StoriesListPlaceProvider implements StoryViewer.PlaceProvider { 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 class StoriesListPlaceProvider implements StoryViewer.PlaceProvider { @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 class StoriesListPlaceProvider implements StoryViewer.PlaceProvider { 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 class StoriesListPlaceProvider implements StoryViewer.PlaceProvider { if (isHiddenArchive) { holder.crossfadeToAvatarImage = cell.avatarImage; } + holder.alpha = 1; updateClip(holder); return true; } @@ -115,6 +129,7 @@ public class StoriesListPlaceProvider implements StoryViewer.PlaceProvider { holder.storyImage = cell.replyImageReceiver; } holder.clipParent = (View) cell.getParent(); + holder.alpha = 1; updateClip(holder); return true; } @@ -129,6 +144,7 @@ public class StoriesListPlaceProvider implements StoryViewer.PlaceProvider { holder.storyImage = cell.getPhotoImage(); } holder.clipParent = (View) cell.getParent(); + holder.alpha = 1; updateClip(holder); return true; } @@ -156,6 +172,7 @@ public class StoriesListPlaceProvider implements StoryViewer.PlaceProvider { } }; holder.clipParent = (View) cell.getParent(); + holder.alpha = 1; updateClip(holder); return true; } @@ -166,6 +183,7 @@ public class StoriesListPlaceProvider implements StoryViewer.PlaceProvider { 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 class StoriesListPlaceProvider implements StoryViewer.PlaceProvider { 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 class StoriesListPlaceProvider implements StoryViewer.PlaceProvider { holder.params = cell.avatarStoryParams; holder.avatarImage = cell.avatarImage; holder.clipParent = (View) cell.getParent(); + holder.alpha = 1; updateClip(holder); return true; } @@ -211,6 +235,21 @@ public class StoriesListPlaceProvider implements StoryViewer.PlaceProvider { } } + @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 class StoriesListPlaceProvider implements StoryViewer.PlaceProvider { 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 ec44cd255..8f5016e4d 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.SQLite.SQLitePreparedStatement; 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.HashSet; 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 class StoriesStorage { 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 class StoriesStorage { 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 class StoriesStorage { 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 class StoriesStorage { 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 @@ public class StoriesStorage { 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 @@ public class StoriesStorage { 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 class StoriesStorage { 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 class StoriesStorage { } 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 class StoriesStorage { 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 class StoriesStorage { } 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 @@ public class StoriesStorage { 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 @@ public class StoriesStorage { 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 @@ public class StoriesStorage { 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 @@ public class StoriesStorage { } 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 @@ public class StoriesStorage { } 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 @@ public class StoriesStorage { } 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 class StoriesStorage { 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 class StoriesStorage { } //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 class StoriesStorage { 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 class StoriesStorage { 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 dc39fb335..0a0009233 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.GradientTools; 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 class StoriesUtilities { } if (state == STATE_PROGRESS) { params.animateFromUnreadState = unreadState; + params.progressToProgressSegments = 0; } if (animated) { params.prevState = params.currentState; @@ -216,10 +221,10 @@ public class StoriesUtilities { 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 class StoriesUtilities { unreadPaint.setAlpha(255); closeFriendsPaint = getCloseFriendsPaint(avatarImage); closeFriendsPaint.setAlpha(255); - checkGrayPaint(); + checkGrayPaint(params.resourcesProvider); } float inset; if (params.drawSegments) { @@ -247,100 +252,7 @@ public class StoriesUtilities { 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 class StoriesUtilities { 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 class StoriesUtilities { } 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 class StoriesUtilities { } } + 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 @@ public class StoriesUtilities { } } - 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 @@ public class StoriesUtilities { 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 @@ public class StoriesUtilities { } } - 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 class StoriesUtilities { 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 class StoriesUtilities { 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 class StoriesUtilities { 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 class StoriesUtilities { 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 class StoriesUtilities { public boolean drawHiddenStoriesAsSegments; public long crossfadeToDialog; public float crossfadeToDialogProgress; + public float progressToProgressSegments; private long dialogId; public int currentState; @@ -786,9 +973,17 @@ public class StoriesUtilities { ButtonBounce buttonBounce; public boolean allowLongress = false; + public Theme.ResourcesProvider resourcesProvider; + public AvatarStoryParams(boolean isStoryCell) { - this.isStoryCell = 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 class StoriesUtilities { } 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 @@ public class StoriesUtilities { })); } - 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 b66ac70ac..39ea58819 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 androidx.viewpager.widget.ViewPager; 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 class StoriesViewPager extends ViewPager { }; 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 class StoriesViewPager extends ViewPager { 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 class StoriesViewPager extends ViewPager { addOnPageChangeListener(new OnPageChangeListener() { - @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { selectedPosition = position; @@ -175,6 +177,13 @@ public class StoriesViewPager extends ViewPager { } 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 @@ public class StoriesViewPager extends ViewPager { 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 class StoriesViewPager extends ViewPager { AndroidUtilities.runOnUIThread(lockTouchRunnable, duration); } + public ArrayList getDialogIds() { + return dialogs; + } + private class PageLayout extends FrameLayout { public PeerStoriesView peerStoryView; @@ -412,4 +445,40 @@ public class StoriesViewPager extends ViewPager { } } + 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 67392a842..2db9e5586 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.Color; 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.Spannable; 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.DynamicAnimation; 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 class StoryCaptionView extends NestedScrollView { } 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 class StoryCaptionView extends NestedScrollView { 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 class StoryCaptionView extends NestedScrollView { 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 class StoryCaptionView extends NestedScrollView { } 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); - 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; + 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; + + float progressToExpand; + //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 class StoryCaptionView extends NestedScrollView { 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 = ""; } - isSpoilersRevealed = false; - // invalidateSpoilers(); - this.text = text; - sizeCached = 0; - if (getMeasuredWidth() > 0) { - createLayout(getMeasuredWidth()); + if (TextUtils.equals(state[0].text, text)) { + state[0].translating = translating; + invalidate(); + return; } - requestLayout(); - invalidate(); + isSpoilersRevealed = false; + 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; + } + } + + 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 @@ public class StoryCaptionView extends NestedScrollView { 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 @@ public class StoryCaptionView extends NestedScrollView { 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); - } - } - 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 class StoryCaptionView extends NestedScrollView { 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 StoryCaptionView extends NestedScrollView { @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; - } + if (state == null || state[0].fullLayout == null) { + return 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; - } - + boolean linkResult = state[0].touch(event); boolean b = linkResult || super.onTouchEvent(event); return b; } @@ -926,21 +1157,12 @@ public class StoryCaptionView extends NestedScrollView { @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 class StoryCaptionView extends NestedScrollView { @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 8ada537bf..c9ddbdde3 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 @@ public class StoryContainsEmojiButton extends View { 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 000000000..8ffaf3436 --- /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 000000000..a61474522 --- /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 e401c71fd..5b30b972b 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 62fe0795f..39a35e3ea 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.graphics.SurfaceTexture; 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 androidx.viewpager.widget.ViewPager; 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.FileStreamLoadOperation; 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.tgnet.TLRPC; 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 org.telegram.ui.LaunchActivity; 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 class StoryViewer { 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 class StoryViewer { @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 class StoryViewer { openCloseAnimator = null; } if (isShowing) { + doOnAnimationReadyRunnables.clear(); return; } ATTACH_TO_FRAGMENT = !AndroidUtilities.isTablet(); @@ -326,6 +339,7 @@ public class StoryViewer { progressToDismiss = 0; isShowing = true; isLongpressed = false; + isTranslating = false; savedPositions.clear(); AndroidUtilities.cancelRunOnUIThread(longPressRunnable); windowLayoutParams = new WindowManager.LayoutParams(); @@ -369,23 +383,14 @@ public class StoryViewer { @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 class StoryViewer { } else { selfStoriesViewsOffset += distanceY; } + Bulletin.hideVisible(windowView); storiesViewPager.getCurrentPeerView().invalidate(); containerView.invalidate(); if (selfStoriesViewsOffset < 0) { @@ -431,6 +437,7 @@ public class StoryViewer { k = 0.3f; } swipeToDismissOffset -= distanceY * k; + Bulletin.hideVisible(windowView); updateProgressToDismiss(); return true; } @@ -687,9 +694,17 @@ public class StoryViewer { 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 class StoryViewer { 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 class StoryViewer { } 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 class StoryViewer { 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 class StoryViewer { 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 class StoryViewer { } 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 class StoryViewer { delayedTapRunnable = null; } setInTouchMode(false); + verticalScrollDetected = false; } boolean selfViewsViewVisible = selfStoryViewsView != null && selfStoryViewsView.progressToOpen == 1f; if (!inSwipeToDissmissMode && !selfViewsViewVisible) { @@ -933,7 +956,7 @@ public class StoryViewer { 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 @@ public class StoryViewer { 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 @@ public class StoryViewer { 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 @@ public class StoryViewer { 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 class StoryViewer { 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 class StoryViewer { 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 class StoryViewer { updatePlayingMode(); } + @Override + public void setIsLikesReaction(boolean show) { + StoryViewer.this.isLikesReactions = show; + updatePlayingMode(); + } + @Override public int getKeyboardHeight() { return realKeyboardHeight; @@ -1385,6 +1451,9 @@ public class StoryViewer { } AndroidUtilities.removeFromParent(aspectRatioFrameLayout); windowView.addView(aspectRatioFrameLayout); + if (surfaceView != null) { + surfaceView.setVisibility(View.INVISIBLE); + } AndroidUtilities.removeFromParent(containerView); windowView.addView(containerView); @@ -1463,9 +1532,12 @@ public class StoryViewer { 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 class StoryViewer { 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 @@ public class StoryViewer { } 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 class StoryViewer { 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 @@ public class StoryViewer { 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 class StoryViewer { } 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 class StoryViewer { 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 class StoryViewer { 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 @@ public class StoryViewer { 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 class StoryViewer { 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 class StoryViewer { 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 class StoryViewer { } globalInstances.remove(this); + doOnAnimationReadyRunnables.clear(); selfStoriesViewsOffset = 0; lastStoryItem = null; } @@ -2100,6 +2219,9 @@ public class StoryViewer { public boolean onBackPressed() { if (selfStoriesViewsOffset != 0) { + if (selfStoryViewsView.onBackPressed()) { + return true; + } cancelSwipeToViews(false); return true; } else if (closeKeyboardOrEmoji()) { @@ -2116,7 +2238,7 @@ public class StoryViewer { 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 class StoryViewer { realKeyboardHeight = keyboardHeight; storiesViewPager.setKeyboardHeight(keyboardHeight); storiesViewPager.requestLayout(); + if (selfStoryViewsView != null) { + selfStoryViewsView.setKeyboardHeight(keyboardHeight); + } } } @@ -2294,13 +2419,67 @@ public class StoryViewer { } 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 class StoryViewer { 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 class StoryViewer { crossfadeToAvatarImage = null; clipTop = 0; clipBottom = 0; + storyId = 0; + bgPaint = null; + alpha = 1; } } @@ -2540,8 +2726,12 @@ public class StoryViewer { 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 d8faa683b..000000000 --- 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 60bfb97e3..9b9c4ff9e 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 class ButtonWithCounterView extends FrameLayout { setWillNotDraw(false); } - public void setText(String newText, boolean animated) { + public void setText(CharSequence newText, boolean animated) { if (animated) { text.cancelAnimation(); } @@ -215,6 +215,8 @@ public class ButtonWithCounterView extends FrameLayout { private CircularProgressDrawable loadingDrawable; + private int globalAlpha = 255; + @Override protected void onDraw(Canvas canvas) { rippleView.draw(canvas); @@ -248,7 +250,7 @@ public class ButtonWithCounterView extends FrameLayout { (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 @@ public class ButtonWithCounterView extends FrameLayout { 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 class ButtonWithCounterView extends FrameLayout { 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 1d431a7f5..2018b6448 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.core.graphics.ColorUtils; 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 class CaptionContainerView extends FrameLayout { } } + 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 class CaptionContainerView extends FrameLayout { } 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 class CaptionContainerView extends FrameLayout { 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 class CaptionContainerView extends FrameLayout { 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 @@ public class CaptionContainerView extends FrameLayout { 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 class CaptionContainerView extends FrameLayout { 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 class CaptionContainerView extends FrameLayout { } } + 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 @@ public class CaptionContainerView extends FrameLayout { } 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 @@ public class CaptionContainerView extends FrameLayout { 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 @@ public class CaptionContainerView extends FrameLayout { 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 64d528b2c..761aa4509 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 @@ public class DownloadButton extends ImageView { 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 90deeb0fc..a93706e5f 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 android.util.Log; 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 class DraftsController { 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 class DraftsController { 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 class DraftsController { 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 class DraftsController { 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 class DraftsController { 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 class DraftsController { 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 class DraftsController { 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 class DraftsController { 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 class DraftsController { 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 class DraftsController { 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 class DraftsController { 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 class DraftsController { 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 class DraftsController { 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 ed79e7031..991b78695 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 class DualCameraView extends CameraView implements CameraController.Error -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 class DualCameraView extends CameraView implements CameraController.Error -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 02e432140..0ea721d7a 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.BitmapShader; 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.ImageLocation; 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 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. public int spanCount = 8; - public int currentType; - public Page(Context context) { super(context); @@ -161,7 +563,7 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. return; } if (onDocumentSelected != null) { - onDocumentSelected.run(document); + onDocumentSelected.run(null, document, false); } dismiss(); }); @@ -262,6 +664,8 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. } private float lockTop = -1; + + @Override public float top() { if (lockTop >= 0) { return lockTop; @@ -284,6 +688,7 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. return lockTop + listView.getPaddingTop(); } + @Override public void updateTops() { float top = Math.max(0, top()); tabsStrip.setTranslationY(dp(16) + top); @@ -302,8 +707,9 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 class EmojiBottomSheet extends BottomSheet implements NotificationCenter. } 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 class EmojiBottomSheet extends BottomSheet implements NotificationCenter. // 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 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. } 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 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. if (blurBitmapMatrix == null) { blurBitmapMatrix = new Matrix(); } - blurBitmapMatrix.postScale(8, 8); + blurBitmapMatrix.postScale(scale, scale); blurBitmapShader.setLocalMatrix(blurBitmapMatrix); invalidate(); } @@ -982,16 +1423,15 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. } @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 class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. }); 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 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 class EmojiBottomSheet extends BottomSheet implements NotificationCenter. 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 @@ public class EmojiBottomSheet extends BottomSheet implements NotificationCenter. ); } } + + 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 a9533642a..2d18cd04c 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 static org.telegram.messenger.AndroidUtilities.dpf2; 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.PorterDuffColorFilter; 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.ViewConfiguration; 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.GridLayoutManager; 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 @@ import java.util.HashMap; 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 class GalleryListView extends FrameLayout implements NotificationCenter.N 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 class GalleryListView extends FrameLayout implements NotificationCenter.N } } + 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 @@ public class GalleryListView extends FrameLayout implements NotificationCenter.N 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 class GalleryListView extends FrameLayout implements NotificationCenter.N 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 @@ public class GalleryListView extends FrameLayout implements NotificationCenter.N } } - private static class HeaderView extends TextView { + private class HeaderView extends FrameLayout { + + public TextView textView; + public ImageView searchButton; + public HeaderView(Context context, boolean onlyPhotos) { super(context); + setPadding(dp(onlyPhotos ? 14 : 16), dp(16), dp(8), dp(10)); - setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - setTextColor(0xFFFFFFFF); - setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); - setPadding(dp(16), dp(16), dp(21), 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)); + } - setText(LocaleController.getString(onlyPhotos ? R.string.AddImage : R.string.ChoosePhotoOrVideo)); + 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 class GalleryListView extends FrameLayout implements NotificationCenter.N } 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())); } - return Math.max(0, Math.min(top, getHeight())); + if (listView == null) { + return resultTop; + } + return AndroidUtilities.lerp(0, resultTop, listView.getAlpha()); } @Override @@ -1145,7 +1404,12 @@ public class GalleryListView extends FrameLayout implements NotificationCenter.N 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 @@ public class GalleryListView extends FrameLayout implements NotificationCenter.N 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 d9b85e336..4ac5d3fe0 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.Animator; 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.StaticLayout; 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 class HintView2 extends View { 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 class HintView2 extends View { 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; - } - } - 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()); - } - // 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; + 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--; + } + + leftWidth = paint.measureText(text.subSequence(0, mid).toString()); + rightWidth = paint.measureText(text.subSequence(mid, text.length()).toString().trim()); + + // 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 class HintView2 extends View { 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 class HintView2 extends View { 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 @@ public class HintView2 extends View { 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 @@ public class HintView2 extends View { 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 @@ public class HintView2 extends View { 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 @@ public class HintView2 extends View { 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 @@ public class HintView2 extends View { 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 @@ public class HintView2 extends View { 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 @@ public class HintView2 extends View { 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 @@ public class HintView2 extends View { @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 @@ public class HintView2 extends View { 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 fb39c912f..4d203b5cc 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.Rect; 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 com.google.android.gms.vision.face.FaceDetector; 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.SharedConfig; 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.UndoStore; 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai } } + @Override + public Paint getPaint(String paintKey) { + return resourcesProvider.getPaint(paintKey); + } + private ColorFilter animatedEmojiColorFilter; @Override @@ -461,43 +482,66 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai } } }; + + EmojiBottomSheet.savedPosition = 1; } private ObjectAnimator previewViewTranslationAnimator; @@ -1055,6 +1106,37 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai view.setScaleY(entity.scale); view.setRotation((float) (-entity.rotation / Math.PI * 180)); } - initialEntities = null; entitiesView.setVisibility(View.VISIBLE); } } @@ -1802,15 +1986,41 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai } } 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai }); } 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai } } + 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 @@ public class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai } 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 class PaintView extends SizeNotifierFrameLayoutPhoto implements IPhotoPai 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 000000000..a461a778d --- /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 4b9b18d1b..99d4bdb02 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.Paint; 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 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.MessagesController; import org.telegram.messenger.R; @@ -73,7 +75,9 @@ public class PreviewHighlightView extends FrameLayout { 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 class PreviewHighlightView extends FrameLayout { } 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 7f9f08ff9..3b3ef3adb 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.view.ViewConfiguration; 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.VideoEditTextureView; 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 @@ public class PreviewView extends FrameLayout { 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 class PreviewView extends FrameLayout { if (seekTo > 0) { videoPlayer.seekTo(seekTo); } + videoPlayer.setMute(entry.muted); videoTimelineView.setVideoPath(uri.toString(), entry.left, entry.right); } @@ -1081,4 +1088,12 @@ public class PreviewView extends FrameLayout { 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 a368a5b41..60a10ea92 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 class StoryEntry extends IStoryPart { 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 class StoryEntry extends IStoryPart { // paint public File paintFile; + public File paintEntitiesFile; public long averageDuration = 5000; public ArrayList mediaEntities; public List stickers; @@ -162,7 +172,7 @@ public class StoryEntry extends IStoryPart { 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 class StoryEntry extends IStoryPart { 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 class StoryEntry extends IStoryPart { } } + 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 class StoryEntry extends IStoryPart { 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 class StoryEntry extends IStoryPart { paintFile.delete(); paintFile = null; } + if (paintEntitiesFile != null) { + paintEntitiesFile.delete(); + paintEntitiesFile = null; + } } public void destroy(boolean draft) { @@ -501,6 +529,7 @@ public class StoryEntry extends IStoryPart { } 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 18d1a99b2..56c41c453 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.Rect; 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.SizeNotifierFrameLayout; 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification private class Page extends FrameLayout implements View.OnClickListener, NotificationCenter.NotificationCenterDelegate { public int pageType; + private final LongSparseArray changelog = new LongSparseArray<>(); private final ArrayList selectedUsers = new ArrayList<>(); private final HashMap> selectedUsersByGroup = new HashMap<>(); @@ -317,6 +326,13 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification } 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification .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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification participantsObj.participants.add(chatParticipant); } selectChat(id, participantsObj); - }); + }, 200); } else { MessagesController.getInstance(currentAccount).loadFullChat(id, 0, true); } @@ -458,6 +488,7 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification } } userIds.remove(id); + changelog.put(id, false); } else { Iterator>> iterator = selectedUsersByGroup.entrySet().iterator(); while (iterator.hasNext()) { @@ -473,13 +504,14 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification .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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification } } else { selectedUsersByGroup.put(id, groupUsers); + for (long userId : groupUsers) { + changelog.put(userId, true); + } updateSpans(true); updateButton(true); updateCheckboxes(true); @@ -712,6 +750,8 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification } 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification } } } + 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification } 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification // 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification } } + 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification }); 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification @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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification } } + 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification } } }); - 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification if (updateHeight != null) { updateHeight.run(); } + if (scroll) { + fullScroll(View.FOCUS_DOWN); + scroll = false; + } } }); removingSpans.clear(); @@ -3096,6 +3357,10 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification if (updateHeight != null) { updateHeight.run(); } + if (scroll) { + fullScroll(View.FOCUS_DOWN); + scroll = false; + } } }); animators.clear(); @@ -3160,6 +3425,10 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification if (updateHeight != null) { updateHeight.run(); } + if (scroll) { + fullScroll(View.FOCUS_DOWN); + scroll = false; + } } }); animators.clear(); @@ -3218,6 +3487,22 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification } 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification @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 class StoryPrivacyBottomSheet extends BottomSheet implements Notification 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification } } + 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification } 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 @@ public class StoryPrivacyBottomSheet extends BottomSheet implements Notification } 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 48547aed3..78625309b 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.Build; 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.LayoutHelper; 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg navigateTo(PAGE_PREVIEW, false); switchToEditMode(EDIT_MODE_NONE, false); - if (outputEntry != null) { - captionEdit.setText(outputEntry.caption); - } - addNotificationObservers(); } @@ -460,13 +478,13 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg if (windowView != null) { Bulletin.removeDelegate(windowView); } + if (captionContainer != null) { + Bulletin.removeDelegate(captionContainer); + } } private Runnable onCloseListener; @@ -770,9 +791,10 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg if (scrollingX) { r = modeSwitcherView.stopScroll(velocityX) || r; } + galleryClosing = false; scrollingY = false; scrollingX = false; return r; @@ -1320,6 +1343,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg }); previewView.setVisibility(View.GONE); previewView.whenError(() -> { + videoError = true; previewButtons.setShareEnabled(false); downloadButton.showFailedVideo(); }); @@ -1568,11 +1606,62 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } private void upload(boolean asStory) { - applyPaint(true); + applyPaint(); if (outputEntry == null) { close(true); return; @@ -1922,7 +2051,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg }); } } + + @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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg galleryListView = null; galleryOpenCloseAnimator = null; galleryListViewOpening = null; + captionEdit.keyboardNotifier.ignore(currentPage != PAGE_PREVIEW); } }); galleryOpenCloseAnimator.setDuration(450L); @@ -2948,7 +3053,10 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg @Override protected void onGalleryClick() { + captionEdit.keyboardNotifier.ignore(true); destroyGalleryListView(); createGalleryListView(true); animateGalleryListView(true); @@ -3249,7 +3389,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg @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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg removeCurrentEntity(); } super.onEntityDragEnd(delete); + multitouch = false; } @Override @@ -3278,6 +3419,28 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg // privacySelector.setVisibility(View.VISIBLE); if (isVideo) { muteButton.setVisibility(View.VISIBLE); + playButton.setVisibility(View.VISIBLE); } videoTimelineView.setVisibility(View.VISIBLE); } @@ -3456,6 +3620,7 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg } } - private void applyPaint(boolean drawEntities) { + private void applyPaint() { if (paintView == null || outputEntry == null) { return; } @@ -3484,17 +3649,41 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 @@ public class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg 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 class StoryRecorder implements NotificationCenter.NotificationCenterDeleg SourceView getView(); } + 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 void appendColors() { + sparseIntArray.append(Theme.key_dialogBackground, 0xFF1E1E1E); + sparseIntArray.append(Theme.key_windowBackgroundGray, 0xFF000000); + } + }; + } + + @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; - 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; - } - @Override - public Activity getParentActivity() { - return StoryRecorder.this.activity; - } - }, 0, false); - sheet.setOnDismissListener(d -> { - if (previewView != null) { - previewView.updatePauseReason(4, false); - } - }); - sheet.show(); - })).show(true); + + 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 1998a851f..cae833713 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 class ThemePreviewActivity extends BaseFragment implements DownloadContro 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 6892e565f..d1611b250 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 class TwoStepVerificationSetupActivity extends BaseFragment { 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 @@ public class TwoStepVerificationSetupActivity extends BaseFragment { 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 @@ public class TwoStepVerificationSetupActivity extends BaseFragment { 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 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 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 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 SPNhNs0000V@L(# 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 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 000000000..084a0fb5d --- /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 1c7d94f12..ce527feca 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 62ecb8b93..9f0b2df9d 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 b20a2c85c..2f7d61dd6 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 b9ac4c354..384c31343 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 43efbca00..f4d988618 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 class HuaweiMapsProvider implements IMapsProvider { return huaweiMap.getMaxZoomLevel(); } + @Override + public float getMinZoomLevel() { + return huaweiMap.getMinZoomLevel(); + } + @SuppressLint("MissingPermission") @Override public void setMyLocationEnabled(boolean enabled) { @@ -156,6 +161,11 @@ public class HuaweiMapsProvider implements IMapsProvider { }); } + @Override + public void setOnCameraIdleListener(Runnable callback) { + huaweiMap.setOnCameraIdleListener(callback::run); + } + @Override public CameraPosition getCameraPosition() { com.huawei.hms.maps.model.CameraPosition pos = huaweiMap.getCameraPosition();